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