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