3 Data Link Provider Interface (DLPI) network interface code. */
6 * Copyright (c) 1996-1999 Internet Software Consortium.
7 * Use is subject to license terms which appear in the file named
8 * ISC-LICENSE that should have accompanied this file when you
9 * received it. If a file named ISC-LICENSE did not accompany this
10 * file, or you are not sure the one you have is correct, you may
11 * obtain an applicable copy of the license at:
13 * http://www.isc.org/isc-license-1.0.html.
15 * This file is part of the ISC DHCP distribution. The documentation
16 * associated with this file is listed in the file DOCUMENTATION,
17 * included in the top-level directory of this release.
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
22 * This software was written for the Internet Software Consortium
23 * by Eric James Negaard, <lmdejn@lmd.ericsson.se>. To learn more about
24 * the Internet Software Consortium, see ``http://www.vix.com/isc''.
28 * Based largely in part to the existing NIT code in nit.c.
30 * This code has been developed and tested on sparc-based machines running
31 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
36 * Implementation notes:
38 * I first tried to write this code to the "vanilla" DLPI 2.0 API.
39 * It worked on a Sun Ultra-1 with a hme interface, but didn't work
40 * on Sun SparcStation 5's with "le" interfaces (the packets sent out
41 * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead
42 * of the expected 0x0800).
44 * Therefore I added the "DLPI_RAW" code which is a Sun extension to
45 * the DLPI standard. This code works on both of the above machines.
46 * This is configurable in the OS-dependent include file by defining
49 * It quickly became apparant that I should also use the "pfmod"
50 * STREAMS module to cut down on the amount of user level packet
51 * processing. I don't know how widely available "pfmod" is, so it's
52 * use is conditionally included. This is configurable in the
53 * OS-dependent include file by defining USE_DLPI_PFMOD.
55 * A major quirk on the Sun's at least, is that no packets seem to get
56 * sent out the interface until six seconds after the interface is
57 * first "attached" to [per system reboot] (it's actually from when
58 * the interface is attached, not when it is plumbed, so putting a
59 * sleep into the dhclient-script at PREINIT time doesn't help). I
60 * HAVE tried, without success to poll the fd to see when it is ready
61 * for writing. This doesn't help at all. If the sleeps are not done,
62 * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so
63 * I've put them here, when register_send and register_receive are
64 * called (split up into two three-second sleeps between the notices,
65 * so that it doesn't seem like so long when you're watching :-). The
66 * amount of time to sleep is configurable in the OS-dependent include
67 * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds
72 static char copyright
[] =
73 "$Id: dlpi.c,v 1.13 1999/09/08 01:43:39 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
78 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
80 # include <sys/ioctl.h>
81 # include <sys/time.h>
82 # include <sys/dlpi.h>
84 # ifdef USE_DLPI_PFMOD
85 # include <sys/pfmod.h>
91 # include <netinet/in_systm.h>
92 # include "includes/netinet/ip.h"
93 # include "includes/netinet/udp.h"
94 # include "includes/netinet/if_ether.h"
96 # ifdef USE_DLPI_PFMOD
98 # define DLPI_MODNAME "DLPI+RAW+PFMOD"
100 # define DLPI_MODNAME "DLPI+PFMOD"
104 # define DLPI_MODNAME "DLPI+RAW"
106 # define DLPI_MODNAME "DLPI"
111 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
114 static int strioctl
PROTO ((int fd
, int cmd
, int timeout
, int len
, char *dp
));
116 #define DLPI_MAXDLBUF 8192 /* Buffer size */
117 #define DLPI_MAXDLADDR 1024 /* Max address size */
118 #define DLPI_DEVDIR "/dev/" /* Device directory */
119 #define DLPI_DEFAULTSAP 0x0800 /* IP protocol */
121 static void dlpi_makeaddr
PROTO ((unsigned char *physaddr
, int physaddrlen
,
122 unsigned char *sap
, int saplen
,
123 unsigned char *buf
));
124 static void dlpi_parseaddr
PROTO ((unsigned char *buf
,
125 unsigned char *physaddr
,
126 int physaddrlen
, unsigned char *sap
,
128 static int dlpiopen
PROTO ((char *ifname
));
129 static int dlpiunit
PROTO ((char *ifname
));
130 static int dlpiinforeq
PROTO ((int fd
));
131 static int dlpiphysaddrreq
PROTO ((int fd
, unsigned long addrtype
));
132 static int dlpiattachreq
PROTO ((int fd
, unsigned long ppa
));
133 static int dlpibindreq
PROTO ((int fd
, unsigned long sap
, unsigned long max_conind
,
134 unsigned long service_mode
, unsigned long conn_mgmt
,
135 unsigned long xidtest
));
136 static int dlpidetachreq
PROTO ((int fd
));
137 static int dlpiunbindreq
PROTO ((int fd
));
138 static int dlpiokack
PROTO ((int fd
, char *bufp
));
139 static int dlpiinfoack
PROTO ((int fd
, char *bufp
));
140 static int dlpiphysaddrack
PROTO ((int fd
, char *bufp
));
141 static int dlpibindack
PROTO ((int fd
, char *bufp
));
142 static int dlpiunitdatareq
PROTO ((int fd
, unsigned char *addr
,
143 int addrlen
, unsigned long minpri
,
144 unsigned long maxpri
, unsigned char *data
,
146 static int dlpiunitdataind
PROTO ((int fd
,
147 unsigned char *dstaddr
,
148 unsigned long *dstaddrlen
,
149 unsigned char *srcaddr
,
150 unsigned long *srcaddrlen
,
151 unsigned long *grpaddr
,
156 static void sigalrm
PROTO ((int sig
));
158 static int expected
PROTO ((unsigned long prim
, union DL_primitives
*dlp
,
160 static int strgetmsg
PROTO ((int fd
, struct strbuf
*ctlp
,
161 struct strbuf
*datap
, int *flagsp
,
164 /* Reinitializes the specified interface after an address change. This
165 is not required for packet-filter APIs. */
168 void if_reinitialize_send (info
)
169 struct interface_info
*info
;
174 #ifdef USE_DLPI_RECEIVE
175 void if_reinitialize_receive (info
)
176 struct interface_info
*info
;
181 /* Called by get_interface_list for each interface that's discovered.
182 Opens a packet filter for each interface and adds it to the select
185 int if_register_dlpi (info
)
186 struct interface_info
*info
;
190 long buf
[DLPI_MAXDLBUF
];
191 union DL_primitives
*dlp
;
193 dlp
= (union DL_primitives
*)buf
;
195 /* Open a DLPI device */
196 if ((sock
= dlpiopen (info
-> name
)) < 0) {
197 log_fatal ("Can't open DLPI device for %s: %m", info
-> name
);
201 * Get information about the provider.
205 * Submit a DL_INFO_REQ request, to find
206 * the dl_mac_type and dl_provider_style
208 if (dlpiinforeq(sock
) < 0 || dlpiinfoack(sock
, (char *)buf
) < 0) {
209 log_fatal ("Can't get DLPI MAC type for %s: %m", info
-> name
);
211 switch (dlp
-> info_ack
.dl_mac_type
) {
212 case DL_CSMACD
: /* IEEE 802.3 */
214 info
-> hw_address
.htype
= HTYPE_ETHER
;
216 /* adding token ring 5/1999 - mayer@ping.at */
218 info
-> hw_address
.htype
= HTYPE_IEEE802
;
221 info
-> hw_address
.htype
= HTYPE_FDDI
;
224 log_fatal ("%s: unknown DLPI MAC type %d",
226 dlp
-> info_ack
.dl_mac_type
);
231 if (dlp
-> info_ack
.dl_provider_style
== DL_STYLE2
) {
233 * Attach to the device. If this fails, the device
236 unit
= dlpiunit (info
-> name
);
238 if (dlpiattachreq (sock
, unit
) < 0
239 || dlpiokack (sock
, (char *)buf
) < 0) {
240 log_fatal ("Can't attach DLPI device for %s: %m", info
-> name
);
245 * Bind to the IP service access point (SAP), connectionless (CLDLS).
247 if (dlpibindreq (sock
, DLPI_DEFAULTSAP
, 0, DL_CLDLS
, 0, 0) < 0
248 || dlpibindack (sock
, (char *)buf
) < 0) {
249 log_fatal ("Can't bind DLPI device for %s: %m", info
-> name
);
253 * Submit a DL_PHYS_ADDR_REQ request, to find
254 * the hardware address
256 if (dlpiphysaddrreq (sock
, DL_CURR_PHYS_ADDR
) < 0
257 || dlpiphysaddrack (sock
, (char *)buf
) < 0) {
258 log_fatal ("Can't get DLPI hardware address for %s: %m",
262 info
-> hw_address
.hlen
= dlp
-> physaddr_ack
.dl_addr_length
;
263 memcpy (info
-> hw_address
.haddr
,
264 (char *)buf
+ dlp
-> physaddr_ack
.dl_addr_offset
,
265 dlp
-> physaddr_ack
.dl_addr_length
);
268 if (strioctl (sock
, DLIOCRAW
, INFTIM
, 0, 0) < 0) {
269 log_fatal ("Can't set DLPI RAW mode for %s: %m",
274 #ifdef USE_DLPI_PFMOD
275 if (ioctl (sock
, I_PUSH
, "pfmod") < 0) {
276 log_fatal ("Can't push packet filter onto DLPI for %s: %m",
285 strioctl (fd
, cmd
, timeout
, len
, dp
)
296 sio
.ic_timout
= timeout
;
300 if ((rslt
= ioctl (fd
, I_STR
, &sio
)) < 0) {
308 void if_register_send (info
)
309 struct interface_info
*info
;
311 /* If we're using the DLPI API for sending and receiving,
312 we don't need to register this interface twice. */
313 #ifndef USE_DLPI_RECEIVE
314 # ifdef USE_DLPI_PFMOD
315 struct packetfilt pf
;
318 info
-> wfdesc
= if_register_dlpi (info
);
320 # ifdef USE_DLPI_PFMOD
321 /* Set up an PFMOD filter that rejects everything... */
324 pf
.Pf_Filter
[0] = ENF_PUSHZERO
;
326 /* Install the filter */
327 if (strioctl (info
-> wfdesc
, PFIOCSETF
, INFTIM
,
328 sizeof (pf
), (char *)&pf
) < 0) {
329 log_fatal ("Can't set PFMOD send filter on %s: %m", info
-> name
);
332 # endif /* USE_DLPI_PFMOD */
333 #else /* !defined (USE_DLPI_RECEIVE) */
335 * If using DLPI for both send and receive, simply re-use
336 * the read file descriptor that was set up earlier.
338 info
-> wfdesc
= info
-> rfdesc
;
341 if (!quiet_interface_discovery
)
342 log_info ("Sending on DLPI/%s/%s%s%s",
344 print_hw_addr (info
-> hw_address
.htype
,
345 info
-> hw_address
.hlen
,
346 info
-> hw_address
.haddr
),
347 (info
-> shared_network
? "/" : ""),
348 (info
-> shared_network
?
349 info
-> shared_network
-> name
: ""));
351 #ifdef DLPI_FIRST_SEND_WAIT
352 /* See the implementation notes at the beginning of this file */
353 # ifdef USE_DLPI_RECEIVE
354 sleep (DLPI_FIRST_SEND_WAIT
- (DLPI_FIRST_SEND_WAIT
/ 2));
356 sleep (DLPI_FIRST_SEND_WAIT
);
360 #endif /* USE_DLPI_SEND */
362 #ifdef USE_DLPI_RECEIVE
363 /* Packet filter program...
364 XXX Changes to the filter program may require changes to the constant
365 offsets used in if_register_send to patch the NIT program! XXX */
367 void if_register_receive (info
)
368 struct interface_info
*info
;
370 #ifdef USE_DLPI_PFMOD
371 struct packetfilt pf
;
374 /* Open a DLPI device and hang it on this interface... */
375 info
-> rfdesc
= if_register_dlpi (info
);
377 #ifdef USE_DLPI_PFMOD
378 /* Set up the PFMOD filter program. */
379 /* XXX Unlike the BPF filter program, this one won't work if the
380 XXX IP packet is fragmented or if there are options on the IP
386 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 6;
387 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
388 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (ETHERTYPE_IP
);
389 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
;
390 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (IPPROTO_UDP
);
391 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 11;
392 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSH00FF
+ ENF_AND
;
393 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_CAND
;
394 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 18;
395 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
396 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (local_port
);
399 * The packets that will be received on this file descriptor
400 * will be IP packets (due to the SAP that was specified in
401 * the dlbind call). There will be no ethernet header.
402 * Therefore, setup the packet filter to check the protocol
403 * field for UDP, and the destination port number equal
404 * to the local port. All offsets are relative to the start
407 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
;
408 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (IPPROTO_UDP
);
409 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 4;
410 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSH00FF
+ ENF_AND
;
411 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_CAND
;
412 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 11;
413 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
414 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (local_port
);
417 /* Install the filter... */
418 if (strioctl (info
-> rfdesc
, PFIOCSETF
, INFTIM
,
419 sizeof (pf
), (char *)&pf
) < 0) {
420 log_fatal ("Can't set PFMOD receive filter on %s: %m", info
-> name
);
424 if (!quiet_interface_discovery
)
425 log_info ("Listening on DLPI/%s/%s%s%s",
427 print_hw_addr (info
-> hw_address
.htype
,
428 info
-> hw_address
.hlen
,
429 info
-> hw_address
.haddr
),
430 (info
-> shared_network
? "/" : ""),
431 (info
-> shared_network
?
432 info
-> shared_network
-> name
: ""));
434 #ifdef DLPI_FIRST_SEND_WAIT
435 /* See the implementation notes at the beginning of this file */
436 # ifdef USE_DLPI_SEND
437 sleep (DLPI_FIRST_SEND_WAIT
/ 2);
439 sleep (DLPI_FIRST_SEND_WAIT
);
443 #endif /* USE_DLPI_RECEIVE */
446 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
447 struct interface_info
*interface
;
448 struct packet
*packet
;
449 struct dhcp_packet
*raw
;
452 struct sockaddr_in
*to
;
453 struct hardware
*hto
;
456 unsigned char dbuf
[1536];
457 unsigned char sap
[2];
458 unsigned char dstaddr
[DLPI_MAXDLADDR
];
463 if (!strcmp (interface
-> name
, "fallback"))
464 return send_fallback (interface
, packet
, raw
,
469 /* Assemble the headers... */
471 assemble_hw_header (interface
, dbuf
, &dbuflen
, hto
);
473 assemble_udp_ip_header (interface
, dbuf
, &dbuflen
, from
.s_addr
,
474 to
-> sin_addr
.s_addr
, to
-> sin_port
,
475 (unsigned char *)raw
, len
);
477 /* Copy the data into the buffer (yuk). */
478 memcpy (dbuf
+ dbuflen
, raw
, len
);
482 result
= write (interface
-> wfdesc
, dbuf
, dbuflen
);
484 /* XXX: Assumes ethernet, with two byte SAP */
485 sap
[0] = 0x08; /* ETHERTYPE_IP, high byte */
486 sap
[1] = 0x0; /* ETHERTYPE_IP, low byte */
487 saplen
= -2; /* -2 indicates a two byte SAP at the end
490 /* Setup the destination address */
491 if (hto
&& hto
-> hlen
== interface
-> hw_address
.hlen
) {
492 dlpi_makeaddr (hto
-> haddr
, hto
-> hlen
, sap
, saplen
, dstaddr
);
494 /* XXX: Assumes broadcast addr is all ones */
495 /* Really should get the broadcast address as part of the
496 * dlpiinforeq, and store it somewhere in the interface structure.
498 unsigned char bcast_ether
[DLPI_MAXDLADDR
];
500 memset ((char *)bcast_ether
, 0xFF, interface
-> hw_address
.hlen
);
501 dlpi_makeaddr (bcast_ether
, interface
-> hw_address
.hlen
,
502 sap
, saplen
, dstaddr
);
504 addrlen
= interface
-> hw_address
.hlen
+ ABS (saplen
);
506 /* Send the packet down the wire... */
507 result
= dlpiunitdatareq (interface
-> wfdesc
, dstaddr
, addrlen
,
508 0, 0, dbuf
, dbuflen
);
511 log_error ("send_packet: %m");
514 #endif /* USE_DLPI_SEND */
516 #ifdef USE_DLPI_RECEIVE
517 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
518 struct interface_info
*interface
;
521 struct sockaddr_in
*from
;
522 struct hardware
*hfrom
;
524 unsigned char dbuf
[1536];
525 unsigned char sap
[2];
526 unsigned char srcaddr
[DLPI_MAXDLADDR
];
527 unsigned long srcaddrlen
;
536 length
= read (interface
-> rfdesc
, dbuf
, sizeof (dbuf
));
538 length
= dlpiunitdataind (interface
-> rfdesc
, (unsigned char *)NULL
,
539 (unsigned long *)NULL
, srcaddr
, &srcaddrlen
,
540 (unsigned long *)NULL
, dbuf
, sizeof (dbuf
));
548 /* Copy sender info */
549 /* XXX: Assumes ethernet, where SAP comes at end of haddr */
551 if (hfrom
&& srcaddrlen
== ABS(saplen
) + interface
-> hw_address
.hlen
) {
552 hfrom
-> htype
= interface
-> hw_address
.htype
;
553 hfrom
-> hlen
= interface
-> hw_address
.hlen
;
554 dlpi_parseaddr (srcaddr
, hfrom
-> haddr
,
555 interface
-> hw_address
.hlen
, sap
, saplen
);
557 memset ((char *)hfrom
, '\0', sizeof (*hfrom
));
561 /* Decode the IP and UDP headers... */
564 /* Decode the physical header... */
565 offset
= decode_hw_header (interface
, dbuf
, bufix
, hfrom
);
567 /* If a physical layer checksum failed (dunno of any
568 physical layer that supports this, but WTH), skip this
576 offset
= decode_udp_ip_header (interface
, dbuf
, bufix
,
577 from
, (unsigned char *)0, length
);
579 /* If the IP or UDP checksum was bad, skip the packet... */
587 /* Copy out the data in the packet... */
588 memcpy (buf
, &dbuf
[bufix
], length
);
593 /* Common DLPI routines ...
595 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
597 * Based largely in part to the example code contained in the document
598 * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
599 * by Neal Nuckolls of SunSoft Internet Engineering.
601 * This code has been developed and tested on sparc-based machines running
602 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
605 * The usual disclaimers apply. This code works for me. Don't blame me
606 * if it makes your machine or network go down in flames. That taken
607 * into consideration, use this code as you wish. If you make usefull
608 * modifications I'd appreciate hearing about it.
611 #define DLPI_MAXWAIT 15 /* Max timeout */
613 static void dlpi_makeaddr (physaddr
, physaddrlen
, sap
, saplen
, buf
)
614 unsigned char *physaddr
;
621 * If the saplen is negative, the SAP goes at the end of the address,
622 * otherwise it goes at the beginning.
625 memcpy ((char *)buf
, (char *)sap
, saplen
);
626 memcpy ((char *)&buf
[saplen
], (char *)physaddr
, physaddrlen
);
628 memcpy ((char *)buf
, (char *)physaddr
, physaddrlen
);
629 memcpy ((char *)&buf
[physaddrlen
], (char *)sap
, 0 - saplen
);
633 static void dlpi_parseaddr (buf
, physaddr
, physaddrlen
, sap
, saplen
)
635 unsigned char *physaddr
;
641 * If the saplen is negative, the SAP is at the end of the address,
642 * otherwise it is at the beginning.
645 memcpy ((char *)sap
, (char *)buf
, saplen
);
646 memcpy ((char *)physaddr
, (char *)&buf
[saplen
], physaddrlen
);
648 memcpy ((char *)physaddr
, (char *)buf
, physaddrlen
);
649 memcpy ((char *)sap
, (char *)&buf
[physaddrlen
], 0 - saplen
);
654 * Parse an interface name and extract the unit number
657 static int dlpiunit (ifname
)
668 /* Advance to the end of the name */
671 /* Back up to the start of the first digit */
672 while ((*(cp
-1) >= '0' && *(cp
-1) <= '9') || *(cp
- 1) == ':') cp
--;
674 /* Convert the unit number */
676 while (*cp
>= '0' && *cp
<= '9') {
678 unit
+= (*cp
++ - '0');
685 * dlpiopen - open the DLPI device for a given interface name
687 static int dlpiopen (ifname
)
697 /* Open a DLPI device */
698 if (*ifname
== '/') {
701 /* Prepend the device directory */
702 memcpy (devname
, DLPI_DEVDIR
, strlen (DLPI_DEVDIR
));
703 dp
= &devname
[strlen (DLPI_DEVDIR
)];
706 /* Find the end of the interface name */
710 /* And back up to the first digit (unit number) */
711 while ((*(ep
- 1) >= '0' && *(ep
- 1) <= '9') || *(ep
- 1) == ':')
714 /* Copy everything up to the unit number */
720 return open (devname
, O_RDWR
, 0);
724 * dlpiinforeq - request information about the data link provider.
727 static int dlpiinforeq (fd
)
730 dl_info_req_t info_req
;
734 info_req
.dl_primitive
= DL_INFO_REQ
;
737 ctl
.len
= sizeof (info_req
);
738 ctl
.buf
= (char *)&info_req
;
742 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
746 * dlpiphysaddrreq - request the current physical address.
748 static int dlpiphysaddrreq (fd
, addrtype
)
750 unsigned long addrtype
;
752 dl_phys_addr_req_t physaddr_req
;
756 physaddr_req
.dl_primitive
= DL_PHYS_ADDR_REQ
;
757 physaddr_req
.dl_addr_type
= addrtype
;
760 ctl
.len
= sizeof (physaddr_req
);
761 ctl
.buf
= (char *)&physaddr_req
;
765 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
769 * dlpiattachreq - send a request to attach to a specific unit.
771 static int dlpiattachreq (fd
, ppa
)
775 dl_attach_req_t attach_req
;
779 attach_req
.dl_primitive
= DL_ATTACH_REQ
;
780 attach_req
.dl_ppa
= ppa
;
783 ctl
.len
= sizeof (attach_req
);
784 ctl
.buf
= (char *)&attach_req
;
788 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
792 * dlpibindreq - send a request to bind to a specific SAP address.
794 static int dlpibindreq (fd
, sap
, max_conind
, service_mode
, conn_mgmt
, xidtest
)
796 unsigned long max_conind
;
797 unsigned long service_mode
;
798 unsigned long conn_mgmt
;
799 unsigned long xidtest
;
802 dl_bind_req_t bind_req
;
806 bind_req
.dl_primitive
= DL_BIND_REQ
;
807 bind_req
.dl_sap
= sap
;
808 bind_req
.dl_max_conind
= max_conind
;
809 bind_req
.dl_service_mode
= service_mode
;
810 bind_req
.dl_conn_mgmt
= conn_mgmt
;
811 bind_req
.dl_xidtest_flg
= xidtest
;
814 ctl
.len
= sizeof (bind_req
);
815 ctl
.buf
= (char *)&bind_req
;
819 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
823 * dlpiunbindreq - send a request to unbind.
825 static int dlpiunbindreq (fd
)
828 dl_unbind_req_t unbind_req
;
832 unbind_req
.dl_primitive
= DL_UNBIND_REQ
;
835 ctl
.len
= sizeof (unbind_req
);
836 ctl
.buf
= (char *)&unbind_req
;
840 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
845 * dlpidetachreq - send a request to detach.
847 static int dlpidetachreq (fd
)
850 dl_detach_req_t detach_req
;
854 detach_req
.dl_primitive
= DL_DETACH_REQ
;
857 ctl
.len
= sizeof (detach_req
);
858 ctl
.buf
= (char *)&detach_req
;
862 return putmsg (fd
, &ctl
, (struct strbuf
*)NULL
, flags
);
867 * dlpibindack - receive an ack to a dlbindreq.
869 static int dlpibindack (fd
, bufp
)
873 union DL_primitives
*dlp
;
877 ctl
.maxlen
= DLPI_MAXDLBUF
;
881 if (strgetmsg (fd
, &ctl
,
882 (struct strbuf
*)NULL
, &flags
, "dlpibindack") < 0) {
886 dlp
= (union DL_primitives
*)ctl
.buf
;
888 if (!expected (DL_BIND_ACK
, dlp
, flags
) < 0) {
892 if (ctl
.len
< sizeof (dl_bind_ack_t
)) {
893 /* Returned structure is too short */
901 * dlpiokack - general acknowledgement reception.
903 static int dlpiokack (fd
, bufp
)
907 union DL_primitives
*dlp
;
911 ctl
.maxlen
= DLPI_MAXDLBUF
;
915 if (strgetmsg (fd
, &ctl
,
916 (struct strbuf
*)NULL
, &flags
, "dlpiokack") < 0) {
920 dlp
= (union DL_primitives
*)ctl
.buf
;
922 if (!expected (DL_OK_ACK
, dlp
, flags
) < 0) {
926 if (ctl
.len
< sizeof (dl_ok_ack_t
)) {
927 /* Returned structure is too short */
935 * dlpiinfoack - receive an ack to a dlinforeq.
937 static int dlpiinfoack (fd
, bufp
)
941 union DL_primitives
*dlp
;
945 ctl
.maxlen
= DLPI_MAXDLBUF
;
949 if (strgetmsg (fd
, &ctl
, (struct strbuf
*)NULL
, &flags
,
950 "dlpiinfoack") < 0) {
954 dlp
= (union DL_primitives
*) ctl
.buf
;
956 if (!expected (DL_INFO_ACK
, dlp
, flags
) < 0) {
960 if (ctl
.len
< sizeof (dl_info_ack_t
)) {
961 /* Returned structure is too short */
969 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
971 int dlpiphysaddrack (fd
, bufp
)
975 union DL_primitives
*dlp
;
979 ctl
.maxlen
= DLPI_MAXDLBUF
;
983 if (strgetmsg (fd
, &ctl
, (struct strbuf
*)NULL
, &flags
,
984 "dlpiphysaddrack") < 0) {
988 dlp
= (union DL_primitives
*)ctl
.buf
;
990 if (!expected (DL_PHYS_ADDR_ACK
, dlp
, flags
) < 0) {
994 if (ctl
.len
< sizeof (dl_phys_addr_ack_t
)) {
995 /* Returned structure is too short */
1002 int dlpiunitdatareq (fd
, addr
, addrlen
, minpri
, maxpri
, dbuf
, dbuflen
)
1004 unsigned char *addr
;
1006 unsigned long minpri
;
1007 unsigned long maxpri
;
1008 unsigned char *dbuf
;
1011 long buf
[DLPI_MAXDLBUF
];
1012 union DL_primitives
*dlp
;
1013 struct strbuf ctl
, data
;
1015 /* Set up the control information... */
1016 dlp
= (union DL_primitives
*)buf
;
1017 dlp
-> unitdata_req
.dl_primitive
= DL_UNITDATA_REQ
;
1018 dlp
-> unitdata_req
.dl_dest_addr_length
= addrlen
;
1019 dlp
-> unitdata_req
.dl_dest_addr_offset
= sizeof (dl_unitdata_req_t
);
1020 dlp
-> unitdata_req
.dl_priority
.dl_min
= minpri
;
1021 dlp
-> unitdata_req
.dl_priority
.dl_max
= maxpri
;
1023 /* Append the destination address */
1024 memcpy ((char *)buf
+ dlp
-> unitdata_req
.dl_dest_addr_offset
,
1028 ctl
.len
= dlp
-> unitdata_req
.dl_dest_addr_offset
+ addrlen
;
1029 ctl
.buf
= (char *)buf
;
1032 data
.buf
= (char *)dbuf
;
1035 /* Send the packet down the wire... */
1036 return putmsg (fd
, &ctl
, &data
, 0);
1039 static int dlpiunitdataind (fd
, daddr
, daddrlen
,
1040 saddr
, saddrlen
, grpaddr
, dbuf
, dlen
)
1042 unsigned char *daddr
;
1043 unsigned long *daddrlen
;
1044 unsigned char *saddr
;
1045 unsigned long *saddrlen
;
1046 unsigned long *grpaddr
;
1047 unsigned char *dbuf
;
1050 long buf
[DLPI_MAXDLBUF
];
1051 union DL_primitives
*dlp
;
1052 struct strbuf ctl
, data
;
1056 /* Set up the msg_buf structure... */
1057 dlp
= (union DL_primitives
*)buf
;
1058 dlp
-> unitdata_ind
.dl_primitive
= DL_UNITDATA_IND
;
1060 ctl
.maxlen
= DLPI_MAXDLBUF
;
1062 ctl
.buf
= (char *)buf
;
1066 data
.buf
= (char *)dbuf
;
1068 result
= getmsg (fd
, &ctl
, &data
, &flags
);
1074 if (ctl
.len
< sizeof (dl_unitdata_ind_t
) ||
1075 dlp
-> unitdata_ind
.dl_primitive
!= DL_UNITDATA_IND
) {
1079 if (data
.len
<= 0) {
1083 /* Copy sender info */
1085 memcpy (saddr
, &buf
[dlp
-> unitdata_ind
.dl_src_addr_offset
],
1086 dlp
-> unitdata_ind
.dl_src_addr_length
);
1089 *saddrlen
= dlp
-> unitdata_ind
.dl_src_addr_length
;
1092 /* Copy destination info */
1094 memcpy (daddr
, &buf
[dlp
-> unitdata_ind
.dl_dest_addr_offset
],
1095 dlp
-> unitdata_ind
.dl_dest_addr_length
);
1098 *daddrlen
= dlp
-> unitdata_ind
.dl_dest_addr_length
;
1102 *grpaddr
= dlp
-> unitdata_ind
.dl_group_address
;
1109 * expected - see if we got what we wanted.
1111 static int expected (prim
, dlp
, msgflags
)
1113 union DL_primitives
*dlp
;
1116 if (msgflags
!= RS_HIPRI
) {
1117 /* Message was not M_PCPROTO */
1121 if (dlp
-> dl_primitive
!= prim
) {
1122 /* Incorrect/unexpected return message */
1130 * strgetmsg - get a message from a stream, with timeout.
1132 static int strgetmsg (fd
, ctlp
, datap
, flagsp
, caller
)
1133 struct strbuf
*ctlp
, *datap
;
1149 pfd
.events
= POLLPRI
; /* We're only interested in knowing
1150 * when we can receive the next high
1155 now
= time (&starttime
);
1156 while (now
<= starttime
+ DLPI_MAXWAIT
) {
1157 to_msec
= ((starttime
+ DLPI_MAXWAIT
) - now
) * 1000;
1158 count
= poll (&pfd
, 1, to_msec
);
1161 /* log_fatal ("strgetmsg: timeout"); */
1163 } else if (count
< 0) {
1164 if (errno
== EAGAIN
|| errno
== EINTR
) {
1168 /* log_fatal ("poll: %m"); */
1175 #else /* defined (USE_POLL) */
1177 * Start timer. Can't use select, since it might return true if there
1178 * were non High-Priority data available on the stream.
1180 (void) sigset (SIGALRM
, sigalrm
);
1182 if (alarm (DLPI_MAXWAIT
) < 0) {
1183 /* log_fatal ("alarm: %m"); */
1186 #endif /* !defined (USE_POLL) */
1189 * Set flags argument and issue getmsg ().
1192 if ((result
= getmsg (fd
, ctlp
, datap
, flagsp
)) < 0) {
1200 if (alarm (0) < 0) {
1201 /* log_fatal ("alarm: %m"); */
1207 * Check for MOREDATA and/or MORECTL.
1209 if (result
& (MORECTL
|MOREDATA
)) {
1214 * Check for at least sizeof (long) control data portion.
1216 if (ctlp
-> len
< sizeof (long)) {
1225 * sigalrm - handle alarms.
1227 static void sigalrm (sig
)
1230 fprintf (stderr
, "strgetmsg: timeout");
1233 #endif /* !defined (USE_POLL) */
1235 int can_unicast_without_arp (ip
)
1236 struct interface_info
*ip
;
1241 int can_receive_unicast_unconfigured (ip
)
1242 struct interface_info
*ip
;
1247 void maybe_setup_fallback ()
1249 isc_result_t status
;
1250 struct interface_info
*fbi
;
1251 fbi
= setup_fallback ();
1253 if_register_fallback (fbi
);
1255 fbi
-> type
= dhcp_type_interface
;
1256 status
= omapi_register_io_object ((omapi_object_t
)fbi
,
1258 fallback_discard
, 0, 0);
1259 if (status
!= ISC_R_SUCCESS
)
1260 log_fatal ("Can't register I/O handle for %s: %s",
1261 fbi
-> name
, isc_result_totext (status
));
1264 #endif /* USE_DLPI */