Home | History | Annotate | Line # | Download | only in isibootd
isibootd.c revision 1.3.26.1
      1  1.3.26.1    martin /*	$NetBSD: isibootd.c,v 1.3.26.1 2021/02/07 13:54:01 martin Exp $	*/
      2       1.1   tsutsui /*	Id: isiboot.c,v 1.2 1999/12/26 14:33:33 nisimura Exp 	*/
      3       1.1   tsutsui 
      4       1.1   tsutsui /*-
      5       1.1   tsutsui  * Copyright (c) 2000, 2011 The NetBSD Foundation, Inc.
      6       1.1   tsutsui  * All rights reserved.
      7       1.1   tsutsui  *
      8       1.1   tsutsui  * This code is derived from software contributed to The NetBSD Foundation
      9       1.1   tsutsui  * by Tohru Nishimura.
     10       1.1   tsutsui  *
     11       1.1   tsutsui  * Redistribution and use in source and binary forms, with or without
     12       1.1   tsutsui  * modification, are permitted provided that the following conditions
     13       1.1   tsutsui  * are met:
     14       1.1   tsutsui  * 1. Redistributions of source code must retain the above copyright
     15       1.1   tsutsui  *    notice, this list of conditions and the following disclaimer.
     16       1.1   tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     17       1.1   tsutsui  *    notice, this list of conditions and the following disclaimer in the
     18       1.1   tsutsui  *    documentation and/or other materials provided with the distribution.
     19       1.1   tsutsui  *
     20       1.1   tsutsui  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21       1.1   tsutsui  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22       1.1   tsutsui  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23       1.1   tsutsui  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24       1.1   tsutsui  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25       1.1   tsutsui  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26       1.1   tsutsui  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27       1.1   tsutsui  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28       1.1   tsutsui  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29       1.1   tsutsui  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30       1.1   tsutsui  * POSSIBILITY OF SUCH DAMAGE.
     31       1.1   tsutsui  */
     32       1.1   tsutsui 
     33       1.1   tsutsui #include <sys/param.h>
     34       1.1   tsutsui #include <sys/types.h>
     35       1.1   tsutsui #include <sys/endian.h>
     36       1.1   tsutsui #include <sys/ioctl.h>
     37       1.1   tsutsui #include <sys/socket.h>
     38       1.1   tsutsui 
     39       1.1   tsutsui #include <net/bpf.h>
     40       1.1   tsutsui #include <net/if.h>
     41       1.1   tsutsui #include <net/if_dl.h>
     42       1.1   tsutsui #include <net/if_ether.h>
     43       1.1   tsutsui 
     44       1.1   tsutsui #include <err.h>
     45       1.1   tsutsui #include <fcntl.h>
     46       1.1   tsutsui #include <ifaddrs.h>
     47       1.1   tsutsui #include <netdb.h>
     48       1.1   tsutsui #include <paths.h>
     49       1.1   tsutsui #include <poll.h>
     50       1.1   tsutsui #include <stddef.h>
     51       1.1   tsutsui #include <stdio.h>
     52       1.1   tsutsui #include <stdlib.h>
     53       1.1   tsutsui #include <string.h>
     54       1.1   tsutsui #include <unistd.h>
     55       1.1   tsutsui #include <util.h>
     56       1.1   tsutsui 
     57       1.1   tsutsui #define	TRACE(l, x) if ((l) <= dbg) printf x
     58       1.1   tsutsui 
     59       1.1   tsutsui /*
     60       1.3  nisimura  * Integrated Solutions Inc. "ISIBOOT" boot enet protocol.
     61       1.1   tsutsui  *
     62       1.1   tsutsui  * Following data format depends on m68k order, and aligned harmful
     63       1.1   tsutsui  * to RISC processors.
     64       1.1   tsutsui  */
     65       1.3  nisimura #define	ISIBOOT_FRAMETYPE	0x80df
     66       1.3  nisimura #define	ISIBOOT_FRAMELEN	1468
     67       1.1   tsutsui struct frame {
     68       1.1   tsutsui 	uint8_t dst[ETHER_ADDR_LEN];
     69       1.1   tsutsui 	uint8_t src[ETHER_ADDR_LEN];
     70       1.1   tsutsui 	uint16_t type;
     71       1.1   tsutsui 	uint16_t pad_0;
     72       1.1   tsutsui 	uint16_t seqno;
     73       1.1   tsutsui 	uint8_t opcode;
     74       1.1   tsutsui 	uint8_t pad_1;
     75       1.1   tsutsui 	uint8_t pos[4];
     76       1.1   tsutsui 	uint8_t siz[4];
     77       1.3  nisimura 	uint8_t data[ISIBOOT_FRAMELEN - 28];
     78       1.1   tsutsui } __packed;
     79       1.1   tsutsui 
     80       1.1   tsutsui struct station {
     81       1.1   tsutsui 	int 	fd;
     82       1.1   tsutsui 	char	name[MAXHOSTNAMELEN];
     83       1.1   tsutsui 	char	ifname[IFNAMSIZ];
     84       1.1   tsutsui 	uint8_t addr[ETHER_ADDR_LEN];
     85       1.1   tsutsui } station;
     86       1.1   tsutsui 
     87       1.1   tsutsui struct session {
     88       1.1   tsutsui 	struct session *next;
     89       1.1   tsutsui 	int state;
     90       1.1   tsutsui 	FILE *file;
     91       1.1   tsutsui 	uint8_t addr[ETHER_ADDR_LEN];
     92       1.1   tsutsui } *activelist, *freelist;
     93       1.1   tsutsui #define	NEWPOOL 10
     94       1.1   tsutsui 
     95       1.1   tsutsui #define	WAITING	0	/* implicit state after receiving the first frame */
     96       1.1   tsutsui #define	OPENING	1	/* waiting for OPEN after CONNECT is received */
     97       1.1   tsutsui #define	TRANSFER 2	/* data transferring state after OPEN is well done */
     98       1.1   tsutsui static __unused const char *state[] = { "WAITING", "OPENING", "TRANSFER" };
     99       1.1   tsutsui 
    100       1.1   tsutsui #define	CONNECT	0
    101       1.1   tsutsui #define	OPEN	1
    102       1.1   tsutsui #define	READ	2
    103       1.1   tsutsui #define	CLOSE	4
    104       1.1   tsutsui static __unused const char *op[] =
    105       1.1   tsutsui     { "CONNECT", "OPEN", "READ", "WRITE", "CLOSE", "FIND" };
    106       1.1   tsutsui 
    107       1.1   tsutsui static void createbpfport(char *, uint8_t **, size_t *, struct station *);
    108       1.1   tsutsui static struct session *search(uint8_t *);
    109       1.1   tsutsui static void closedown(struct session *);
    110       1.1   tsutsui static void makepool(void);
    111       1.1   tsutsui static char *etheraddr(uint8_t *);
    112       1.1   tsutsui static int pickif(char *, uint8_t *);
    113       1.1   tsutsui static __dead void usage(void);
    114       1.1   tsutsui 
    115       1.3  nisimura #define	ISIBOOT_FRAME(buf)	((buf) + ((struct bpf_hdr *)(buf))->bh_hdrlen)
    116       1.1   tsutsui 
    117       1.1   tsutsui #define	PATH_DEFBOOTDIR	"/tftpboot"
    118       1.1   tsutsui 
    119       1.1   tsutsui int
    120       1.1   tsutsui main(int argc, char *argv[])
    121       1.1   tsutsui {
    122       1.1   tsutsui 	int cc, dbg, dflag;
    123       1.1   tsutsui 	size_t iolen;
    124       1.1   tsutsui 	uint32_t pos, siz;
    125       1.1   tsutsui 	size_t nread;
    126       1.1   tsutsui 	char *ifname, *p;
    127       1.1   tsutsui 	const char *bootwd, *servername, *filename;
    128       1.1   tsutsui 	uint8_t *iobuf;
    129       1.1   tsutsui 	struct session *cp;
    130       1.1   tsutsui 	struct frame *fp;
    131       1.1   tsutsui 	struct pollfd pollfd;
    132       1.1   tsutsui 	char clientname[MAXHOSTNAMELEN + 1];
    133       1.1   tsutsui 	struct hostent *clientent;
    134       1.1   tsutsui 
    135       1.1   tsutsui 	ifname = NULL;
    136       1.1   tsutsui 	bootwd = PATH_DEFBOOTDIR;
    137       1.1   tsutsui 	dbg = 0;
    138       1.1   tsutsui 	dflag = 0;
    139       1.1   tsutsui 	while ((cc = getopt(argc, argv, "i:s:d:")) != -1) {
    140       1.1   tsutsui 		switch (cc) {
    141       1.1   tsutsui 		case 'i':
    142       1.1   tsutsui 			ifname = optarg;
    143       1.1   tsutsui 			break;
    144       1.1   tsutsui 		case 's':
    145       1.1   tsutsui 			bootwd = optarg;
    146       1.1   tsutsui 			break;
    147       1.1   tsutsui 		case 'd':
    148       1.1   tsutsui 			dflag = 1;
    149       1.1   tsutsui 			dbg = atoi(optarg);
    150       1.1   tsutsui 			break;
    151       1.1   tsutsui 		default:
    152       1.1   tsutsui 			usage();
    153       1.1   tsutsui 			/* NOTREACHED */
    154       1.1   tsutsui 		}
    155       1.1   tsutsui 	}
    156       1.1   tsutsui 	argv += optind;
    157       1.1   tsutsui 	argc -= optind;
    158       1.1   tsutsui 
    159       1.1   tsutsui 	if (geteuid() != 0)
    160       1.1   tsutsui 		warnx("WARNING: run by non root priviledge");
    161       1.1   tsutsui 
    162       1.1   tsutsui 	memset(station.name, 0, sizeof(station.name));
    163       1.1   tsutsui 	gethostname(station.name, sizeof(station.name) - 1);
    164       1.1   tsutsui 	if ((p = strchr(station.name, '.')) != NULL)
    165       1.1   tsutsui 		*p = '\0';
    166       1.1   tsutsui 
    167       1.1   tsutsui 	createbpfport(ifname, &iobuf, &iolen, &station);
    168       1.1   tsutsui 
    169       1.1   tsutsui 	TRACE(1, ("Using interface: %s (%s)\n",
    170       1.1   tsutsui 	    station.ifname, etheraddr(station.addr)));
    171       1.1   tsutsui 
    172       1.1   tsutsui 	if (!dflag) {
    173       1.1   tsutsui 		if (daemon(0, 0))
    174       1.1   tsutsui 			err(EXIT_FAILURE, "can not start daemon");
    175       1.1   tsutsui #ifdef __NetBSD__
    176       1.1   tsutsui 		pidfile(NULL);
    177       1.1   tsutsui #endif
    178       1.1   tsutsui 	}
    179       1.1   tsutsui 
    180       1.1   tsutsui 	if (chdir(bootwd) < 0)
    181       1.1   tsutsui 		err(EXIT_FAILURE, "can not chdir to %s", bootwd);
    182       1.1   tsutsui 
    183       1.1   tsutsui 	pollfd.fd = station.fd;
    184       1.1   tsutsui 	pollfd.events = POLLIN;
    185       1.1   tsutsui 	for (;;) {
    186       1.1   tsutsui 		poll(&pollfd, 1, INFTIM);
    187       1.1   tsutsui 		read(pollfd.fd, iobuf, iolen);	/* returns 1468 */
    188       1.3  nisimura 		fp = (struct frame *)ISIBOOT_FRAME(iobuf);
    189       1.1   tsutsui 
    190       1.1   tsutsui 		/* ignore own TX packets */
    191       1.1   tsutsui 		if (memcmp(fp->src, station.addr, ETHER_ADDR_LEN) == 0)
    192       1.1   tsutsui 			continue;
    193       1.1   tsutsui 
    194       1.1   tsutsui 		/* check if the received Ethernet address is in ethers(5) */
    195       1.1   tsutsui 		if (ether_ntohost(clientname, (struct ether_addr *)fp->src)) {
    196       1.1   tsutsui 			TRACE(3, ("'%s' is not in ethers(5)\n",
    197       1.1   tsutsui 			    etheraddr(fp->src)));
    198       1.1   tsutsui 			continue;
    199       1.1   tsutsui 		}
    200       1.1   tsutsui 		/* check if the client has a valid hostname */
    201       1.1   tsutsui 		clientname[sizeof(clientname) - 1] = '\0';
    202       1.1   tsutsui 		clientent = gethostbyname(clientname);
    203       1.1   tsutsui 		if (clientent == NULL || clientent->h_addrtype != AF_INET) {
    204       1.1   tsutsui 			TRACE(3, ("'%s' is not a valid host\n", clientname));
    205       1.1   tsutsui 			continue;
    206       1.1   tsutsui 		}
    207       1.1   tsutsui 
    208       1.1   tsutsui 		cp = search(fp->src);
    209       1.1   tsutsui 		TRACE(2, ("[%s] ", etheraddr(fp->src)));
    210       1.1   tsutsui 		switch (cp->state) {
    211       1.1   tsutsui 		case WAITING:
    212       1.1   tsutsui 			if (fp->opcode != CONNECT) {
    213       1.1   tsutsui 				TRACE(2, ("not connected\n"));
    214       1.1   tsutsui 				continue;
    215       1.1   tsutsui 			}
    216       1.1   tsutsui 			/* check if specified servername is mine */
    217       1.1   tsutsui 			fp->data[sizeof(fp->data) - 1] = '\0';
    218       1.1   tsutsui 			servername = (char *)fp->data;
    219       1.1   tsutsui 			if (strcmp(servername, station.name) != 0) {
    220       1.1   tsutsui 				TRACE(3, ("'%s' not for me\n", servername));
    221       1.1   tsutsui 				continue;
    222       1.1   tsutsui 			}
    223       1.1   tsutsui 			cp->state = OPENING;
    224       1.1   tsutsui 			TRACE(2, ("new connection\n"));
    225       1.1   tsutsui 			break;
    226       1.1   tsutsui 		case OPENING:
    227       1.1   tsutsui 			if (fp->opcode != OPEN)
    228       1.1   tsutsui 				goto aborting;	/* out of phase */
    229       1.1   tsutsui 
    230       1.1   tsutsui 			/* don't allow files outside the specified dir */
    231       1.1   tsutsui 			fp->data[sizeof(fp->data) - 1] = '\0';
    232       1.1   tsutsui 			filename = strrchr((char *)fp->data, '/');
    233       1.1   tsutsui 			if (filename != NULL)
    234       1.1   tsutsui 				filename++;
    235       1.1   tsutsui 			else
    236       1.1   tsutsui 				filename = (char *)fp->data;
    237       1.1   tsutsui 
    238       1.1   tsutsui 			cp->file = fopen(filename, "r");
    239       1.1   tsutsui 			if (cp->file == NULL) {
    240       1.1   tsutsui 				TRACE(1, ("failed to open '%s'\n", filename));
    241       1.1   tsutsui 				goto closedown;	/* no such file */
    242       1.1   tsutsui 			}
    243       1.1   tsutsui 			cp->state = TRANSFER;
    244       1.1   tsutsui 			TRACE(2, ("open '%s'\n", filename));
    245       1.1   tsutsui 			break;
    246       1.1   tsutsui 		case TRANSFER:
    247       1.1   tsutsui 			if (fp->opcode == CLOSE) {
    248       1.1   tsutsui 				TRACE(2, ("connection closed\n"));
    249       1.1   tsutsui 				goto closedown;	/* close request */
    250       1.1   tsutsui 			}
    251       1.1   tsutsui 			if (fp->opcode != READ)
    252       1.1   tsutsui 				goto aborting;	/* out of phase */
    253       1.1   tsutsui 			siz = be32dec(fp->siz);
    254       1.1   tsutsui 			pos = be32dec(fp->pos);
    255       1.1   tsutsui 			nread = siz;
    256       1.1   tsutsui 			if (nread > sizeof(fp->data) ||
    257       1.1   tsutsui 			    fseek(cp->file, pos, 0L) < 0 ||
    258       1.1   tsutsui 			    fread(fp->data, 1, nread, cp->file) < nread) {
    259       1.1   tsutsui 				be32enc(fp->siz, 0); /* corrupted file */
    260       1.1   tsutsui 			}
    261       1.1   tsutsui 			TRACE(3, ("%u@%u\n", siz, pos));
    262       1.1   tsutsui 			break;
    263       1.1   tsutsui  aborting:
    264       1.1   tsutsui 			TRACE(1, ("out of phase\n"));
    265       1.1   tsutsui  closedown:
    266       1.1   tsutsui 			closedown(cp);
    267       1.1   tsutsui 			fp->opcode = CLOSE;
    268       1.1   tsutsui 			break;
    269       1.1   tsutsui 		}
    270       1.1   tsutsui 		memcpy(fp->dst, fp->src, ETHER_ADDR_LEN);
    271       1.1   tsutsui 		memcpy(fp->src, station.addr, ETHER_ADDR_LEN);
    272       1.3  nisimura 		write(pollfd.fd, fp, ISIBOOT_FRAMELEN);
    273       1.1   tsutsui 	}
    274       1.1   tsutsui 	/* NOTREACHED */
    275       1.1   tsutsui }
    276       1.1   tsutsui 
    277       1.1   tsutsui struct session *
    278       1.1   tsutsui search(uint8_t *client)
    279       1.1   tsutsui {
    280       1.1   tsutsui 	struct session *cp;
    281       1.1   tsutsui 
    282       1.1   tsutsui 	for (cp = activelist; cp; cp = cp->next) {
    283       1.1   tsutsui 		if (memcmp(client, cp->addr, ETHER_ADDR_LEN) == 0)
    284       1.1   tsutsui 			return cp;
    285       1.1   tsutsui 	}
    286       1.1   tsutsui 	if (freelist == NULL)
    287       1.1   tsutsui 		makepool();
    288       1.1   tsutsui 	cp = freelist;
    289       1.1   tsutsui 	freelist = cp->next;
    290       1.1   tsutsui 	cp->next = activelist;
    291       1.1   tsutsui 	activelist = cp;
    292       1.1   tsutsui 
    293       1.1   tsutsui 	cp->state = WAITING;
    294       1.1   tsutsui 	cp->file = NULL;
    295       1.1   tsutsui 	memcpy(cp->addr, client, ETHER_ADDR_LEN);
    296       1.1   tsutsui 	return cp;
    297       1.1   tsutsui }
    298       1.1   tsutsui 
    299       1.1   tsutsui void
    300       1.1   tsutsui closedown(struct session *cp)
    301       1.1   tsutsui {
    302       1.1   tsutsui 	struct session *cpp;
    303       1.1   tsutsui 
    304       1.1   tsutsui 	cpp = activelist;
    305       1.1   tsutsui 	if (cpp == cp)
    306       1.1   tsutsui 		activelist = cp->next;
    307       1.1   tsutsui 	else {
    308       1.1   tsutsui 		do {
    309       1.1   tsutsui 			if (cpp->next == cp)
    310       1.1   tsutsui 				break;
    311       1.1   tsutsui 		} while (NULL != (cpp = cpp->next)); /* should never happen */
    312       1.1   tsutsui 		cpp->next = cp->next;
    313       1.1   tsutsui 	}
    314       1.1   tsutsui 	cp->next = freelist;
    315       1.1   tsutsui 	freelist = cp;
    316       1.1   tsutsui 
    317       1.1   tsutsui 	if (cp->file != NULL)
    318       1.1   tsutsui 		fclose(cp->file);
    319       1.1   tsutsui 	cp->file = NULL;
    320       1.1   tsutsui 	memset(cp->addr, 0, ETHER_ADDR_LEN);
    321       1.1   tsutsui }
    322       1.1   tsutsui 
    323       1.1   tsutsui void
    324       1.1   tsutsui makepool(void)
    325       1.1   tsutsui {
    326       1.1   tsutsui 	struct session *cp;
    327       1.1   tsutsui 	int n;
    328       1.1   tsutsui 
    329       1.1   tsutsui 	freelist = calloc(NEWPOOL, sizeof(struct session));
    330       1.1   tsutsui 	if (freelist == NULL)
    331       1.1   tsutsui 		err(EXIT_FAILURE, "Can't allocate pool");
    332       1.1   tsutsui 	cp = freelist;
    333       1.1   tsutsui 	for (n = 0; n < NEWPOOL - 1; n++) {
    334       1.1   tsutsui 		cp->next = cp + 1;
    335       1.1   tsutsui 		cp++;
    336       1.1   tsutsui 	}
    337       1.1   tsutsui }
    338       1.1   tsutsui 
    339       1.1   tsutsui char *
    340       1.1   tsutsui etheraddr(uint8_t *e)
    341       1.1   tsutsui {
    342       1.1   tsutsui 	static char address[sizeof("xx:xx:xx:xx:xx:xx")];
    343       1.1   tsutsui 
    344       1.1   tsutsui 	snprintf(address, sizeof(address), "%02x:%02x:%02x:%02x:%02x:%02x",
    345       1.1   tsutsui 	    e[0], e[1], e[2], e[3], e[4], e[5]);
    346       1.1   tsutsui 	return address;
    347       1.1   tsutsui }
    348       1.1   tsutsui 
    349       1.1   tsutsui static struct bpf_insn bpf_insn[] = {
    350       1.1   tsutsui 	{ BPF_LD|BPF_H|BPF_ABS,  0, 0, offsetof(struct frame, type) },
    351       1.3  nisimura 	{ BPF_JMP|BPF_JEQ|BPF_K, 0, 1, ISIBOOT_FRAMETYPE },
    352       1.3  nisimura 	{ BPF_RET|BPF_K,         0, 0, ISIBOOT_FRAMELEN },
    353       1.1   tsutsui 	{ BPF_RET|BPF_K,         0, 0, 0x0 }
    354       1.1   tsutsui };
    355       1.1   tsutsui static struct bpf_program bpf_pgm = {
    356       1.1   tsutsui 	sizeof(bpf_insn) / sizeof(bpf_insn[0]),
    357       1.1   tsutsui 	bpf_insn
    358       1.1   tsutsui };
    359       1.1   tsutsui 
    360       1.1   tsutsui void
    361       1.1   tsutsui createbpfport(char *ifname, uint8_t **iobufp, size_t *iolenp,
    362       1.1   tsutsui     struct station *st)
    363       1.1   tsutsui {
    364       1.1   tsutsui 	struct ifreq ifr;
    365       1.1   tsutsui 	int fd;
    366       1.1   tsutsui 	u_int type;
    367  1.3.26.1    martin 	u_int buflen;
    368       1.1   tsutsui 	uint8_t dladdr[ETHER_ADDR_LEN], *buf;
    369       1.1   tsutsui #ifdef BIOCIMMEDIATE
    370       1.1   tsutsui 	u_int flag;
    371       1.1   tsutsui #endif
    372       1.1   tsutsui #ifndef _PATH_BPF
    373       1.1   tsutsui 	char devbpf[PATH_MAX];
    374       1.1   tsutsui 	int n;
    375       1.1   tsutsui #endif
    376       1.1   tsutsui 
    377       1.1   tsutsui #ifdef _PATH_BPF
    378       1.1   tsutsui 	fd = open(_PATH_BPF, O_RDWR, 0);
    379       1.1   tsutsui #else
    380       1.1   tsutsui 	n = 0;
    381       1.1   tsutsui 	do {
    382       1.1   tsutsui 		snprintf(devbpf, sizeof(devbpf), "/dev/bpf%d", n++);
    383       1.1   tsutsui 		fd = open(devbpf, O_RDWR, 0);
    384       1.1   tsutsui 	} while (fd == -1 && errno == EBUSY);
    385       1.1   tsutsui #endif
    386       1.1   tsutsui 	if (fd == -1)
    387       1.1   tsutsui 		err(EXIT_FAILURE, "No bpf device available");
    388       1.1   tsutsui 	memset(&ifr, 0, sizeof(ifr));
    389       1.1   tsutsui 	if (ifname != NULL)
    390       1.1   tsutsui 		strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    391       1.1   tsutsui 	if (pickif(ifr.ifr_name, dladdr) < 0)
    392       1.1   tsutsui 		errx(EXIT_FAILURE,
    393       1.1   tsutsui 		    "No network interface available: %s\n", ifr.ifr_name);
    394       1.1   tsutsui 
    395       1.1   tsutsui 	ioctl(fd, BIOCSETIF, &ifr);
    396       1.1   tsutsui 	ioctl(fd, BIOCGDLT, &type);	/* XXX - should check whether EN10MB */
    397       1.1   tsutsui #ifdef BIOCIMMEDIATE
    398       1.1   tsutsui 	flag = 1;
    399       1.1   tsutsui 	ioctl(fd, BIOCIMMEDIATE, &flag);
    400       1.1   tsutsui #endif
    401       1.1   tsutsui 	ioctl(fd, BIOCGBLEN, &buflen);
    402       1.1   tsutsui 	ioctl(fd, BIOCSETF, &bpf_pgm);
    403       1.1   tsutsui 
    404       1.1   tsutsui 	buf = malloc(buflen);
    405       1.1   tsutsui 	if (buf == NULL)
    406       1.1   tsutsui 		err(EXIT_FAILURE, "Can't allocate buffer");
    407       1.1   tsutsui 	*iobufp = buf;
    408       1.1   tsutsui 	*iolenp = buflen;
    409       1.1   tsutsui 	st->fd = fd;
    410       1.1   tsutsui 	strlcpy(st->ifname, ifr.ifr_name, sizeof(st->ifname));
    411       1.1   tsutsui 	memcpy(st->addr, dladdr, ETHER_ADDR_LEN);
    412       1.1   tsutsui }
    413       1.1   tsutsui 
    414       1.1   tsutsui int
    415       1.1   tsutsui pickif(char *xname, uint8_t *dladdr)
    416       1.1   tsutsui {
    417       1.1   tsutsui #define	MATCH(x, v) ((v) == ((v) & (x)))
    418       1.1   tsutsui #ifndef CLLADDR
    419       1.1   tsutsui #define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
    420       1.1   tsutsui #endif
    421       1.1   tsutsui 	int s, error;
    422       1.1   tsutsui 	struct ifaddrs *ifaddrs, *ifa;
    423       1.1   tsutsui 	const struct sockaddr_dl *sdl;
    424       1.1   tsutsui 
    425       1.1   tsutsui 	error = -1;
    426       1.1   tsutsui 	s = socket(AF_INET, SOCK_DGRAM, 0);
    427       1.1   tsutsui 	if (s == -1)
    428       1.1   tsutsui 		return error;
    429       1.1   tsutsui 	if (getifaddrs(&ifaddrs) == -1)
    430       1.1   tsutsui 		goto out;
    431       1.1   tsutsui 
    432       1.1   tsutsui 	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
    433       1.1   tsutsui 		if (ifa->ifa_addr->sa_family == AF_LINK) {
    434       1.1   tsutsui 			if (MATCH(ifa->ifa_flags, IFF_UP | IFF_BROADCAST)) {
    435       1.1   tsutsui 				sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
    436       1.1   tsutsui 				if (xname[0] == '\0') {
    437       1.1   tsutsui 					strlcpy(xname, ifa->ifa_name,
    438       1.1   tsutsui 					    IFNAMSIZ);
    439       1.1   tsutsui 					memcpy(dladdr, CLLADDR(sdl),
    440       1.1   tsutsui 					    ETHER_ADDR_LEN);
    441       1.1   tsutsui 					error = 0;
    442       1.1   tsutsui 					break;
    443       1.1   tsutsui 				} else if (strcmp(xname, ifa->ifa_name) == 0) {
    444       1.1   tsutsui 					memcpy(dladdr, CLLADDR(sdl),
    445       1.1   tsutsui 					    ETHER_ADDR_LEN);
    446       1.1   tsutsui 					error = 0;
    447       1.1   tsutsui 					break;
    448       1.1   tsutsui 				}
    449       1.1   tsutsui 			}
    450       1.1   tsutsui 		}
    451       1.1   tsutsui 	}
    452       1.1   tsutsui 	freeifaddrs(ifaddrs);
    453       1.1   tsutsui  out:
    454       1.1   tsutsui 	close(s);
    455       1.1   tsutsui 	return error;
    456       1.1   tsutsui #undef MATCH
    457       1.1   tsutsui }
    458       1.1   tsutsui 
    459       1.1   tsutsui void
    460       1.1   tsutsui usage(void)
    461       1.1   tsutsui {
    462       1.1   tsutsui 
    463       1.1   tsutsui 	fprintf(stderr,
    464       1.1   tsutsui 	    "usage: %s [-d tracelevel] [-i interface] [-s directory]\n",
    465       1.1   tsutsui 	    getprogname());
    466       1.1   tsutsui 	exit(0);
    467       1.1   tsutsui }
    468