common/dlpi.c

Go to the documentation of this file.
00001 /* dlpi.c
00002  
00003    Data Link Provider Interface (DLPI) network interface code. */
00004 
00005 /*
00006  * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1996-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  * This software was written for Internet Systems Consortium
00029  * by Eric James Negaard, <lmdejn@lmd.ericsson.se>.  To learn more about
00030  * Internet Systems Consortium, see ``https://www.isc.org''.
00031  *
00032  * Joost Mulders has also done considerable work in debugging the DLPI API
00033  * support on Solaris and getting this code to work properly on a variety
00034  * of different Solaris platforms.
00035  */
00036 
00037 /*
00038  * Based largely in part to the existing NIT code in nit.c.
00039  *
00040  * This code has been developed and tested on sparc-based machines running
00041  * SunOS 5.5.1, with le and hme network interfaces.  It should be pretty
00042  * generic, though.
00043  */
00044 
00045 /*
00046  * Implementation notes:
00047  *
00048  * I first tried to write this code to the "vanilla" DLPI 2.0 API.
00049  * It worked on a Sun Ultra-1 with a hme interface, but didn't work
00050  * on Sun SparcStation 5's with "le" interfaces (the packets sent out
00051  * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead
00052  * of the expected 0x0800).
00053  *
00054  * Therefore I added the "DLPI_RAW" code which is a Sun extension to
00055  * the DLPI standard.  This code works on both of the above machines.
00056  * This is configurable in the OS-dependent include file by defining
00057  * USE_DLPI_RAW.
00058  *
00059  * It quickly became apparant that I should also use the "pfmod"
00060  * STREAMS module to cut down on the amount of user level packet
00061  * processing.  I don't know how widely available "pfmod" is, so it's
00062  * use is conditionally included. This is configurable in the
00063  * OS-dependent include file by defining USE_DLPI_PFMOD.
00064  *
00065  * A major quirk on the Sun's at least, is that no packets seem to get
00066  * sent out the interface until six seconds after the interface is
00067  * first "attached" to [per system reboot] (it's actually from when
00068  * the interface is attached, not when it is plumbed, so putting a
00069  * sleep into the dhclient-script at PREINIT time doesn't help).  I
00070  * HAVE tried, without success to poll the fd to see when it is ready
00071  * for writing.  This doesn't help at all. If the sleeps are not done,
00072  * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so
00073  * I've put them here, when register_send and register_receive are
00074  * called (split up into two three-second sleeps between the notices,
00075  * so that it doesn't seem like so long when you're watching :-).  The
00076  * amount of time to sleep is configurable in the OS-dependent include
00077  * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds
00078  * to sleep.
00079  */
00080 
00081 /*
00082  * The Open Group Technical Standard can be found here:
00083  * http://www.opengroup.org/onlinepubs/009618899/index.htm
00084  *
00085  * The HP DLPI Programmer's Guide can be found here:
00086  * http://docs.hp.com/en/B2355-90139/index.html
00087  */
00088 
00089 #include "dhcpd.h"
00090 
00091 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) || \
00092     defined(USE_DLPI_HWADDR)
00093 
00094 # include <sys/ioctl.h>
00095 # include <sys/time.h>
00096 # include <sys/dlpi.h>
00097 # include <stropts.h>
00098 # ifdef USE_DLPI_PFMOD
00099 #  include <sys/pfmod.h>
00100 # endif
00101 #include <poll.h>
00102 #include <errno.h>
00103 
00104 # include <netinet/in_systm.h>
00105 # include "includes/netinet/ip.h"
00106 # include "includes/netinet/udp.h"
00107 # include "includes/netinet/if_ether.h"
00108 
00109 # ifdef USE_DLPI_PFMOD
00110 #  ifdef USE_DLPI_RAW
00111 #   define DLPI_MODNAME "DLPI+RAW+PFMOD"
00112 #  else
00113 #   define DLPI_MODNAME "DLPI+PFMOD"
00114 #  endif
00115 # else
00116 #  ifdef USE_DLPI_RAW
00117 #   define DLPI_MODNAME "DLPI+RAW"
00118 #  else
00119 #   define DLPI_MODNAME "DLPI"
00120 #  endif
00121 # endif
00122 
00123 # ifndef ABS
00124 #  define ABS(x) ((x) >= 0 ? (x) : 0-(x))
00125 # endif
00126 
00127 #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
00128 static int strioctl (int fd, int cmd, int timeout, int len, char *dp);
00129 #endif
00130 
00131 #define DLPI_MAXDLBUF           8192    /* Buffer size */
00132 #define DLPI_MAXDLADDR          1024    /* Max address size */
00133 #define DLPI_DEVDIR             "/dev/" /* Device directory */
00134 
00135 static int dlpiopen(const char *ifname);
00136 static int dlpiunit (char *ifname);
00137 static int dlpiinforeq (int fd);
00138 static int dlpiphysaddrreq (int fd, unsigned long addrtype);
00139 static int dlpiattachreq (int fd, unsigned long ppa);
00140 static int dlpibindreq (int fd, unsigned long sap, unsigned long max_conind,
00141                         unsigned long service_mode, unsigned long conn_mgmt,
00142                         unsigned long xidtest);
00143 #if defined(UNUSED_DLPI_INTERFACE)
00144 /* These functions are unused at present, but may be used at a later date.
00145  * defined out to avoid compiler warnings about unused static functions.
00146  */
00147 static int dlpidetachreq (int fd);
00148 static int dlpiunbindreq (int fd);
00149 #endif
00150 static int dlpiokack (int fd, char *bufp);
00151 static int dlpiinfoack (int fd, char *bufp);
00152 static int dlpiphysaddrack (int fd, char *bufp);
00153 static int dlpibindack (int fd, char *bufp);
00154 #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
00155 /* These functions are not used if we're only sourcing the get_hw_addr()
00156  * function (for USE_SOCKETS).
00157  */
00158 static int dlpiunitdatareq (int fd, unsigned char *addr, int addrlen, 
00159                             unsigned long minpri, unsigned long maxpri, 
00160                             unsigned char *data, int datalen);
00161 static int dlpiunitdataind (int fd,
00162                             unsigned char *dstaddr,
00163                             unsigned long *dstaddrlen,
00164                             unsigned char *srcaddr,
00165                             unsigned long *srcaddrlen,
00166                             unsigned long *grpaddr,
00167                             unsigned char *data,
00168                             int datalen);
00169 #endif /* !USE_DLPI_HWADDR: USE_DLPI_SEND || USE_DLPI_RECEIVE */
00170 static int expected (unsigned long prim, union DL_primitives *dlp, 
00171                      int msgflags);
00172 static int strgetmsg (int fd, struct strbuf *ctlp, struct strbuf *datap,
00173                       int *flagsp, char *caller);
00174 
00175 /* Reinitializes the specified interface after an address change.   This
00176    is not required for packet-filter APIs. */
00177 
00178 #ifdef USE_DLPI_SEND
00179 void if_reinitialize_send (info)
00180         struct interface_info *info;
00181 {
00182 }
00183 #endif
00184 
00185 #ifdef USE_DLPI_RECEIVE
00186 void if_reinitialize_receive (info)
00187         struct interface_info *info;
00188 {
00189 }
00190 #endif
00191 
00192 /* Called by get_interface_list for each interface that's discovered.
00193    Opens a packet filter for each interface and adds it to the select
00194    mask. */
00195 
00196 int if_register_dlpi (info)
00197         struct interface_info *info;
00198 {
00199         int sock;
00200         int unit;
00201         long buf [DLPI_MAXDLBUF];
00202         union DL_primitives *dlp;
00203 
00204         dlp = (union DL_primitives *)buf;
00205 
00206         /* Open a DLPI device */
00207         if ((sock = dlpiopen (info -> name)) < 0) {
00208             log_fatal ("Can't open DLPI device for %s: %m", info -> name);
00209         }
00210 
00211         /*
00212          * Submit a DL_INFO_REQ request, to find the dl_mac_type and 
00213          * dl_provider_style
00214          */
00215         if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
00216             log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
00217         } else {
00218             switch (dlp -> info_ack.dl_mac_type) {
00219               case DL_CSMACD: /* IEEE 802.3 */
00220               case DL_ETHER:
00221                 info -> hw_address.hbuf [0] = HTYPE_ETHER;
00222                 break;
00223               /* adding token ring 5/1999 - mayer@ping.at  */ 
00224               case DL_TPR:
00225                 info -> hw_address.hbuf [0] = HTYPE_IEEE802;
00226                 break;
00227               case DL_FDDI:
00228                 info -> hw_address.hbuf [0] = HTYPE_FDDI;
00229                 break;
00230               default:
00231                 log_fatal("%s: unsupported DLPI MAC type %lu", info->name,
00232                           (unsigned long)dlp->info_ack.dl_mac_type);
00233                 break;
00234             }
00235             /*
00236              * copy the sap length and broadcast address of this interface
00237              * to interface_info. This fixes nothing but seemed nicer than to
00238              * assume -2 and ffffff.
00239              */
00240             info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length;
00241             info -> dlpi_broadcast_addr.hlen = 
00242              dlp -> info_ack.dl_brdcst_addr_length;
00243             memcpy (info -> dlpi_broadcast_addr.hbuf, 
00244              (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset, 
00245              dlp -> info_ack.dl_brdcst_addr_length);
00246         }
00247 
00248         if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
00249             /*
00250              * Attach to the device.  If this fails, the device
00251              * does not exist.
00252              */
00253             unit = dlpiunit (info -> name);
00254         
00255             if (dlpiattachreq (sock, unit) < 0
00256                 || dlpiokack (sock, (char *)buf) < 0) {
00257                 log_fatal ("Can't attach DLPI device for %s: %m", info -> name);
00258             }
00259         }
00260 
00261         /*
00262          * Bind to the IP service access point (SAP), connectionless (CLDLS).
00263          */
00264         if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0
00265             || dlpibindack (sock, (char *)buf) < 0) {
00266             log_fatal ("Can't bind DLPI device for %s: %m", info -> name);
00267         }
00268 
00269         /*
00270          * Submit a DL_PHYS_ADDR_REQ request, to find
00271          * the hardware address
00272          */
00273         if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0
00274             || dlpiphysaddrack (sock, (char *)buf) < 0) {
00275             log_fatal ("Can't get DLPI hardware address for %s: %m",
00276                    info -> name);
00277         }
00278 
00279         info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1;
00280         memcpy (&info -> hw_address.hbuf [1],
00281                 (char *)buf + dlp -> physaddr_ack.dl_addr_offset,
00282                 dlp -> physaddr_ack.dl_addr_length);
00283 
00284 #ifdef USE_DLPI_RAW
00285         if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
00286             log_fatal ("Can't set DLPI RAW mode for %s: %m",
00287                    info -> name);
00288         }
00289 #endif
00290 
00291 #ifdef USE_DLPI_PFMOD
00292         if (ioctl (sock, I_PUSH, "pfmod") < 0) {
00293             log_fatal ("Can't push packet filter onto DLPI for %s: %m",
00294                    info -> name);
00295         }
00296 #endif
00297 
00298         return sock;
00299 }
00300 
00301 #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
00302 static int
00303 strioctl (fd, cmd, timeout, len, dp)
00304 int fd;
00305 int cmd;
00306 int timeout;
00307 int len;
00308 char *dp;
00309 {
00310     struct strioctl sio;
00311     int rslt;
00312 
00313     sio.ic_cmd = cmd;
00314     sio.ic_timout = timeout;
00315     sio.ic_len = len;
00316     sio.ic_dp = dp;
00317 
00318     if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
00319         return rslt;
00320     } else {
00321         return sio.ic_len;
00322     }
00323 }
00324 #endif /* USE_DPI_PFMOD || USE_DLPI_RAW */
00325 
00326 #ifdef USE_DLPI_SEND
00327 void if_register_send (info)
00328         struct interface_info *info;
00329 {
00330         /* If we're using the DLPI API for sending and receiving,
00331            we don't need to register this interface twice. */
00332 #ifndef USE_DLPI_RECEIVE
00333 # ifdef USE_DLPI_PFMOD
00334         struct packetfilt pf;
00335 # endif
00336 
00337         info -> wfdesc = if_register_dlpi (info);
00338 
00339 # ifdef USE_DLPI_PFMOD
00340         /* Set up an PFMOD filter that rejects everything... */
00341         pf.Pf_Priority = 0;
00342         pf.Pf_FilterLen = 1;
00343         pf.Pf_Filter [0] = ENF_PUSHZERO;
00344 
00345         /* Install the filter */
00346         if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM,
00347                       sizeof (pf), (char *)&pf) < 0) {
00348             log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name);
00349         }
00350 
00351 # endif /* USE_DLPI_PFMOD */
00352 #else /* !defined (USE_DLPI_RECEIVE) */
00353         /*
00354          * If using DLPI for both send and receive, simply re-use
00355          * the read file descriptor that was set up earlier.
00356          */
00357         info -> wfdesc = info -> rfdesc;
00358 #endif
00359 
00360         if (!quiet_interface_discovery)
00361                 log_info ("Sending on   DLPI/%s/%s%s%s",
00362                       info -> name,
00363                       print_hw_addr (info -> hw_address.hbuf [0],
00364                                      info -> hw_address.hlen - 1,
00365                                      &info -> hw_address.hbuf [1]),
00366                       (info -> shared_network ? "/" : ""),
00367                       (info -> shared_network ?
00368                        info -> shared_network -> name : ""));
00369 
00370 #ifdef DLPI_FIRST_SEND_WAIT
00371 /* See the implementation notes at the beginning of this file */
00372 # ifdef USE_DLPI_RECEIVE
00373         sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2));
00374 # else
00375         sleep (DLPI_FIRST_SEND_WAIT);
00376 # endif
00377 #endif
00378 }
00379 
00380 void if_deregister_send (info)
00381         struct interface_info *info;
00382 {
00383         /* If we're using the DLPI API for sending and receiving,
00384            we don't need to register this interface twice. */
00385 #ifndef USE_DLPI_RECEIVE
00386         close (info -> wfdesc);
00387 #endif
00388         info -> wfdesc = -1;
00389 
00390         if (!quiet_interface_discovery)
00391                 log_info ("Disabling output on DLPI/%s/%s%s%s",
00392                       info -> name,
00393                       print_hw_addr (info -> hw_address.hbuf [0],
00394                                      info -> hw_address.hlen - 1,
00395                                      &info -> hw_address.hbuf [1]),
00396                       (info -> shared_network ? "/" : ""),
00397                       (info -> shared_network ?
00398                        info -> shared_network -> name : ""));
00399 }
00400 #endif /* USE_DLPI_SEND */
00401 
00402 #ifdef USE_DLPI_RECEIVE
00403 /* Packet filter program...
00404    XXX Changes to the filter program may require changes to the constant
00405    offsets used in if_register_send to patch the NIT program! XXX */
00406 
00407 void if_register_receive (info)
00408         struct interface_info *info;
00409 {
00410 #ifdef USE_DLPI_PFMOD
00411         struct packetfilt pf;
00412         struct ip iphdr;
00413         u_int16_t offset;
00414 #endif
00415 
00416         /* Open a DLPI device and hang it on this interface... */
00417         info -> rfdesc = if_register_dlpi (info);
00418 
00419 #ifdef USE_DLPI_PFMOD
00420         /* Set up the PFMOD filter program. */
00421         /* XXX Unlike the BPF filter program, this one won't work if the
00422            XXX IP packet is fragmented or if there are options on the IP
00423            XXX header. */
00424         pf.Pf_Priority = 0;
00425         pf.Pf_FilterLen = 0;
00426 
00427 #if defined (USE_DLPI_RAW)
00428 # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
00429     /*
00430      * ethertype == ETHERTYPE_IP
00431      */
00432     offset = 12;
00433     pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
00434     pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
00435     pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
00436 # else
00437 # define ETHER_H_PREFIX (0)
00438 # endif /* USE_DLPI_RAW */
00439         /*
00440          * The packets that will be received on this file descriptor
00441          * will be IP packets (due to the SAP that was specified in
00442          * the dlbind call).  There will be no ethernet header.
00443          * Therefore, setup the packet filter to check the protocol
00444          * field for UDP, and the destination port number equal
00445          * to the local port.  All offsets are relative to the start
00446          * of an IP packet.
00447          */
00448 
00449         /*
00450          * BOOTPS destination port
00451          */
00452         offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t);
00453         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
00454         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
00455         pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
00456 
00457         /*
00458          * protocol should be udp. this is a byte compare, test for
00459          * endianess.
00460          */
00461         offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr);
00462         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
00463         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND;
00464         pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF);
00465         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
00466       pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
00467 
00468         /* Install the filter... */
00469         if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
00470                       sizeof (pf), (char *)&pf) < 0) {
00471             log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name);
00472         }
00473 #endif /* USE_DLPI_PFMOD */
00474 
00475         if (!quiet_interface_discovery)
00476                 log_info ("Listening on DLPI/%s/%s%s%s",
00477                       info -> name,
00478                       print_hw_addr (info -> hw_address.hbuf [0],
00479                                      info -> hw_address.hlen - 1,
00480                                      &info -> hw_address.hbuf [1]),
00481                       (info -> shared_network ? "/" : ""),
00482                       (info -> shared_network ?
00483                        info -> shared_network -> name : ""));
00484 
00485 #ifdef DLPI_FIRST_SEND_WAIT
00486 /* See the implementation notes at the beginning of this file */
00487 # ifdef USE_DLPI_SEND
00488         sleep (DLPI_FIRST_SEND_WAIT / 2);
00489 # else
00490         sleep (DLPI_FIRST_SEND_WAIT);
00491 # endif
00492 #endif
00493 }
00494 
00495 void if_deregister_receive (info)
00496         struct interface_info *info;
00497 {
00498         /* If we're using the DLPI API for sending and receiving,
00499            we don't need to register this interface twice. */
00500 #ifndef USE_DLPI_SEND
00501         close (info -> rfdesc);
00502 #endif
00503         info -> rfdesc = -1;
00504 
00505         if (!quiet_interface_discovery)
00506                 log_info ("Disabling input on DLPI/%s/%s%s%s",
00507                       info -> name,
00508                       print_hw_addr (info -> hw_address.hbuf [0],
00509                                      info -> hw_address.hlen - 1,
00510                                      &info -> hw_address.hbuf [1]),
00511                       (info -> shared_network ? "/" : ""),
00512                       (info -> shared_network ?
00513                        info -> shared_network -> name : ""));
00514 }
00515 #endif /* USE_DLPI_RECEIVE */
00516 
00517 #ifdef USE_DLPI_SEND
00518 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
00519         struct interface_info *interface;
00520         struct packet *packet;
00521         struct dhcp_packet *raw;
00522         size_t len;
00523         struct in_addr from;
00524         struct sockaddr_in *to;
00525         struct hardware *hto;
00526 {
00527 #ifdef USE_DLPI_RAW
00528         double hh [32];
00529         int fudge;
00530 #endif
00531         double ih [1536 / sizeof (double)];
00532         unsigned char *dbuf = (unsigned char *)ih;
00533         unsigned dbuflen;
00534         unsigned char dstaddr [DLPI_MAXDLADDR];
00535         unsigned addrlen;
00536         int result;
00537 
00538         if (!strcmp (interface -> name, "fallback"))
00539                 return send_fallback (interface, packet, raw,
00540                                       len, from, to, hto);
00541 
00542         if (hto == NULL && interface->anycast_mac_addr.hlen)
00543                 hto = &interface->anycast_mac_addr;
00544 
00545         dbuflen = 0;
00546 
00547         /* Assemble the headers... */
00548 #ifdef USE_DLPI_RAW
00549         assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto);
00550       if (dbuflen > sizeof hh)
00551               log_fatal ("send_packet: hh buffer too small.\n");
00552         fudge = dbuflen % 4; /* IP header must be word-aligned. */
00553         memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen);
00554         dbuflen += fudge;
00555 #endif
00556         assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr,
00557                                 to -> sin_addr.s_addr, to -> sin_port,
00558                                 (unsigned char *)raw, len);
00559 
00560         /* Copy the data into the buffer (yuk). */
00561         memcpy (dbuf + dbuflen, raw, len);
00562         dbuflen += len;
00563 
00564 #ifdef USE_DLPI_RAW
00565         result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
00566 #else
00567 
00568         /*
00569          * Setup the destination address (DLSAP) in dstaddr 
00570          *
00571          * If sap_length < 0 we must deliver the DLSAP as phys+sap. 
00572          * If sap_length > 0 we must deliver the DLSAP as sap+phys.
00573          *
00574          * sap = Service Access Point == ETHERTYPE_IP
00575          * sap + datalink address is called DLSAP in dlpi speak.
00576          */
00577         { /* ENCODE DLSAP */
00578           unsigned char phys [DLPI_MAXDLADDR];
00579           unsigned char sap [4];
00580           int sap_len = interface -> dlpi_sap_length;
00581           int phys_len = interface -> hw_address.hlen - 1;
00582 
00583           /* sap = htons (ETHERTYPE_IP) kludge */
00584           memset (sap, 0, sizeof (sap));
00585 # if (BYTE_ORDER == LITTLE_ENDIAN)
00586           sap [0] = 0x00;
00587           sap [1] = 0x08;
00588 # else
00589           sap [0] = 0x08;
00590           sap [1] = 0x00;
00591 # endif
00592 
00593         if (hto && hto -> hlen == interface -> hw_address.hlen)
00594              memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
00595           else 
00596              memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, 
00597               interface -> dlpi_broadcast_addr.hlen);
00598 
00599           if (sap_len < 0) { 
00600              memcpy ( dstaddr, phys, phys_len);
00601              memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
00602           }
00603           else {
00604              memcpy ( dstaddr, (void *) sap, sap_len);
00605              memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
00606           }
00607         addrlen = phys_len + ABS (sap_len);
00608       } /* ENCODE DLSAP */
00609 
00610         result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
00611                                   0, 0, dbuf, dbuflen);
00612 #endif /* USE_DLPI_RAW */
00613         if (result < 0)
00614                 log_error ("send_packet: %m");
00615         return result;
00616 }
00617 #endif /* USE_DLPI_SEND */
00618 
00619 #ifdef USE_DLPI_RECEIVE
00620 ssize_t receive_packet (interface, buf, len, from, hfrom)
00621         struct interface_info *interface;
00622         unsigned char *buf;
00623         size_t len;
00624         struct sockaddr_in *from;
00625         struct hardware *hfrom;
00626 {
00627         unsigned char dbuf [1536];
00628         unsigned char srcaddr [DLPI_MAXDLADDR];
00629         unsigned long srcaddrlen;
00630         int length = 0;
00631         int offset = 0;
00632         int bufix = 0;
00633         unsigned paylen;
00634         
00635 #ifdef USE_DLPI_RAW
00636         length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
00637 #else   
00638         length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
00639                                   (unsigned long *)NULL, srcaddr, &srcaddrlen,
00640                                   (unsigned long *)NULL, dbuf, sizeof (dbuf));
00641 #endif
00642 
00643         if (length <= 0) {
00644             log_error("receive_packet: %m");
00645             return length;
00646         }
00647 
00648 # if !defined (USE_DLPI_RAW)
00649         /*
00650          * Copy the sender's hw address into hfrom
00651          * If sap_len < 0 the DLSAP is as phys+sap.
00652          * If sap_len > 0 the DLSAP is as sap+phys.
00653          *
00654          * sap is discarded here.
00655          */
00656         { /* DECODE DLSAP */
00657           int sap_len = interface -> dlpi_sap_length;
00658           int phys_len = interface -> hw_address.hlen - 1;
00659 
00660           if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) {
00661             hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
00662             hfrom -> hlen = interface -> hw_address.hlen;
00663             
00664             if (sap_len < 0) {
00665               memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
00666             }
00667             else {
00668               memcpy((char *)&hfrom->hbuf[1], srcaddr + sap_len, phys_len);
00669             }
00670           } 
00671           else if (hfrom) {
00672             memset (hfrom, '\0', sizeof *hfrom);
00673           }
00674         } /* DECODE_DLSAP */
00675 
00676 # endif /* !defined (USE_DLPI_RAW) */
00677 
00678         /* Decode the IP and UDP headers... */
00679         bufix = 0;
00680 #ifdef USE_DLPI_RAW
00681         /* Decode the physical header... */
00682         offset = decode_hw_header (interface, dbuf, bufix, hfrom);
00683 
00684         /* If a physical layer checksum failed (dunno of any
00685            physical layer that supports this, but WTH), skip this
00686            packet. */
00687         if (offset < 0) {
00688                 return 0;
00689         }
00690         bufix += offset;
00691         length -= offset;
00692 #endif
00693         offset = decode_udp_ip_header (interface, dbuf, bufix,
00694                                        from, length, &paylen, 0);
00695 
00696         /*
00697          * If the IP or UDP checksum was bad, skip the packet...
00698          *
00699          * Note: this happens all the time when writing packets via the
00700          * fallback socket.  The packet received by streams does not have
00701          * the IP or UDP checksums filled in, as those are calculated by
00702          * the hardware.
00703          */
00704         if (offset < 0) {
00705                 return 0;
00706         }
00707 
00708         bufix += offset;
00709         length -= offset;
00710 
00711         if (length < paylen)
00712                 log_fatal("Internal inconsistency at %s:%d.", MDL);
00713 
00714         /* Copy out the data in the packet... */
00715         memcpy(buf, &dbuf [bufix], paylen);
00716         return paylen;
00717 }
00718 #endif
00719 
00720 /* Common DLPI routines ...
00721  *
00722  * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
00723  *
00724  * Based largely in part to the example code contained in the document
00725  * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
00726  * by Neal Nuckolls of SunSoft Internet Engineering.
00727  * 
00728  * This code has been developed and tested on sparc-based machines running
00729  * SunOS 5.5.1, with le and hme network interfaces.  It should be pretty
00730  * generic, though.
00731  * 
00732  * The usual disclaimers apply.  This code works for me.  Don't blame me
00733  * if it makes your machine or network go down in flames.  That taken
00734  * into consideration, use this code as you wish.  If you make usefull
00735  * modifications I'd appreciate hearing about it.
00736  */
00737 
00738 #define DLPI_MAXWAIT            15      /* Max timeout */
00739 
00740 
00741 /*
00742  * Parse an interface name and extract the unit number
00743  */
00744 
00745 static int dlpiunit (ifname)
00746         char *ifname;
00747 {
00748         char *cp;
00749         int unit;
00750         
00751         if (!ifname) {
00752                 return 0;
00753         }
00754         
00755         /* Advance to the end of the name */
00756         cp = ifname;
00757         while (*cp) cp++;
00758         /* Back up to the start of the first digit */
00759         while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
00760         
00761         /* Convert the unit number */
00762         unit = 0;
00763         while (*cp >= '0' && *cp <= '9') {
00764                 unit *= 10;
00765                 unit += (*cp++ - '0');
00766         }
00767         
00768         return unit;
00769 }
00770 
00771 /*
00772  * dlpiopen - open the DLPI device for a given interface name
00773  */
00774 static int
00775 dlpiopen(const char *ifname) {
00776         char devname [50];
00777         char *dp;
00778         const char *cp, *ep;
00779         
00780         if (!ifname) {
00781                 return -1;
00782         }
00783         
00784         /* Open a DLPI device */
00785         if (*ifname == '/') {
00786                 dp = devname;
00787         } else {
00788                 /* Prepend the device directory */
00789                 memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
00790                 dp = &devname [strlen (DLPI_DEVDIR)];
00791         }
00792 
00793         /* Find the end of the interface name */
00794         ep = cp = ifname;
00795         while (*ep)
00796                 ep++;
00797         /* And back up to the first digit (unit number) */
00798         while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
00799                 ep--;
00800         
00801         /* Copy everything up to the unit number */
00802         while (cp < ep) {
00803                 *dp++ = *cp++;
00804         }
00805         *dp = '\0';
00806         
00807         return open (devname, O_RDWR | O_CLOEXEC, 0);
00808 }
00809 
00810 /*
00811  * dlpiinforeq - request information about the data link provider.
00812  */
00813 
00814 static int dlpiinforeq (fd)
00815         int fd;
00816 {
00817         dl_info_req_t info_req;
00818         struct strbuf ctl;
00819         int flags;
00820         
00821         info_req.dl_primitive = DL_INFO_REQ;
00822         
00823         ctl.maxlen = 0;
00824         ctl.len = sizeof (info_req);
00825         ctl.buf = (char *)&info_req;
00826         
00827         flags = RS_HIPRI;
00828         
00829         return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
00830 }
00831 
00832 /*
00833  * dlpiphysaddrreq - request the current physical address.
00834  */
00835 static int dlpiphysaddrreq (fd, addrtype)
00836         int fd;
00837         unsigned long addrtype;
00838 {
00839         dl_phys_addr_req_t physaddr_req;
00840         struct strbuf ctl;
00841         int flags;
00842         
00843         physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
00844         physaddr_req.dl_addr_type = addrtype;
00845         
00846         ctl.maxlen = 0;
00847         ctl.len = sizeof (physaddr_req);
00848         ctl.buf = (char *)&physaddr_req;
00849         
00850         flags = RS_HIPRI;
00851         
00852         return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
00853 }
00854 
00855 /*
00856  * dlpiattachreq - send a request to attach to a specific unit.
00857  */
00858 static int dlpiattachreq (fd, ppa)
00859         unsigned long ppa;
00860         int fd;
00861 {
00862         dl_attach_req_t attach_req;
00863         struct strbuf ctl;
00864         int flags;
00865         
00866         attach_req.dl_primitive = DL_ATTACH_REQ;
00867         attach_req.dl_ppa = ppa;
00868         
00869         ctl.maxlen = 0;
00870         ctl.len = sizeof (attach_req);
00871         ctl.buf = (char *)&attach_req;
00872         
00873         flags = 0;
00874         
00875         return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
00876 }
00877 
00878 /*
00879  * dlpibindreq - send a request to bind to a specific SAP address.
00880  */
00881 static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
00882         unsigned long sap;
00883         unsigned long max_conind;
00884         unsigned long service_mode;
00885         unsigned long conn_mgmt;
00886         unsigned long xidtest;
00887         int fd;
00888 {
00889         dl_bind_req_t bind_req;
00890         struct strbuf ctl;
00891         int flags;
00892         
00893         bind_req.dl_primitive = DL_BIND_REQ;
00894         bind_req.dl_sap = sap;
00895         bind_req.dl_max_conind = max_conind;
00896         bind_req.dl_service_mode = service_mode;
00897         bind_req.dl_conn_mgmt = conn_mgmt;
00898         bind_req.dl_xidtest_flg = xidtest;
00899         
00900         ctl.maxlen = 0;
00901         ctl.len = sizeof (bind_req);
00902         ctl.buf = (char *)&bind_req;
00903         
00904         flags = 0;
00905         
00906         return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
00907 }
00908 
00909 #if defined(UNUSED_DLPI_INTERFACE)
00910 /*
00911  * dlpiunbindreq - send a request to unbind.  This function is not actually
00912  *      used by ISC DHCP, but is included for completeness in case it is
00913  *      ever required for new work.
00914  */
00915 static int dlpiunbindreq (fd)
00916         int fd;
00917 {
00918         dl_unbind_req_t unbind_req;
00919         struct strbuf ctl;
00920         int flags;
00921         
00922         unbind_req.dl_primitive = DL_UNBIND_REQ;
00923         
00924         ctl.maxlen = 0;
00925         ctl.len = sizeof (unbind_req);
00926         ctl.buf = (char *)&unbind_req;
00927         
00928         flags = 0;
00929         
00930         return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
00931 }
00932 
00933 
00934 /*
00935  * dlpidetachreq - send a request to detach.  This function is not actually
00936  *      used by ISC DHCP, but is included for completeness in case it is
00937  *      ever required for new work.
00938  */
00939 static int dlpidetachreq (fd)
00940         int fd;
00941 {
00942         dl_detach_req_t detach_req;
00943         struct strbuf ctl;
00944         int flags;
00945         
00946         detach_req.dl_primitive = DL_DETACH_REQ;
00947         
00948         ctl.maxlen = 0;
00949         ctl.len = sizeof (detach_req);
00950         ctl.buf = (char *)&detach_req;
00951         
00952         flags = 0;
00953         
00954         return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
00955 }
00956 #endif /* UNUSED_DLPI_INTERFACE */
00957 
00958 
00959 /*
00960  * dlpibindack - receive an ack to a dlbindreq.
00961  */
00962 static int dlpibindack (fd, bufp)
00963         char *bufp;
00964         int fd;
00965 {
00966         union DL_primitives *dlp;
00967         struct strbuf ctl;
00968         int flags;
00969         
00970         ctl.maxlen = DLPI_MAXDLBUF;
00971         ctl.len = 0;
00972         ctl.buf = bufp;
00973 
00974         if (strgetmsg (fd, &ctl,
00975                        (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
00976                 return -1;
00977         }
00978         
00979         dlp = (union DL_primitives *)ctl.buf;
00980         
00981         if (expected (DL_BIND_ACK, dlp, flags) == -1) {
00982                 return -1;
00983         }
00984         
00985         if (ctl.len < sizeof (dl_bind_ack_t)) {
00986                 /* Returned structure is too short */
00987                 return -1;
00988         }
00989 
00990         return 0;
00991 }
00992 
00993 /*
00994  * dlpiokack - general acknowledgement reception.
00995  */
00996 static int dlpiokack (fd, bufp)
00997         char *bufp;
00998         int fd;
00999 {
01000         union DL_primitives *dlp;
01001         struct strbuf ctl;
01002         int flags;
01003         
01004         ctl.maxlen = DLPI_MAXDLBUF;
01005         ctl.len = 0;
01006         ctl.buf = bufp;
01007         
01008         if (strgetmsg (fd, &ctl,
01009                        (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
01010                 return -1;
01011         }
01012         
01013         dlp = (union DL_primitives *)ctl.buf;
01014         
01015         if (expected (DL_OK_ACK, dlp, flags) == -1) {
01016                 return -1;
01017         }
01018         
01019         if (ctl.len < sizeof (dl_ok_ack_t)) {
01020                 /* Returned structure is too short */
01021                 return -1;
01022         }
01023         
01024         return 0;
01025 }
01026 
01027 /*
01028  * dlpiinfoack - receive an ack to a dlinforeq.
01029  */
01030 static int dlpiinfoack (fd, bufp)
01031         char *bufp;
01032         int fd;
01033 {
01034         union DL_primitives *dlp;
01035         struct strbuf ctl;
01036         int flags;
01037         
01038         ctl.maxlen = DLPI_MAXDLBUF;
01039         ctl.len = 0;
01040         ctl.buf = bufp;
01041         
01042         if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
01043                        "dlpiinfoack") < 0) {
01044                 return -1;
01045         }
01046         
01047         dlp = (union DL_primitives *) ctl.buf;
01048         
01049         if (expected (DL_INFO_ACK, dlp, flags) == -1) {
01050                 return -1;
01051         }
01052         
01053         if (ctl.len < sizeof (dl_info_ack_t)) {
01054                 /* Returned structure is too short */
01055                 return -1;
01056         }
01057         
01058         return 0;
01059 }
01060 
01061 /*
01062  * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
01063  */
01064 int dlpiphysaddrack (fd, bufp)
01065         char *bufp;
01066         int fd;
01067 {
01068         union DL_primitives *dlp;
01069         struct strbuf ctl;
01070         int flags;
01071         
01072         ctl.maxlen = DLPI_MAXDLBUF;
01073         ctl.len = 0;
01074         ctl.buf = bufp;
01075         
01076         if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
01077                        "dlpiphysaddrack") < 0) {
01078                 return -1;
01079         }
01080 
01081         dlp = (union DL_primitives *)ctl.buf;
01082         
01083         if (expected (DL_PHYS_ADDR_ACK, dlp, flags) == -1) {
01084                 return -1;
01085         }
01086 
01087         if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
01088                 /* Returned structure is too short */
01089                 return -1;
01090         }
01091         
01092         return 0;
01093 }
01094 
01095 #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
01096 int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
01097         int fd;
01098         unsigned char *addr;
01099         int addrlen;
01100         unsigned long minpri;
01101         unsigned long maxpri;
01102         unsigned char *dbuf;
01103         int dbuflen;
01104 {
01105         long buf [DLPI_MAXDLBUF];
01106         union DL_primitives *dlp;
01107         struct strbuf ctl, data;
01108         
01109         /* Set up the control information... */
01110         dlp = (union DL_primitives *)buf;
01111         dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ;
01112         dlp -> unitdata_req.dl_dest_addr_length = addrlen;
01113         dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
01114         dlp -> unitdata_req.dl_priority.dl_min = minpri;
01115         dlp -> unitdata_req.dl_priority.dl_max = maxpri;
01116 
01117         /* Append the destination address */
01118         memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
01119                 addr, addrlen);
01120         
01121         ctl.maxlen = 0;
01122         ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
01123         ctl.buf = (char *)buf;
01124 
01125         data.maxlen = 0;
01126         data.buf = (char *)dbuf;
01127         data.len = dbuflen;
01128 
01129         /* Send the packet down the wire... */
01130         return putmsg (fd, &ctl, &data, 0);
01131 }
01132 
01133 static int dlpiunitdataind (fd, daddr, daddrlen,
01134                             saddr, saddrlen, grpaddr, dbuf, dlen)
01135         int fd;
01136         unsigned char *daddr;
01137         unsigned long *daddrlen;
01138         unsigned char *saddr;
01139         unsigned long *saddrlen;
01140         unsigned long *grpaddr;
01141         unsigned char *dbuf;
01142         int dlen;
01143 {
01144         long buf [DLPI_MAXDLBUF];
01145         union DL_primitives *dlp;
01146         struct strbuf ctl, data;
01147         int flags = 0;
01148         int result;
01149 
01150         /* Set up the msg_buf structure... */
01151         dlp = (union DL_primitives *)buf;
01152         dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
01153 
01154         ctl.maxlen = DLPI_MAXDLBUF;
01155         ctl.len = 0;
01156         ctl.buf = (char *)buf;
01157 
01158         data.maxlen = dlen;
01159         data.len = 0;
01160         data.buf = (char *)dbuf;
01161 
01162         result = getmsg (fd, &ctl, &data, &flags);
01163 
01164         if (result < 0) {
01165                 log_debug("dlpiunitdataind: %m");
01166                 return -1;
01167         }
01168 
01169         if (ctl.len < sizeof (dl_unitdata_ind_t) ||
01170             dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
01171                 return -1;
01172         }
01173 
01174         if (data.len <= 0) {
01175                 return data.len;
01176         }
01177 
01178         /* Copy sender info */
01179         if (saddr) {
01180                 memcpy (saddr,
01181                         (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset,
01182                         dlp -> unitdata_ind.dl_src_addr_length);
01183         }
01184         if (saddrlen) {
01185                 *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
01186         }
01187 
01188         /* Copy destination info */
01189         if (daddr) {
01190                 memcpy (daddr,
01191                         (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset,
01192                         dlp -> unitdata_ind.dl_dest_addr_length);
01193         }
01194         if (daddrlen) {
01195                 *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
01196         }
01197 
01198         if (grpaddr) {
01199                 *grpaddr = dlp -> unitdata_ind.dl_group_address;
01200         }
01201 
01202         return data.len;
01203 }
01204 #endif /* !USE_DLPI_HWADDR: USE_DLPI_RECEIVE || USE_DLPI_SEND */
01205 
01206 /*
01207  * expected - see if we got what we wanted.
01208  */
01209 static int expected (prim, dlp, msgflags)
01210         unsigned long prim;
01211         union DL_primitives *dlp;
01212         int msgflags;
01213 {
01214         if (msgflags != RS_HIPRI) {
01215                 /* Message was not M_PCPROTO */
01216                 return -1;
01217         }
01218 
01219         if (dlp->dl_primitive != prim) {
01220                 /* Incorrect/unexpected return message */
01221                 return -1;
01222         }
01223         
01224         return 0;
01225 }
01226 
01227 /*
01228  * strgetmsg - get a message from a stream, with timeout.
01229  */
01230 static int strgetmsg (fd, ctlp, datap, flagsp, caller)
01231         struct strbuf *ctlp, *datap;
01232         char *caller;
01233         int *flagsp;
01234         int fd;
01235 {
01236         int result;
01237         struct pollfd pfd;
01238         int count;
01239         time_t now;
01240         time_t starttime;
01241         int to_msec;
01242         
01243         pfd.fd = fd;
01244         pfd.events = POLLPRI;   /* We're only interested in knowing
01245                                  * when we can receive the next high
01246                                  * priority message.
01247                                  */
01248         pfd.revents = 0;
01249 
01250         now = time (&starttime);
01251         while (now <= starttime + DLPI_MAXWAIT) {
01252                 to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000;
01253                 count = poll (&pfd, 1, to_msec);
01254                 
01255                 if (count == 0) {
01256                         /* log_fatal ("strgetmsg: timeout"); */
01257                         return -1;
01258                 } else if (count < 0) {
01259                         if (errno == EAGAIN || errno == EINTR) {
01260                                 time (&now);
01261                                 continue;
01262                         } else {
01263                                 /* log_fatal ("poll: %m"); */
01264                                 return -1;
01265                         }
01266                 } else {
01267                         break;
01268                 }
01269         }
01270 
01271         /*
01272          * Set flags argument and issue getmsg ().
01273          */
01274         *flagsp = 0;
01275         if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
01276                 return result;
01277         }
01278 
01279         /*
01280          * Check for MOREDATA and/or MORECTL.
01281          */
01282         if (result & (MORECTL|MOREDATA)) {
01283                 return -1;
01284         }
01285 
01286         /*
01287          * Check for at least sizeof (long) control data portion.
01288          */
01289         if (ctlp -> len < sizeof (long)) {
01290                 return -1;
01291         }
01292 
01293         return 0;
01294 }
01295 
01296 #if defined(USE_DLPI_SEND)
01297 int can_unicast_without_arp (ip)
01298         struct interface_info *ip;
01299 {
01300         return 1;
01301 }
01302 
01303 int can_receive_unicast_unconfigured (ip)
01304         struct interface_info *ip;
01305 {
01306         return 1;
01307 }
01308 
01309 int supports_multiple_interfaces (ip)
01310         struct interface_info *ip;
01311 {
01312         return 1;
01313 }
01314 
01315 void maybe_setup_fallback ()
01316 {
01317         isc_result_t status;
01318         struct interface_info *fbi = (struct interface_info *)0;
01319         if (setup_fallback (&fbi, MDL)) {
01320                 if_register_fallback (fbi);
01321                 status = omapi_register_io_object ((omapi_object_t *)fbi,
01322                                                    if_readsocket, 0,
01323                                                    fallback_discard, 0, 0);
01324                 if (status != ISC_R_SUCCESS)
01325                         log_fatal ("Can't register I/O handle for %s: %s",
01326                                    fbi -> name, isc_result_totext (status));
01327                 interface_dereference (&fbi, MDL);
01328         }
01329 }
01330 #endif /* USE_DLPI_SEND */
01331 
01332 void 
01333 get_hw_addr(const char *name, struct hardware *hw) {
01334         int sock, unit;
01335         long buf[DLPI_MAXDLBUF];
01336         union DL_primitives *dlp;
01337 
01338         dlp = (union DL_primitives *)buf;
01339 
01340         /* 
01341          * Open a DLPI device.
01342          */
01343         sock = dlpiopen(name);
01344         if (sock < 0) {
01345                 log_fatal("Can't open DLPI device for %s: %m", name);
01346         }
01347 
01348         /*
01349          * Submit a DL_INFO_REQ request, to find the dl_mac_type and 
01350          * dl_provider_style
01351          */
01352         if (dlpiinforeq(sock) < 0) {
01353             log_fatal("Can't request DLPI MAC type for %s: %m", name);
01354         }
01355         if (dlpiinfoack(sock, (char *)buf) < 0) {
01356             log_fatal("Can't get DLPI MAC type for %s: %m", name);
01357         }
01358         switch (dlp->info_ack.dl_mac_type) {
01359                 case DL_CSMACD: /* IEEE 802.3 */
01360                 case DL_ETHER:
01361                         hw->hbuf[0] = HTYPE_ETHER;
01362                         break;
01363                 case DL_TPR:
01364                         hw->hbuf[0] = HTYPE_IEEE802;
01365                         break;
01366                 case DL_FDDI:
01367                         hw->hbuf[0] = HTYPE_FDDI;
01368                         break;
01369                 default:
01370                         log_fatal("%s: unsupported DLPI MAC type %lu", name,
01371                                   (unsigned long)dlp->info_ack.dl_mac_type);
01372         }
01373 
01374         if (dlp->info_ack.dl_provider_style == DL_STYLE2) {
01375                 /*
01376                  * Attach to the device.  If this fails, the device
01377                  * does not exist.
01378                  */
01379                 unit = dlpiunit((char *)name);
01380 
01381                 if (dlpiattachreq(sock, unit) < 0 ||
01382                     dlpiokack(sock, (char *)buf) < 0) {
01383                         log_fatal("Can't attach DLPI device for %s: %m",
01384                                   name);
01385                 }
01386         }
01387 
01388         /*
01389          * Submit a DL_PHYS_ADDR_REQ request, to find
01390          * the hardware address.
01391          */
01392         if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) {
01393                 log_fatal("Can't request DLPI hardware address for %s: %m",
01394                           name);
01395         }
01396         if (dlpiphysaddrack(sock, (char *)buf) < 0) {
01397                 log_fatal("Can't get DLPI hardware address for %s: %m",
01398                           name);
01399         }
01400         if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) {
01401                 memcpy(hw->hbuf+1, 
01402                        (char *)buf + dlp->physaddr_ack.dl_addr_offset,
01403                        dlp->physaddr_ack.dl_addr_length);
01404                 hw->hlen = dlp->physaddr_ack.dl_addr_length + 1;
01405         } else {
01406                 memcpy(hw->hbuf+1, 
01407                        (char *)buf + dlp->physaddr_ack.dl_addr_offset,
01408                        sizeof(hw->hbuf)-1);
01409                 hw->hlen = sizeof(hw->hbuf);
01410         }
01411 
01412         close(sock);
01413 }
01414 #endif /* USE_DLPI_SEND || USE_DLPI_RECEIVE || USE_DLPI_HWADDR */

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1