File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / bpf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (12 years ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* bpf.c
    2: 
    3:    BPF socket interface code, originally contributed by Archie Cobbs. */
    4: 
    5: /*
    6:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
    7:  * Copyright (c) 1996-2003 by Internet Software Consortium
    8:  *
    9:  * Permission to use, copy, modify, and distribute this software for any
   10:  * purpose with or without fee is hereby granted, provided that the above
   11:  * copyright notice and this permission notice appear in all copies.
   12:  *
   13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   20:  *
   21:  *   Internet Systems Consortium, Inc.
   22:  *   950 Charter Street
   23:  *   Redwood City, CA 94063
   24:  *   <info@isc.org>
   25:  *   https://www.isc.org/
   26:  *
   27:  * This software was contributed to Internet Systems Consortium
   28:  * by Archie Cobbs.
   29:  *
   30:  * Patches for FDDI support on Digital Unix were written by Bill
   31:  * Stapleton, and maintained for a while by Mike Meredith before he
   32:  * managed to get me to integrate them.
   33:  */
   34: 
   35: #include "dhcpd.h"
   36: #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)	\
   37: 				|| defined (USE_LPF_RECEIVE)
   38: # if defined (USE_LPF_RECEIVE)
   39: #  include <asm/types.h>
   40: #  include <linux/filter.h>
   41: #  define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */
   42: # else
   43: #  include <sys/ioctl.h>
   44: #  include <sys/uio.h>
   45: #  include <net/bpf.h>
   46: #  include <net/if_types.h>
   47: #  if defined (NEED_OSF_PFILT_HACKS)
   48: #   include <net/pfilt.h>
   49: #  endif
   50: # endif
   51: 
   52: #include <netinet/in_systm.h>
   53: #include "includes/netinet/ip.h"
   54: #include "includes/netinet/udp.h"
   55: #include "includes/netinet/if_ether.h"
   56: #endif
   57: 
   58: #ifdef USE_BPF_RECEIVE
   59: #include <ifaddrs.h>
   60: #endif
   61: 
   62: #include <errno.h>
   63: 
   64: /* Reinitializes the specified interface after an address change.   This
   65:    is not required for packet-filter APIs. */
   66: 
   67: #ifdef USE_BPF_SEND
   68: void if_reinitialize_send (info)
   69: 	struct interface_info *info;
   70: {
   71: }
   72: #endif
   73: 
   74: #ifdef USE_BPF_RECEIVE
   75: void if_reinitialize_receive (info)
   76: 	struct interface_info *info;
   77: {
   78: }
   79: #endif
   80: 
   81: /* Called by get_interface_list for each interface that's discovered.
   82:    Opens a packet filter for each interface and adds it to the select
   83:    mask. */
   84: 
   85: #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE)
   86: int if_register_bpf (info)
   87: 	struct interface_info *info;
   88: {
   89: 	int sock;
   90: 	char filename[50];
   91: 	int b;
   92: 
   93: 	/* Open a BPF device */
   94: 	for (b = 0; 1; b++) {
   95: 		/* %Audit% 31 bytes max. %2004.06.17,Safe% */
   96: 		sprintf(filename, BPF_FORMAT, b);
   97: 		sock = open (filename, O_RDWR, 0);
   98: 		if (sock < 0) {
   99: 			if (errno == EBUSY) {
  100: 				continue;
  101: 			} else {
  102: 				if (!b)
  103: 					log_fatal ("No bpf devices.%s%s%s",
  104: 					       "   Please read the README",
  105: 					       " section for your operating",
  106: 					       " system.");
  107: 				log_fatal ("Can't find free bpf: %m");
  108: 			}
  109: 		} else {
  110: 			break;
  111: 		}
  112: 	}
  113: 
  114: 	/* Set the BPF device to point at this interface. */
  115: 	if (ioctl (sock, BIOCSETIF, info -> ifp) < 0)
  116: 		log_fatal ("Can't attach interface %s to bpf device %s: %m",
  117: 		       info -> name, filename);
  118: 
  119: 	get_hw_addr(info->name, &info->hw_address);
  120: 
  121: 	return sock;
  122: }
  123: #endif /* USE_BPF_SEND || USE_BPF_RECEIVE */
  124: 
  125: #ifdef USE_BPF_SEND
  126: void if_register_send (info)
  127: 	struct interface_info *info;
  128: {
  129: 	/* If we're using the bpf API for sending and receiving,
  130: 	   we don't need to register this interface twice. */
  131: #ifndef USE_BPF_RECEIVE
  132: 	info -> wfdesc = if_register_bpf (info, interface);
  133: #else
  134: 	info -> wfdesc = info -> rfdesc;
  135: #endif
  136: 	if (!quiet_interface_discovery)
  137: 		log_info ("Sending on   BPF/%s/%s%s%s",
  138: 		      info -> name,
  139: 		      print_hw_addr (info -> hw_address.hbuf [0],
  140: 				     info -> hw_address.hlen - 1,
  141: 				     &info -> hw_address.hbuf [1]),
  142: 		      (info -> shared_network ? "/" : ""),
  143: 		      (info -> shared_network ?
  144: 		       info -> shared_network -> name : ""));
  145: }
  146: 
  147: void if_deregister_send (info)
  148: 	struct interface_info *info;
  149: {
  150: 	/* If we're using the bpf API for sending and receiving,
  151: 	   we don't need to register this interface twice. */
  152: #ifndef USE_BPF_RECEIVE
  153: 	close (info -> wfdesc);
  154: #endif
  155: 	info -> wfdesc = -1;
  156: 
  157: 	if (!quiet_interface_discovery)
  158: 		log_info ("Disabling output on BPF/%s/%s%s%s",
  159: 		      info -> name,
  160: 		      print_hw_addr (info -> hw_address.hbuf [0],
  161: 				     info -> hw_address.hlen - 1,
  162: 				     &info -> hw_address.hbuf [1]),
  163: 		      (info -> shared_network ? "/" : ""),
  164: 		      (info -> shared_network ?
  165: 		       info -> shared_network -> name : ""));
  166: }
  167: #endif /* USE_BPF_SEND */
  168: 
  169: #if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE)
  170: /* Packet filter program...
  171:    XXX Changes to the filter program may require changes to the constant
  172:    offsets used in if_register_send to patch the BPF program! XXX */
  173: 
  174: struct bpf_insn dhcp_bpf_filter [] = {
  175: 	/* Make sure this is an IP packet... */
  176: 	BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
  177: 	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
  178: 
  179: 	/* Make sure it's a UDP packet... */
  180: 	BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
  181: 	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
  182: 
  183: 	/* Make sure this isn't a fragment... */
  184: 	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
  185: 	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
  186: 
  187: 	/* Get the IP header length... */
  188: 	BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
  189: 
  190: 	/* Make sure it's to the right port... */
  191: 	BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
  192: 	BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),             /* patch */
  193: 
  194: 	/* If we passed all the tests, ask for the whole packet. */
  195: 	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
  196: 
  197: 	/* Otherwise, drop it. */
  198: 	BPF_STMT(BPF_RET+BPF_K, 0),
  199: };
  200: 
  201: #if defined (DEC_FDDI)
  202: struct bpf_insn *bpf_fddi_filter;
  203: #endif
  204: 
  205: int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);
  206: #if defined (HAVE_TR_SUPPORT)
  207: struct bpf_insn dhcp_bpf_tr_filter [] = {
  208:         /* accept all token ring packets due to variable length header */
  209:         /* if we want to get clever, insert the program here */
  210: 
  211: 	/* If we passed all the tests, ask for the whole packet. */
  212: 	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
  213: 
  214: 	/* Otherwise, drop it. */
  215: 	BPF_STMT(BPF_RET+BPF_K, 0),
  216: };
  217: 
  218: int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter /
  219: 			      sizeof (struct bpf_insn));
  220: #endif /* HAVE_TR_SUPPORT */
  221: #endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */
  222: 
  223: #if defined (USE_BPF_RECEIVE)
  224: void if_register_receive (info)
  225: 	struct interface_info *info;
  226: {
  227: 	int flag = 1;
  228: 	struct bpf_version v;
  229: 	struct bpf_program p;
  230: #ifdef NEED_OSF_PFILT_HACKS
  231: 	u_int32_t bits;
  232: #endif
  233: #ifdef DEC_FDDI
  234: 	int link_layer;
  235: #endif /* DEC_FDDI */
  236: 
  237: 	/* Open a BPF device and hang it on this interface... */
  238: 	info -> rfdesc = if_register_bpf (info);
  239: 
  240: 	/* Make sure the BPF version is in range... */
  241: 	if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0)
  242: 		log_fatal ("Can't get BPF version: %m");
  243: 
  244: 	if (v.bv_major != BPF_MAJOR_VERSION ||
  245: 	    v.bv_minor < BPF_MINOR_VERSION)
  246: 		log_fatal ("BPF version mismatch - recompile DHCP!");
  247: 
  248: 	/* Set immediate mode so that reads return as soon as a packet
  249: 	   comes in, rather than waiting for the input buffer to fill with
  250: 	   packets. */
  251: 	if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0)
  252: 		log_fatal ("Can't set immediate mode on bpf device: %m");
  253: 
  254: #ifdef NEED_OSF_PFILT_HACKS
  255: 	/* Allow the copyall flag to be set... */
  256: 	if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
  257: 		log_fatal ("Can't set ALLOWCOPYALL: %m");
  258: 
  259: 	/* Clear all the packet filter mode bits first... */
  260: 	bits = 0;
  261: 	if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
  262: 		log_fatal ("Can't clear pfilt bits: %m");
  263: 
  264: 	/* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */
  265: 	bits = ENBATCH | ENCOPYALL | ENBPFHDR;
  266: 	if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
  267: 		log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m");
  268: #endif
  269: 	/* Get the required BPF buffer length from the kernel. */
  270: 	if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0)
  271: 		log_fatal ("Can't get bpf buffer length: %m");
  272: 	info -> rbuf = dmalloc (info -> rbuf_max, MDL);
  273: 	if (!info -> rbuf)
  274: 		log_fatal ("Can't allocate %ld bytes for bpf input buffer.",
  275: 			   (long)(info -> rbuf_max));
  276: 	info -> rbuf_offset = 0;
  277: 	info -> rbuf_len = 0;
  278: 
  279: 	/* Set up the bpf filter program structure. */
  280: 	p.bf_len = dhcp_bpf_filter_len;
  281: 
  282: #ifdef DEC_FDDI
  283: 	/* See if this is an FDDI interface, flag it for later. */
  284: 	if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 &&
  285: 	    link_layer == DLT_FDDI) {
  286: 		if (!bpf_fddi_filter) {
  287: 			bpf_fddi_filter = dmalloc (sizeof bpf_fddi_filter,
  288: 						    MDL);
  289: 			if (!bpf_fddi_filter)
  290: 				log_fatal ("No memory for FDDI filter.");
  291: 			memcpy (bpf_fddi_filter,
  292: 				dhcp_bpf_filter, sizeof dhcp_bpf_filter);
  293: 			/* Patch the BPF program to account for the difference
  294: 			   in length between ethernet headers (14), FDDI and
  295: 			   802.2 headers (16 +8=24, +10).
  296: 			   XXX changes to filter program may require changes to
  297: 			   XXX the insn number(s) used below! */
  298: 			bpf_fddi_filter[0].k += 10;
  299: 			bpf_fddi_filter[2].k += 10;
  300: 			bpf_fddi_filter[4].k += 10;
  301: 			bpf_fddi_filter[6].k += 10;
  302: 			bpf_fddi_filter[7].k += 10;
  303: 		}
  304: 		p.bf_insns = bpf_fddi_filter;
  305: 	} else
  306: #endif /* DEC_FDDI */
  307: 	p.bf_insns = dhcp_bpf_filter;
  308: 
  309:         /* Patch the server port into the BPF  program...
  310: 	   XXX changes to filter program may require changes
  311: 	   to the insn number(s) used below! XXX */
  312: 	dhcp_bpf_filter [8].k = ntohs (local_port);
  313: 
  314: 	if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0)
  315: 		log_fatal ("Can't install packet filter program: %m");
  316: 	if (!quiet_interface_discovery)
  317: 		log_info ("Listening on BPF/%s/%s%s%s",
  318: 		      info -> name,
  319: 		      print_hw_addr (info -> hw_address.hbuf [0],
  320: 				     info -> hw_address.hlen - 1,
  321: 				     &info -> hw_address.hbuf [1]),
  322: 		      (info -> shared_network ? "/" : ""),
  323: 		      (info -> shared_network ?
  324: 		       info -> shared_network -> name : ""));
  325: }
  326: 
  327: void if_deregister_receive (info)
  328: 	struct interface_info *info;
  329: {
  330: 	close (info -> rfdesc);
  331: 	info -> rfdesc = -1;
  332: 
  333: 	if (!quiet_interface_discovery)
  334: 		log_info ("Disabling input on BPF/%s/%s%s%s",
  335: 		      info -> name,
  336: 		      print_hw_addr (info -> hw_address.hbuf [0],
  337: 				     info -> hw_address.hlen - 1,
  338: 				     &info -> hw_address.hbuf [1]),
  339: 		      (info -> shared_network ? "/" : ""),
  340: 		      (info -> shared_network ?
  341: 		       info -> shared_network -> name : ""));
  342: }
  343: #endif /* USE_BPF_RECEIVE */
  344: 
  345: #ifdef USE_BPF_SEND
  346: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
  347: 	struct interface_info *interface;
  348: 	struct packet *packet;
  349: 	struct dhcp_packet *raw;
  350: 	size_t len;
  351: 	struct in_addr from;
  352: 	struct sockaddr_in *to;
  353: 	struct hardware *hto;
  354: {
  355: 	unsigned hbufp = 0, ibufp = 0;
  356: 	double hw [4];
  357: 	double ip [32];
  358: 	struct iovec iov [3];
  359: 	int result;
  360: 
  361: 	if (!strcmp (interface -> name, "fallback"))
  362: 		return send_fallback (interface, packet, raw,
  363: 				      len, from, to, hto);
  364: 
  365: 	/* Assemble the headers... */
  366: 	assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
  367: 	assemble_udp_ip_header (interface,
  368: 				(unsigned char *)ip, &ibufp, from.s_addr,
  369: 				to -> sin_addr.s_addr, to -> sin_port,
  370: 				(unsigned char *)raw, len);
  371: 
  372: 	/* Fire it off */
  373: 	iov [0].iov_base = ((char *)hw);
  374: 	iov [0].iov_len = hbufp;
  375: 	iov [1].iov_base = ((char *)ip);
  376: 	iov [1].iov_len = ibufp;
  377: 	iov [2].iov_base = (char *)raw;
  378: 	iov [2].iov_len = len;
  379: 
  380: 	result = writev(interface -> wfdesc, iov, 3);
  381: 	if (result < 0)
  382: 		log_error ("send_packet: %m");
  383: 	return result;
  384: }
  385: #endif /* USE_BPF_SEND */
  386: 
  387: #ifdef USE_BPF_RECEIVE
  388: ssize_t receive_packet (interface, buf, len, from, hfrom)
  389: 	struct interface_info *interface;
  390: 	unsigned char *buf;
  391: 	size_t len;
  392: 	struct sockaddr_in *from;
  393: 	struct hardware *hfrom;
  394: {
  395: 	int length = 0;
  396: 	int offset = 0;
  397: 	struct bpf_hdr hdr;
  398: 	unsigned paylen;
  399: 
  400: 	/* All this complexity is because BPF doesn't guarantee
  401: 	   that only one packet will be returned at a time.   We're
  402: 	   getting what we deserve, though - this is a terrible abuse
  403: 	   of the BPF interface.   Sigh. */
  404: 
  405: 	/* Process packets until we get one we can return or until we've
  406: 	   done a read and gotten nothing we can return... */
  407: 
  408: 	do {
  409: 		/* If the buffer is empty, fill it. */
  410: 		if (interface -> rbuf_offset == interface -> rbuf_len) {
  411: 			length = read (interface -> rfdesc,
  412: 				       interface -> rbuf,
  413: 				       (size_t)interface -> rbuf_max);
  414: 			if (length <= 0) {
  415: #ifdef __FreeBSD__
  416: 				if (errno == ENXIO) {
  417: #else
  418: 				if (errno == EIO) {
  419: #endif
  420: 					dhcp_interface_remove
  421: 						((omapi_object_t *)interface,
  422: 						 (omapi_object_t *)0);
  423: 				}
  424: 				return length;
  425: 			}
  426: 			interface -> rbuf_offset = 0;
  427: 			interface -> rbuf_len = BPF_WORDALIGN (length);
  428: 		}
  429: 
  430: 		/* If there isn't room for a whole bpf header, something went
  431: 		   wrong, but we'll ignore it and hope it goes away... XXX */
  432: 		if (interface -> rbuf_len -
  433: 		    interface -> rbuf_offset < sizeof hdr) {
  434: 			interface -> rbuf_offset = interface -> rbuf_len;
  435: 			continue;
  436: 		}
  437: 
  438: 		/* Copy out a bpf header... */
  439: 		memcpy (&hdr, &interface -> rbuf [interface -> rbuf_offset],
  440: 			sizeof hdr);
  441: 
  442: 		/* If the bpf header plus data doesn't fit in what's left
  443: 		   of the buffer, stick head in sand yet again... */
  444: 		if (interface -> rbuf_offset +
  445: 		    hdr.bh_hdrlen + hdr.bh_caplen > interface -> rbuf_len) {
  446: 			interface -> rbuf_offset = interface -> rbuf_len;
  447: 			continue;
  448: 		}
  449: 
  450: 		/* If the captured data wasn't the whole packet, or if
  451: 		   the packet won't fit in the input buffer, all we
  452: 		   can do is drop it. */
  453: 		if (hdr.bh_caplen != hdr.bh_datalen) {
  454: 			interface -> rbuf_offset =
  455: 				BPF_WORDALIGN (interface -> rbuf_offset +
  456: 					       hdr.bh_hdrlen + hdr.bh_caplen);
  457: 			continue;
  458: 		}
  459: 
  460: 		/* Skip over the BPF header... */
  461: 		interface -> rbuf_offset += hdr.bh_hdrlen;
  462: 
  463: 		/* Decode the physical header... */
  464: 		offset = decode_hw_header (interface,
  465: 					   interface -> rbuf,
  466: 					   interface -> rbuf_offset,
  467: 					   hfrom);
  468: 
  469: 		/* If a physical layer checksum failed (dunno of any
  470: 		   physical layer that supports this, but WTH), skip this
  471: 		   packet. */
  472: 		if (offset < 0) {
  473: 			interface -> rbuf_offset = 
  474: 				BPF_WORDALIGN (interface -> rbuf_offset +
  475: 					       hdr.bh_caplen);
  476: 			continue;
  477: 		}
  478: 		interface -> rbuf_offset += offset;
  479: 		hdr.bh_caplen -= offset;
  480: 
  481: 		/* Decode the IP and UDP headers... */
  482: 		offset = decode_udp_ip_header (interface,
  483: 					       interface -> rbuf,
  484: 					       interface -> rbuf_offset,
  485:   					       from, hdr.bh_caplen, &paylen);
  486: 
  487: 		/* If the IP or UDP checksum was bad, skip the packet... */
  488: 		if (offset < 0) {
  489: 			interface -> rbuf_offset = 
  490: 				BPF_WORDALIGN (interface -> rbuf_offset +
  491: 					       hdr.bh_caplen);
  492: 			continue;
  493: 		}
  494: 		interface -> rbuf_offset = interface -> rbuf_offset + offset;
  495: 		hdr.bh_caplen -= offset;
  496: 
  497: 		/* If there's not enough room to stash the packet data,
  498: 		   we have to skip it (this shouldn't happen in real
  499: 		   life, though). */
  500: 		if (hdr.bh_caplen > len) {
  501: 			interface -> rbuf_offset =
  502: 				BPF_WORDALIGN (interface -> rbuf_offset +
  503: 					       hdr.bh_caplen);
  504: 			continue;
  505: 		}
  506: 
  507: 		/* Copy out the data in the packet... */
  508: 		memcpy(buf, interface->rbuf + interface->rbuf_offset, paylen);
  509: 		interface -> rbuf_offset =
  510: 			BPF_WORDALIGN (interface -> rbuf_offset +
  511: 				       hdr.bh_caplen);
  512: 		return paylen;
  513: 	} while (!length);
  514: 	return 0;
  515: }
  516: 
  517: int can_unicast_without_arp (ip)
  518: 	struct interface_info *ip;
  519: {
  520: 	return 1;
  521: }
  522: 
  523: int can_receive_unicast_unconfigured (ip)
  524: 	struct interface_info *ip;
  525: {
  526: 	return 1;
  527: }
  528: 
  529: int supports_multiple_interfaces (ip)
  530: 	struct interface_info *ip;
  531: {
  532: 	return 1;
  533: }
  534: 
  535: void maybe_setup_fallback ()
  536: {
  537: 	isc_result_t status;
  538: 	struct interface_info *fbi = (struct interface_info *)0;
  539: 	if (setup_fallback (&fbi, MDL)) {
  540: 		if_register_fallback (fbi);
  541: 		status = omapi_register_io_object ((omapi_object_t *)fbi,
  542: 						   if_readsocket, 0,
  543: 						   fallback_discard, 0, 0);
  544: 		if (status != ISC_R_SUCCESS)
  545: 			log_fatal ("Can't register I/O handle for %s: %s",
  546: 				   fbi -> name, isc_result_totext (status));
  547: 		interface_dereference (&fbi, MDL);
  548: 	}
  549: }
  550: 
  551: void
  552: get_hw_addr(const char *name, struct hardware *hw) {
  553: 	struct ifaddrs *ifa;
  554: 	struct ifaddrs *p;
  555: 	struct sockaddr_dl *sa;
  556: 
  557: 	if (getifaddrs(&ifa) != 0) {
  558: 		log_fatal("Error getting interface information; %m");
  559: 	}
  560: 
  561: 	/*
  562: 	 * Loop through our interfaces finding a match.
  563: 	 */
  564: 	sa = NULL;
  565: 	for (p=ifa; (p != NULL) && (sa == NULL); p = p->ifa_next) {
  566: 		if ((p->ifa_addr->sa_family == AF_LINK) && 
  567: 		    !strcmp(p->ifa_name, name)) {
  568: 		    	sa = (struct sockaddr_dl *)p->ifa_addr;
  569: 		}
  570: 	}
  571: 	if (sa == NULL) {
  572: 		log_fatal("No interface called '%s'", name);
  573: 	}
  574: 
  575: 	/*
  576: 	 * Pull out the appropriate information.
  577: 	 */
  578:         switch (sa->sdl_type) {
  579:                 case IFT_ETHER:
  580:                         hw->hlen = sa->sdl_alen + 1;
  581:                         hw->hbuf[0] = HTYPE_ETHER;
  582:                         memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
  583:                         break;
  584: 		case IFT_ISO88023:
  585: 		case IFT_ISO88024: /* "token ring" */
  586: 		case IFT_ISO88025:
  587: 		case IFT_ISO88026:
  588:                         hw->hlen = sa->sdl_alen + 1;
  589:                         hw->hbuf[0] = HTYPE_IEEE802;
  590:                         memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
  591:                         break;
  592: #ifdef IFT_FDDI
  593:                 case IFT_FDDI:
  594:                         hw->hlen = sa->sdl_alen + 1;
  595:                         hw->hbuf[0] = HTYPE_FDDI;
  596:                         memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
  597:                         break;
  598: #endif /* IFT_FDDI */
  599:                 default:
  600:                         log_fatal("Unsupported device type %d for \"%s\"",
  601:                                   sa->sdl_type, name);
  602:         }
  603: 
  604: 	freeifaddrs(ifa);
  605: }
  606: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>