Annotation of embedaddon/dhcp/common/dlpi.c, revision 1.1

1.1     ! misho       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>