3 Data Link Provider Interface (DLPI) network interface code. */
6 * Copyright (c) 1996-2000 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''.
42 * Based largely in part to the existing NIT code in nit.c.
44 * This code has been developed and tested on sparc-based machines running
45 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
50 * Implementation notes:
52 * I first tried to write this code to the "vanilla" DLPI 2.0 API.
53 * It worked on a Sun Ultra-1 with a hme interface, but didn't work
54 * on Sun SparcStation 5's with "le" interfaces (the packets sent out
55 * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead
56 * of the expected 0x0800).
58 * Therefore I added the "DLPI_RAW" code which is a Sun extension to
59 * the DLPI standard. This code works on both of the above machines.
60 * This is configurable in the OS-dependent include file by defining
63 * It quickly became apparant that I should also use the "pfmod"
64 * STREAMS module to cut down on the amount of user level packet
65 * processing. I don't know how widely available "pfmod" is, so it's
66 * use is conditionally included. This is configurable in the
67 * OS-dependent include file by defining USE_DLPI_PFMOD.
69 * A major quirk on the Sun's at least, is that no packets seem to get
70 * sent out the interface until six seconds after the interface is
71 * first "attached" to [per system reboot] (it's actually from when
72 * the interface is attached, not when it is plumbed, so putting a
73 * sleep into the dhclient-script at PREINIT time doesn't help). I
74 * HAVE tried, without success to poll the fd to see when it is ready
75 * for writing. This doesn't help at all. If the sleeps are not done,
76 * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so
77 * I've put them here, when register_send and register_receive are
78 * called (split up into two three-second sleeps between the notices,
79 * so that it doesn't seem like so long when you're watching :-). The
80 * amount of time to sleep is configurable in the OS-dependent include
81 * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds
86 static char copyright
[] =
87 "$Id: dlpi.c,v 1.20 2000/05/16 23:02:15 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
92 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
94 # include <sys/ioctl.h>
95 # include <sys/time.h>
96 # include <sys/dlpi.h>
98 # ifdef USE_DLPI_PFMOD
99 # include <sys/pfmod.h>
105 # include <netinet/in_systm.h>
106 # include "includes/netinet/ip.h"
107 # include "includes/netinet/udp.h"
108 # include "includes/netinet/if_ether.h"
110 # ifdef USE_DLPI_PFMOD
112 # define DLPI_MODNAME "DLPI+RAW+PFMOD"
114 # define DLPI_MODNAME "DLPI+PFMOD"
118 # define DLPI_MODNAME "DLPI+RAW"
120 # define DLPI_MODNAME "DLPI"
125 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
128 static int strioctl
PROTO ((int fd
, int cmd
, int timeout
, int len
, char *dp
));
130 #define DLPI_MAXDLBUF 8192 /* Buffer size */
131 #define DLPI_MAXDLADDR 1024 /* Max address size */
132 #define DLPI_DEVDIR "/dev/" /* Device directory */
133 #define DLPI_DEFAULTSAP 0x0800 /* IP protocol */
135 static void dlpi_makeaddr
PROTO ((unsigned char *physaddr
, int physaddrlen
,
136 unsigned char *sap
, int saplen
,
137 unsigned char *buf
));
138 static void dlpi_parseaddr
PROTO ((unsigned char *buf
,
139 unsigned char *physaddr
,
140 int physaddrlen
, unsigned char *sap
,
142 static int dlpiopen
PROTO ((char *ifname
));
143 static int dlpiunit
PROTO ((char *ifname
));
144 static int dlpiinforeq
PROTO ((int fd
));
145 static int dlpiphysaddrreq
PROTO ((int fd
, unsigned long addrtype
));
146 static int dlpiattachreq
PROTO ((int fd
, unsigned long ppa
));
147 static int dlpibindreq
PROTO ((int fd
, unsigned long sap
, unsigned long max_conind
,
148 unsigned long service_mode
, unsigned long conn_mgmt
,
149 unsigned long xidtest
));
150 static int dlpidetachreq
PROTO ((int fd
));
151 static int dlpiunbindreq
PROTO ((int fd
));
152 static int dlpiokack
PROTO ((int fd
, char *bufp
));
153 static int dlpiinfoack
PROTO ((int fd
, char *bufp
));
154 static int dlpiphysaddrack
PROTO ((int fd
, char *bufp
));
155 static int dlpibindack
PROTO ((int fd
, char *bufp
));
156 static int dlpiunitdatareq
PROTO ((int fd
, unsigned char *addr
,
157 int addrlen
, unsigned long minpri
,
158 unsigned long maxpri
, unsigned char *data
,
160 static int dlpiunitdataind
PROTO ((int fd
,
161 unsigned char *dstaddr
,
162 unsigned long *dstaddrlen
,
163 unsigned char *srcaddr
,
164 unsigned long *srcaddrlen
,
165 unsigned long *grpaddr
,
170 static void sigalrm
PROTO ((int sig
));
172 static int expected
PROTO ((unsigned long prim
, union DL_primitives
*dlp
,
174 static int strgetmsg
PROTO ((int fd
, struct strbuf
*ctlp
,
175 struct strbuf
*datap
, int *flagsp
,
178 /* Reinitializes the specified interface after an address change. This
179 is not required for packet-filter APIs. */
182 void if_reinitialize_send (info
)
183 struct interface_info
*info
;
188 #ifdef USE_DLPI_RECEIVE
189 void if_reinitialize_receive (info
)
190 struct interface_info
*info
;
195 /* Called by get_interface_list for each interface that's discovered.
196 Opens a packet filter for each interface and adds it to the select
199 int if_register_dlpi (info
)
200 struct interface_info
*info
;
204 long buf
[DLPI_MAXDLBUF
];
205 union DL_primitives
*dlp
;
207 dlp
= (union DL_primitives
*)buf
;
209 /* Open a DLPI device */
210 if ((sock
= dlpiopen (info
-> name
)) < 0) {
211 log_fatal ("Can't open DLPI device for %s: %m", info
-> name
);
215 * Get information about the provider.
219 * Submit a DL_INFO_REQ request, to find
220 * the dl_mac_type and dl_provider_style
222 if (dlpiinforeq(sock
) < 0 || dlpiinfoack(sock
, (char *)buf
) < 0) {
223 log_fatal ("Can't get DLPI MAC type for %s: %m", info
-> name
);
225 switch (dlp
-> info_ack
.dl_mac_type
) {
226 case DL_CSMACD
: /* IEEE 802.3 */
228 info
-> hw_address
.hbuf
[0] = HTYPE_ETHER
;
230 /* adding token ring 5/1999 - mayer@ping.at */
232 info
-> hw_address
.hbuf
[0] = HTYPE_IEEE802
;
235 info
-> hw_address
.hbuf
[0] = HTYPE_FDDI
;
238 log_fatal ("%s: unknown DLPI MAC type %ld",
240 dlp
-> info_ack
.dl_mac_type
);
245 if (dlp
-> info_ack
.dl_provider_style
== DL_STYLE2
) {
247 * Attach to the device. If this fails, the device
250 unit
= dlpiunit (info
-> name
);
252 if (dlpiattachreq (sock
, unit
) < 0
253 || dlpiokack (sock
, (char *)buf
) < 0) {
254 log_fatal ("Can't attach DLPI device for %s: %m", info
-> name
);
259 * Bind to the IP service access point (SAP), connectionless (CLDLS).
261 if (dlpibindreq (sock
, DLPI_DEFAULTSAP
, 0, DL_CLDLS
, 0, 0) < 0
262 || dlpibindack (sock
, (char *)buf
) < 0) {
263 log_fatal ("Can't bind DLPI device for %s: %m", info
-> name
);
267 * Submit a DL_PHYS_ADDR_REQ request, to find
268 * the hardware address
270 if (dlpiphysaddrreq (sock
, DL_CURR_PHYS_ADDR
) < 0
271 || dlpiphysaddrack (sock
, (char *)buf
) < 0) {
272 log_fatal ("Can't get DLPI hardware address for %s: %m",
276 info
-> hw_address
.hlen
= dlp
-> physaddr_ack
.dl_addr_length
+ 1;
277 memcpy (&info
-> hw_address
.hbuf
[1],
278 (char *)buf
+ dlp
-> physaddr_ack
.dl_addr_offset
,
279 dlp
-> physaddr_ack
.dl_addr_length
);
282 if (strioctl (sock
, DLIOCRAW
, INFTIM
, 0, 0) < 0) {
283 log_fatal ("Can't set DLPI RAW mode for %s: %m",
288 #ifdef USE_DLPI_PFMOD
289 if (ioctl (sock
, I_PUSH
, "pfmod") < 0) {
290 log_fatal ("Can't push packet filter onto DLPI for %s: %m",
299 strioctl (fd
, cmd
, timeout
, len
, dp
)
310 sio
.ic_timout
= timeout
;
314 if ((rslt
= ioctl (fd
, I_STR
, &sio
)) < 0) {
322 void if_register_send (info
)
323 struct interface_info
*info
;
325 /* If we're using the DLPI API for sending and receiving,
326 we don't need to register this interface twice. */
327 #ifndef USE_DLPI_RECEIVE
328 # ifdef USE_DLPI_PFMOD
329 struct packetfilt pf
;
332 info
-> wfdesc
= if_register_dlpi (info
);
334 # ifdef USE_DLPI_PFMOD
335 /* Set up an PFMOD filter that rejects everything... */
338 pf
.Pf_Filter
[0] = ENF_PUSHZERO
;
340 /* Install the filter */
341 if (strioctl (info
-> wfdesc
, PFIOCSETF
, INFTIM
,
342 sizeof (pf
), (char *)&pf
) < 0) {
343 log_fatal ("Can't set PFMOD send filter on %s: %m", info
-> name
);
346 # endif /* USE_DLPI_PFMOD */
347 #else /* !defined (USE_DLPI_RECEIVE) */
349 * If using DLPI for both send and receive, simply re-use
350 * the read file descriptor that was set up earlier.
352 info
-> wfdesc
= info
-> rfdesc
;
355 if (!quiet_interface_discovery
)
356 log_info ("Sending on DLPI/%s/%s%s%s",
358 print_hw_addr (info
-> hw_address
.hbuf
[0],
359 info
-> hw_address
.hlen
- 1,
360 &info
-> hw_address
.hbuf
[1]),
361 (info
-> shared_network
? "/" : ""),
362 (info
-> shared_network
?
363 info
-> shared_network
-> name
: ""));
365 #ifdef DLPI_FIRST_SEND_WAIT
366 /* See the implementation notes at the beginning of this file */
367 # ifdef USE_DLPI_RECEIVE
368 sleep (DLPI_FIRST_SEND_WAIT
- (DLPI_FIRST_SEND_WAIT
/ 2));
370 sleep (DLPI_FIRST_SEND_WAIT
);
375 void if_deregister_send (info
)
376 struct interface_info
*info
;
378 /* If we're using the DLPI API for sending and receiving,
379 we don't need to register this interface twice. */
380 #ifndef USE_DLPI_RECEIVE
381 close (info
-> wfdesc
);
385 if (!quiet_interface_discovery
)
386 log_info ("Disabling output on DLPI/%s/%s%s%s",
388 print_hw_addr (info
-> hw_address
.hbuf
[0],
389 info
-> hw_address
.hlen
- 1,
390 &info
-> hw_address
.hbuf
[1]),
391 (info
-> shared_network
? "/" : ""),
392 (info
-> shared_network
?
393 info
-> shared_network
-> name
: ""));
395 #endif /* USE_DLPI_SEND */
397 #ifdef USE_DLPI_RECEIVE
398 /* Packet filter program...
399 XXX Changes to the filter program may require changes to the constant
400 offsets used in if_register_send to patch the NIT program! XXX */
402 void if_register_receive (info
)
403 struct interface_info
*info
;
405 #ifdef USE_DLPI_PFMOD
406 struct packetfilt pf
;
409 /* Open a DLPI device and hang it on this interface... */
410 info
-> rfdesc
= if_register_dlpi (info
);
412 #ifdef USE_DLPI_PFMOD
413 /* Set up the PFMOD filter program. */
414 /* XXX Unlike the BPF filter program, this one won't work if the
415 XXX IP packet is fragmented or if there are options on the IP
421 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 6;
422 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
423 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (ETHERTYPE_IP
);
424 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
;
425 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (IPPROTO_UDP
);
426 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 11;
427 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSH00FF
+ ENF_AND
;
428 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_CAND
;
429 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 18;
430 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
431 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (local_port
);
434 * The packets that will be received on this file descriptor
435 * will be IP packets (due to the SAP that was specified in
436 * the dlbind call). There will be no ethernet header.
437 * Therefore, setup the packet filter to check the protocol
438 * field for UDP, and the destination port number equal
439 * to the local port. All offsets are relative to the start
442 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
;
443 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (IPPROTO_UDP
);
444 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 4;
445 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSH00FF
+ ENF_AND
;
446 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_CAND
;
447 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 11;
448 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
449 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (local_port
);
452 /* Install the filter... */
453 if (strioctl (info
-> rfdesc
, PFIOCSETF
, INFTIM
,
454 sizeof (pf
), (char *)&pf
) < 0) {
455 log_fatal ("Can't set PFMOD receive filter on %s: %m", info
-> name
);
459 if (!quiet_interface_discovery
)
460 log_info ("Listening on DLPI/%s/%s%s%s",
462 print_hw_addr (info
-> hw_address
.hbuf
[0],
463 info
-> hw_address
.hlen
- 1,
464 &info
-> hw_address
.hbuf
[1]),
465 (info
-> shared_network
? "/" : ""),
466 (info
-> shared_network
?
467 info
-> shared_network
-> name
: ""));
469 #ifdef DLPI_FIRST_SEND_WAIT
470 /* See the implementation notes at the beginning of this file */
471 # ifdef USE_DLPI_SEND
472 sleep (DLPI_FIRST_SEND_WAIT
/ 2);
474 sleep (DLPI_FIRST_SEND_WAIT
);
479 void if_deregister_receive (info
)
480 struct interface_info
*info
;
482 /* If we're using the DLPI API for sending and receiving,
483 we don't need to register this interface twice. */
484 #ifndef USE_DLPI_SEND
485 close (info
-> rfdesc
);
489 if (!quiet_interface_discovery
)
490 log_info ("Disabling input on DLPI/%s/%s%s%s",
492 print_hw_addr (info
-> hw_address
.hbuf
[0],
493 info
-> hw_address
.hlen
- 1,
494 &info
-> hw_address
.hbuf
[1]),
495 (info
-> shared_network
? "/" : ""),
496 (info
-> shared_network
?
497 info
-> shared_network
-> name
: ""));
499 #endif /* USE_DLPI_RECEIVE */
502 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
503 struct interface_info
*interface
;
504 struct packet
*packet
;
505 struct dhcp_packet
*raw
;
508 struct sockaddr_in
*to
;
509 struct hardware
*hto
;
512 unsigned char dbuf
[1536];
513 unsigned char sap
[2];
514 unsigned char dstaddr
[DLPI_MAXDLADDR
];
519 if (!strcmp (interface
-> name
, "fallback"))
520 return send_fallback (interface
, packet
, raw
,
525 /* Assemble the headers... */
527 assemble_hw_header (interface
, dbuf
, &dbuflen
, hto
);
529 assemble_udp_ip_header (interface
, dbuf
, &dbuflen
, from
.s_addr
,
530 to
-> sin_addr
.s_addr
, to
-> sin_port
,
531 (unsigned char *)raw
, len
);
533 /* Copy the data into the buffer (yuk). */
534 memcpy (dbuf
+ dbuflen
, raw
, len
);
538 result
= write (interface
-> wfdesc
, dbuf
, dbuflen
);
540 /* XXX: Assumes ethernet, with two byte SAP */
541 sap
[0] = 0x08; /* ETHERTYPE_IP, high byte */
542 sap
[1] = 0x0; /* ETHERTYPE_IP, low byte */
543 saplen
= -2; /* -2 indicates a two byte SAP at the end
546 /* Setup the destination address */
547 if (hto
&& hto
-> hlen
== interface
-> hw_address
.hlen
) {
548 dlpi_makeaddr (&hto
-> hbuf
[1],
549 hto
-> hlen
- 1, sap
, saplen
, dstaddr
);
551 /* XXX: Assumes broadcast addr is all ones */
552 /* Really should get the broadcast address as part of the
553 * dlpiinforeq, and store it somewhere in the interface structure.
555 unsigned char bcast_ether
[DLPI_MAXDLADDR
];
557 memset ((char *)bcast_ether
, 0xFF,
558 interface
-> hw_address
.hlen
- 1);
559 dlpi_makeaddr (bcast_ether
, interface
-> hw_address
.hlen
- 1,
560 sap
, saplen
, dstaddr
);
562 addrlen
= interface
-> hw_address
.hlen
- 1 + ABS (saplen
);
564 /* Send the packet down the wire... */
565 result
= dlpiunitdatareq (interface
-> wfdesc
, dstaddr
, addrlen
,
566 0, 0, dbuf
, dbuflen
);
569 log_error ("send_packet: %m");
572 #endif /* USE_DLPI_SEND */
574 #ifdef USE_DLPI_RECEIVE
575 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
576 struct interface_info
*interface
;
579 struct sockaddr_in
*from
;
580 struct hardware
*hfrom
;
582 unsigned char dbuf
[1536];
583 unsigned char sap
[2];
584 unsigned char srcaddr
[DLPI_MAXDLADDR
];
585 unsigned long srcaddrlen
;
594 length
= read (interface
-> rfdesc
, dbuf
, sizeof (dbuf
));
596 length
= dlpiunitdataind (interface
-> rfdesc
, (unsigned char *)NULL
,
597 (unsigned long *)NULL
, srcaddr
, &srcaddrlen
,
598 (unsigned long *)NULL
, dbuf
, sizeof (dbuf
));
606 /* Copy sender info */
607 /* XXX: Assumes ethernet, where SAP comes at end of haddr */
609 if (hfrom
&& (srcaddrlen
==
610 ABS (saplen
) + interface
-> hw_address
.hlen
- 1)) {
611 hfrom
-> hbuf
[0] = interface
-> hw_address
.hbuf
[0];
612 hfrom
-> hlen
= interface
-> hw_address
.hlen
;
613 dlpi_parseaddr (srcaddr
, &hfrom
-> hbuf
[1],
614 interface
-> hw_address
.hlen
- 1, sap
, saplen
);
616 memset (hfrom
, '\0', sizeof *hfrom
);
620 /* Decode the IP and UDP headers... */
623 /* Decode the physical header... */
624 offset
= decode_hw_header (interface
, dbuf
, bufix
, hfrom
);
626 /* If a physical layer checksum failed (dunno of any
627 physical layer that supports this, but WTH), skip this
635 offset
= decode_udp_ip_header (interface
, dbuf
, bufix
,
636 from
, (unsigned char *)0, length
);
638 /* If the IP or UDP checksum was bad, skip the packet... */
646 /* Copy out the data in the packet... */
647 memcpy (buf
, &dbuf
[bufix
], length
);
652 /* Common DLPI routines ...
654 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
656 * Based largely in part to the example code contained in the document
657 * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
658 * by Neal Nuckolls of SunSoft Internet Engineering.
660 * This code has been developed and tested on sparc-based machines running
661 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
664 * The usual disclaimers apply. This code works for me. Don't blame me
665 * if it makes your machine or network go down in flames. That taken
666 * into consideration, use this code as you wish. If you make usefull
667 * modifications I'd appreciate hearing about it.
670 #define DLPI_MAXWAIT 15 /* Max timeout */
672 static void dlpi_makeaddr (physaddr
, physaddrlen
, sap
, saplen
, buf
)
673 unsigned char *physaddr
;
680 * If the saplen is negative, the SAP goes at the end of the address,
681 * otherwise it goes at the beginning.
684 memcpy ((char *)buf
, (char *)sap
, saplen
);
685 memcpy ((char *)&buf
[saplen
], (char *)physaddr
, physaddrlen
);
687 memcpy ((char *)buf
, (char *)physaddr
, physaddrlen
);
688 memcpy ((char *)&buf
[physaddrlen
], (char *)sap
, 0 - saplen
);
692 static void dlpi_parseaddr (buf
, physaddr
, physaddrlen
, sap
, saplen
)
694 unsigned char *physaddr
;
700 * If the saplen is negative, the SAP is at the end of the address,
701 * otherwise it is at the beginning.
704 memcpy ((char *)sap
, (char *)buf
, saplen
);
705 memcpy ((char *)physaddr
, (char *)&buf
[saplen
], physaddrlen
);
707 memcpy ((char *)physaddr
, (char *)buf
, physaddrlen
);
708 memcpy ((char *)sap
, (char *)&buf
[physaddrlen
], 0 - saplen
);
713 * Parse an interface name and extract the unit number
716 static int dlpiunit (ifname
)
727 /* Advance to the end of the name */
730 /* Back up to the start of the first digit */
731 while ((*(cp
-1) >= '0' && *(cp
-1) <= '9') || *(cp
- 1) == ':') cp
--;
733 /* Convert the unit number */
735 while (*cp
>= '0' && *cp
<= '9') {
737 unit
+= (*cp
++ - '0');
744 * dlpiopen - open the DLPI device for a given interface name
746 static int dlpiopen (ifname
)
756 /* Open a DLPI device */
757 if (*ifname
== '/') {
760 /* Prepend the device directory */
761 memcpy (devname
, DLPI_DEVDIR
, strlen (DLPI_DEVDIR
));
762 dp
= &devname
[strlen (DLPI_DEVDIR
)];
765 /* Find the end of the interface name */
769 /* And back up to the first digit (unit number) */
770 while ((*(ep
- 1) >= '0' && *(ep
- 1) <= '9') || *(ep
- 1) == ':')
773 /* Copy everything up to the unit number */
779 return open (devname
, O_RDWR
, 0);
783 * dlpiinforeq - request information about the data link provider.
786 static int dlpiinforeq (fd
)
789 dl_info_req_t info_req
;
793 info_req
.dl_primitive
= DL_INFO_REQ
;
796 ctl
.len
= sizeof (info_req
);
797 ctl
.buf
= (char *)&info_req
;
801 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
805 * dlpiphysaddrreq - request the current physical address.
807 static int dlpiphysaddrreq (fd
, addrtype
)
809 unsigned long addrtype
;
811 dl_phys_addr_req_t physaddr_req
;
815 physaddr_req
.dl_primitive
= DL_PHYS_ADDR_REQ
;
816 physaddr_req
.dl_addr_type
= addrtype
;
819 ctl
.len
= sizeof (physaddr_req
);
820 ctl
.buf
= (char *)&physaddr_req
;
824 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
828 * dlpiattachreq - send a request to attach to a specific unit.
830 static int dlpiattachreq (fd
, ppa
)
834 dl_attach_req_t attach_req
;
838 attach_req
.dl_primitive
= DL_ATTACH_REQ
;
839 attach_req
.dl_ppa
= ppa
;
842 ctl
.len
= sizeof (attach_req
);
843 ctl
.buf
= (char *)&attach_req
;
847 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
851 * dlpibindreq - send a request to bind to a specific SAP address.
853 static int dlpibindreq (fd
, sap
, max_conind
, service_mode
, conn_mgmt
, xidtest
)
855 unsigned long max_conind
;
856 unsigned long service_mode
;
857 unsigned long conn_mgmt
;
858 unsigned long xidtest
;
861 dl_bind_req_t bind_req
;
865 bind_req
.dl_primitive
= DL_BIND_REQ
;
866 bind_req
.dl_sap
= sap
;
867 bind_req
.dl_max_conind
= max_conind
;
868 bind_req
.dl_service_mode
= service_mode
;
869 bind_req
.dl_conn_mgmt
= conn_mgmt
;
870 bind_req
.dl_xidtest_flg
= xidtest
;
873 ctl
.len
= sizeof (bind_req
);
874 ctl
.buf
= (char *)&bind_req
;
878 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
882 * dlpiunbindreq - send a request to unbind.
884 static int dlpiunbindreq (fd
)
887 dl_unbind_req_t unbind_req
;
891 unbind_req
.dl_primitive
= DL_UNBIND_REQ
;
894 ctl
.len
= sizeof (unbind_req
);
895 ctl
.buf
= (char *)&unbind_req
;
899 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
904 * dlpidetachreq - send a request to detach.
906 static int dlpidetachreq (fd
)
909 dl_detach_req_t detach_req
;
913 detach_req
.dl_primitive
= DL_DETACH_REQ
;
916 ctl
.len
= sizeof (detach_req
);
917 ctl
.buf
= (char *)&detach_req
;
921 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
926 * dlpibindack - receive an ack to a dlbindreq.
928 static int dlpibindack (fd
, bufp
)
932 union DL_primitives
*dlp
;
936 ctl
.maxlen
= DLPI_MAXDLBUF
;
940 if (strgetmsg (fd
, &ctl
,
941 (struct strbuf
*)NULL
, &flags
, "dlpibindack") < 0) {
945 dlp
= (union DL_primitives
*)ctl
.buf
;
947 if (!expected (DL_BIND_ACK
, dlp
, flags
) < 0) {
951 if (ctl
.len
< sizeof (dl_bind_ack_t
)) {
952 /* Returned structure is too short */
960 * dlpiokack - general acknowledgement reception.
962 static int dlpiokack (fd
, bufp
)
966 union DL_primitives
*dlp
;
970 ctl
.maxlen
= DLPI_MAXDLBUF
;
974 if (strgetmsg (fd
, &ctl
,
975 (struct strbuf
*)NULL
, &flags
, "dlpiokack") < 0) {
979 dlp
= (union DL_primitives
*)ctl
.buf
;
981 if (!expected (DL_OK_ACK
, dlp
, flags
) < 0) {
985 if (ctl
.len
< sizeof (dl_ok_ack_t
)) {
986 /* Returned structure is too short */
994 * dlpiinfoack - receive an ack to a dlinforeq.
996 static int dlpiinfoack (fd
, bufp
)
1000 union DL_primitives
*dlp
;
1004 ctl
.maxlen
= DLPI_MAXDLBUF
;
1008 if (strgetmsg (fd
, &ctl
, (struct strbuf
*)NULL
, &flags
,
1009 "dlpiinfoack") < 0) {
1013 dlp
= (union DL_primitives
*) ctl
.buf
;
1015 if (!expected (DL_INFO_ACK
, dlp
, flags
) < 0) {
1019 if (ctl
.len
< sizeof (dl_info_ack_t
)) {
1020 /* Returned structure is too short */
1028 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1030 int dlpiphysaddrack (fd
, bufp
)
1034 union DL_primitives
*dlp
;
1038 ctl
.maxlen
= DLPI_MAXDLBUF
;
1042 if (strgetmsg (fd
, &ctl
, (struct strbuf
*)NULL
, &flags
,
1043 "dlpiphysaddrack") < 0) {
1047 dlp
= (union DL_primitives
*)ctl
.buf
;
1049 if (!expected (DL_PHYS_ADDR_ACK
, dlp
, flags
) < 0) {
1053 if (ctl
.len
< sizeof (dl_phys_addr_ack_t
)) {
1054 /* Returned structure is too short */
1061 int dlpiunitdatareq (fd
, addr
, addrlen
, minpri
, maxpri
, dbuf
, dbuflen
)
1063 unsigned char *addr
;
1065 unsigned long minpri
;
1066 unsigned long maxpri
;
1067 unsigned char *dbuf
;
1070 long buf
[DLPI_MAXDLBUF
];
1071 union DL_primitives
*dlp
;
1072 struct strbuf ctl
, data
;
1074 /* Set up the control information... */
1075 dlp
= (union DL_primitives
*)buf
;
1076 dlp
-> unitdata_req
.dl_primitive
= DL_UNITDATA_REQ
;
1077 dlp
-> unitdata_req
.dl_dest_addr_length
= addrlen
;
1078 dlp
-> unitdata_req
.dl_dest_addr_offset
= sizeof (dl_unitdata_req_t
);
1079 dlp
-> unitdata_req
.dl_priority
.dl_min
= minpri
;
1080 dlp
-> unitdata_req
.dl_priority
.dl_max
= maxpri
;
1082 /* Append the destination address */
1083 memcpy ((char *)buf
+ dlp
-> unitdata_req
.dl_dest_addr_offset
,
1087 ctl
.len
= dlp
-> unitdata_req
.dl_dest_addr_offset
+ addrlen
;
1088 ctl
.buf
= (char *)buf
;
1091 data
.buf
= (char *)dbuf
;
1094 /* Send the packet down the wire... */
1095 return putmsg (fd
, &ctl
, &data
, 0);
1098 static int dlpiunitdataind (fd
, daddr
, daddrlen
,
1099 saddr
, saddrlen
, grpaddr
, dbuf
, dlen
)
1101 unsigned char *daddr
;
1102 unsigned long *daddrlen
;
1103 unsigned char *saddr
;
1104 unsigned long *saddrlen
;
1105 unsigned long *grpaddr
;
1106 unsigned char *dbuf
;
1109 long buf
[DLPI_MAXDLBUF
];
1110 union DL_primitives
*dlp
;
1111 struct strbuf ctl
, data
;
1115 /* Set up the msg_buf structure... */
1116 dlp
= (union DL_primitives
*)buf
;
1117 dlp
-> unitdata_ind
.dl_primitive
= DL_UNITDATA_IND
;
1119 ctl
.maxlen
= DLPI_MAXDLBUF
;
1121 ctl
.buf
= (char *)buf
;
1125 data
.buf
= (char *)dbuf
;
1127 result
= getmsg (fd
, &ctl
, &data
, &flags
);
1133 if (ctl
.len
< sizeof (dl_unitdata_ind_t
) ||
1134 dlp
-> unitdata_ind
.dl_primitive
!= DL_UNITDATA_IND
) {
1138 if (data
.len
<= 0) {
1142 /* Copy sender info */
1144 memcpy (saddr
, &buf
[dlp
-> unitdata_ind
.dl_src_addr_offset
],
1145 dlp
-> unitdata_ind
.dl_src_addr_length
);
1148 *saddrlen
= dlp
-> unitdata_ind
.dl_src_addr_length
;
1151 /* Copy destination info */
1153 memcpy (daddr
, &buf
[dlp
-> unitdata_ind
.dl_dest_addr_offset
],
1154 dlp
-> unitdata_ind
.dl_dest_addr_length
);
1157 *daddrlen
= dlp
-> unitdata_ind
.dl_dest_addr_length
;
1161 *grpaddr
= dlp
-> unitdata_ind
.dl_group_address
;
1168 * expected - see if we got what we wanted.
1170 static int expected (prim
, dlp
, msgflags
)
1172 union DL_primitives
*dlp
;
1175 if (msgflags
!= RS_HIPRI
) {
1176 /* Message was not M_PCPROTO */
1180 if (dlp
-> dl_primitive
!= prim
) {
1181 /* Incorrect/unexpected return message */
1189 * strgetmsg - get a message from a stream, with timeout.
1191 static int strgetmsg (fd
, ctlp
, datap
, flagsp
, caller
)
1192 struct strbuf
*ctlp
, *datap
;
1208 pfd
.events
= POLLPRI
; /* We're only interested in knowing
1209 * when we can receive the next high
1214 now
= time (&starttime
);
1215 while (now
<= starttime
+ DLPI_MAXWAIT
) {
1216 to_msec
= ((starttime
+ DLPI_MAXWAIT
) - now
) * 1000;
1217 count
= poll (&pfd
, 1, to_msec
);
1220 /* log_fatal ("strgetmsg: timeout"); */
1222 } else if (count
< 0) {
1223 if (errno
== EAGAIN
|| errno
== EINTR
) {
1227 /* log_fatal ("poll: %m"); */
1234 #else /* defined (USE_POLL) */
1236 * Start timer. Can't use select, since it might return true if there
1237 * were non High-Priority data available on the stream.
1239 (void) sigset (SIGALRM
, sigalrm
);
1241 if (alarm (DLPI_MAXWAIT
) < 0) {
1242 /* log_fatal ("alarm: %m"); */
1245 #endif /* !defined (USE_POLL) */
1248 * Set flags argument and issue getmsg ().
1251 if ((result
= getmsg (fd
, ctlp
, datap
, flagsp
)) < 0) {
1259 if (alarm (0) < 0) {
1260 /* log_fatal ("alarm: %m"); */
1266 * Check for MOREDATA and/or MORECTL.
1268 if (result
& (MORECTL
|MOREDATA
)) {
1273 * Check for at least sizeof (long) control data portion.
1275 if (ctlp
-> len
< sizeof (long)) {
1284 * sigalrm - handle alarms.
1286 static void sigalrm (sig
)
1289 fprintf (stderr
, "strgetmsg: timeout");
1292 #endif /* !defined (USE_POLL) */
1294 int can_unicast_without_arp (ip
)
1295 struct interface_info
*ip
;
1300 int can_receive_unicast_unconfigured (ip
)
1301 struct interface_info
*ip
;
1306 void maybe_setup_fallback ()
1308 isc_result_t status
;
1309 struct interface_info
*fbi
= (struct interface_info
*)0;
1310 if (setup_fallback (&fbi
, MDL
)) {
1311 if_register_fallback (fbi
);
1312 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
1314 fallback_discard
, 0, 0);
1315 if (status
!= ISC_R_SUCCESS
)
1316 log_fatal ("Can't register I/O handle for %s: %s",
1317 fbi
-> name
, isc_result_totext (status
));
1320 #endif /* USE_DLPI */