File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / nit.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: /* nit.c
    2: 
    3:    Network Interface Tap (NIT) network interface code, by Ted Lemon
    4:    with one crucial tidbit of help from Stu Grossmen. */
    5: 
    6: /*
    7:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
    8:  * Copyright (c) 1996-2003 by Internet Software Consortium
    9:  *
   10:  * Permission to use, copy, modify, and distribute this software for any
   11:  * purpose with or without fee is hereby granted, provided that the above
   12:  * copyright notice and this permission notice appear in all copies.
   13:  *
   14:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   15:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   16:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   17:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   18:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   19:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   20:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   21:  *
   22:  *   Internet Systems Consortium, Inc.
   23:  *   950 Charter Street
   24:  *   Redwood City, CA 94063
   25:  *   <info@isc.org>
   26:  *   https://www.isc.org/
   27:  *
   28:  * This software has been written for Internet Systems Consortium
   29:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
   30:  * To learn more about Internet Systems Consortium, see
   31:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
   32:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
   33:  * ``http://www.nominum.com''.
   34:  */
   35: 
   36: #include "dhcpd.h"
   37: #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
   38: #include <sys/ioctl.h>
   39: #include <sys/uio.h>
   40: 
   41: #include <sys/time.h>
   42: #include <net/nit.h>
   43: #include <net/nit_if.h>
   44: #include <net/nit_pf.h>
   45: #include <net/nit_buf.h>
   46: #include <sys/stropts.h>
   47: #include <net/packetfilt.h>
   48: 
   49: #include <netinet/in_systm.h>
   50: #include "includes/netinet/ip.h"
   51: #include "includes/netinet/udp.h"
   52: #include "includes/netinet/if_ether.h"
   53: 
   54: /* Reinitializes the specified interface after an address change.   This
   55:    is not required for packet-filter APIs. */
   56: 
   57: #ifdef USE_NIT_SEND
   58: void if_reinitialize_send (info)
   59: 	struct interface_info *info;
   60: {
   61: }
   62: #endif
   63: 
   64: #ifdef USE_NIT_RECEIVE
   65: void if_reinitialize_receive (info)
   66: 	struct interface_info *info;
   67: {
   68: }
   69: #endif
   70: 
   71: /* Called by get_interface_list for each interface that's discovered.
   72:    Opens a packet filter for each interface and adds it to the select
   73:    mask. */
   74: 
   75: int if_register_nit (info)
   76: 	struct interface_info *info;
   77: {
   78: 	int sock;
   79: 	char filename[50];
   80: 	struct ifreq ifr;
   81: 	struct strioctl sio;
   82: 
   83: 	/* Open a NIT device */
   84: 	sock = open ("/dev/nit", O_RDWR);
   85: 	if (sock < 0)
   86: 		log_fatal ("Can't open NIT device for %s: %m", info -> name);
   87: 
   88: 	/* Set the NIT device to point at this interface. */
   89: 	sio.ic_cmd = NIOCBIND;
   90: 	sio.ic_len = sizeof *(info -> ifp);
   91: 	sio.ic_dp = (char *)(info -> ifp);
   92: 	sio.ic_timout = INFTIM;
   93: 	if (ioctl (sock, I_STR, &sio) < 0)
   94: 		log_fatal ("Can't attach interface %s to nit device: %m",
   95: 		       info -> name);
   96: 
   97: 	/* Get the low-level address... */
   98: 	sio.ic_cmd = SIOCGIFADDR;
   99: 	sio.ic_len = sizeof ifr;
  100: 	sio.ic_dp = (char *)&ifr;
  101: 	sio.ic_timout = INFTIM;
  102: 	if (ioctl (sock, I_STR, &sio) < 0)
  103: 		log_fatal ("Can't get physical layer address for %s: %m",
  104: 		       info -> name);
  105: 
  106: 	/* XXX code below assumes ethernet interface! */
  107: 	info -> hw_address.hlen = 7;
  108: 	info -> hw_address.hbuf [0] = ARPHRD_ETHER;
  109: 	memcpy (&info -> hw_address.hbuf [1],
  110: 		ifr.ifr_ifru.ifru_addr.sa_data, 6);
  111: 
  112: 	if (ioctl (sock, I_PUSH, "pf") < 0)
  113: 		log_fatal ("Can't push packet filter onto NIT for %s: %m",
  114: 		       info -> name);
  115: 
  116: 	return sock;
  117: }
  118: #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
  119: 
  120: #ifdef USE_NIT_SEND
  121: void if_register_send (info)
  122: 	struct interface_info *info;
  123: {
  124: 	/* If we're using the nit API for sending and receiving,
  125: 	   we don't need to register this interface twice. */
  126: #ifndef USE_NIT_RECEIVE
  127: 	struct packetfilt pf;
  128: 	struct strioctl sio;
  129: 
  130: 	info -> wfdesc = if_register_nit (info);
  131: 
  132: 	pf.Pf_Priority = 0;
  133: 	pf.Pf_FilterLen = 1;
  134: 	pf.Pf_Filter [0] = ENF_PUSHZERO;
  135: 
  136: 	/* Set up an NIT filter that rejects everything... */
  137: 	sio.ic_cmd = NIOCSETF;
  138: 	sio.ic_len = sizeof pf;
  139: 	sio.ic_dp = (char *)&pf;
  140: 	sio.ic_timout = INFTIM;
  141: 	if (ioctl (info -> wfdesc, I_STR, &sio) < 0)
  142: 		log_fatal ("Can't set NIT filter: %m");
  143: #else
  144: 	info -> wfdesc = info -> rfdesc;
  145: #endif
  146:         if (!quiet_interface_discovery)
  147: 		log_info ("Sending on   NIT/%s%s%s",
  148: 		      print_hw_addr (info -> hw_address.hbuf [0],
  149: 				     info -> hw_address.hlen - 1,
  150: 				     &info -> hw_address.hbuf [1]),
  151: 		      (info -> shared_network ? "/" : ""),
  152: 		      (info -> shared_network ?
  153: 		       info -> shared_network -> name : ""));
  154: }
  155: 
  156: void if_deregister_send (info)
  157: 	struct interface_info *info;
  158: {
  159: 	/* If we're using the nit API for sending and receiving,
  160: 	   we don't need to register this interface twice. */
  161: #ifndef USE_NIT_RECEIVE
  162: 	close (info -> wfdesc);
  163: #endif
  164: 	info -> wfdesc = -1;
  165:         if (!quiet_interface_discovery)
  166: 		log_info ("Disabling output on NIT/%s%s%s",
  167: 		      print_hw_addr (info -> hw_address.hbuf [0],
  168: 				     info -> hw_address.hlen - 1,
  169: 				     &info -> hw_address.hbuf [1]),
  170: 		      (info -> shared_network ? "/" : ""),
  171: 		      (info -> shared_network ?
  172: 		       info -> shared_network -> name : ""));
  173: }
  174: #endif /* USE_NIT_SEND */
  175: 
  176: #ifdef USE_NIT_RECEIVE
  177: /* Packet filter program...
  178:    XXX Changes to the filter program may require changes to the constant
  179:    offsets used in if_register_send to patch the NIT program! XXX */
  180: 
  181: void if_register_receive (info)
  182: 	struct interface_info *info;
  183: {
  184: 	int flag = 1;
  185: 	u_int32_t x;
  186: 	struct packetfilt pf;
  187: 	struct strioctl sio;
  188: 	u_int16_t addr [2];
  189: 	struct timeval t;
  190: 
  191: 	/* Open a NIT device and hang it on this interface... */
  192: 	info -> rfdesc = if_register_nit (info);
  193: 
  194: 	/* Set the snap length to 0, which means always take the whole
  195: 	   packet. */
  196: 	x = 0;
  197: 	if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0)
  198: 		log_fatal ("Can't set NIT snap length on %s: %m", info -> name);
  199: 
  200: 	/* Set the stream to byte stream mode */
  201: 	if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0)
  202: 		log_info ("I_SRDOPT failed on %s: %m", info -> name);
  203: 
  204: #if 0
  205: 	/* Push on the chunker... */
  206: 	if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0)
  207: 		log_fatal ("Can't push chunker onto NIT STREAM: %m");
  208: 
  209: 	/* Set the timeout to zero. */
  210: 	t.tv_sec = 0;
  211: 	t.tv_usec = 0;
  212: 	if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0)
  213: 		log_fatal ("Can't set chunk timeout: %m");
  214: #endif
  215: 
  216: 	/* Ask for no header... */
  217: 	x = 0;
  218: 	if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0)
  219: 		log_fatal ("Can't set NIT flags on %s: %m", info -> name);
  220: 
  221: 	/* Set up the NIT filter program. */
  222: 	/* XXX Unlike the BPF filter program, this one won't work if the
  223: 	   XXX IP packet is fragmented or if there are options on the IP
  224: 	   XXX header. */
  225: 	pf.Pf_Priority = 0;
  226: 	pf.Pf_FilterLen = 0;
  227: 
  228: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6;
  229: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
  230: 	pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
  231: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
  232: 	pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
  233: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
  234: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
  235: 	pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF);
  236: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
  237: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18;
  238: 	pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
  239: 	pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
  240: 
  241: 	/* Install the filter... */
  242: 	sio.ic_cmd = NIOCSETF;
  243: 	sio.ic_len = sizeof pf;
  244: 	sio.ic_dp = (char *)&pf;
  245: 	sio.ic_timout = INFTIM;
  246: 	if (ioctl (info -> rfdesc, I_STR, &sio) < 0)
  247: 		log_fatal ("Can't set NIT filter on %s: %m", info -> name);
  248: 
  249:         if (!quiet_interface_discovery)
  250: 		log_info ("Listening on NIT/%s%s%s",
  251: 		      print_hw_addr (info -> hw_address.hbuf [0],
  252: 				     info -> hw_address.hlen - 1,
  253: 				     &info -> hw_address.hbuf [1]),
  254: 		      (info -> shared_network ? "/" : ""),
  255: 		      (info -> shared_network ?
  256: 		       info -> shared_network -> name : ""));
  257: }
  258: 
  259: void if_deregister_receive (info)
  260: 	struct interface_info *info;
  261: {
  262: 	/* If we're using the nit API for sending and receiving,
  263: 	   we don't need to register this interface twice. */
  264: 	close (info -> rfdesc);
  265: 	info -> rfdesc = -1;
  266: 
  267:         if (!quiet_interface_discovery)
  268: 		log_info ("Disabling input on NIT/%s%s%s",
  269: 		      print_hw_addr (info -> hw_address.hbuf [0],
  270: 				     info -> hw_address.hlen - 1,
  271: 				     &info -> hw_address.hbuf [1]),
  272: 		      (info -> shared_network ? "/" : ""),
  273: 		      (info -> shared_network ?
  274: 		       info -> shared_network -> name : ""));
  275: }
  276: #endif /* USE_NIT_RECEIVE */
  277: 
  278: #ifdef USE_NIT_SEND
  279: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
  280: 	struct interface_info *interface;
  281: 	struct packet *packet;
  282: 	struct dhcp_packet *raw;
  283: 	size_t len;
  284: 	struct in_addr from;
  285: 	struct sockaddr_in *to;
  286: 	struct hardware *hto;
  287: {
  288: 	unsigned hbufp, ibufp;
  289: 	double hh [16];
  290: 	double ih [1536 / sizeof (double)];
  291: 	unsigned char *buf = (unsigned char *)ih;
  292: 	struct sockaddr *junk;
  293: 	struct strbuf ctl, data;
  294: 	struct sockaddr_in foo;
  295: 	int result;
  296: 
  297: 	if (!strcmp (interface -> name, "fallback"))
  298: 		return send_fallback (interface, packet, raw,
  299: 				      len, from, to, hto);
  300: 
  301: 	/* Start with the sockaddr struct... */
  302: 	junk = (struct sockaddr *)&hh [0];
  303: 	hbufp = (((unsigned char *)&junk -> sa_data [0]) -
  304: 		 (unsigned char *)&hh[0]);
  305: 	ibufp = 0;
  306: 
  307: 	/* Assemble the headers... */
  308: 	assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto);
  309: 	assemble_udp_ip_header (interface, buf, &ibufp,
  310: 				from.s_addr, to -> sin_addr.s_addr,
  311: 				to -> sin_port, (unsigned char *)raw, len);
  312: 
  313: 	/* Copy the data into the buffer (yuk). */
  314: 	memcpy (buf + ibufp, raw, len);
  315: 
  316: 	/* Set up the sockaddr structure... */
  317: #if USE_SIN_LEN
  318: 	junk -> sa_len = hbufp - 2; /* XXX */
  319: #endif
  320: 	junk -> sa_family = AF_UNSPEC;
  321: 
  322: 	/* Set up the msg_buf structure... */
  323: 	ctl.buf = (char *)&hh [0];
  324: 	ctl.maxlen = ctl.len = hbufp;
  325: 	data.buf = (char *)&ih [0];
  326: 	data.maxlen = data.len = ibufp + len;
  327: 
  328: 	result = putmsg (interface -> wfdesc, &ctl, &data, 0);
  329: 	if (result < 0)
  330: 		log_error ("send_packet: %m");
  331: 	return result;
  332: }
  333: #endif /* USE_NIT_SEND */
  334: 
  335: #ifdef USE_NIT_RECEIVE
  336: ssize_t receive_packet (interface, buf, len, from, hfrom)
  337: 	struct interface_info *interface;
  338: 	unsigned char *buf;
  339: 	size_t len;
  340: 	struct sockaddr_in *from;
  341: 	struct hardware *hfrom;
  342: {
  343: 	int nread;
  344: 	int length = 0;
  345: 	int offset = 0;
  346: 	unsigned char ibuf [1536];
  347: 	int bufix = 0;
  348: 	unsigned paylen;
  349: 
  350: 	length = read (interface -> rfdesc, ibuf, sizeof ibuf);
  351: 	if (length <= 0)
  352: 		return length;
  353: 
  354: 	/* Decode the physical header... */
  355: 	offset = decode_hw_header (interface, ibuf, bufix, hfrom);
  356: 
  357: 	/* If a physical layer checksum failed (dunno of any
  358: 	   physical layer that supports this, but WTH), skip this
  359: 	   packet. */
  360: 	if (offset < 0) {
  361: 		return 0;
  362: 	}
  363: 
  364: 	bufix += offset;
  365: 	length -= offset;
  366: 
  367: 	/* Decode the IP and UDP headers... */
  368: 	offset = decode_udp_ip_header (interface, ibuf, bufix,
  369: 				       from, length, &paylen);
  370: 
  371: 	/* If the IP or UDP checksum was bad, skip the packet... */
  372: 	if (offset < 0)
  373: 		return 0;
  374: 
  375: 	bufix += offset;
  376: 	length -= offset;
  377: 
  378: 	if (length < paylen)
  379: 		log_fatal("Internal inconsistency at %s:%d.", MDL);
  380: 
  381: 	/* Copy out the data in the packet... */
  382: 	memcpy(buf, &ibuf[bufix], paylen);
  383: 	return paylen;
  384: }
  385: 
  386: int can_unicast_without_arp (ip)
  387: 	struct interface_info *ip;
  388: {
  389: 	return 1;
  390: }
  391: 
  392: int can_receive_unicast_unconfigured (ip)
  393: 	struct interface_info *ip;
  394: {
  395: 	return 1;
  396: }
  397: 
  398: int supports_multiple_interfaces (ip)
  399: 	struct interface_info *ip;
  400: {
  401: 	return 1;
  402: }
  403: 
  404: void maybe_setup_fallback ()
  405: {
  406: 	isc_result_t status;
  407: 	struct interface_info *fbi = (struct interface_info *)0;
  408: 	if (setup_fallback (&fbi, MDL)) {
  409: 		if_register_fallback (fbi);
  410: 		status = omapi_register_io_object ((omapi_object_t *)fbi,
  411: 						   if_readsocket, 0,
  412: 						   fallback_discard, 0, 0);
  413: 		if (status != ISC_R_SUCCESS)
  414: 			log_fatal ("Can't register I/O handle for %s: %s",
  415: 				   fbi -> name, isc_result_totext (status));
  416: 		interface_dereference (&fbi, MDL);
  417: 	}
  418: }
  419: #endif

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