3 Data Link Provider Interface (DLPI) network interface code. */
6 * Copyright (c) 1996-2002 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
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''.
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.
46 * Based largely in part to the existing NIT code in nit.c.
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
54 * Implementation notes:
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).
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
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.
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
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";
96 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
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>
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"
114 # ifdef USE_DLPI_PFMOD
116 # define DLPI_MODNAME "DLPI+RAW+PFMOD"
118 # define DLPI_MODNAME "DLPI+PFMOD"
122 # define DLPI_MODNAME "DLPI+RAW"
124 # define DLPI_MODNAME "DLPI"
129 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
132 static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp));
134 #define DLPI_MAXDLBUF 8192 /* Buffer size */
135 #define DLPI_MAXDLADDR 1024 /* Max address size */
136 #define DLPI_DEVDIR "/dev/" /* Device directory */
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,
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,
166 static void sigalrm PROTO ((int sig));
168 static int expected PROTO ((unsigned long prim, union DL_primitives *dlp,
170 static int strgetmsg PROTO ((int fd, struct strbuf *ctlp,
171 struct strbuf *datap, int *flagsp,
174 /* Reinitializes the specified interface after an address change. This
175 is not required for packet-filter APIs. */
178 void if_reinitialize_send (info)
179 struct interface_info *info;
184 #ifdef USE_DLPI_RECEIVE
185 void if_reinitialize_receive (info)
186 struct interface_info *info;
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
195 int if_register_dlpi (info)
196 struct interface_info *info;
200 long buf [DLPI_MAXDLBUF];
201 union DL_primitives *dlp;
203 dlp = (union DL_primitives *)buf;
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);
212 * Submit a DL_INFO_REQ request, to find the dl_mac_type and
215 if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
216 log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
218 switch (dlp -> info_ack.dl_mac_type) {
219 case DL_CSMACD: /* IEEE 802.3 */
221 info -> hw_address.hbuf [0] = HTYPE_ETHER;
223 /* adding token ring 5/1999 - mayer@ping.at */
225 info -> hw_address.hbuf [0] = HTYPE_IEEE802;
228 info -> hw_address.hbuf [0] = HTYPE_FDDI;
231 log_fatal ("%s: unsupported DLPI MAC type %ld",
232 info -> name, dlp -> info_ack.dl_mac_type);
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.
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);
248 if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
250 * Attach to the device. If this fails, the device
253 unit = dlpiunit (info -> name);
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);
262 * Bind to the IP service access point (SAP), connectionless (CLDLS).
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);
270 * Submit a DL_PHYS_ADDR_REQ request, to find
271 * the hardware address
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",
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);
285 if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
286 log_fatal ("Can't set DLPI RAW mode for %s: %m",
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",
302 strioctl (fd, cmd, timeout, len, dp)
313 sio.ic_timout = timeout;
317 if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
325 void if_register_send (info)
326 struct interface_info *info;
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;
335 info -> wfdesc = if_register_dlpi (info);
337 # ifdef USE_DLPI_PFMOD
338 /* Set up an PFMOD filter that rejects everything... */
341 pf.Pf_Filter [0] = ENF_PUSHZERO;
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);
349 # endif /* USE_DLPI_PFMOD */
350 #else /* !defined (USE_DLPI_RECEIVE) */
352 * If using DLPI for both send and receive, simply re-use
353 * the read file descriptor that was set up earlier.
355 info -> wfdesc = info -> rfdesc;
358 if (!quiet_interface_discovery)
359 log_info ("Sending on DLPI/%s/%s%s%s",
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 : ""));
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));
373 sleep (DLPI_FIRST_SEND_WAIT);
378 void if_deregister_send (info)
379 struct interface_info *info;
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);
388 if (!quiet_interface_discovery)
389 log_info ("Disabling output on DLPI/%s/%s%s%s",
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 : ""));
398 #endif /* USE_DLPI_SEND */
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 */
405 void if_register_receive (info)
406 struct interface_info *info;
408 #ifdef USE_DLPI_PFMOD
409 struct packetfilt pf;
414 /* Open a DLPI device and hang it on this interface... */
415 info -> rfdesc = if_register_dlpi (info);
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
425 #if defined (USE_DLPI_RAW)
426 # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
428 * ethertype == ETHERTYPE_IP
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);
435 # define ETHER_H_PREFIX (0)
436 # endif /* USE_DLPI_RAW */
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
448 * BOOTPS destination port
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;
456 * protocol should be udp. this is a byte compare, test for
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);
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);
471 #endif /* USE_DLPI_PFMOD */
473 if (!quiet_interface_discovery)
474 log_info ("Listening on DLPI/%s/%s%s%s",
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 : ""));
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);
488 sleep (DLPI_FIRST_SEND_WAIT);
493 void if_deregister_receive (info)
494 struct interface_info *info;
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);
503 if (!quiet_interface_discovery)
504 log_info ("Disabling input on DLPI/%s/%s%s%s",
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 : ""));
513 #endif /* USE_DLPI_RECEIVE */
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;
522 struct sockaddr_in *to;
523 struct hardware *hto;
527 double ih [1536 / sizeof (double)];
528 unsigned char *dbuf = (unsigned char *)ih;
530 unsigned char dstaddr [DLPI_MAXDLADDR];
535 if (!strcmp (interface -> name, "fallback"))
536 return send_fallback (interface, packet, raw,
541 /* Assemble the headers... */
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);
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);
556 /* Copy the data into the buffer (yuk). */
557 memcpy (dbuf + dbuflen, raw, len);
561 result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
565 * Setup the destination address (DLSAP) in dstaddr
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.
570 * sap = Service Access Point == ETHERTYPE_IP
571 * sap + datalink address is called DLSAP in dlpi speak.
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;
579 /* sap = htons (ETHERTYPE_IP) kludge */
580 memset (sap, 0, sizeof (sap));
581 # if (BYTE_ORDER == LITTLE_ENDIAN)
589 if (hto && hto -> hlen == interface -> hw_address.hlen)
590 memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
592 memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf,
593 interface -> dlpi_broadcast_addr.hlen);
596 memcpy ( dstaddr, phys, phys_len);
597 memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
600 memcpy ( dstaddr, (void *) sap, sap_len);
601 memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
603 addrlen = phys_len + ABS (sap_len);
606 result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
607 0, 0, dbuf, dbuflen);
608 #endif /* USE_DLPI_RAW */
610 log_error ("send_packet: %m");
613 #endif /* USE_DLPI_SEND */
615 #ifdef USE_DLPI_RECEIVE
616 ssize_t receive_packet (interface, buf, len, from, hfrom)
617 struct interface_info *interface;
620 struct sockaddr_in *from;
621 struct hardware *hfrom;
623 unsigned char dbuf [1536];
624 unsigned char srcaddr [DLPI_MAXDLADDR];
625 unsigned long srcaddrlen;
633 length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
635 length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
636 (unsigned long *)NULL, srcaddr, &srcaddrlen,
637 (unsigned long *)NULL, dbuf, sizeof (dbuf));
644 # if !defined (USE_DLPI_RAW)
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.
650 * sap is discarded here.
653 int sap_len = interface -> dlpi_sap_length;
654 int phys_len = interface -> hw_address.hlen - 1;
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;
661 memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
664 memcpy ((char *) &hfrom -> hbuf [1], (char *) &srcaddr [phys_len],
669 memset (hfrom, '\0', sizeof *hfrom);
673 # endif /* !defined (USE_DLPI_RAW) */
675 /* Decode the IP and UDP headers... */
678 /* Decode the physical header... */
679 offset = decode_hw_header (interface, dbuf, bufix, hfrom);
681 /* If a physical layer checksum failed (dunno of any
682 physical layer that supports this, but WTH), skip this
690 offset = decode_udp_ip_header (interface, dbuf, bufix,
691 from, (unsigned char *)0, length);
693 /* If the IP or UDP checksum was bad, skip the packet... */
701 /* Copy out the data in the packet... */
702 memcpy (buf, &dbuf [bufix], length);
707 /* Common DLPI routines ...
709 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
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.
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
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.
725 #define DLPI_MAXWAIT 15 /* Max timeout */
729 * Parse an interface name and extract the unit number
732 static int dlpiunit (ifname)
743 /* Advance to the end of the name */
746 /* Back up to the start of the first digit */
747 while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
749 /* Convert the unit number */
751 while (*cp >= '0' && *cp <= '9') {
753 unit += (*cp++ - '0');
760 * dlpiopen - open the DLPI device for a given interface name
762 static int dlpiopen (ifname)
772 /* Open a DLPI device */
773 if (*ifname == '/') {
776 /* Prepend the device directory */
777 memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
778 dp = &devname [strlen (DLPI_DEVDIR)];
781 /* Find the end of the interface name */
785 /* And back up to the first digit (unit number) */
786 while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
789 /* Copy everything up to the unit number */
795 return open (devname, O_RDWR, 0);
799 * dlpiinforeq - request information about the data link provider.
802 static int dlpiinforeq (fd)
805 dl_info_req_t info_req;
809 info_req.dl_primitive = DL_INFO_REQ;
812 ctl.len = sizeof (info_req);
813 ctl.buf = (char *)&info_req;
817 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
821 * dlpiphysaddrreq - request the current physical address.
823 static int dlpiphysaddrreq (fd, addrtype)
825 unsigned long addrtype;
827 dl_phys_addr_req_t physaddr_req;
831 physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
832 physaddr_req.dl_addr_type = addrtype;
835 ctl.len = sizeof (physaddr_req);
836 ctl.buf = (char *)&physaddr_req;
840 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
844 * dlpiattachreq - send a request to attach to a specific unit.
846 static int dlpiattachreq (fd, ppa)
850 dl_attach_req_t attach_req;
854 attach_req.dl_primitive = DL_ATTACH_REQ;
855 attach_req.dl_ppa = ppa;
858 ctl.len = sizeof (attach_req);
859 ctl.buf = (char *)&attach_req;
863 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
867 * dlpibindreq - send a request to bind to a specific SAP address.
869 static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
871 unsigned long max_conind;
872 unsigned long service_mode;
873 unsigned long conn_mgmt;
874 unsigned long xidtest;
877 dl_bind_req_t bind_req;
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;
889 ctl.len = sizeof (bind_req);
890 ctl.buf = (char *)&bind_req;
894 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
898 * dlpiunbindreq - send a request to unbind.
900 static int dlpiunbindreq (fd)
903 dl_unbind_req_t unbind_req;
907 unbind_req.dl_primitive = DL_UNBIND_REQ;
910 ctl.len = sizeof (unbind_req);
911 ctl.buf = (char *)&unbind_req;
915 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
920 * dlpidetachreq - send a request to detach.
922 static int dlpidetachreq (fd)
925 dl_detach_req_t detach_req;
929 detach_req.dl_primitive = DL_DETACH_REQ;
932 ctl.len = sizeof (detach_req);
933 ctl.buf = (char *)&detach_req;
937 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
942 * dlpibindack - receive an ack to a dlbindreq.
944 static int dlpibindack (fd, bufp)
948 union DL_primitives *dlp;
952 ctl.maxlen = DLPI_MAXDLBUF;
956 if (strgetmsg (fd, &ctl,
957 (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
961 dlp = (union DL_primitives *)ctl.buf;
963 if (!expected (DL_BIND_ACK, dlp, flags) < 0) {
967 if (ctl.len < sizeof (dl_bind_ack_t)) {
968 /* Returned structure is too short */
976 * dlpiokack - general acknowledgement reception.
978 static int dlpiokack (fd, bufp)
982 union DL_primitives *dlp;
986 ctl.maxlen = DLPI_MAXDLBUF;
990 if (strgetmsg (fd, &ctl,
991 (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
995 dlp = (union DL_primitives *)ctl.buf;
997 if (!expected (DL_OK_ACK, dlp, flags) < 0) {
1001 if (ctl.len < sizeof (dl_ok_ack_t)) {
1002 /* Returned structure is too short */
1010 * dlpiinfoack - receive an ack to a dlinforeq.
1012 static int dlpiinfoack (fd, bufp)
1016 union DL_primitives *dlp;
1020 ctl.maxlen = DLPI_MAXDLBUF;
1024 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1025 "dlpiinfoack") < 0) {
1029 dlp = (union DL_primitives *) ctl.buf;
1031 if (!expected (DL_INFO_ACK, dlp, flags) < 0) {
1035 if (ctl.len < sizeof (dl_info_ack_t)) {
1036 /* Returned structure is too short */
1044 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1046 int dlpiphysaddrack (fd, bufp)
1050 union DL_primitives *dlp;
1054 ctl.maxlen = DLPI_MAXDLBUF;
1058 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1059 "dlpiphysaddrack") < 0) {
1063 dlp = (union DL_primitives *)ctl.buf;
1065 if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) {
1069 if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
1070 /* Returned structure is too short */
1077 int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
1079 unsigned char *addr;
1081 unsigned long minpri;
1082 unsigned long maxpri;
1083 unsigned char *dbuf;
1086 long buf [DLPI_MAXDLBUF];
1087 union DL_primitives *dlp;
1088 struct strbuf ctl, data;
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;
1098 /* Append the destination address */
1099 memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
1103 ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
1104 ctl.buf = (char *)buf;
1107 data.buf = (char *)dbuf;
1110 /* Send the packet down the wire... */
1111 return putmsg (fd, &ctl, &data, 0);
1114 static int dlpiunitdataind (fd, daddr, daddrlen,
1115 saddr, saddrlen, grpaddr, dbuf, dlen)
1117 unsigned char *daddr;
1118 unsigned long *daddrlen;
1119 unsigned char *saddr;
1120 unsigned long *saddrlen;
1121 unsigned long *grpaddr;
1122 unsigned char *dbuf;
1125 long buf [DLPI_MAXDLBUF];
1126 union DL_primitives *dlp;
1127 struct strbuf ctl, data;
1131 /* Set up the msg_buf structure... */
1132 dlp = (union DL_primitives *)buf;
1133 dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
1135 ctl.maxlen = DLPI_MAXDLBUF;
1137 ctl.buf = (char *)buf;
1141 data.buf = (char *)dbuf;
1143 result = getmsg (fd, &ctl, &data, &flags);
1149 if (ctl.len < sizeof (dl_unitdata_ind_t) ||
1150 dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
1154 if (data.len <= 0) {
1158 /* Copy sender info */
1161 (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset,
1162 dlp -> unitdata_ind.dl_src_addr_length);
1165 *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
1168 /* Copy destination info */
1171 (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset,
1172 dlp -> unitdata_ind.dl_dest_addr_length);
1175 *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
1179 *grpaddr = dlp -> unitdata_ind.dl_group_address;
1186 * expected - see if we got what we wanted.
1188 static int expected (prim, dlp, msgflags)
1190 union DL_primitives *dlp;
1193 if (msgflags != RS_HIPRI) {
1194 /* Message was not M_PCPROTO */
1198 if (dlp -> dl_primitive != prim) {
1199 /* Incorrect/unexpected return message */
1207 * strgetmsg - get a message from a stream, with timeout.
1209 static int strgetmsg (fd, ctlp, datap, flagsp, caller)
1210 struct strbuf *ctlp, *datap;
1226 pfd.events = POLLPRI; /* We're only interested in knowing
1227 * when we can receive the next high
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);
1238 /* log_fatal ("strgetmsg: timeout"); */
1240 } else if (count < 0) {
1241 if (errno == EAGAIN || errno == EINTR) {
1245 /* log_fatal ("poll: %m"); */
1252 #else /* defined (USE_POLL) */
1254 * Start timer. Can't use select, since it might return true if there
1255 * were non High-Priority data available on the stream.
1257 (void) sigset (SIGALRM, sigalrm);
1259 if (alarm (DLPI_MAXWAIT) < 0) {
1260 /* log_fatal ("alarm: %m"); */
1263 #endif /* !defined (USE_POLL) */
1266 * Set flags argument and issue getmsg ().
1269 if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
1277 if (alarm (0) < 0) {
1278 /* log_fatal ("alarm: %m"); */
1284 * Check for MOREDATA and/or MORECTL.
1286 if (result & (MORECTL|MOREDATA)) {
1291 * Check for at least sizeof (long) control data portion.
1293 if (ctlp -> len < sizeof (long)) {
1302 * sigalrm - handle alarms.
1304 static void sigalrm (sig)
1307 fprintf (stderr, "strgetmsg: timeout");
1310 #endif /* !defined (USE_POLL) */
1312 int can_unicast_without_arp (ip)
1313 struct interface_info *ip;
1318 int can_receive_unicast_unconfigured (ip)
1319 struct interface_info *ip;
1324 int supports_multiple_interfaces (ip)
1325 struct interface_info *ip;
1330 void maybe_setup_fallback ()
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,
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);
1345 #endif /* USE_DLPI */