]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/dlpi.c
e4a60c646673d04a82538a6513d2c3f2661c94dc
[thirdparty/dhcp.git] / common / dlpi.c
1 /* dlpi.c
2
3 Data Link Provider Interface (DLPI) network interface code. */
4
5 /*
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:
12 *
13 * http://www.isc.org/isc-license-1.0.html.
14 *
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.
18 *
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
21 *
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''.
25 */
26
27 /*
28 * Based largely in part to the existing NIT code in nit.c.
29 *
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
32 * generic, though.
33 */
34
35 /*
36 * Implementation notes:
37 *
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).
43 *
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
47 * USE_DLPI_RAW.
48 *
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.
54 *
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
68 * to sleep.
69 */
70
71 #ifndef lint
72 static char copyright[] =
73 "$Id: dlpi.c,v 1.18 2000/03/06 19:39:53 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
74 #endif /* not lint */
75
76 #include "dhcpd.h"
77
78 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
79
80 # include <sys/ioctl.h>
81 # include <sys/time.h>
82 # include <sys/dlpi.h>
83 # include <stropts.h>
84 # ifdef USE_DLPI_PFMOD
85 # include <sys/pfmod.h>
86 # endif
87 # ifdef USE_POLL
88 # include <poll.h>
89 # endif
90
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"
95
96 # ifdef USE_DLPI_PFMOD
97 # ifdef USE_DLPI_RAW
98 # define DLPI_MODNAME "DLPI+RAW+PFMOD"
99 # else
100 # define DLPI_MODNAME "DLPI+PFMOD"
101 # endif
102 # else
103 # ifdef USE_DLPI_RAW
104 # define DLPI_MODNAME "DLPI+RAW"
105 # else
106 # define DLPI_MODNAME "DLPI"
107 # endif
108 # endif
109
110 # ifndef ABS
111 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
112 # endif
113
114 static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp));
115
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 */
120
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,
127 int saplen));
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,
145 int datalen));
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,
152 unsigned char *data,
153 int datalen));
154
155 # ifndef USE_POLL
156 static void sigalrm PROTO ((int sig));
157 # endif
158 static int expected PROTO ((unsigned long prim, union DL_primitives *dlp,
159 int msgflags));
160 static int strgetmsg PROTO ((int fd, struct strbuf *ctlp,
161 struct strbuf *datap, int *flagsp,
162 char *caller));
163
164 /* Reinitializes the specified interface after an address change. This
165 is not required for packet-filter APIs. */
166
167 #ifdef USE_DLPI_SEND
168 void if_reinitialize_send (info)
169 struct interface_info *info;
170 {
171 }
172 #endif
173
174 #ifdef USE_DLPI_RECEIVE
175 void if_reinitialize_receive (info)
176 struct interface_info *info;
177 {
178 }
179 #endif
180
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
183 mask. */
184
185 int if_register_dlpi (info)
186 struct interface_info *info;
187 {
188 int sock;
189 int unit;
190 long buf [DLPI_MAXDLBUF];
191 union DL_primitives *dlp;
192
193 dlp = (union DL_primitives *)buf;
194
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);
198 }
199
200 /*
201 * Get information about the provider.
202 */
203
204 /*
205 * Submit a DL_INFO_REQ request, to find
206 * the dl_mac_type and dl_provider_style
207 */
208 if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
209 log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
210 } else {
211 switch (dlp -> info_ack.dl_mac_type) {
212 case DL_CSMACD: /* IEEE 802.3 */
213 case DL_ETHER:
214 info -> hw_address.hbuf [0] = HTYPE_ETHER;
215 break;
216 /* adding token ring 5/1999 - mayer@ping.at */
217 case DL_TPR:
218 info -> hw_address.hbuf [0] = HTYPE_IEEE802;
219 break;
220 case DL_FDDI:
221 info -> hw_address.hbuf [0] = HTYPE_FDDI;
222 break;
223 default:
224 log_fatal ("%s: unknown DLPI MAC type %ld",
225 info -> name,
226 dlp -> info_ack.dl_mac_type);
227 break;
228 }
229 }
230
231 if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
232 /*
233 * Attach to the device. If this fails, the device
234 * does not exist.
235 */
236 unit = dlpiunit (info -> name);
237
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);
241 }
242 }
243
244 /*
245 * Bind to the IP service access point (SAP), connectionless (CLDLS).
246 */
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);
250 }
251
252 /*
253 * Submit a DL_PHYS_ADDR_REQ request, to find
254 * the hardware address
255 */
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",
259 info -> name);
260 }
261
262 info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1;
263 memcpy (&info -> hw_address.hbuf [1],
264 (char *)buf + dlp -> physaddr_ack.dl_addr_offset,
265 dlp -> physaddr_ack.dl_addr_length);
266
267 #ifdef USE_DLPI_RAW
268 if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
269 log_fatal ("Can't set DLPI RAW mode for %s: %m",
270 info -> name);
271 }
272 #endif
273
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",
277 info -> name);
278 }
279 #endif
280
281 return sock;
282 }
283
284 static int
285 strioctl (fd, cmd, timeout, len, dp)
286 int fd;
287 int cmd;
288 int timeout;
289 int len;
290 char *dp;
291 {
292 struct strioctl sio;
293 int rslt;
294
295 sio.ic_cmd = cmd;
296 sio.ic_timout = timeout;
297 sio.ic_len = len;
298 sio.ic_dp = dp;
299
300 if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
301 return rslt;
302 } else {
303 return sio.ic_len;
304 }
305 }
306
307 #ifdef USE_DLPI_SEND
308 void if_register_send (info)
309 struct interface_info *info;
310 {
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;
316 # endif
317
318 info -> wfdesc = if_register_dlpi (info);
319
320 # ifdef USE_DLPI_PFMOD
321 /* Set up an PFMOD filter that rejects everything... */
322 pf.Pf_Priority = 0;
323 pf.Pf_FilterLen = 1;
324 pf.Pf_Filter [0] = ENF_PUSHZERO;
325
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);
330 }
331
332 # endif /* USE_DLPI_PFMOD */
333 #else /* !defined (USE_DLPI_RECEIVE) */
334 /*
335 * If using DLPI for both send and receive, simply re-use
336 * the read file descriptor that was set up earlier.
337 */
338 info -> wfdesc = info -> rfdesc;
339 #endif
340
341 if (!quiet_interface_discovery)
342 log_info ("Sending on DLPI/%s/%s%s%s",
343 info -> name,
344 print_hw_addr (info -> hw_address.hbuf [0],
345 info -> hw_address.hlen - 1,
346 &info -> hw_address.hbuf [1]),
347 (info -> shared_network ? "/" : ""),
348 (info -> shared_network ?
349 info -> shared_network -> name : ""));
350
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));
355 # else
356 sleep (DLPI_FIRST_SEND_WAIT);
357 # endif
358 #endif
359 }
360
361 void if_deregister_send (info)
362 struct interface_info *info;
363 {
364 /* If we're using the DLPI API for sending and receiving,
365 we don't need to register this interface twice. */
366 #ifndef USE_DLPI_RECEIVE
367 close (info -> wfdesc);
368 #endif
369 info -> wfdesc = -1;
370
371 if (!quiet_interface_discovery)
372 log_info ("Disabling output on DLPI/%s/%s%s%s",
373 info -> name,
374 print_hw_addr (info -> hw_address.hbuf [0],
375 info -> hw_address.hlen - 1,
376 &info -> hw_address.hbuf [1]),
377 (info -> shared_network ? "/" : ""),
378 (info -> shared_network ?
379 info -> shared_network -> name : ""));
380 }
381 #endif /* USE_DLPI_SEND */
382
383 #ifdef USE_DLPI_RECEIVE
384 /* Packet filter program...
385 XXX Changes to the filter program may require changes to the constant
386 offsets used in if_register_send to patch the NIT program! XXX */
387
388 void if_register_receive (info)
389 struct interface_info *info;
390 {
391 #ifdef USE_DLPI_PFMOD
392 struct packetfilt pf;
393 #endif
394
395 /* Open a DLPI device and hang it on this interface... */
396 info -> rfdesc = if_register_dlpi (info);
397
398 #ifdef USE_DLPI_PFMOD
399 /* Set up the PFMOD filter program. */
400 /* XXX Unlike the BPF filter program, this one won't work if the
401 XXX IP packet is fragmented or if there are options on the IP
402 XXX header. */
403 pf.Pf_Priority = 0;
404 pf.Pf_FilterLen = 0;
405
406 #ifdef USE_DLPI_RAW
407 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6;
408 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
409 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
410 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
411 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
412 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
413 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSH00FF + ENF_AND;
414 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
415 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18;
416 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
417 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (local_port);
418 #else
419 /*
420 * The packets that will be received on this file descriptor
421 * will be IP packets (due to the SAP that was specified in
422 * the dlbind call). There will be no ethernet header.
423 * Therefore, setup the packet filter to check the protocol
424 * field for UDP, and the destination port number equal
425 * to the local port. All offsets are relative to the start
426 * of an IP packet.
427 */
428 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
429 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
430 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 4;
431 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSH00FF + ENF_AND;
432 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
433 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
434 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
435 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (local_port);
436 #endif
437
438 /* Install the filter... */
439 if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
440 sizeof (pf), (char *)&pf) < 0) {
441 log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name);
442 }
443 #endif
444
445 if (!quiet_interface_discovery)
446 log_info ("Listening on DLPI/%s/%s%s%s",
447 info -> name,
448 print_hw_addr (info -> hw_address.hbuf [0],
449 info -> hw_address.hlen - 1,
450 &info -> hw_address.hbuf [1]),
451 (info -> shared_network ? "/" : ""),
452 (info -> shared_network ?
453 info -> shared_network -> name : ""));
454
455 #ifdef DLPI_FIRST_SEND_WAIT
456 /* See the implementation notes at the beginning of this file */
457 # ifdef USE_DLPI_SEND
458 sleep (DLPI_FIRST_SEND_WAIT / 2);
459 # else
460 sleep (DLPI_FIRST_SEND_WAIT);
461 # endif
462 #endif
463 }
464
465 void if_deregister_receive (info)
466 struct interface_info *info;
467 {
468 /* If we're using the DLPI API for sending and receiving,
469 we don't need to register this interface twice. */
470 #ifndef USE_DLPI_SEND
471 close (info -> rfdesc);
472 #endif
473 info -> rfdesc = -1;
474
475 if (!quiet_interface_discovery)
476 log_info ("Disabling input on DLPI/%s/%s%s%s",
477 info -> name,
478 print_hw_addr (info -> hw_address.hbuf [0],
479 info -> hw_address.hlen - 1,
480 &info -> hw_address.hbuf [1]),
481 (info -> shared_network ? "/" : ""),
482 (info -> shared_network ?
483 info -> shared_network -> name : ""));
484 }
485 #endif /* USE_DLPI_RECEIVE */
486
487 #ifdef USE_DLPI_SEND
488 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
489 struct interface_info *interface;
490 struct packet *packet;
491 struct dhcp_packet *raw;
492 size_t len;
493 struct in_addr from;
494 struct sockaddr_in *to;
495 struct hardware *hto;
496 {
497 unsigned dbuflen;
498 unsigned char dbuf [1536];
499 unsigned char sap [2];
500 unsigned char dstaddr [DLPI_MAXDLADDR];
501 unsigned addrlen;
502 int saplen;
503 int result;
504
505 if (!strcmp (interface -> name, "fallback"))
506 return send_fallback (interface, packet, raw,
507 len, from, to, hto);
508
509 dbuflen = 0;
510
511 /* Assemble the headers... */
512 #ifdef USE_DLPI_RAW
513 assemble_hw_header (interface, dbuf, &dbuflen, hto);
514 #endif
515 assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr,
516 to -> sin_addr.s_addr, to -> sin_port,
517 (unsigned char *)raw, len);
518
519 /* Copy the data into the buffer (yuk). */
520 memcpy (dbuf + dbuflen, raw, len);
521 dbuflen += len;
522
523 #ifdef USE_DLPI_RAW
524 result = write (interface -> wfdesc, dbuf, dbuflen);
525 #else
526 /* XXX: Assumes ethernet, with two byte SAP */
527 sap [0] = 0x08; /* ETHERTYPE_IP, high byte */
528 sap [1] = 0x0; /* ETHERTYPE_IP, low byte */
529 saplen = -2; /* -2 indicates a two byte SAP at the end
530 of the address */
531
532 /* Setup the destination address */
533 if (hto && hto -> hlen == interface -> hw_address.hlen) {
534 dlpi_makeaddr (&hto -> hbuf [1],
535 hto -> hlen - 1, sap, saplen, dstaddr);
536 } else {
537 /* XXX: Assumes broadcast addr is all ones */
538 /* Really should get the broadcast address as part of the
539 * dlpiinforeq, and store it somewhere in the interface structure.
540 */
541 unsigned char bcast_ether [DLPI_MAXDLADDR];
542
543 memset ((char *)bcast_ether, 0xFF,
544 interface -> hw_address.hlen - 1);
545 dlpi_makeaddr (bcast_ether, interface -> hw_address.hlen - 1,
546 sap, saplen, dstaddr);
547 }
548 addrlen = interface -> hw_address.hlen - 1 + ABS (saplen);
549
550 /* Send the packet down the wire... */
551 result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
552 0, 0, dbuf, dbuflen);
553 #endif
554 if (result < 0)
555 log_error ("send_packet: %m");
556 return result;
557 }
558 #endif /* USE_DLPI_SEND */
559
560 #ifdef USE_DLPI_RECEIVE
561 ssize_t receive_packet (interface, buf, len, from, hfrom)
562 struct interface_info *interface;
563 unsigned char *buf;
564 size_t len;
565 struct sockaddr_in *from;
566 struct hardware *hfrom;
567 {
568 unsigned char dbuf [1536];
569 unsigned char sap [2];
570 unsigned char srcaddr [DLPI_MAXDLADDR];
571 unsigned long srcaddrlen;
572 int saplen;
573 int flags = 0;
574 int length = 0;
575 int offset = 0;
576 int rslt;
577 int bufix = 0;
578
579 #ifdef USE_DLPI_RAW
580 length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
581 #else
582 length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
583 (unsigned long *)NULL, srcaddr, &srcaddrlen,
584 (unsigned long *)NULL, dbuf, sizeof (dbuf));
585 #endif
586
587 if (length <= 0) {
588 return length;
589 }
590
591 #ifndef USE_DLPI_RAW
592 /* Copy sender info */
593 /* XXX: Assumes ethernet, where SAP comes at end of haddr */
594 saplen = -2;
595 if (hfrom && (srcaddrlen ==
596 ABS (saplen) + interface -> hw_address.hlen - 1)) {
597 hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
598 hfrom -> hlen = interface -> hw_address.hlen;
599 dlpi_parseaddr (srcaddr, &hfrom -> hbuf [1],
600 interface -> hw_address.hlen - 1, sap, saplen);
601 } else if (hfrom) {
602 memset (hfrom, '\0', sizeof *hfrom);
603 }
604 #endif
605
606 /* Decode the IP and UDP headers... */
607 bufix = 0;
608 #ifdef USE_DLPI_RAW
609 /* Decode the physical header... */
610 offset = decode_hw_header (interface, dbuf, bufix, hfrom);
611
612 /* If a physical layer checksum failed (dunno of any
613 physical layer that supports this, but WTH), skip this
614 packet. */
615 if (offset < 0) {
616 return 0;
617 }
618 bufix += offset;
619 length -= offset;
620 #endif
621 offset = decode_udp_ip_header (interface, dbuf, bufix,
622 from, (unsigned char *)0, length);
623
624 /* If the IP or UDP checksum was bad, skip the packet... */
625 if (offset < 0) {
626 return 0;
627 }
628
629 bufix += offset;
630 length -= offset;
631
632 /* Copy out the data in the packet... */
633 memcpy (buf, &dbuf [bufix], length);
634 return length;
635 }
636 #endif
637
638 /* Common DLPI routines ...
639 *
640 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
641 *
642 * Based largely in part to the example code contained in the document
643 * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
644 * by Neal Nuckolls of SunSoft Internet Engineering.
645 *
646 * This code has been developed and tested on sparc-based machines running
647 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
648 * generic, though.
649 *
650 * The usual disclaimers apply. This code works for me. Don't blame me
651 * if it makes your machine or network go down in flames. That taken
652 * into consideration, use this code as you wish. If you make usefull
653 * modifications I'd appreciate hearing about it.
654 */
655
656 #define DLPI_MAXWAIT 15 /* Max timeout */
657
658 static void dlpi_makeaddr (physaddr, physaddrlen, sap, saplen, buf)
659 unsigned char *physaddr;
660 int physaddrlen;
661 unsigned char *sap;
662 int saplen;
663 unsigned char *buf;
664 {
665 /*
666 * If the saplen is negative, the SAP goes at the end of the address,
667 * otherwise it goes at the beginning.
668 */
669 if (saplen >= 0) {
670 memcpy ((char *)buf, (char *)sap, saplen);
671 memcpy ((char *)&buf [saplen], (char *)physaddr, physaddrlen);
672 } else {
673 memcpy ((char *)buf, (char *)physaddr, physaddrlen);
674 memcpy ((char *)&buf [physaddrlen], (char *)sap, 0 - saplen);
675 }
676 }
677
678 static void dlpi_parseaddr (buf, physaddr, physaddrlen, sap, saplen)
679 unsigned char *buf;
680 unsigned char *physaddr;
681 int physaddrlen;
682 unsigned char *sap;
683 int saplen;
684 {
685 /*
686 * If the saplen is negative, the SAP is at the end of the address,
687 * otherwise it is at the beginning.
688 */
689 if (saplen >= 0) {
690 memcpy ((char *)sap, (char *)buf, saplen);
691 memcpy ((char *)physaddr, (char *)&buf [saplen], physaddrlen);
692 } else {
693 memcpy ((char *)physaddr, (char *)buf, physaddrlen);
694 memcpy ((char *)sap, (char *)&buf [physaddrlen], 0 - saplen);
695 }
696 }
697
698 /*
699 * Parse an interface name and extract the unit number
700 */
701
702 static int dlpiunit (ifname)
703 char *ifname;
704 {
705 int fd;
706 char *cp, *dp, *ep;
707 int unit;
708
709 if (!ifname) {
710 return 0;
711 }
712
713 /* Advance to the end of the name */
714 cp = ifname;
715 while (*cp) cp++;
716 /* Back up to the start of the first digit */
717 while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
718
719 /* Convert the unit number */
720 unit = 0;
721 while (*cp >= '0' && *cp <= '9') {
722 unit *= 10;
723 unit += (*cp++ - '0');
724 }
725
726 return unit;
727 }
728
729 /*
730 * dlpiopen - open the DLPI device for a given interface name
731 */
732 static int dlpiopen (ifname)
733 char *ifname;
734 {
735 char devname [50];
736 char *cp, *dp, *ep;
737
738 if (!ifname) {
739 return -1;
740 }
741
742 /* Open a DLPI device */
743 if (*ifname == '/') {
744 dp = devname;
745 } else {
746 /* Prepend the device directory */
747 memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
748 dp = &devname [strlen (DLPI_DEVDIR)];
749 }
750
751 /* Find the end of the interface name */
752 ep = cp = ifname;
753 while (*ep)
754 ep++;
755 /* And back up to the first digit (unit number) */
756 while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
757 ep--;
758
759 /* Copy everything up to the unit number */
760 while (cp < ep) {
761 *dp++ = *cp++;
762 }
763 *dp = '\0';
764
765 return open (devname, O_RDWR, 0);
766 }
767
768 /*
769 * dlpiinforeq - request information about the data link provider.
770 */
771
772 static int dlpiinforeq (fd)
773 int fd;
774 {
775 dl_info_req_t info_req;
776 struct strbuf ctl;
777 int flags;
778
779 info_req.dl_primitive = DL_INFO_REQ;
780
781 ctl.maxlen = 0;
782 ctl.len = sizeof (info_req);
783 ctl.buf = (char *)&info_req;
784
785 flags = RS_HIPRI;
786
787 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
788 }
789
790 /*
791 * dlpiphysaddrreq - request the current physical address.
792 */
793 static int dlpiphysaddrreq (fd, addrtype)
794 int fd;
795 unsigned long addrtype;
796 {
797 dl_phys_addr_req_t physaddr_req;
798 struct strbuf ctl;
799 int flags;
800
801 physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
802 physaddr_req.dl_addr_type = addrtype;
803
804 ctl.maxlen = 0;
805 ctl.len = sizeof (physaddr_req);
806 ctl.buf = (char *)&physaddr_req;
807
808 flags = RS_HIPRI;
809
810 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
811 }
812
813 /*
814 * dlpiattachreq - send a request to attach to a specific unit.
815 */
816 static int dlpiattachreq (fd, ppa)
817 unsigned long ppa;
818 int fd;
819 {
820 dl_attach_req_t attach_req;
821 struct strbuf ctl;
822 int flags;
823
824 attach_req.dl_primitive = DL_ATTACH_REQ;
825 attach_req.dl_ppa = ppa;
826
827 ctl.maxlen = 0;
828 ctl.len = sizeof (attach_req);
829 ctl.buf = (char *)&attach_req;
830
831 flags = 0;
832
833 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
834 }
835
836 /*
837 * dlpibindreq - send a request to bind to a specific SAP address.
838 */
839 static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
840 unsigned long sap;
841 unsigned long max_conind;
842 unsigned long service_mode;
843 unsigned long conn_mgmt;
844 unsigned long xidtest;
845 int fd;
846 {
847 dl_bind_req_t bind_req;
848 struct strbuf ctl;
849 int flags;
850
851 bind_req.dl_primitive = DL_BIND_REQ;
852 bind_req.dl_sap = sap;
853 bind_req.dl_max_conind = max_conind;
854 bind_req.dl_service_mode = service_mode;
855 bind_req.dl_conn_mgmt = conn_mgmt;
856 bind_req.dl_xidtest_flg = xidtest;
857
858 ctl.maxlen = 0;
859 ctl.len = sizeof (bind_req);
860 ctl.buf = (char *)&bind_req;
861
862 flags = 0;
863
864 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
865 }
866
867 /*
868 * dlpiunbindreq - send a request to unbind.
869 */
870 static int dlpiunbindreq (fd)
871 int fd;
872 {
873 dl_unbind_req_t unbind_req;
874 struct strbuf ctl;
875 int flags;
876
877 unbind_req.dl_primitive = DL_UNBIND_REQ;
878
879 ctl.maxlen = 0;
880 ctl.len = sizeof (unbind_req);
881 ctl.buf = (char *)&unbind_req;
882
883 flags = 0;
884
885 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
886 }
887
888
889 /*
890 * dlpidetachreq - send a request to detach.
891 */
892 static int dlpidetachreq (fd)
893 int fd;
894 {
895 dl_detach_req_t detach_req;
896 struct strbuf ctl;
897 int flags;
898
899 detach_req.dl_primitive = DL_DETACH_REQ;
900
901 ctl.maxlen = 0;
902 ctl.len = sizeof (detach_req);
903 ctl.buf = (char *)&detach_req;
904
905 flags = 0;
906
907 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
908 }
909
910
911 /*
912 * dlpibindack - receive an ack to a dlbindreq.
913 */
914 static int dlpibindack (fd, bufp)
915 char *bufp;
916 int fd;
917 {
918 union DL_primitives *dlp;
919 struct strbuf ctl;
920 int flags;
921
922 ctl.maxlen = DLPI_MAXDLBUF;
923 ctl.len = 0;
924 ctl.buf = bufp;
925
926 if (strgetmsg (fd, &ctl,
927 (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
928 return -1;
929 }
930
931 dlp = (union DL_primitives *)ctl.buf;
932
933 if (!expected (DL_BIND_ACK, dlp, flags) < 0) {
934 return -1;
935 }
936
937 if (ctl.len < sizeof (dl_bind_ack_t)) {
938 /* Returned structure is too short */
939 return -1;
940 }
941
942 return 0;
943 }
944
945 /*
946 * dlpiokack - general acknowledgement reception.
947 */
948 static int dlpiokack (fd, bufp)
949 char *bufp;
950 int fd;
951 {
952 union DL_primitives *dlp;
953 struct strbuf ctl;
954 int flags;
955
956 ctl.maxlen = DLPI_MAXDLBUF;
957 ctl.len = 0;
958 ctl.buf = bufp;
959
960 if (strgetmsg (fd, &ctl,
961 (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
962 return -1;
963 }
964
965 dlp = (union DL_primitives *)ctl.buf;
966
967 if (!expected (DL_OK_ACK, dlp, flags) < 0) {
968 return -1;
969 }
970
971 if (ctl.len < sizeof (dl_ok_ack_t)) {
972 /* Returned structure is too short */
973 return -1;
974 }
975
976 return 0;
977 }
978
979 /*
980 * dlpiinfoack - receive an ack to a dlinforeq.
981 */
982 static int dlpiinfoack (fd, bufp)
983 char *bufp;
984 int fd;
985 {
986 union DL_primitives *dlp;
987 struct strbuf ctl;
988 int flags;
989
990 ctl.maxlen = DLPI_MAXDLBUF;
991 ctl.len = 0;
992 ctl.buf = bufp;
993
994 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
995 "dlpiinfoack") < 0) {
996 return -1;
997 }
998
999 dlp = (union DL_primitives *) ctl.buf;
1000
1001 if (!expected (DL_INFO_ACK, dlp, flags) < 0) {
1002 return -1;
1003 }
1004
1005 if (ctl.len < sizeof (dl_info_ack_t)) {
1006 /* Returned structure is too short */
1007 return -1;
1008 }
1009
1010 return 0;
1011 }
1012
1013 /*
1014 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1015 */
1016 int dlpiphysaddrack (fd, bufp)
1017 char *bufp;
1018 int fd;
1019 {
1020 union DL_primitives *dlp;
1021 struct strbuf ctl;
1022 int flags;
1023
1024 ctl.maxlen = DLPI_MAXDLBUF;
1025 ctl.len = 0;
1026 ctl.buf = bufp;
1027
1028 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1029 "dlpiphysaddrack") < 0) {
1030 return -1;
1031 }
1032
1033 dlp = (union DL_primitives *)ctl.buf;
1034
1035 if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) {
1036 return -1;
1037 }
1038
1039 if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
1040 /* Returned structure is too short */
1041 return -1;
1042 }
1043
1044 return 0;
1045 }
1046
1047 int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
1048 int fd;
1049 unsigned char *addr;
1050 int addrlen;
1051 unsigned long minpri;
1052 unsigned long maxpri;
1053 unsigned char *dbuf;
1054 int dbuflen;
1055 {
1056 long buf [DLPI_MAXDLBUF];
1057 union DL_primitives *dlp;
1058 struct strbuf ctl, data;
1059
1060 /* Set up the control information... */
1061 dlp = (union DL_primitives *)buf;
1062 dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ;
1063 dlp -> unitdata_req.dl_dest_addr_length = addrlen;
1064 dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
1065 dlp -> unitdata_req.dl_priority.dl_min = minpri;
1066 dlp -> unitdata_req.dl_priority.dl_max = maxpri;
1067
1068 /* Append the destination address */
1069 memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
1070 addr, addrlen);
1071
1072 ctl.maxlen = 0;
1073 ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
1074 ctl.buf = (char *)buf;
1075
1076 data.maxlen = 0;
1077 data.buf = (char *)dbuf;
1078 data.len = dbuflen;
1079
1080 /* Send the packet down the wire... */
1081 return putmsg (fd, &ctl, &data, 0);
1082 }
1083
1084 static int dlpiunitdataind (fd, daddr, daddrlen,
1085 saddr, saddrlen, grpaddr, dbuf, dlen)
1086 int fd;
1087 unsigned char *daddr;
1088 unsigned long *daddrlen;
1089 unsigned char *saddr;
1090 unsigned long *saddrlen;
1091 unsigned long *grpaddr;
1092 unsigned char *dbuf;
1093 int dlen;
1094 {
1095 long buf [DLPI_MAXDLBUF];
1096 union DL_primitives *dlp;
1097 struct strbuf ctl, data;
1098 int flags = 0;
1099 int result;
1100
1101 /* Set up the msg_buf structure... */
1102 dlp = (union DL_primitives *)buf;
1103 dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
1104
1105 ctl.maxlen = DLPI_MAXDLBUF;
1106 ctl.len = 0;
1107 ctl.buf = (char *)buf;
1108
1109 data.maxlen = dlen;
1110 data.len = 0;
1111 data.buf = (char *)dbuf;
1112
1113 result = getmsg (fd, &ctl, &data, &flags);
1114
1115 if (result != 0) {
1116 return -1;
1117 }
1118
1119 if (ctl.len < sizeof (dl_unitdata_ind_t) ||
1120 dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
1121 return -1;
1122 }
1123
1124 if (data.len <= 0) {
1125 return data.len;
1126 }
1127
1128 /* Copy sender info */
1129 if (saddr) {
1130 memcpy (saddr, &buf [dlp -> unitdata_ind.dl_src_addr_offset],
1131 dlp -> unitdata_ind.dl_src_addr_length);
1132 }
1133 if (saddrlen) {
1134 *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
1135 }
1136
1137 /* Copy destination info */
1138 if (daddr) {
1139 memcpy (daddr, &buf [dlp -> unitdata_ind.dl_dest_addr_offset],
1140 dlp -> unitdata_ind.dl_dest_addr_length);
1141 }
1142 if (daddrlen) {
1143 *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
1144 }
1145
1146 if (grpaddr) {
1147 *grpaddr = dlp -> unitdata_ind.dl_group_address;
1148 }
1149
1150 return data.len;
1151 }
1152
1153 /*
1154 * expected - see if we got what we wanted.
1155 */
1156 static int expected (prim, dlp, msgflags)
1157 unsigned long prim;
1158 union DL_primitives *dlp;
1159 int msgflags;
1160 {
1161 if (msgflags != RS_HIPRI) {
1162 /* Message was not M_PCPROTO */
1163 return 0;
1164 }
1165
1166 if (dlp -> dl_primitive != prim) {
1167 /* Incorrect/unexpected return message */
1168 return 0;
1169 }
1170
1171 return 1;
1172 }
1173
1174 /*
1175 * strgetmsg - get a message from a stream, with timeout.
1176 */
1177 static int strgetmsg (fd, ctlp, datap, flagsp, caller)
1178 struct strbuf *ctlp, *datap;
1179 char *caller;
1180 int *flagsp;
1181 int fd;
1182 {
1183 int result;
1184 #ifdef USE_POLL
1185 struct pollfd pfd;
1186 int count;
1187 time_t now;
1188 time_t starttime;
1189 int to_msec;
1190 #endif
1191
1192 #ifdef USE_POLL
1193 pfd.fd = fd;
1194 pfd.events = POLLPRI; /* We're only interested in knowing
1195 * when we can receive the next high
1196 * priority message.
1197 */
1198 pfd.revents = 0;
1199
1200 now = time (&starttime);
1201 while (now <= starttime + DLPI_MAXWAIT) {
1202 to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000;
1203 count = poll (&pfd, 1, to_msec);
1204
1205 if (count == 0) {
1206 /* log_fatal ("strgetmsg: timeout"); */
1207 return -1;
1208 } else if (count < 0) {
1209 if (errno == EAGAIN || errno == EINTR) {
1210 time (&now);
1211 continue;
1212 } else {
1213 /* log_fatal ("poll: %m"); */
1214 return -1;
1215 }
1216 } else {
1217 break;
1218 }
1219 }
1220 #else /* defined (USE_POLL) */
1221 /*
1222 * Start timer. Can't use select, since it might return true if there
1223 * were non High-Priority data available on the stream.
1224 */
1225 (void) sigset (SIGALRM, sigalrm);
1226
1227 if (alarm (DLPI_MAXWAIT) < 0) {
1228 /* log_fatal ("alarm: %m"); */
1229 return -1;
1230 }
1231 #endif /* !defined (USE_POLL) */
1232
1233 /*
1234 * Set flags argument and issue getmsg ().
1235 */
1236 *flagsp = 0;
1237 if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
1238 return result;
1239 }
1240
1241 #ifndef USE_POLL
1242 /*
1243 * Stop timer.
1244 */
1245 if (alarm (0) < 0) {
1246 /* log_fatal ("alarm: %m"); */
1247 return -1;
1248 }
1249 #endif
1250
1251 /*
1252 * Check for MOREDATA and/or MORECTL.
1253 */
1254 if (result & (MORECTL|MOREDATA)) {
1255 return -1;
1256 }
1257
1258 /*
1259 * Check for at least sizeof (long) control data portion.
1260 */
1261 if (ctlp -> len < sizeof (long)) {
1262 return -1;
1263 }
1264
1265 return 0;
1266 }
1267
1268 #ifndef USE_POLL
1269 /*
1270 * sigalrm - handle alarms.
1271 */
1272 static void sigalrm (sig)
1273 int sig;
1274 {
1275 fprintf (stderr, "strgetmsg: timeout");
1276 exit (1);
1277 }
1278 #endif /* !defined (USE_POLL) */
1279
1280 int can_unicast_without_arp (ip)
1281 struct interface_info *ip;
1282 {
1283 return 1;
1284 }
1285
1286 int can_receive_unicast_unconfigured (ip)
1287 struct interface_info *ip;
1288 {
1289 return 1;
1290 }
1291
1292 void maybe_setup_fallback ()
1293 {
1294 isc_result_t status;
1295 struct interface_info *fbi;
1296 fbi = setup_fallback ();
1297 if (fbi) {
1298 if_register_fallback (fbi);
1299 fbi -> refcnt = 1;
1300 fbi -> type = dhcp_type_interface;
1301 status = omapi_register_io_object ((omapi_object_t *)fbi,
1302 if_readsocket, 0,
1303 fallback_discard, 0, 0);
1304 if (status != ISC_R_SUCCESS)
1305 log_fatal ("Can't register I/O handle for %s: %s",
1306 fbi -> name, isc_result_totext (status));
1307 }
1308 }
1309 #endif /* USE_DLPI */