3 Data Link Provider Interface (DLPI) network interface code. */
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.
23 * Redwood City, CA 94063
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
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
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
81 static char copyright
[] =
82 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
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>
93 # ifdef USE_DLPI_PFMOD
94 # include <sys/pfmod.h>
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
107 # define DLPI_MODNAME "DLPI+RAW+PFMOD"
109 # define DLPI_MODNAME "DLPI+PFMOD"
113 # define DLPI_MODNAME "DLPI+RAW"
115 # define DLPI_MODNAME "DLPI"
120 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
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
,
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
,
157 static void sigalrm
PROTO ((int sig
));
159 static int expected
PROTO ((unsigned long prim
, union DL_primitives
*dlp
,
161 static int strgetmsg
PROTO ((int fd
, struct strbuf
*ctlp
,
162 struct strbuf
*datap
, int *flagsp
,
165 /* Reinitializes the specified interface after an address change. This
166 is not required for packet-filter APIs. */
169 void if_reinitialize_send (info
)
170 struct interface_info
*info
;
175 #ifdef USE_DLPI_RECEIVE
176 void if_reinitialize_receive (info
)
177 struct interface_info
*info
;
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
186 int if_register_dlpi (info
)
187 struct interface_info
*info
;
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
206 if (dlpiinforeq(sock
) < 0 || dlpiinfoack(sock
, (char *)buf
) < 0) {
207 log_fatal ("Can't get DLPI MAC type for %s: %m", info
-> name
);
209 switch (dlp
-> info_ack
.dl_mac_type
) {
210 case DL_CSMACD
: /* IEEE 802.3 */
212 info
-> hw_address
.hbuf
[0] = HTYPE_ETHER
;
214 /* adding token ring 5/1999 - mayer@ping.at */
216 info
-> hw_address
.hbuf
[0] = HTYPE_IEEE802
;
219 info
-> hw_address
.hbuf
[0] = HTYPE_FDDI
;
222 log_fatal ("%s: unsupported DLPI MAC type %ld",
223 info
-> name
, dlp
-> info_ack
.dl_mac_type
);
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
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",
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
);
276 if (strioctl (sock
, DLIOCRAW
, INFTIM
, 0, 0) < 0) {
277 log_fatal ("Can't set DLPI RAW mode for %s: %m",
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",
293 strioctl (fd
, cmd
, timeout
, len
, dp
)
304 sio
.ic_timout
= timeout
;
308 if ((rslt
= ioctl (fd
, I_STR
, &sio
)) < 0) {
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
;
326 info
-> wfdesc
= if_register_dlpi (info
);
328 # ifdef USE_DLPI_PFMOD
329 /* Set up an PFMOD filter that rejects everything... */
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
;
349 if (!quiet_interface_discovery
)
350 log_info ("Sending on DLPI/%s/%s%s%s",
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));
364 sleep (DLPI_FIRST_SEND_WAIT
);
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
);
379 if (!quiet_interface_discovery
)
380 log_info ("Disabling output on DLPI/%s/%s%s%s",
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
;
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
416 #if defined (USE_DLPI_RAW)
417 # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
419 * ethertype == ETHERTYPE_IP
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
);
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
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
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",
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);
479 sleep (DLPI_FIRST_SEND_WAIT
);
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
);
494 if (!quiet_interface_discovery
)
495 log_info ("Disabling input on DLPI/%s/%s%s%s",
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 */
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
;
513 struct sockaddr_in
*to
;
514 struct hardware
*hto
;
518 double ih
[1536 / sizeof (double)];
519 unsigned char *dbuf
= (unsigned char *)ih
;
521 unsigned char dstaddr
[DLPI_MAXDLADDR
];
526 if (!strcmp (interface
-> name
, "fallback"))
527 return send_fallback (interface
, packet
, raw
,
532 /* Assemble the headers... */
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
);
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
);
552 result
= write (interface
-> wfdesc
, dbuf
+ fudge
, dbuflen
- fudge
);
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.
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)
580 if (hto
&& hto
-> hlen
== interface
-> hw_address
.hlen
)
581 memcpy ( phys
, (char *) &hto
-> hbuf
[1], phys_len
);
583 memcpy ( phys
, interface
-> dlpi_broadcast_addr
.hbuf
,
584 interface
-> dlpi_broadcast_addr
.hlen
);
587 memcpy ( dstaddr
, phys
, phys_len
);
588 memcpy ( (char *) &dstaddr
[phys_len
], sap
, ABS (sap_len
));
591 memcpy ( dstaddr
, (void *) sap
, sap_len
);
592 memcpy ( (char *) &dstaddr
[sap_len
], phys
, phys_len
);
594 addrlen
= phys_len
+ ABS (sap_len
);
597 result
= dlpiunitdatareq (interface
-> wfdesc
, dstaddr
, addrlen
,
598 0, 0, dbuf
, dbuflen
);
599 #endif /* USE_DLPI_RAW */
601 log_error ("send_packet: %m");
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
;
611 struct sockaddr_in
*from
;
612 struct hardware
*hfrom
;
614 unsigned char dbuf
[1536];
615 unsigned char srcaddr
[DLPI_MAXDLADDR
];
616 unsigned long srcaddrlen
;
624 length
= read (interface
-> rfdesc
, dbuf
, sizeof (dbuf
));
626 length
= dlpiunitdataind (interface
-> rfdesc
, (unsigned char *)NULL
,
627 (unsigned long *)NULL
, srcaddr
, &srcaddrlen
,
628 (unsigned long *)NULL
, dbuf
, sizeof (dbuf
));
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.
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
;
652 memcpy ((char *) &hfrom
-> hbuf
[1], srcaddr
, phys_len
);
655 memcpy ((char *) &hfrom
-> hbuf
[1], (char *) &srcaddr
[phys_len
],
660 memset (hfrom
, '\0', sizeof *hfrom
);
664 # endif /* !defined (USE_DLPI_RAW) */
666 /* Decode the IP and UDP headers... */
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
681 offset
= decode_udp_ip_header (interface
, dbuf
, bufix
,
684 /* If the IP or UDP checksum was bad, skip the packet... */
692 /* Copy out the data in the packet... */
693 memcpy (buf
, &dbuf
[bufix
], length
);
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
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
)
734 /* Advance to the end of the name */
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 */
742 while (*cp
>= '0' && *cp
<= '9') {
744 unit
+= (*cp
++ - '0');
751 * dlpiopen - open the DLPI device for a given interface name
753 static int dlpiopen (ifname
)
763 /* Open a DLPI device */
764 if (*ifname
== '/') {
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 */
776 /* And back up to the first digit (unit number) */
777 while ((*(ep
- 1) >= '0' && *(ep
- 1) <= '9') || *(ep
- 1) == ':')
780 /* Copy everything up to the unit number */
786 return open (devname
, O_RDWR
, 0);
790 * dlpiinforeq - request information about the data link provider.
793 static int dlpiinforeq (fd
)
796 dl_info_req_t info_req
;
800 info_req
.dl_primitive
= DL_INFO_REQ
;
803 ctl
.len
= sizeof (info_req
);
804 ctl
.buf
= (char *)&info_req
;
808 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
812 * dlpiphysaddrreq - request the current physical address.
814 static int dlpiphysaddrreq (fd
, addrtype
)
816 unsigned long addrtype
;
818 dl_phys_addr_req_t physaddr_req
;
822 physaddr_req
.dl_primitive
= DL_PHYS_ADDR_REQ
;
823 physaddr_req
.dl_addr_type
= addrtype
;
826 ctl
.len
= sizeof (physaddr_req
);
827 ctl
.buf
= (char *)&physaddr_req
;
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
)
841 dl_attach_req_t attach_req
;
845 attach_req
.dl_primitive
= DL_ATTACH_REQ
;
846 attach_req
.dl_ppa
= ppa
;
849 ctl
.len
= sizeof (attach_req
);
850 ctl
.buf
= (char *)&attach_req
;
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
)
862 unsigned long max_conind
;
863 unsigned long service_mode
;
864 unsigned long conn_mgmt
;
865 unsigned long xidtest
;
868 dl_bind_req_t bind_req
;
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
;
880 ctl
.len
= sizeof (bind_req
);
881 ctl
.buf
= (char *)&bind_req
;
885 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
889 * dlpiunbindreq - send a request to unbind.
891 static int dlpiunbindreq (fd
)
894 dl_unbind_req_t unbind_req
;
898 unbind_req
.dl_primitive
= DL_UNBIND_REQ
;
901 ctl
.len
= sizeof (unbind_req
);
902 ctl
.buf
= (char *)&unbind_req
;
906 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
911 * dlpidetachreq - send a request to detach.
913 static int dlpidetachreq (fd
)
916 dl_detach_req_t detach_req
;
920 detach_req
.dl_primitive
= DL_DETACH_REQ
;
923 ctl
.len
= sizeof (detach_req
);
924 ctl
.buf
= (char *)&detach_req
;
928 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
933 * dlpibindack - receive an ack to a dlbindreq.
935 static int dlpibindack (fd
, bufp
)
939 union DL_primitives
*dlp
;
943 ctl
.maxlen
= DLPI_MAXDLBUF
;
947 if (strgetmsg (fd
, &ctl
,
948 (struct strbuf
*)NULL
, &flags
, "dlpibindack") < 0) {
952 dlp
= (union DL_primitives
*)ctl
.buf
;
954 if (!expected (DL_BIND_ACK
, dlp
, flags
) < 0) {
958 if (ctl
.len
< sizeof (dl_bind_ack_t
)) {
959 /* Returned structure is too short */
967 * dlpiokack - general acknowledgement reception.
969 static int dlpiokack (fd
, bufp
)
973 union DL_primitives
*dlp
;
977 ctl
.maxlen
= DLPI_MAXDLBUF
;
981 if (strgetmsg (fd
, &ctl
,
982 (struct strbuf
*)NULL
, &flags
, "dlpiokack") < 0) {
986 dlp
= (union DL_primitives
*)ctl
.buf
;
988 if (!expected (DL_OK_ACK
, dlp
, flags
) < 0) {
992 if (ctl
.len
< sizeof (dl_ok_ack_t
)) {
993 /* Returned structure is too short */
1001 * dlpiinfoack - receive an ack to a dlinforeq.
1003 static int dlpiinfoack (fd
, bufp
)
1007 union DL_primitives
*dlp
;
1011 ctl
.maxlen
= DLPI_MAXDLBUF
;
1015 if (strgetmsg (fd
, &ctl
, (struct strbuf
*)NULL
, &flags
,
1016 "dlpiinfoack") < 0) {
1020 dlp
= (union DL_primitives
*) ctl
.buf
;
1022 if (!expected (DL_INFO_ACK
, dlp
, flags
) < 0) {
1026 if (ctl
.len
< sizeof (dl_info_ack_t
)) {
1027 /* Returned structure is too short */
1035 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1037 int dlpiphysaddrack (fd
, bufp
)
1041 union DL_primitives
*dlp
;
1045 ctl
.maxlen
= DLPI_MAXDLBUF
;
1049 if (strgetmsg (fd
, &ctl
, (struct strbuf
*)NULL
, &flags
,
1050 "dlpiphysaddrack") < 0) {
1054 dlp
= (union DL_primitives
*)ctl
.buf
;
1056 if (!expected (DL_PHYS_ADDR_ACK
, dlp
, flags
) < 0) {
1060 if (ctl
.len
< sizeof (dl_phys_addr_ack_t
)) {
1061 /* Returned structure is too short */
1068 int dlpiunitdatareq (fd
, addr
, addrlen
, minpri
, maxpri
, dbuf
, dbuflen
)
1070 unsigned char *addr
;
1072 unsigned long minpri
;
1073 unsigned long maxpri
;
1074 unsigned char *dbuf
;
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
,
1094 ctl
.len
= dlp
-> unitdata_req
.dl_dest_addr_offset
+ addrlen
;
1095 ctl
.buf
= (char *)buf
;
1098 data
.buf
= (char *)dbuf
;
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
)
1108 unsigned char *daddr
;
1109 unsigned long *daddrlen
;
1110 unsigned char *saddr
;
1111 unsigned long *saddrlen
;
1112 unsigned long *grpaddr
;
1113 unsigned char *dbuf
;
1116 long buf
[DLPI_MAXDLBUF
];
1117 union DL_primitives
*dlp
;
1118 struct strbuf ctl
, data
;
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
;
1128 ctl
.buf
= (char *)buf
;
1132 data
.buf
= (char *)dbuf
;
1134 result
= getmsg (fd
, &ctl
, &data
, &flags
);
1140 if (ctl
.len
< sizeof (dl_unitdata_ind_t
) ||
1141 dlp
-> unitdata_ind
.dl_primitive
!= DL_UNITDATA_IND
) {
1145 if (data
.len
<= 0) {
1149 /* Copy sender info */
1152 (char *)buf
+ dlp
-> unitdata_ind
.dl_src_addr_offset
,
1153 dlp
-> unitdata_ind
.dl_src_addr_length
);
1156 *saddrlen
= dlp
-> unitdata_ind
.dl_src_addr_length
;
1159 /* Copy destination info */
1162 (char *)buf
+ dlp
-> unitdata_ind
.dl_dest_addr_offset
,
1163 dlp
-> unitdata_ind
.dl_dest_addr_length
);
1166 *daddrlen
= dlp
-> unitdata_ind
.dl_dest_addr_length
;
1170 *grpaddr
= dlp
-> unitdata_ind
.dl_group_address
;
1177 * expected - see if we got what we wanted.
1179 static int expected (prim
, dlp
, msgflags
)
1181 union DL_primitives
*dlp
;
1184 if (msgflags
!= RS_HIPRI
) {
1185 /* Message was not M_PCPROTO */
1189 if (dlp
-> dl_primitive
!= prim
) {
1190 /* Incorrect/unexpected return message */
1198 * strgetmsg - get a message from a stream, with timeout.
1200 static int strgetmsg (fd
, ctlp
, datap
, flagsp
, caller
)
1201 struct strbuf
*ctlp
, *datap
;
1217 pfd
.events
= POLLPRI
; /* We're only interested in knowing
1218 * when we can receive the next high
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
);
1229 /* log_fatal ("strgetmsg: timeout"); */
1231 } else if (count
< 0) {
1232 if (errno
== EAGAIN
|| errno
== EINTR
) {
1236 /* log_fatal ("poll: %m"); */
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"); */
1254 #endif /* !defined (USE_POLL) */
1257 * Set flags argument and issue getmsg ().
1260 if ((result
= getmsg (fd
, ctlp
, datap
, flagsp
)) < 0) {
1268 if (alarm (0) < 0) {
1269 /* log_fatal ("alarm: %m"); */
1275 * Check for MOREDATA and/or MORECTL.
1277 if (result
& (MORECTL
|MOREDATA
)) {
1282 * Check for at least sizeof (long) control data portion.
1284 if (ctlp
-> len
< sizeof (long)) {
1293 * sigalrm - handle alarms.
1295 static void sigalrm (sig
)
1298 fprintf (stderr
, "strgetmsg: timeout");
1301 #endif /* !defined (USE_POLL) */
1303 int can_unicast_without_arp (ip
)
1304 struct interface_info
*ip
;
1309 int can_receive_unicast_unconfigured (ip
)
1310 struct interface_info
*ip
;
1315 int supports_multiple_interfaces (ip
)
1316 struct interface_info
*ip
;
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
,
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 */