File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / upf.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 (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* upf.c
    2: 
    3:    Ultrix PacketFilter interface code. */
    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 has been written for Internet Systems Consortium
   28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
   29:  * To learn more about Internet Systems Consortium, see
   30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
   31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
   32:  * ``http://www.nominum.com''.
   33:  */
   34: 
   35: #include "dhcpd.h"
   36: #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
   37: #include <sys/ioctl.h>
   38: #include <sys/uio.h>
   39: 
   40: #include <net/pfilt.h>
   41: #include <netinet/in_systm.h>
   42: #include "includes/netinet/ip.h"
   43: #include "includes/netinet/udp.h"
   44: #include "includes/netinet/if_ether.h"
   45: 
   46: /* Reinitializes the specified interface after an address change.   This
   47:    is not required for packet-filter APIs. */
   48: 
   49: #ifdef USE_UPF_SEND
   50: void if_reinitialize_send (info)
   51: 	struct interface_info *info;
   52: {
   53: }
   54: #endif
   55: 
   56: #ifdef USE_UPF_RECEIVE
   57: void if_reinitialize_receive (info)
   58: 	struct interface_info *info;
   59: {
   60: }
   61: #endif
   62: 
   63: /* Called by get_interface_list for each interface that's discovered.
   64:    Opens a packet filter for each interface and adds it to the select
   65:    mask. */
   66: 
   67: int if_register_upf (info)
   68: 	struct interface_info *info;
   69: {
   70: 	int sock;
   71: 	char filename[50];
   72: 	int b;
   73: 	struct endevp param;
   74: 
   75: 	/* Open a UPF device */
   76: 	for (b = 0; 1; b++) {
   77: 		/* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
   78: 		sprintf(filename, "/dev/pf/pfilt%d", b);
   79: 
   80: 		sock = open (filename, O_RDWR, 0);
   81: 		if (sock < 0) {
   82: 			if (errno == EBUSY) {
   83: 				continue;
   84: 			} else {
   85: 				log_fatal ("Can't find free upf: %m");
   86: 			}
   87: 		} else {
   88: 			break;
   89: 		}
   90: 	}
   91: 
   92: 	/* Set the UPF device to point at this interface. */
   93: 	if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
   94: 		log_fatal ("Can't attach interface %s to upf device %s: %m",
   95: 		       info -> name, filename);
   96: 
   97: 	/* Get the hardware address. */
   98: 	if (ioctl (sock, EIOCDEVP, &param) < 0)
   99: 		log_fatal ("Can't get interface %s hardware address: %m",
  100: 		       info -> name);
  101: 
  102: 	/* We only know how to do ethernet. */
  103: 	if (param.end_dev_type != ENDT_10MB)	
  104: 		log_fatal ("Invalid device type on network interface %s: %d",
  105: 		       info -> name, param.end_dev_type);
  106: 
  107: 	if (param.end_addr_len != 6)
  108: 		log_fatal ("Invalid hardware address length on %s: %d",
  109: 		       info -> name, param.end_addr_len);
  110: 
  111: 	info -> hw_address.hlen = 7;
  112: 	info -> hw_address.hbuf [0] = ARPHRD_ETHER;
  113: 	memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6);
  114: 
  115: 	return sock;
  116: }
  117: #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
  118: 
  119: #ifdef USE_UPF_SEND
  120: void if_register_send (info)
  121: 	struct interface_info *info;
  122: {
  123: 	/* If we're using the upf API for sending and receiving,
  124: 	   we don't need to register this interface twice. */
  125: #ifndef USE_UPF_RECEIVE
  126: 	info -> wfdesc = if_register_upf (info, interface);
  127: #else
  128: 	info -> wfdesc = info -> rfdesc;
  129: #endif
  130:         if (!quiet_interface_discovery)
  131: 		log_info ("Sending on   UPF/%s/%s%s%s",
  132: 		      info -> name,
  133: 		      print_hw_addr (info -> hw_address.hbuf [0],
  134: 				     info -> hw_address.hlen - 1,
  135: 				     &info -> hw_address.hbuf [1]),
  136: 		      (info -> shared_network ? "/" : ""),
  137: 		      (info -> shared_network ?
  138: 		       info -> shared_network -> name : ""));
  139: }
  140: 
  141: void if_deregister_send (info)
  142: 	struct interface_info *info;
  143: {
  144: #ifndef USE_UPF_RECEIVE
  145: 	close (info -> wfdesc);
  146: #endif
  147: 	info -> wfdesc = -1;
  148:         if (!quiet_interface_discovery)
  149: 		log_info ("Disabling output on UPF/%s/%s%s%s",
  150: 		      info -> name,
  151: 		      print_hw_addr (info -> hw_address.hbuf [0],
  152: 				     info -> hw_address.hlen - 1,
  153: 				     &info -> hw_address.hbuf [1]),
  154: 		      (info -> shared_network ? "/" : ""),
  155: 		      (info -> shared_network ?
  156: 		       info -> shared_network -> name : ""));
  157: }
  158: #endif /* USE_UPF_SEND */
  159: 
  160: #ifdef USE_UPF_RECEIVE
  161: /* Packet filter program...
  162:    XXX Changes to the filter program may require changes to the constant
  163:    offsets used in if_register_send to patch the UPF program! XXX */
  164: 
  165: 
  166: void if_register_receive (info)
  167: 	struct interface_info *info;
  168: {
  169: 	int flag = 1;
  170: 	u_int32_t addr;
  171: 	struct enfilter pf;
  172: 	u_int32_t bits;
  173: 
  174: 	/* Open a UPF device and hang it on this interface... */
  175: 	info -> rfdesc = if_register_upf (info);
  176: 
  177: 	/* Allow the copyall flag to be set... */
  178: 	if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
  179: 		log_fatal ("Can't set ALLOWCOPYALL: %m");
  180: 
  181: 	/* Clear all the packet filter mode bits first... */
  182: 	flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
  183: 		ENNONEXCL | ENCOPYALL);
  184: 	if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
  185: 		log_fatal ("Can't clear pfilt bits: %m");
  186: 
  187: 	/* Set the ENBATCH and ENCOPYALL bits... */
  188: 	bits = ENBATCH | ENCOPYALL;
  189: 	if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
  190: 		log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
  191: 
  192: 	/* Set up the UPF filter program. */
  193: 	/* XXX Unlike the BPF filter program, this one won't work if the
  194: 	   XXX IP packet is fragmented or if there are options on the IP
  195: 	   XXX header. */
  196: 	pf.enf_Priority = 0;
  197: 	pf.enf_FilterLen = 0;
  198: 
  199: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
  200: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
  201: 	pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
  202: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
  203: 	pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
  204: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
  205: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
  206: 	pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
  207: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
  208: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
  209: 	pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
  210: 	pf.enf_Filter [pf.enf_FilterLen++] = local_port;
  211: 
  212: 	if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
  213: 		log_fatal ("Can't install packet filter program: %m");
  214:         if (!quiet_interface_discovery)
  215: 		log_info ("Listening on UPF/%s/%s%s%s",
  216: 		      info -> name,
  217: 		      print_hw_addr (info -> hw_address.hbuf [0],
  218: 				     info -> hw_address.hlen - 1,
  219: 				     &info -> hw_address.hbuf [1]),
  220: 		      (info -> shared_network ? "/" : ""),
  221: 		      (info -> shared_network ?
  222: 		       info -> shared_network -> name : ""));
  223: }
  224: 
  225: void if_deregister_receive (info)
  226: 	struct interface_info *info;
  227: {
  228: 	close (info -> rfdesc);
  229: 	info -> rfdesc = -1;
  230:         if (!quiet_interface_discovery)
  231: 		log_info ("Disabling input on UPF/%s/%s%s%s",
  232: 		      info -> name,
  233: 		      print_hw_addr (info -> hw_address.hbuf [0],
  234: 				     info -> hw_address.hlen - 1,
  235: 				     &info -> hw_address.hbuf [1]),
  236: 		      (info -> shared_network ? "/" : ""),
  237: 		      (info -> shared_network ?
  238: 		       info -> shared_network -> name : ""));
  239: }
  240: #endif /* USE_UPF_RECEIVE */
  241: 
  242: #ifdef USE_UPF_SEND
  243: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
  244: 	struct interface_info *interface;
  245: 	struct packet *packet;
  246: 	struct dhcp_packet *raw;
  247: 	size_t len;
  248: 	struct in_addr from;
  249: 	struct sockaddr_in *to;
  250: 	struct hardware *hto;
  251: {
  252: 	unsigned hbufp = 0, ibufp = 0;
  253: 	double hw [4];
  254: 	double ip [32];
  255: 	struct iovec iov [3];
  256: 	int result;
  257: 	int fudge;
  258: 
  259: 	if (!strcmp (interface -> name, "fallback"))
  260: 		return send_fallback (interface, packet, raw,
  261: 				      len, from, to, hto);
  262: 
  263: 	/* Assemble the headers... */
  264: 	assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto);
  265: 	assemble_udp_ip_header (interface,
  266: 				(unsigned char *)ip, &ibufp, from.s_addr,
  267: 				to -> sin_addr.s_addr, to -> sin_port,
  268: 				(unsigned char *)raw, len);
  269: 
  270: 	/* Fire it off */
  271: 	iov [0].iov_base = ((char *)hw);
  272: 	iov [0].iov_len = hbufp;
  273: 	iov [1].iov_base = ((char *)ip);
  274: 	iov [1].iov_len = ibufp;
  275: 	iov [2].iov_base = (char *)raw;
  276: 	iov [2].iov_len = len;
  277: 
  278: 	result = writev(interface -> wfdesc, iov, 3);
  279: 	if (result < 0)
  280: 		log_error ("send_packet: %m");
  281: 	return result;
  282: }
  283: #endif /* USE_UPF_SEND */
  284: 
  285: #ifdef USE_UPF_RECEIVE
  286: ssize_t receive_packet (interface, buf, len, from, hfrom)
  287: 	struct interface_info *interface;
  288: 	unsigned char *buf;
  289: 	size_t len;
  290: 	struct sockaddr_in *from;
  291: 	struct hardware *hfrom;
  292: {
  293: 	int nread;
  294: 	int length = 0;
  295: 	int offset = 0;
  296: 	unsigned char ibuf [1500 + sizeof (struct enstamp)];
  297: 	int bufix = 0;
  298: 	unsigned paylen;
  299: 
  300: 	length = read (interface -> rfdesc, ibuf, sizeof ibuf);
  301: 	if (length <= 0)
  302: 		return length;
  303: 
  304: 	bufix = sizeof (struct enstamp);
  305: 	/* Decode the physical header... */
  306: 	offset = decode_hw_header (interface, ibuf, bufix, hfrom);
  307: 
  308: 	/* If a physical layer checksum failed (dunno of any
  309: 	   physical layer that supports this, but WTH), skip this
  310: 	   packet. */
  311: 	if (offset < 0) {
  312: 		return 0;
  313: 	}
  314: 
  315: 	bufix += offset;
  316: 	length -= offset;
  317: 
  318: 	/* Decode the IP and UDP headers... */
  319: 	offset = decode_udp_ip_header (interface, ibuf, bufix,
  320: 				       from, length, &paylen);
  321: 
  322: 	/* If the IP or UDP checksum was bad, skip the packet... */
  323: 	if (offset < 0)
  324: 		return 0;
  325: 
  326: 	bufix += offset;
  327: 	length -= offset;
  328: 
  329: 	if (length < paylen)
  330: 		log_fatal("Internal inconsistency at %s:%d.", MDL);
  331: 
  332: 	/* Copy out the data in the packet... */
  333: 	memcpy (buf, &ibuf[bufix], paylen);
  334: 	return paylen;
  335: }
  336: 
  337: int can_unicast_without_arp (ip)
  338: 	struct interface_info *ip;
  339: {
  340: 	return 1;
  341: }
  342: 
  343: int can_receive_unicast_unconfigured (ip)
  344: 	struct interface_info *ip;
  345: {
  346: 	return 1;
  347: }
  348: 
  349: int supports_multiple_interfaces (ip)
  350: 	struct interface_info *ip;
  351: {
  352: 	return 1;
  353: }
  354: 
  355: void maybe_setup_fallback ()
  356: {
  357: 	isc_result_t status;
  358: 	struct interface_info *fbi = (struct interface_info *)0;
  359: 	if (setup_fallback (&fbi, MDL)) {
  360: 		if_register_fallback (fbi);
  361: 		status = omapi_register_io_object ((omapi_object_t *)fbi,
  362: 						   if_readsocket, 0,
  363: 						   fallback_discard, 0, 0);
  364: 		if (status != ISC_R_SUCCESS)
  365: 			log_fatal ("Can't register I/O handle for %s: %s",
  366: 				   fbi -> name, isc_result_totext (status));
  367: 		interface_dereference (&fbi, MDL);
  368: 	}
  369: }
  370: #endif

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