tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / common / dlpi.c
blob936ad56e7aabb9612d4e9c92887000f284251ab6
1 /* dlpi.c
3 Data Link Provider Interface (DLPI) network interface code. */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1996-2003 by Internet Software Consortium
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.
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.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
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''.
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.
37 * Based largely in part to the existing NIT code in nit.c.
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.
45 * Implementation notes:
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).
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.
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.
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.
80 #if 0
81 static char copyright[] =
82 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
83 #endif
85 #include "dhcpd.h"
87 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
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
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"
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
119 # ifndef ABS
120 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
121 # endif
123 static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp));
125 #define DLPI_MAXDLBUF 8192 /* Buffer size */
126 #define DLPI_MAXDLADDR 1024 /* Max address size */
127 #define DLPI_DEVDIR "/dev/" /* Device directory */
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));
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));
165 /* Reinitializes the specified interface after an address change. This
166 is not required for packet-filter APIs. */
168 #ifdef USE_DLPI_SEND
169 void if_reinitialize_send (info)
170 struct interface_info *info;
173 #endif
175 #ifdef USE_DLPI_RECEIVE
176 void if_reinitialize_receive (info)
177 struct interface_info *info;
180 #endif
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. */
186 int if_register_dlpi (info)
187 struct interface_info *info;
189 int sock;
190 int unit;
191 long buf [DLPI_MAXDLBUF];
192 union DL_primitives *dlp;
194 dlp = (union DL_primitives *)buf;
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);
203 * Submit a DL_INFO_REQ request, to find the dl_mac_type and
204 * dl_provider_style
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;
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.
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);
239 if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
241 * Attach to the device. If this fails, the device
242 * does not exist.
244 unit = dlpiunit (info -> name);
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);
253 * Bind to the IP service access point (SAP), connectionless (CLDLS).
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);
261 * Submit a DL_PHYS_ADDR_REQ request, to find
262 * the hardware address
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);
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);
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);
280 #endif
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);
287 #endif
289 return sock;
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;
300 struct strioctl sio;
301 int rslt;
303 sio.ic_cmd = cmd;
304 sio.ic_timout = timeout;
305 sio.ic_len = len;
306 sio.ic_dp = dp;
308 if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
309 return rslt;
310 } else {
311 return sio.ic_len;
315 #ifdef USE_DLPI_SEND
316 void if_register_send (info)
317 struct interface_info *info;
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
326 info -> wfdesc = if_register_dlpi (info);
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;
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);
340 # endif /* USE_DLPI_PFMOD */
341 #else /* !defined (USE_DLPI_RECEIVE) */
343 * If using DLPI for both send and receive, simply re-use
344 * the read file descriptor that was set up earlier.
346 info -> wfdesc = info -> rfdesc;
347 #endif
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 : ""));
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
369 void if_deregister_send (info)
370 struct interface_info *info;
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;
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 : ""));
389 #endif /* USE_DLPI_SEND */
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 */
396 void if_register_receive (info)
397 struct interface_info *info;
399 #ifdef USE_DLPI_PFMOD
400 struct packetfilt pf;
401 struct ip iphdr;
402 u_int16_t offset;
403 #endif
405 /* Open a DLPI device and hang it on this interface... */
406 info -> rfdesc = if_register_dlpi (info);
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;
416 #if defined (USE_DLPI_RAW)
417 # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
419 * ethertype == ETHERTYPE_IP
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 */
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.
439 * BOOTPS destination port
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;
447 * protocol should be udp. this is a byte compare, test for
448 * endianess.
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);
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);
462 #endif /* USE_DLPI_PFMOD */
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 : ""));
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
484 void if_deregister_receive (info)
485 struct interface_info *info;
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;
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 : ""));
504 #endif /* USE_DLPI_RECEIVE */
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;
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;
526 if (!strcmp (interface -> name, "fallback"))
527 return send_fallback (interface, packet, raw,
528 len, from, to, hto);
530 dbuflen = 0;
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);
547 /* Copy the data into the buffer (yuk). */
548 memcpy (dbuf + dbuflen, raw, len);
549 dbuflen += len;
551 #ifdef USE_DLPI_RAW
552 result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
553 #else
556 * Setup the destination address (DLSAP) in dstaddr
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.
561 * sap = Service Access Point == ETHERTYPE_IP
562 * sap + datalink address is called DLSAP in dlpi speak.
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;
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
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);
586 if (sap_len < 0) {
587 memcpy ( dstaddr, phys, phys_len);
588 memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
590 else {
591 memcpy ( dstaddr, (void *) sap, sap_len);
592 memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
594 addrlen = phys_len + ABS (sap_len);
595 } /* ENCODE DLSAP */
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;
604 #endif /* USE_DLPI_SEND */
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;
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;
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
631 if (length <= 0) {
632 return length;
635 # if !defined (USE_DLPI_RAW)
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.
641 * sap is discarded here.
643 { /* DECODE DLSAP */
644 int sap_len = interface -> dlpi_sap_length;
645 int phys_len = interface -> hw_address.hlen - 1;
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;
651 if (sap_len < 0) {
652 memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
654 else {
655 memcpy ((char *) &hfrom -> hbuf [1], (char *) &srcaddr [phys_len],
656 phys_len);
659 else if (hfrom) {
660 memset (hfrom, '\0', sizeof *hfrom);
662 } /* DECODE_DLSAP */
664 # endif /* !defined (USE_DLPI_RAW) */
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);
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;
678 bufix += offset;
679 length -= offset;
680 #endif
681 offset = decode_udp_ip_header (interface, dbuf, bufix,
682 from, length);
684 /* If the IP or UDP checksum was bad, skip the packet... */
685 if (offset < 0) {
686 return 0;
689 bufix += offset;
690 length -= offset;
692 /* Copy out the data in the packet... */
693 memcpy (buf, &dbuf [bufix], length);
694 return length;
696 #endif
698 /* Common DLPI routines ...
700 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
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.
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.
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.
716 #define DLPI_MAXWAIT 15 /* Max timeout */
720 * Parse an interface name and extract the unit number
723 static int dlpiunit (ifname)
724 char *ifname;
726 int fd;
727 char *cp, *dp, *ep;
728 int unit;
730 if (!ifname) {
731 return 0;
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--;
740 /* Convert the unit number */
741 unit = 0;
742 while (*cp >= '0' && *cp <= '9') {
743 unit *= 10;
744 unit += (*cp++ - '0');
747 return unit;
751 * dlpiopen - open the DLPI device for a given interface name
753 static int dlpiopen (ifname)
754 char *ifname;
756 char devname [50];
757 char *cp, *dp, *ep;
759 if (!ifname) {
760 return -1;
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)];
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--;
780 /* Copy everything up to the unit number */
781 while (cp < ep) {
782 *dp++ = *cp++;
784 *dp = '\0';
786 return open (devname, O_RDWR, 0);
790 * dlpiinforeq - request information about the data link provider.
793 static int dlpiinforeq (fd)
794 int fd;
796 dl_info_req_t info_req;
797 struct strbuf ctl;
798 int flags;
800 info_req.dl_primitive = DL_INFO_REQ;
802 ctl.maxlen = 0;
803 ctl.len = sizeof (info_req);
804 ctl.buf = (char *)&info_req;
806 flags = RS_HIPRI;
808 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
812 * dlpiphysaddrreq - request the current physical address.
814 static int dlpiphysaddrreq (fd, addrtype)
815 int fd;
816 unsigned long addrtype;
818 dl_phys_addr_req_t physaddr_req;
819 struct strbuf ctl;
820 int flags;
822 physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
823 physaddr_req.dl_addr_type = addrtype;
825 ctl.maxlen = 0;
826 ctl.len = sizeof (physaddr_req);
827 ctl.buf = (char *)&physaddr_req;
829 flags = RS_HIPRI;
831 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
835 * dlpiattachreq - send a request to attach to a specific unit.
837 static int dlpiattachreq (fd, ppa)
838 unsigned long ppa;
839 int fd;
841 dl_attach_req_t attach_req;
842 struct strbuf ctl;
843 int flags;
845 attach_req.dl_primitive = DL_ATTACH_REQ;
846 attach_req.dl_ppa = ppa;
848 ctl.maxlen = 0;
849 ctl.len = sizeof (attach_req);
850 ctl.buf = (char *)&attach_req;
852 flags = 0;
854 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
858 * dlpibindreq - send a request to bind to a specific SAP address.
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;
868 dl_bind_req_t bind_req;
869 struct strbuf ctl;
870 int flags;
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;
879 ctl.maxlen = 0;
880 ctl.len = sizeof (bind_req);
881 ctl.buf = (char *)&bind_req;
883 flags = 0;
885 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
889 * dlpiunbindreq - send a request to unbind.
891 static int dlpiunbindreq (fd)
892 int fd;
894 dl_unbind_req_t unbind_req;
895 struct strbuf ctl;
896 int flags;
898 unbind_req.dl_primitive = DL_UNBIND_REQ;
900 ctl.maxlen = 0;
901 ctl.len = sizeof (unbind_req);
902 ctl.buf = (char *)&unbind_req;
904 flags = 0;
906 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
911 * dlpidetachreq - send a request to detach.
913 static int dlpidetachreq (fd)
914 int fd;
916 dl_detach_req_t detach_req;
917 struct strbuf ctl;
918 int flags;
920 detach_req.dl_primitive = DL_DETACH_REQ;
922 ctl.maxlen = 0;
923 ctl.len = sizeof (detach_req);
924 ctl.buf = (char *)&detach_req;
926 flags = 0;
928 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
933 * dlpibindack - receive an ack to a dlbindreq.
935 static int dlpibindack (fd, bufp)
936 char *bufp;
937 int fd;
939 union DL_primitives *dlp;
940 struct strbuf ctl;
941 int flags;
943 ctl.maxlen = DLPI_MAXDLBUF;
944 ctl.len = 0;
945 ctl.buf = bufp;
947 if (strgetmsg (fd, &ctl,
948 (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
949 return -1;
952 dlp = (union DL_primitives *)ctl.buf;
954 if (!expected (DL_BIND_ACK, dlp, flags) < 0) {
955 return -1;
958 if (ctl.len < sizeof (dl_bind_ack_t)) {
959 /* Returned structure is too short */
960 return -1;
963 return 0;
967 * dlpiokack - general acknowledgement reception.
969 static int dlpiokack (fd, bufp)
970 char *bufp;
971 int fd;
973 union DL_primitives *dlp;
974 struct strbuf ctl;
975 int flags;
977 ctl.maxlen = DLPI_MAXDLBUF;
978 ctl.len = 0;
979 ctl.buf = bufp;
981 if (strgetmsg (fd, &ctl,
982 (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
983 return -1;
986 dlp = (union DL_primitives *)ctl.buf;
988 if (!expected (DL_OK_ACK, dlp, flags) < 0) {
989 return -1;
992 if (ctl.len < sizeof (dl_ok_ack_t)) {
993 /* Returned structure is too short */
994 return -1;
997 return 0;
1001 * dlpiinfoack - receive an ack to a dlinforeq.
1003 static int dlpiinfoack (fd, bufp)
1004 char *bufp;
1005 int fd;
1007 union DL_primitives *dlp;
1008 struct strbuf ctl;
1009 int flags;
1011 ctl.maxlen = DLPI_MAXDLBUF;
1012 ctl.len = 0;
1013 ctl.buf = bufp;
1015 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1016 "dlpiinfoack") < 0) {
1017 return -1;
1020 dlp = (union DL_primitives *) ctl.buf;
1022 if (!expected (DL_INFO_ACK, dlp, flags) < 0) {
1023 return -1;
1026 if (ctl.len < sizeof (dl_info_ack_t)) {
1027 /* Returned structure is too short */
1028 return -1;
1031 return 0;
1035 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1037 int dlpiphysaddrack (fd, bufp)
1038 char *bufp;
1039 int fd;
1041 union DL_primitives *dlp;
1042 struct strbuf ctl;
1043 int flags;
1045 ctl.maxlen = DLPI_MAXDLBUF;
1046 ctl.len = 0;
1047 ctl.buf = bufp;
1049 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1050 "dlpiphysaddrack") < 0) {
1051 return -1;
1054 dlp = (union DL_primitives *)ctl.buf;
1056 if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) {
1057 return -1;
1060 if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
1061 /* Returned structure is too short */
1062 return -1;
1065 return 0;
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;
1077 long buf [DLPI_MAXDLBUF];
1078 union DL_primitives *dlp;
1079 struct strbuf ctl, data;
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;
1089 /* Append the destination address */
1090 memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
1091 addr, addrlen);
1093 ctl.maxlen = 0;
1094 ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
1095 ctl.buf = (char *)buf;
1097 data.maxlen = 0;
1098 data.buf = (char *)dbuf;
1099 data.len = dbuflen;
1101 /* Send the packet down the wire... */
1102 return putmsg (fd, &ctl, &data, 0);
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;
1116 long buf [DLPI_MAXDLBUF];
1117 union DL_primitives *dlp;
1118 struct strbuf ctl, data;
1119 int flags = 0;
1120 int result;
1122 /* Set up the msg_buf structure... */
1123 dlp = (union DL_primitives *)buf;
1124 dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
1126 ctl.maxlen = DLPI_MAXDLBUF;
1127 ctl.len = 0;
1128 ctl.buf = (char *)buf;
1130 data.maxlen = dlen;
1131 data.len = 0;
1132 data.buf = (char *)dbuf;
1134 result = getmsg (fd, &ctl, &data, &flags);
1136 if (result != 0) {
1137 return -1;
1140 if (ctl.len < sizeof (dl_unitdata_ind_t) ||
1141 dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
1142 return -1;
1145 if (data.len <= 0) {
1146 return data.len;
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);
1155 if (saddrlen) {
1156 *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
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);
1165 if (daddrlen) {
1166 *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
1169 if (grpaddr) {
1170 *grpaddr = dlp -> unitdata_ind.dl_group_address;
1173 return data.len;
1177 * expected - see if we got what we wanted.
1179 static int expected (prim, dlp, msgflags)
1180 unsigned long prim;
1181 union DL_primitives *dlp;
1182 int msgflags;
1184 if (msgflags != RS_HIPRI) {
1185 /* Message was not M_PCPROTO */
1186 return 0;
1189 if (dlp -> dl_primitive != prim) {
1190 /* Incorrect/unexpected return message */
1191 return 0;
1194 return 1;
1198 * strgetmsg - get a message from a stream, with timeout.
1200 static int strgetmsg (fd, ctlp, datap, flagsp, caller)
1201 struct strbuf *ctlp, *datap;
1202 char *caller;
1203 int *flagsp;
1204 int fd;
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
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.
1221 pfd.revents = 0;
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);
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;
1239 } else {
1240 break;
1243 #else /* defined (USE_POLL) */
1245 * Start timer. Can't use select, since it might return true if there
1246 * were non High-Priority data available on the stream.
1248 (void) sigset (SIGALRM, sigalrm);
1250 if (alarm (DLPI_MAXWAIT) < 0) {
1251 /* log_fatal ("alarm: %m"); */
1252 return -1;
1254 #endif /* !defined (USE_POLL) */
1257 * Set flags argument and issue getmsg ().
1259 *flagsp = 0;
1260 if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
1261 return result;
1264 #ifndef USE_POLL
1266 * Stop timer.
1268 if (alarm (0) < 0) {
1269 /* log_fatal ("alarm: %m"); */
1270 return -1;
1272 #endif
1275 * Check for MOREDATA and/or MORECTL.
1277 if (result & (MORECTL|MOREDATA)) {
1278 return -1;
1282 * Check for at least sizeof (long) control data portion.
1284 if (ctlp -> len < sizeof (long)) {
1285 return -1;
1288 return 0;
1291 #ifndef USE_POLL
1293 * sigalrm - handle alarms.
1295 static void sigalrm (sig)
1296 int sig;
1298 fprintf (stderr, "strgetmsg: timeout");
1299 exit (1);
1301 #endif /* !defined (USE_POLL) */
1303 int can_unicast_without_arp (ip)
1304 struct interface_info *ip;
1306 return 1;
1309 int can_receive_unicast_unconfigured (ip)
1310 struct interface_info *ip;
1312 return 1;
1315 int supports_multiple_interfaces (ip)
1316 struct interface_info *ip;
1318 return 1;
1321 void maybe_setup_fallback ()
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);
1336 #endif /* USE_DLPI */