File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / dlpi.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:30:18 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /* dlpi.c
    2:  
    3:    Data Link Provider Interface (DLPI) network interface code. */
    4: 
    5: /*
    6:  * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
    7:  * Copyright (c) 2004,2007 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 was written for Internet Systems Consortium
   29:  * by Eric James Negaard, <lmdejn@lmd.ericsson.se>.  To learn more about
   30:  * Internet Systems Consortium, see ``https://www.isc.org''.
   31:  *
   32:  * Joost Mulders has also done considerable work in debugging the DLPI API
   33:  * support on Solaris and getting this code to work properly on a variety
   34:  * of different Solaris platforms.
   35:  */
   36: 
   37: /*
   38:  * Based largely in part to the existing NIT code in nit.c.
   39:  *
   40:  * This code has been developed and tested on sparc-based machines running
   41:  * SunOS 5.5.1, with le and hme network interfaces.  It should be pretty
   42:  * generic, though.
   43:  */
   44: 
   45: /*
   46:  * Implementation notes:
   47:  *
   48:  * I first tried to write this code to the "vanilla" DLPI 2.0 API.
   49:  * It worked on a Sun Ultra-1 with a hme interface, but didn't work
   50:  * on Sun SparcStation 5's with "le" interfaces (the packets sent out
   51:  * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead
   52:  * of the expected 0x0800).
   53:  *
   54:  * Therefore I added the "DLPI_RAW" code which is a Sun extension to
   55:  * the DLPI standard.  This code works on both of the above machines.
   56:  * This is configurable in the OS-dependent include file by defining
   57:  * USE_DLPI_RAW.
   58:  *
   59:  * It quickly became apparant that I should also use the "pfmod"
   60:  * STREAMS module to cut down on the amount of user level packet
   61:  * processing.  I don't know how widely available "pfmod" is, so it's
   62:  * use is conditionally included. This is configurable in the
   63:  * OS-dependent include file by defining USE_DLPI_PFMOD.
   64:  *
   65:  * A major quirk on the Sun's at least, is that no packets seem to get
   66:  * sent out the interface until six seconds after the interface is
   67:  * first "attached" to [per system reboot] (it's actually from when
   68:  * the interface is attached, not when it is plumbed, so putting a
   69:  * sleep into the dhclient-script at PREINIT time doesn't help).  I
   70:  * HAVE tried, without success to poll the fd to see when it is ready
   71:  * for writing.  This doesn't help at all. If the sleeps are not done,
   72:  * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so
   73:  * I've put them here, when register_send and register_receive are
   74:  * called (split up into two three-second sleeps between the notices,
   75:  * so that it doesn't seem like so long when you're watching :-).  The
   76:  * amount of time to sleep is configurable in the OS-dependent include
   77:  * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds
   78:  * to sleep.
   79:  */
   80: 
   81: /*
   82:  * The Open Group Technical Standard can be found here:
   83:  * http://www.opengroup.org/onlinepubs/009618899/index.htm
   84:  *
   85:  * The HP DLPI Programmer's Guide can be found here:
   86:  * http://docs.hp.com/en/B2355-90139/index.html
   87:  */
   88: 
   89: #include "dhcpd.h"
   90: 
   91: #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) || \
   92:     defined(USE_DLPI_HWADDR)
   93: 
   94: # include <sys/ioctl.h>
   95: # include <sys/time.h>
   96: # include <sys/dlpi.h>
   97: # include <stropts.h>
   98: # ifdef USE_DLPI_PFMOD
   99: #  include <sys/pfmod.h>
  100: # endif
  101: #include <poll.h>
  102: #include <errno.h>
  103: 
  104: # include <netinet/in_systm.h>
  105: # include "includes/netinet/ip.h"
  106: # include "includes/netinet/udp.h"
  107: # include "includes/netinet/if_ether.h"
  108: 
  109: # ifdef USE_DLPI_PFMOD
  110: #  ifdef USE_DLPI_RAW
  111: #   define DLPI_MODNAME "DLPI+RAW+PFMOD"
  112: #  else
  113: #   define DLPI_MODNAME "DLPI+PFMOD"
  114: #  endif
  115: # else
  116: #  ifdef USE_DLPI_RAW
  117: #   define DLPI_MODNAME "DLPI+RAW"
  118: #  else
  119: #   define DLPI_MODNAME "DLPI"
  120: #  endif
  121: # endif
  122: 
  123: # ifndef ABS
  124: #  define ABS(x) ((x) >= 0 ? (x) : 0-(x))
  125: # endif
  126: 
  127: #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
  128: static int strioctl (int fd, int cmd, int timeout, int len, char *dp);
  129: #endif
  130: 
  131: #define DLPI_MAXDLBUF		8192	/* Buffer size */
  132: #define DLPI_MAXDLADDR		1024	/* Max address size */
  133: #define DLPI_DEVDIR		"/dev/"	/* Device directory */
  134: 
  135: static int dlpiopen(const char *ifname);
  136: static int dlpiunit (char *ifname);
  137: static int dlpiinforeq (int fd);
  138: static int dlpiphysaddrreq (int fd, unsigned long addrtype);
  139: static int dlpiattachreq (int fd, unsigned long ppa);
  140: static int dlpibindreq (int fd, unsigned long sap, unsigned long max_conind,
  141: 			unsigned long service_mode, unsigned long conn_mgmt,
  142: 			unsigned long xidtest);
  143: #if defined(UNUSED_DLPI_INTERFACE)
  144: /* These functions are unused at present, but may be used at a later date.
  145:  * defined out to avoid compiler warnings about unused static functions.
  146:  */
  147: static int dlpidetachreq (int fd);
  148: static int dlpiunbindreq (int fd);
  149: #endif
  150: static int dlpiokack (int fd, char *bufp);
  151: static int dlpiinfoack (int fd, char *bufp);
  152: static int dlpiphysaddrack (int fd, char *bufp);
  153: static int dlpibindack (int fd, char *bufp);
  154: #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
  155: /* These functions are not used if we're only sourcing the get_hw_addr()
  156:  * function (for USE_SOCKETS).
  157:  */
  158: static int dlpiunitdatareq (int fd, unsigned char *addr, int addrlen, 
  159: 			    unsigned long minpri, unsigned long maxpri, 
  160: 			    unsigned char *data, int datalen);
  161: static int dlpiunitdataind (int fd,
  162: 			    unsigned char *dstaddr,
  163: 			    unsigned long *dstaddrlen,
  164: 			    unsigned char *srcaddr,
  165: 			    unsigned long *srcaddrlen,
  166: 			    unsigned long *grpaddr,
  167: 			    unsigned char *data,
  168: 			    int datalen);
  169: #endif /* !USE_DLPI_HWADDR: USE_DLPI_SEND || USE_DLPI_RECEIVE */
  170: static int expected (unsigned long prim, union DL_primitives *dlp, 
  171: 		     int msgflags);
  172: static int strgetmsg (int fd, struct strbuf *ctlp, struct strbuf *datap,
  173: 		      int *flagsp, char *caller);
  174: 
  175: /* Reinitializes the specified interface after an address change.   This
  176:    is not required for packet-filter APIs. */
  177: 
  178: #ifdef USE_DLPI_SEND
  179: void if_reinitialize_send (info)
  180: 	struct interface_info *info;
  181: {
  182: }
  183: #endif
  184: 
  185: #ifdef USE_DLPI_RECEIVE
  186: void if_reinitialize_receive (info)
  187: 	struct interface_info *info;
  188: {
  189: }
  190: #endif
  191: 
  192: /* Called by get_interface_list for each interface that's discovered.
  193:    Opens a packet filter for each interface and adds it to the select
  194:    mask. */
  195: 
  196: int if_register_dlpi (info)
  197: 	struct interface_info *info;
  198: {
  199: 	int sock;
  200: 	int unit;
  201: 	long buf [DLPI_MAXDLBUF];
  202: 	union DL_primitives *dlp;
  203: 
  204: 	dlp = (union DL_primitives *)buf;
  205: 
  206: 	/* Open a DLPI device */
  207: 	if ((sock = dlpiopen (info -> name)) < 0) {
  208: 	    log_fatal ("Can't open DLPI device for %s: %m", info -> name);
  209: 	}
  210: 
  211: 	/*
  212: 	 * Submit a DL_INFO_REQ request, to find the dl_mac_type and 
  213:          * dl_provider_style
  214: 	 */
  215: 	if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
  216: 	    log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
  217: 	} else {
  218: 	    switch (dlp -> info_ack.dl_mac_type) {
  219: 	      case DL_CSMACD: /* IEEE 802.3 */
  220: 	      case DL_ETHER:
  221: 		info -> hw_address.hbuf [0] = HTYPE_ETHER;
  222: 		break;
  223: 	      /* adding token ring 5/1999 - mayer@ping.at  */ 
  224: 	      case DL_TPR:
  225: 		info -> hw_address.hbuf [0] = HTYPE_IEEE802;
  226: 		break;
  227: 	      case DL_FDDI:
  228: 		info -> hw_address.hbuf [0] = HTYPE_FDDI;
  229: 		break;
  230: 	      default:
  231: 		log_fatal("%s: unsupported DLPI MAC type %lu", info->name,
  232: 			  (unsigned long)dlp->info_ack.dl_mac_type);
  233: 		break;
  234: 	    }
  235:             /*
  236:              * copy the sap length and broadcast address of this interface
  237:              * to interface_info. This fixes nothing but seemed nicer than to
  238:              * assume -2 and ffffff.
  239:              */
  240:             info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length;
  241:             info -> dlpi_broadcast_addr.hlen = 
  242:              dlp -> info_ack.dl_brdcst_addr_length;
  243:             memcpy (info -> dlpi_broadcast_addr.hbuf, 
  244:              (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset, 
  245:              dlp -> info_ack.dl_brdcst_addr_length);
  246: 	}
  247: 
  248: 	if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
  249: 	    /*
  250: 	     * Attach to the device.  If this fails, the device
  251: 	     * does not exist.
  252: 	     */
  253: 	    unit = dlpiunit (info -> name);
  254: 	
  255: 	    if (dlpiattachreq (sock, unit) < 0
  256: 		|| dlpiokack (sock, (char *)buf) < 0) {
  257: 		log_fatal ("Can't attach DLPI device for %s: %m", info -> name);
  258: 	    }
  259: 	}
  260: 
  261: 	/*
  262: 	 * Bind to the IP service access point (SAP), connectionless (CLDLS).
  263: 	 */
  264: 	if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0
  265: 	    || dlpibindack (sock, (char *)buf) < 0) {
  266: 	    log_fatal ("Can't bind DLPI device for %s: %m", info -> name);
  267: 	}
  268: 
  269: 	/*
  270: 	 * Submit a DL_PHYS_ADDR_REQ request, to find
  271: 	 * the hardware address
  272: 	 */
  273: 	if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0
  274: 	    || dlpiphysaddrack (sock, (char *)buf) < 0) {
  275: 	    log_fatal ("Can't get DLPI hardware address for %s: %m",
  276: 		   info -> name);
  277: 	}
  278: 
  279: 	info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1;
  280: 	memcpy (&info -> hw_address.hbuf [1],
  281: 		(char *)buf + dlp -> physaddr_ack.dl_addr_offset,
  282: 		dlp -> physaddr_ack.dl_addr_length);
  283: 
  284: #ifdef USE_DLPI_RAW
  285: 	if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
  286: 	    log_fatal ("Can't set DLPI RAW mode for %s: %m",
  287: 		   info -> name);
  288: 	}
  289: #endif
  290: 
  291: #ifdef USE_DLPI_PFMOD
  292: 	if (ioctl (sock, I_PUSH, "pfmod") < 0) {
  293: 	    log_fatal ("Can't push packet filter onto DLPI for %s: %m",
  294: 		   info -> name);
  295: 	}
  296: #endif
  297: 
  298: 	return sock;
  299: }
  300: 
  301: #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
  302: static int
  303: strioctl (fd, cmd, timeout, len, dp)
  304: int fd;
  305: int cmd;
  306: int timeout;
  307: int len;
  308: char *dp;
  309: {
  310:     struct strioctl sio;
  311:     int rslt;
  312: 
  313:     sio.ic_cmd = cmd;
  314:     sio.ic_timout = timeout;
  315:     sio.ic_len = len;
  316:     sio.ic_dp = dp;
  317: 
  318:     if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
  319: 	return rslt;
  320:     } else {
  321: 	return sio.ic_len;
  322:     }
  323: }
  324: #endif /* USE_DPI_PFMOD || USE_DLPI_RAW */
  325: 
  326: #ifdef USE_DLPI_SEND
  327: void if_register_send (info)
  328: 	struct interface_info *info;
  329: {
  330: 	/* If we're using the DLPI API for sending and receiving,
  331: 	   we don't need to register this interface twice. */
  332: #ifndef USE_DLPI_RECEIVE
  333: # ifdef USE_DLPI_PFMOD
  334: 	struct packetfilt pf;
  335: # endif
  336: 
  337: 	info -> wfdesc = if_register_dlpi (info);
  338: 
  339: # ifdef USE_DLPI_PFMOD
  340: 	/* Set up an PFMOD filter that rejects everything... */
  341: 	pf.Pf_Priority = 0;
  342: 	pf.Pf_FilterLen = 1;
  343: 	pf.Pf_Filter [0] = ENF_PUSHZERO;
  344: 
  345: 	/* Install the filter */
  346: 	if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM,
  347: 		      sizeof (pf), (char *)&pf) < 0) {
  348: 	    log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name);
  349: 	}
  350: 
  351: # endif /* USE_DLPI_PFMOD */
  352: #else /* !defined (USE_DLPI_RECEIVE) */
  353: 	/*
  354: 	 * If using DLPI for both send and receive, simply re-use
  355: 	 * the read file descriptor that was set up earlier.
  356: 	 */
  357: 	info -> wfdesc = info -> rfdesc;
  358: #endif
  359: 
  360:         if (!quiet_interface_discovery)
  361: 		log_info ("Sending on   DLPI/%s/%s%s%s",
  362: 		      info -> name,
  363: 		      print_hw_addr (info -> hw_address.hbuf [0],
  364: 				     info -> hw_address.hlen - 1,
  365: 				     &info -> hw_address.hbuf [1]),
  366: 		      (info -> shared_network ? "/" : ""),
  367: 		      (info -> shared_network ?
  368: 		       info -> shared_network -> name : ""));
  369: 
  370: #ifdef DLPI_FIRST_SEND_WAIT
  371: /* See the implementation notes at the beginning of this file */
  372: # ifdef USE_DLPI_RECEIVE
  373: 	sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2));
  374: # else
  375: 	sleep (DLPI_FIRST_SEND_WAIT);
  376: # endif
  377: #endif
  378: }
  379: 
  380: void if_deregister_send (info)
  381: 	struct interface_info *info;
  382: {
  383: 	/* If we're using the DLPI API for sending and receiving,
  384: 	   we don't need to register this interface twice. */
  385: #ifndef USE_DLPI_RECEIVE
  386: 	close (info -> wfdesc);
  387: #endif
  388: 	info -> wfdesc = -1;
  389: 
  390:         if (!quiet_interface_discovery)
  391: 		log_info ("Disabling output on DLPI/%s/%s%s%s",
  392: 		      info -> name,
  393: 		      print_hw_addr (info -> hw_address.hbuf [0],
  394: 				     info -> hw_address.hlen - 1,
  395: 				     &info -> hw_address.hbuf [1]),
  396: 		      (info -> shared_network ? "/" : ""),
  397: 		      (info -> shared_network ?
  398: 		       info -> shared_network -> name : ""));
  399: }
  400: #endif /* USE_DLPI_SEND */
  401: 
  402: #ifdef USE_DLPI_RECEIVE
  403: /* Packet filter program...
  404:    XXX Changes to the filter program may require changes to the constant
  405:    offsets used in if_register_send to patch the NIT program! XXX */
  406: 
  407: void if_register_receive (info)
  408: 	struct interface_info *info;
  409: {
  410: #ifdef USE_DLPI_PFMOD
  411: 	struct packetfilt pf;
  412:         struct ip iphdr;
  413:         u_int16_t offset;
  414: #endif
  415: 
  416: 	/* Open a DLPI device and hang it on this interface... */
  417: 	info -> rfdesc = if_register_dlpi (info);
  418: 
  419: #ifdef USE_DLPI_PFMOD
  420: 	/* Set up the PFMOD filter program. */
  421: 	/* XXX Unlike the BPF filter program, this one won't work if the
  422: 	   XXX IP packet is fragmented or if there are options on the IP
  423: 	   XXX header. */
  424: 	pf.Pf_Priority = 0;
  425: 	pf.Pf_FilterLen = 0;
  426: 
  427: #if defined (USE_DLPI_RAW)
  428: # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
  429:     /*
  430:      * ethertype == ETHERTYPE_IP
  431:      */
  432:     offset = 12;
  433:     pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
  434:     pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
  435:     pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
  436: # else
  437: # define ETHER_H_PREFIX (0)
  438: # endif /* USE_DLPI_RAW */
  439: 	/*
  440: 	 * The packets that will be received on this file descriptor
  441: 	 * will be IP packets (due to the SAP that was specified in
  442: 	 * the dlbind call).  There will be no ethernet header.
  443: 	 * Therefore, setup the packet filter to check the protocol
  444: 	 * field for UDP, and the destination port number equal
  445: 	 * to the local port.  All offsets are relative to the start
  446: 	 * of an IP packet.
  447: 	 */
  448: 
  449:         /*
  450:          * BOOTPS destination port
  451:          */
  452:         offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t);
  453:         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
  454:         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
  455:         pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
  456: 
  457:         /*
  458:          * protocol should be udp. this is a byte compare, test for
  459:          * endianess.
  460:          */
  461:         offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr);
  462:         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
  463:         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND;
  464:         pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF);
  465:         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
  466:       pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
  467: 
  468: 	/* Install the filter... */
  469: 	if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
  470: 		      sizeof (pf), (char *)&pf) < 0) {
  471: 	    log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name);
  472: 	}
  473: #endif /* USE_DLPI_PFMOD */
  474: 
  475:         if (!quiet_interface_discovery)
  476: 		log_info ("Listening on DLPI/%s/%s%s%s",
  477: 		      info -> name,
  478: 		      print_hw_addr (info -> hw_address.hbuf [0],
  479: 				     info -> hw_address.hlen - 1,
  480: 				     &info -> hw_address.hbuf [1]),
  481: 		      (info -> shared_network ? "/" : ""),
  482: 		      (info -> shared_network ?
  483: 		       info -> shared_network -> name : ""));
  484: 
  485: #ifdef DLPI_FIRST_SEND_WAIT
  486: /* See the implementation notes at the beginning of this file */
  487: # ifdef USE_DLPI_SEND
  488: 	sleep (DLPI_FIRST_SEND_WAIT / 2);
  489: # else
  490: 	sleep (DLPI_FIRST_SEND_WAIT);
  491: # endif
  492: #endif
  493: }
  494: 
  495: void if_deregister_receive (info)
  496: 	struct interface_info *info;
  497: {
  498: 	/* If we're using the DLPI API for sending and receiving,
  499: 	   we don't need to register this interface twice. */
  500: #ifndef USE_DLPI_SEND
  501: 	close (info -> rfdesc);
  502: #endif
  503: 	info -> rfdesc = -1;
  504: 
  505:         if (!quiet_interface_discovery)
  506: 		log_info ("Disabling input on DLPI/%s/%s%s%s",
  507: 		      info -> name,
  508: 		      print_hw_addr (info -> hw_address.hbuf [0],
  509: 				     info -> hw_address.hlen - 1,
  510: 				     &info -> hw_address.hbuf [1]),
  511: 		      (info -> shared_network ? "/" : ""),
  512: 		      (info -> shared_network ?
  513: 		       info -> shared_network -> name : ""));
  514: }
  515: #endif /* USE_DLPI_RECEIVE */
  516: 
  517: #ifdef USE_DLPI_SEND
  518: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
  519: 	struct interface_info *interface;
  520: 	struct packet *packet;
  521: 	struct dhcp_packet *raw;
  522: 	size_t len;
  523: 	struct in_addr from;
  524: 	struct sockaddr_in *to;
  525: 	struct hardware *hto;
  526: {
  527: #ifdef USE_DLPI_RAW
  528: 	double hh [32];
  529: #endif
  530: 	double ih [1536 / sizeof (double)];
  531: 	unsigned char *dbuf = (unsigned char *)ih;
  532: 	unsigned dbuflen;
  533: 	unsigned char dstaddr [DLPI_MAXDLADDR];
  534: 	unsigned addrlen;
  535: 	int result;
  536: 	int fudge;
  537: 
  538: 	if (!strcmp (interface -> name, "fallback"))
  539: 		return send_fallback (interface, packet, raw,
  540: 				      len, from, to, hto);
  541: 
  542: 	dbuflen = 0;
  543: 
  544: 	/* Assemble the headers... */
  545: #ifdef USE_DLPI_RAW
  546: 	assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto);
  547:       if (dbuflen > sizeof hh)
  548:               log_fatal ("send_packet: hh buffer too small.\n");
  549: 	fudge = dbuflen % 4; /* IP header must be word-aligned. */
  550: 	memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen);
  551: 	dbuflen += fudge;
  552: #else
  553: 	fudge = 0;
  554: #endif
  555: 	assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr,
  556: 				to -> sin_addr.s_addr, to -> sin_port,
  557: 				(unsigned char *)raw, len);
  558: 
  559: 	/* Copy the data into the buffer (yuk). */
  560: 	memcpy (dbuf + dbuflen, raw, len);
  561: 	dbuflen += len;
  562: 
  563: #ifdef USE_DLPI_RAW
  564: 	result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
  565: #else
  566: 
  567: 	/*
  568:          * Setup the destination address (DLSAP) in dstaddr 
  569:          *
  570:          * If sap_length < 0 we must deliver the DLSAP as phys+sap. 
  571:          * If sap_length > 0 we must deliver the DLSAP as sap+phys.
  572:          *
  573:          * sap = Service Access Point == ETHERTYPE_IP
  574:          * sap + datalink address is called DLSAP in dlpi speak.
  575:          */
  576:         { /* ENCODE DLSAP */
  577:           unsigned char phys [DLPI_MAXDLADDR];
  578:           unsigned char sap [4];
  579:           int sap_len = interface -> dlpi_sap_length;
  580:           int phys_len = interface -> hw_address.hlen - 1;
  581: 
  582:           /* sap = htons (ETHERTYPE_IP) kludge */
  583:           memset (sap, 0, sizeof (sap));
  584: # if (BYTE_ORDER == LITTLE_ENDIAN)
  585:           sap [0] = 0x00;
  586:           sap [1] = 0x08;
  587: # else
  588:           sap [0] = 0x08;
  589:           sap [1] = 0x00;
  590: # endif
  591: 
  592:         if (hto && hto -> hlen == interface -> hw_address.hlen)
  593:              memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
  594:           else 
  595:              memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, 
  596:               interface -> dlpi_broadcast_addr.hlen);
  597:            
  598:           if (sap_len < 0) { 
  599:              memcpy ( dstaddr, phys, phys_len);
  600:              memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
  601:           }
  602:           else {
  603:              memcpy ( dstaddr, (void *) sap, sap_len);
  604:              memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
  605:           }
  606:         addrlen = phys_len + ABS (sap_len);
  607:       } /* ENCODE DLSAP */
  608: 
  609: 	result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
  610: 				  0, 0, dbuf, dbuflen);
  611: #endif /* USE_DLPI_RAW */
  612: 	if (result < 0)
  613: 		log_error ("send_packet: %m");
  614: 	return result;
  615: }
  616: #endif /* USE_DLPI_SEND */
  617: 
  618: #ifdef USE_DLPI_RECEIVE
  619: ssize_t receive_packet (interface, buf, len, from, hfrom)
  620: 	struct interface_info *interface;
  621: 	unsigned char *buf;
  622: 	size_t len;
  623: 	struct sockaddr_in *from;
  624: 	struct hardware *hfrom;
  625: {
  626: 	unsigned char dbuf [1536];
  627: 	unsigned char srcaddr [DLPI_MAXDLADDR];
  628: 	unsigned long srcaddrlen;
  629: 	int length = 0;
  630: 	int offset = 0;
  631: 	int bufix = 0;
  632: 	unsigned paylen;
  633: 	
  634: #ifdef USE_DLPI_RAW
  635: 	length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
  636: #else	
  637: 	length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
  638: 				  (unsigned long *)NULL, srcaddr, &srcaddrlen,
  639: 				  (unsigned long *)NULL, dbuf, sizeof (dbuf));
  640: #endif
  641: 
  642: 	if (length <= 0) {
  643: 	    log_error("receive_packet: %m");
  644: 	    return length;
  645: 	}
  646: 
  647: # if !defined (USE_DLPI_RAW)
  648:         /*
  649:          * Copy the sender's hw address into hfrom
  650:          * If sap_len < 0 the DLSAP is as phys+sap.
  651:          * If sap_len > 0 the DLSAP is as sap+phys.
  652:          *
  653:          * sap is discarded here.
  654:          */
  655:         { /* DECODE DLSAP */
  656:           int sap_len = interface -> dlpi_sap_length;
  657:           int phys_len = interface -> hw_address.hlen - 1;
  658: 
  659:           if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) {
  660:             hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
  661:             hfrom -> hlen = interface -> hw_address.hlen;
  662:             
  663:             if (sap_len < 0) {
  664:               memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
  665:             }
  666:             else {
  667:               memcpy((char *)&hfrom->hbuf[1], srcaddr + sap_len, phys_len);
  668:             }
  669:           } 
  670:           else if (hfrom) {
  671:             memset (hfrom, '\0', sizeof *hfrom);
  672:           }
  673:         } /* DECODE_DLSAP */
  674: 
  675: # endif /* !defined (USE_DLPI_RAW) */
  676: 
  677: 	/* Decode the IP and UDP headers... */
  678: 	bufix = 0;
  679: #ifdef USE_DLPI_RAW
  680: 	/* Decode the physical header... */
  681: 	offset = decode_hw_header (interface, dbuf, bufix, hfrom);
  682: 
  683: 	/* If a physical layer checksum failed (dunno of any
  684: 	   physical layer that supports this, but WTH), skip this
  685: 	   packet. */
  686: 	if (offset < 0) {
  687: 		return 0;
  688: 	}
  689: 	bufix += offset;
  690: 	length -= offset;
  691: #endif
  692: 	offset = decode_udp_ip_header (interface, dbuf, bufix,
  693: 				       from, length, &paylen);
  694: 
  695: 	/*
  696: 	 * If the IP or UDP checksum was bad, skip the packet...
  697: 	 *
  698: 	 * Note: this happens all the time when writing packets via the
  699: 	 * fallback socket.  The packet received by streams does not have
  700: 	 * the IP or UDP checksums filled in, as those are calculated by
  701: 	 * the hardware.
  702: 	 */
  703: 	if (offset < 0) {
  704: 		return 0;
  705: 	}
  706: 
  707: 	bufix += offset;
  708: 	length -= offset;
  709: 
  710: 	if (length < paylen)
  711: 		log_fatal("Internal inconsistency at %s:%d.", MDL);
  712: 
  713: 	/* Copy out the data in the packet... */
  714: 	memcpy(buf, &dbuf [bufix], paylen);
  715: 	return paylen;
  716: }
  717: #endif
  718: 
  719: /* Common DLPI routines ...
  720:  *
  721:  * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
  722:  *
  723:  * Based largely in part to the example code contained in the document
  724:  * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
  725:  * by Neal Nuckolls of SunSoft Internet Engineering.
  726:  * 
  727:  * This code has been developed and tested on sparc-based machines running
  728:  * SunOS 5.5.1, with le and hme network interfaces.  It should be pretty
  729:  * generic, though.
  730:  * 
  731:  * The usual disclaimers apply.  This code works for me.  Don't blame me
  732:  * if it makes your machine or network go down in flames.  That taken
  733:  * into consideration, use this code as you wish.  If you make usefull
  734:  * modifications I'd appreciate hearing about it.
  735:  */
  736: 
  737: #define DLPI_MAXWAIT		15	/* Max timeout */
  738: 
  739: 
  740: /*
  741:  * Parse an interface name and extract the unit number
  742:  */
  743: 
  744: static int dlpiunit (ifname)
  745: 	char *ifname;
  746: {
  747: 	char *cp;
  748: 	int unit;
  749: 	
  750: 	if (!ifname) {
  751: 		return 0;
  752: 	}
  753: 	
  754: 	/* Advance to the end of the name */
  755: 	cp = ifname;
  756: 	while (*cp) cp++;
  757: 	/* Back up to the start of the first digit */
  758: 	while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
  759: 	
  760: 	/* Convert the unit number */
  761: 	unit = 0;
  762: 	while (*cp >= '0' && *cp <= '9') {
  763: 		unit *= 10;
  764: 		unit += (*cp++ - '0');
  765: 	}
  766: 	
  767: 	return unit;
  768: }
  769: 
  770: /*
  771:  * dlpiopen - open the DLPI device for a given interface name
  772:  */
  773: static int
  774: dlpiopen(const char *ifname) {
  775: 	char devname [50];
  776: 	char *dp;
  777: 	const char *cp, *ep;
  778: 	
  779: 	if (!ifname) {
  780: 		return -1;
  781: 	}
  782: 	
  783: 	/* Open a DLPI device */
  784: 	if (*ifname == '/') {
  785: 		dp = devname;
  786: 	} else {
  787: 		/* Prepend the device directory */
  788: 		memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
  789: 		dp = &devname [strlen (DLPI_DEVDIR)];
  790: 	}
  791: 
  792: 	/* Find the end of the interface name */
  793: 	ep = cp = ifname;
  794: 	while (*ep)
  795: 		ep++;
  796: 	/* And back up to the first digit (unit number) */
  797: 	while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
  798: 		ep--;
  799: 	
  800: 	/* Copy everything up to the unit number */
  801: 	while (cp < ep) {
  802: 		*dp++ = *cp++;
  803: 	}
  804: 	*dp = '\0';
  805: 	
  806: 	return open (devname, O_RDWR, 0);
  807: }
  808: 
  809: /*
  810:  * dlpiinforeq - request information about the data link provider.
  811:  */
  812: 
  813: static int dlpiinforeq (fd)
  814: 	int fd;
  815: {
  816: 	dl_info_req_t info_req;
  817: 	struct strbuf ctl;
  818: 	int flags;
  819: 	
  820: 	info_req.dl_primitive = DL_INFO_REQ;
  821: 	
  822: 	ctl.maxlen = 0;
  823: 	ctl.len = sizeof (info_req);
  824: 	ctl.buf = (char *)&info_req;
  825: 	
  826: 	flags = RS_HIPRI;
  827: 	
  828: 	return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
  829: }
  830: 
  831: /*
  832:  * dlpiphysaddrreq - request the current physical address.
  833:  */
  834: static int dlpiphysaddrreq (fd, addrtype)
  835: 	int fd;
  836: 	unsigned long addrtype;
  837: {
  838: 	dl_phys_addr_req_t physaddr_req;
  839: 	struct strbuf ctl;
  840: 	int flags;
  841: 	
  842: 	physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
  843: 	physaddr_req.dl_addr_type = addrtype;
  844: 	
  845: 	ctl.maxlen = 0;
  846: 	ctl.len = sizeof (physaddr_req);
  847: 	ctl.buf = (char *)&physaddr_req;
  848: 	
  849: 	flags = RS_HIPRI;
  850: 	
  851: 	return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
  852: }
  853: 
  854: /*
  855:  * dlpiattachreq - send a request to attach to a specific unit.
  856:  */
  857: static int dlpiattachreq (fd, ppa)
  858: 	unsigned long ppa;
  859: 	int fd;
  860: {
  861: 	dl_attach_req_t	attach_req;
  862: 	struct strbuf ctl;
  863: 	int flags;
  864: 	
  865: 	attach_req.dl_primitive = DL_ATTACH_REQ;
  866: 	attach_req.dl_ppa = ppa;
  867: 	
  868: 	ctl.maxlen = 0;
  869: 	ctl.len = sizeof (attach_req);
  870: 	ctl.buf = (char *)&attach_req;
  871: 	
  872: 	flags = 0;
  873: 	
  874: 	return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
  875: }
  876: 
  877: /*
  878:  * dlpibindreq - send a request to bind to a specific SAP address.
  879:  */
  880: static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
  881: 	unsigned long sap;
  882: 	unsigned long max_conind;
  883: 	unsigned long service_mode;
  884: 	unsigned long conn_mgmt;
  885: 	unsigned long xidtest;
  886: 	int fd;
  887: {
  888: 	dl_bind_req_t bind_req;
  889: 	struct strbuf ctl;
  890: 	int flags;
  891: 	
  892: 	bind_req.dl_primitive = DL_BIND_REQ;
  893: 	bind_req.dl_sap = sap;
  894: 	bind_req.dl_max_conind = max_conind;
  895: 	bind_req.dl_service_mode = service_mode;
  896: 	bind_req.dl_conn_mgmt = conn_mgmt;
  897: 	bind_req.dl_xidtest_flg = xidtest;
  898: 	
  899: 	ctl.maxlen = 0;
  900: 	ctl.len = sizeof (bind_req);
  901: 	ctl.buf = (char *)&bind_req;
  902: 	
  903: 	flags = 0;
  904: 	
  905: 	return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
  906: }
  907: 
  908: #if defined(UNUSED_DLPI_INTERFACE)
  909: /*
  910:  * dlpiunbindreq - send a request to unbind.  This function is not actually
  911:  *	used by ISC DHCP, but is included for completeness in case it is
  912:  *	ever required for new work.
  913:  */
  914: static int dlpiunbindreq (fd)
  915: 	int fd;
  916: {
  917: 	dl_unbind_req_t	unbind_req;
  918: 	struct strbuf ctl;
  919: 	int flags;
  920: 	
  921: 	unbind_req.dl_primitive = DL_UNBIND_REQ;
  922: 	
  923: 	ctl.maxlen = 0;
  924: 	ctl.len = sizeof (unbind_req);
  925: 	ctl.buf = (char *)&unbind_req;
  926: 	
  927: 	flags = 0;
  928: 	
  929: 	return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
  930: }
  931: 
  932: 
  933: /*
  934:  * dlpidetachreq - send a request to detach.  This function is not actually
  935:  *	used by ISC DHCP, but is included for completeness in case it is
  936:  *	ever required for new work.
  937:  */
  938: static int dlpidetachreq (fd)
  939: 	int fd;
  940: {
  941: 	dl_detach_req_t	detach_req;
  942: 	struct strbuf ctl;
  943: 	int flags;
  944: 	
  945: 	detach_req.dl_primitive = DL_DETACH_REQ;
  946: 	
  947: 	ctl.maxlen = 0;
  948: 	ctl.len = sizeof (detach_req);
  949: 	ctl.buf = (char *)&detach_req;
  950: 	
  951: 	flags = 0;
  952: 	
  953: 	return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
  954: }
  955: #endif /* UNUSED_DLPI_INTERFACE */
  956: 
  957: 
  958: /*
  959:  * dlpibindack - receive an ack to a dlbindreq.
  960:  */
  961: static int dlpibindack (fd, bufp)
  962: 	char *bufp;
  963: 	int fd;
  964: {
  965: 	union DL_primitives *dlp;
  966: 	struct strbuf ctl;
  967: 	int flags;
  968: 	
  969: 	ctl.maxlen = DLPI_MAXDLBUF;
  970: 	ctl.len = 0;
  971: 	ctl.buf = bufp;
  972: 
  973: 	if (strgetmsg (fd, &ctl,
  974: 		       (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
  975: 		return -1;
  976: 	}
  977: 	
  978: 	dlp = (union DL_primitives *)ctl.buf;
  979: 	
  980: 	if (expected (DL_BIND_ACK, dlp, flags) == -1) {
  981: 		return -1;
  982: 	}
  983: 	
  984: 	if (ctl.len < sizeof (dl_bind_ack_t)) {
  985: 		/* Returned structure is too short */
  986: 		return -1;
  987: 	}
  988: 
  989: 	return 0;
  990: }
  991: 
  992: /*
  993:  * dlpiokack - general acknowledgement reception.
  994:  */
  995: static int dlpiokack (fd, bufp)
  996: 	char *bufp;
  997: 	int fd;
  998: {
  999: 	union DL_primitives *dlp;
 1000: 	struct strbuf ctl;
 1001: 	int flags;
 1002: 	
 1003: 	ctl.maxlen = DLPI_MAXDLBUF;
 1004: 	ctl.len = 0;
 1005: 	ctl.buf = bufp;
 1006: 	
 1007: 	if (strgetmsg (fd, &ctl,
 1008: 		       (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
 1009: 		return -1;
 1010: 	}
 1011: 	
 1012: 	dlp = (union DL_primitives *)ctl.buf;
 1013: 	
 1014: 	if (expected (DL_OK_ACK, dlp, flags) == -1) {
 1015: 		return -1;
 1016: 	}
 1017: 	
 1018: 	if (ctl.len < sizeof (dl_ok_ack_t)) {
 1019: 		/* Returned structure is too short */
 1020: 		return -1;
 1021: 	}
 1022: 	
 1023: 	return 0;
 1024: }
 1025: 
 1026: /*
 1027:  * dlpiinfoack - receive an ack to a dlinforeq.
 1028:  */
 1029: static int dlpiinfoack (fd, bufp)
 1030: 	char *bufp;
 1031: 	int fd;
 1032: {
 1033: 	union DL_primitives *dlp;
 1034: 	struct strbuf ctl;
 1035: 	int flags;
 1036: 	
 1037: 	ctl.maxlen = DLPI_MAXDLBUF;
 1038: 	ctl.len = 0;
 1039: 	ctl.buf = bufp;
 1040: 	
 1041: 	if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
 1042: 		       "dlpiinfoack") < 0) {
 1043: 		return -1;
 1044: 	}
 1045: 	
 1046: 	dlp = (union DL_primitives *) ctl.buf;
 1047: 	
 1048: 	if (expected (DL_INFO_ACK, dlp, flags) == -1) {
 1049: 		return -1;
 1050: 	}
 1051: 	
 1052: 	if (ctl.len < sizeof (dl_info_ack_t)) {
 1053: 		/* Returned structure is too short */
 1054: 		return -1;
 1055: 	}
 1056: 	
 1057: 	return 0;
 1058: }
 1059: 
 1060: /*
 1061:  * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
 1062:  */
 1063: int dlpiphysaddrack (fd, bufp)
 1064: 	char *bufp;
 1065: 	int fd;
 1066: {
 1067: 	union DL_primitives *dlp;
 1068: 	struct strbuf ctl;
 1069: 	int flags;
 1070: 	
 1071: 	ctl.maxlen = DLPI_MAXDLBUF;
 1072: 	ctl.len = 0;
 1073: 	ctl.buf = bufp;
 1074: 	
 1075: 	if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
 1076: 		       "dlpiphysaddrack") < 0) {
 1077: 		return -1;
 1078: 	}
 1079: 
 1080: 	dlp = (union DL_primitives *)ctl.buf;
 1081: 	
 1082: 	if (expected (DL_PHYS_ADDR_ACK, dlp, flags) == -1) {
 1083: 		return -1;
 1084: 	}
 1085: 
 1086: 	if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
 1087: 		/* Returned structure is too short */
 1088: 		return -1;
 1089: 	}
 1090: 	
 1091: 	return 0;
 1092: }
 1093: 
 1094: #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
 1095: int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
 1096: 	int fd;
 1097: 	unsigned char *addr;
 1098: 	int addrlen;
 1099: 	unsigned long minpri;
 1100: 	unsigned long maxpri;
 1101: 	unsigned char *dbuf;
 1102: 	int dbuflen;
 1103: {
 1104: 	long buf [DLPI_MAXDLBUF];
 1105: 	union DL_primitives *dlp;
 1106: 	struct strbuf ctl, data;
 1107: 	
 1108: 	/* Set up the control information... */
 1109: 	dlp = (union DL_primitives *)buf;
 1110: 	dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ;
 1111: 	dlp -> unitdata_req.dl_dest_addr_length = addrlen;
 1112: 	dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
 1113: 	dlp -> unitdata_req.dl_priority.dl_min = minpri;
 1114: 	dlp -> unitdata_req.dl_priority.dl_max = maxpri;
 1115: 
 1116: 	/* Append the destination address */
 1117: 	memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
 1118: 		addr, addrlen);
 1119: 	
 1120: 	ctl.maxlen = 0;
 1121: 	ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
 1122: 	ctl.buf = (char *)buf;
 1123: 
 1124: 	data.maxlen = 0;
 1125: 	data.buf = (char *)dbuf;
 1126: 	data.len = dbuflen;
 1127: 
 1128: 	/* Send the packet down the wire... */
 1129: 	return putmsg (fd, &ctl, &data, 0);
 1130: }
 1131: 
 1132: static int dlpiunitdataind (fd, daddr, daddrlen,
 1133: 			    saddr, saddrlen, grpaddr, dbuf, dlen)
 1134: 	int fd;
 1135: 	unsigned char *daddr;
 1136: 	unsigned long *daddrlen;
 1137: 	unsigned char *saddr;
 1138: 	unsigned long *saddrlen;
 1139: 	unsigned long *grpaddr;
 1140: 	unsigned char *dbuf;
 1141: 	int dlen;
 1142: {
 1143: 	long buf [DLPI_MAXDLBUF];
 1144: 	union DL_primitives *dlp;
 1145: 	struct strbuf ctl, data;
 1146: 	int flags = 0;
 1147: 	int result;
 1148: 
 1149: 	/* Set up the msg_buf structure... */
 1150: 	dlp = (union DL_primitives *)buf;
 1151: 	dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
 1152: 
 1153: 	ctl.maxlen = DLPI_MAXDLBUF;
 1154: 	ctl.len = 0;
 1155: 	ctl.buf = (char *)buf;
 1156: 
 1157: 	data.maxlen = dlen;
 1158: 	data.len = 0;
 1159: 	data.buf = (char *)dbuf;
 1160: 
 1161: 	result = getmsg (fd, &ctl, &data, &flags);
 1162: 
 1163: 	if (result < 0) {
 1164: 		log_debug("dlpiunitdataind: %m");
 1165: 		return -1;
 1166: 	}
 1167: 
 1168: 	if (ctl.len < sizeof (dl_unitdata_ind_t) ||
 1169: 	    dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
 1170: 		return -1;
 1171: 	}
 1172: 
 1173: 	if (data.len <= 0) {
 1174: 		return data.len;
 1175: 	}
 1176: 
 1177: 	/* Copy sender info */
 1178: 	if (saddr) {
 1179: 		memcpy (saddr,
 1180: 			(char *)buf + dlp -> unitdata_ind.dl_src_addr_offset,
 1181: 			dlp -> unitdata_ind.dl_src_addr_length);
 1182: 	}
 1183: 	if (saddrlen) {
 1184: 		*saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
 1185: 	}
 1186: 
 1187: 	/* Copy destination info */
 1188: 	if (daddr) {
 1189: 		memcpy (daddr,
 1190: 			(char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset,
 1191: 			dlp -> unitdata_ind.dl_dest_addr_length);
 1192: 	}
 1193: 	if (daddrlen) {
 1194: 		*daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
 1195: 	}
 1196: 
 1197: 	if (grpaddr) {
 1198: 		*grpaddr = dlp -> unitdata_ind.dl_group_address;
 1199: 	}
 1200: 
 1201: 	return data.len;
 1202: }
 1203: #endif /* !USE_DLPI_HWADDR: USE_DLPI_RECEIVE || USE_DLPI_SEND */
 1204: 
 1205: /*
 1206:  * expected - see if we got what we wanted.
 1207:  */
 1208: static int expected (prim, dlp, msgflags)
 1209: 	unsigned long prim;
 1210: 	union DL_primitives *dlp;
 1211: 	int msgflags;
 1212: {
 1213: 	if (msgflags != RS_HIPRI) {
 1214: 		/* Message was not M_PCPROTO */
 1215: 		return -1;
 1216: 	}
 1217: 
 1218: 	if (dlp->dl_primitive != prim) {
 1219: 		/* Incorrect/unexpected return message */
 1220: 		return -1;
 1221: 	}
 1222: 	
 1223: 	return 0;
 1224: }
 1225: 
 1226: /*
 1227:  * strgetmsg - get a message from a stream, with timeout.
 1228:  */
 1229: static int strgetmsg (fd, ctlp, datap, flagsp, caller)
 1230: 	struct strbuf *ctlp, *datap;
 1231: 	char *caller;
 1232: 	int *flagsp;
 1233: 	int fd;
 1234: {
 1235: 	int result;
 1236: 	struct pollfd pfd;
 1237: 	int count;
 1238: 	time_t now;
 1239: 	time_t starttime;
 1240: 	int to_msec;
 1241: 	
 1242: 	pfd.fd = fd;
 1243: 	pfd.events = POLLPRI;	/* We're only interested in knowing
 1244: 				 * when we can receive the next high
 1245: 				 * priority message.
 1246: 				 */
 1247: 	pfd.revents = 0;
 1248: 
 1249: 	now = time (&starttime);
 1250: 	while (now <= starttime + DLPI_MAXWAIT) {
 1251: 		to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000;
 1252: 		count = poll (&pfd, 1, to_msec);
 1253: 		
 1254: 		if (count == 0) {
 1255: 			/* log_fatal ("strgetmsg: timeout"); */
 1256: 			return -1;
 1257: 		} else if (count < 0) {
 1258: 			if (errno == EAGAIN || errno == EINTR) {
 1259: 				time (&now);
 1260: 				continue;
 1261: 			} else {
 1262: 				/* log_fatal ("poll: %m"); */
 1263: 				return -1;
 1264: 			}
 1265: 		} else {
 1266: 			break;
 1267: 		}
 1268: 	}
 1269: 
 1270: 	/*
 1271: 	 * Set flags argument and issue getmsg ().
 1272: 	 */
 1273: 	*flagsp = 0;
 1274: 	if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
 1275: 		return result;
 1276: 	}
 1277: 
 1278: 	/*
 1279: 	 * Check for MOREDATA and/or MORECTL.
 1280: 	 */
 1281: 	if (result & (MORECTL|MOREDATA)) {
 1282: 		return -1;
 1283: 	}
 1284: 
 1285: 	/*
 1286: 	 * Check for at least sizeof (long) control data portion.
 1287: 	 */
 1288: 	if (ctlp -> len < sizeof (long)) {
 1289: 		return -1;
 1290: 	}
 1291: 
 1292: 	return 0;
 1293: }
 1294: 
 1295: #if defined(USE_DLPI_SEND)
 1296: int can_unicast_without_arp (ip)
 1297: 	struct interface_info *ip;
 1298: {
 1299: 	return 1;
 1300: }
 1301: 
 1302: int can_receive_unicast_unconfigured (ip)
 1303: 	struct interface_info *ip;
 1304: {
 1305: 	return 1;
 1306: }
 1307: 
 1308: int supports_multiple_interfaces (ip)
 1309: 	struct interface_info *ip;
 1310: {
 1311: 	return 1;
 1312: }
 1313: 
 1314: void maybe_setup_fallback ()
 1315: {
 1316: 	isc_result_t status;
 1317: 	struct interface_info *fbi = (struct interface_info *)0;
 1318: 	if (setup_fallback (&fbi, MDL)) {
 1319: 		if_register_fallback (fbi);
 1320: 		status = omapi_register_io_object ((omapi_object_t *)fbi,
 1321: 						   if_readsocket, 0,
 1322: 						   fallback_discard, 0, 0);
 1323: 		if (status != ISC_R_SUCCESS)
 1324: 			log_fatal ("Can't register I/O handle for %s: %s",
 1325: 				   fbi -> name, isc_result_totext (status));
 1326: 		interface_dereference (&fbi, MDL);
 1327: 	}
 1328: }
 1329: #endif /* USE_DLPI_SEND */
 1330: 
 1331: void 
 1332: get_hw_addr(const char *name, struct hardware *hw) {
 1333: 	int sock, unit;
 1334: 	long buf[DLPI_MAXDLBUF];
 1335:         union DL_primitives *dlp;
 1336: 
 1337:         dlp = (union DL_primitives *)buf;
 1338: 
 1339: 	/* 
 1340: 	 * Open a DLPI device.
 1341: 	 */
 1342: 	sock = dlpiopen(name);
 1343: 	if (sock < 0) {
 1344: 		log_fatal("Can't open DLPI device for %s: %m", name);
 1345: 	}
 1346: 
 1347: 	/*
 1348: 	 * Submit a DL_INFO_REQ request, to find the dl_mac_type and 
 1349:          * dl_provider_style
 1350: 	 */
 1351: 	if (dlpiinforeq(sock) < 0) {
 1352: 	    log_fatal("Can't request DLPI MAC type for %s: %m", name);
 1353: 	}
 1354: 	if (dlpiinfoack(sock, (char *)buf) < 0) {
 1355: 	    log_fatal("Can't get DLPI MAC type for %s: %m", name);
 1356: 	}
 1357: 	switch (dlp->info_ack.dl_mac_type) {
 1358: 		case DL_CSMACD: /* IEEE 802.3 */
 1359: 		case DL_ETHER:
 1360: 			hw->hbuf[0] = HTYPE_ETHER;
 1361: 			break;
 1362: 		case DL_TPR:
 1363: 			hw->hbuf[0] = HTYPE_IEEE802;
 1364: 			break;
 1365: 		case DL_FDDI:
 1366: 			hw->hbuf[0] = HTYPE_FDDI;
 1367: 			break;
 1368: 		default:
 1369: 			log_fatal("%s: unsupported DLPI MAC type %lu", name,
 1370: 				  (unsigned long)dlp->info_ack.dl_mac_type);
 1371: 	}
 1372: 
 1373: 	if (dlp->info_ack.dl_provider_style == DL_STYLE2) {
 1374: 		/*
 1375: 		 * Attach to the device.  If this fails, the device
 1376: 		 * does not exist.
 1377: 		 */
 1378: 		unit = dlpiunit((char *)name);
 1379: 
 1380: 		if (dlpiattachreq(sock, unit) < 0 ||
 1381: 		    dlpiokack(sock, (char *)buf) < 0) {
 1382: 			log_fatal("Can't attach DLPI device for %s: %m",
 1383: 				  name);
 1384: 		}
 1385: 	}
 1386: 
 1387: 	/*
 1388: 	 * Submit a DL_PHYS_ADDR_REQ request, to find
 1389: 	 * the hardware address.
 1390: 	 */
 1391: 	if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) {
 1392: 		log_fatal("Can't request DLPI hardware address for %s: %m",
 1393: 			  name);
 1394: 	}
 1395: 	if (dlpiphysaddrack(sock, (char *)buf) < 0) {
 1396: 		log_fatal("Can't get DLPI hardware address for %s: %m",
 1397: 			  name);
 1398: 	}
 1399: 	if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) {
 1400: 		memcpy(hw->hbuf+1, 
 1401: 		       (char *)buf + dlp->physaddr_ack.dl_addr_offset,
 1402: 		       dlp->physaddr_ack.dl_addr_length);
 1403: 		hw->hlen = dlp->physaddr_ack.dl_addr_length + 1;
 1404: 	} else {
 1405: 		memcpy(hw->hbuf+1, 
 1406: 		       (char *)buf + dlp->physaddr_ack.dl_addr_offset,
 1407: 		       sizeof(hw->hbuf)-1);
 1408: 		hw->hlen = sizeof(hw->hbuf);
 1409: 	}
 1410: 
 1411: 	close(sock);
 1412: }
 1413: #endif /* USE_DLPI_SEND || USE_DLPI_RECEIVE || USE_DLPI_HWADDR */

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