]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/dlpi.c
- Fix all the OMAPI objects in the DHCP server and client that weren't
[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-2000 Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
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.
21 *
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
34 * SUCH DAMAGE.
35 *
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''.
39 */
40
41 /*
42 * Based largely in part to the existing NIT code in nit.c.
43 *
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
46 * generic, though.
47 */
48
49 /*
50 * Implementation notes:
51 *
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).
57 *
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
61 * USE_DLPI_RAW.
62 *
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.
68 *
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
82 * to sleep.
83 */
84
85 #ifndef lint
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";
88 #endif /* not lint */
89
90 #include "dhcpd.h"
91
92 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
93
94 # include <sys/ioctl.h>
95 # include <sys/time.h>
96 # include <sys/dlpi.h>
97 # include <stropts.h>
98 # ifdef USE_DLPI_PFMOD
99 # include <sys/pfmod.h>
100 # endif
101 # ifdef USE_POLL
102 # include <poll.h>
103 # endif
104
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"
109
110 # ifdef USE_DLPI_PFMOD
111 # ifdef USE_DLPI_RAW
112 # define DLPI_MODNAME "DLPI+RAW+PFMOD"
113 # else
114 # define DLPI_MODNAME "DLPI+PFMOD"
115 # endif
116 # else
117 # ifdef USE_DLPI_RAW
118 # define DLPI_MODNAME "DLPI+RAW"
119 # else
120 # define DLPI_MODNAME "DLPI"
121 # endif
122 # endif
123
124 # ifndef ABS
125 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
126 # endif
127
128 static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp));
129
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 */
134
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,
141 int saplen));
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,
159 int datalen));
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,
166 unsigned char *data,
167 int datalen));
168
169 # ifndef USE_POLL
170 static void sigalrm PROTO ((int sig));
171 # endif
172 static int expected PROTO ((unsigned long prim, union DL_primitives *dlp,
173 int msgflags));
174 static int strgetmsg PROTO ((int fd, struct strbuf *ctlp,
175 struct strbuf *datap, int *flagsp,
176 char *caller));
177
178 /* Reinitializes the specified interface after an address change. This
179 is not required for packet-filter APIs. */
180
181 #ifdef USE_DLPI_SEND
182 void if_reinitialize_send (info)
183 struct interface_info *info;
184 {
185 }
186 #endif
187
188 #ifdef USE_DLPI_RECEIVE
189 void if_reinitialize_receive (info)
190 struct interface_info *info;
191 {
192 }
193 #endif
194
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
197 mask. */
198
199 int if_register_dlpi (info)
200 struct interface_info *info;
201 {
202 int sock;
203 int unit;
204 long buf [DLPI_MAXDLBUF];
205 union DL_primitives *dlp;
206
207 dlp = (union DL_primitives *)buf;
208
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);
212 }
213
214 /*
215 * Get information about the provider.
216 */
217
218 /*
219 * Submit a DL_INFO_REQ request, to find
220 * the dl_mac_type and dl_provider_style
221 */
222 if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
223 log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
224 } else {
225 switch (dlp -> info_ack.dl_mac_type) {
226 case DL_CSMACD: /* IEEE 802.3 */
227 case DL_ETHER:
228 info -> hw_address.hbuf [0] = HTYPE_ETHER;
229 break;
230 /* adding token ring 5/1999 - mayer@ping.at */
231 case DL_TPR:
232 info -> hw_address.hbuf [0] = HTYPE_IEEE802;
233 break;
234 case DL_FDDI:
235 info -> hw_address.hbuf [0] = HTYPE_FDDI;
236 break;
237 default:
238 log_fatal ("%s: unknown DLPI MAC type %ld",
239 info -> name,
240 dlp -> info_ack.dl_mac_type);
241 break;
242 }
243 }
244
245 if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
246 /*
247 * Attach to the device. If this fails, the device
248 * does not exist.
249 */
250 unit = dlpiunit (info -> name);
251
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);
255 }
256 }
257
258 /*
259 * Bind to the IP service access point (SAP), connectionless (CLDLS).
260 */
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);
264 }
265
266 /*
267 * Submit a DL_PHYS_ADDR_REQ request, to find
268 * the hardware address
269 */
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",
273 info -> name);
274 }
275
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);
280
281 #ifdef USE_DLPI_RAW
282 if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
283 log_fatal ("Can't set DLPI RAW mode for %s: %m",
284 info -> name);
285 }
286 #endif
287
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",
291 info -> name);
292 }
293 #endif
294
295 return sock;
296 }
297
298 static int
299 strioctl (fd, cmd, timeout, len, dp)
300 int fd;
301 int cmd;
302 int timeout;
303 int len;
304 char *dp;
305 {
306 struct strioctl sio;
307 int rslt;
308
309 sio.ic_cmd = cmd;
310 sio.ic_timout = timeout;
311 sio.ic_len = len;
312 sio.ic_dp = dp;
313
314 if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
315 return rslt;
316 } else {
317 return sio.ic_len;
318 }
319 }
320
321 #ifdef USE_DLPI_SEND
322 void if_register_send (info)
323 struct interface_info *info;
324 {
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;
330 # endif
331
332 info -> wfdesc = if_register_dlpi (info);
333
334 # ifdef USE_DLPI_PFMOD
335 /* Set up an PFMOD filter that rejects everything... */
336 pf.Pf_Priority = 0;
337 pf.Pf_FilterLen = 1;
338 pf.Pf_Filter [0] = ENF_PUSHZERO;
339
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);
344 }
345
346 # endif /* USE_DLPI_PFMOD */
347 #else /* !defined (USE_DLPI_RECEIVE) */
348 /*
349 * If using DLPI for both send and receive, simply re-use
350 * the read file descriptor that was set up earlier.
351 */
352 info -> wfdesc = info -> rfdesc;
353 #endif
354
355 if (!quiet_interface_discovery)
356 log_info ("Sending on DLPI/%s/%s%s%s",
357 info -> name,
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 : ""));
364
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));
369 # else
370 sleep (DLPI_FIRST_SEND_WAIT);
371 # endif
372 #endif
373 }
374
375 void if_deregister_send (info)
376 struct interface_info *info;
377 {
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);
382 #endif
383 info -> wfdesc = -1;
384
385 if (!quiet_interface_discovery)
386 log_info ("Disabling output on DLPI/%s/%s%s%s",
387 info -> name,
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 : ""));
394 }
395 #endif /* USE_DLPI_SEND */
396
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 */
401
402 void if_register_receive (info)
403 struct interface_info *info;
404 {
405 #ifdef USE_DLPI_PFMOD
406 struct packetfilt pf;
407 #endif
408
409 /* Open a DLPI device and hang it on this interface... */
410 info -> rfdesc = if_register_dlpi (info);
411
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
416 XXX header. */
417 pf.Pf_Priority = 0;
418 pf.Pf_FilterLen = 0;
419
420 #ifdef USE_DLPI_RAW
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);
432 #else
433 /*
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
440 * of an IP packet.
441 */
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);
450 #endif
451
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);
456 }
457 #endif
458
459 if (!quiet_interface_discovery)
460 log_info ("Listening on DLPI/%s/%s%s%s",
461 info -> name,
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 : ""));
468
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);
473 # else
474 sleep (DLPI_FIRST_SEND_WAIT);
475 # endif
476 #endif
477 }
478
479 void if_deregister_receive (info)
480 struct interface_info *info;
481 {
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);
486 #endif
487 info -> rfdesc = -1;
488
489 if (!quiet_interface_discovery)
490 log_info ("Disabling input on DLPI/%s/%s%s%s",
491 info -> name,
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 : ""));
498 }
499 #endif /* USE_DLPI_RECEIVE */
500
501 #ifdef USE_DLPI_SEND
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;
506 size_t len;
507 struct in_addr from;
508 struct sockaddr_in *to;
509 struct hardware *hto;
510 {
511 unsigned dbuflen;
512 unsigned char dbuf [1536];
513 unsigned char sap [2];
514 unsigned char dstaddr [DLPI_MAXDLADDR];
515 unsigned addrlen;
516 int saplen;
517 int result;
518
519 if (!strcmp (interface -> name, "fallback"))
520 return send_fallback (interface, packet, raw,
521 len, from, to, hto);
522
523 dbuflen = 0;
524
525 /* Assemble the headers... */
526 #ifdef USE_DLPI_RAW
527 assemble_hw_header (interface, dbuf, &dbuflen, hto);
528 #endif
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);
532
533 /* Copy the data into the buffer (yuk). */
534 memcpy (dbuf + dbuflen, raw, len);
535 dbuflen += len;
536
537 #ifdef USE_DLPI_RAW
538 result = write (interface -> wfdesc, dbuf, dbuflen);
539 #else
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
544 of the address */
545
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);
550 } else {
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.
554 */
555 unsigned char bcast_ether [DLPI_MAXDLADDR];
556
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);
561 }
562 addrlen = interface -> hw_address.hlen - 1 + ABS (saplen);
563
564 /* Send the packet down the wire... */
565 result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
566 0, 0, dbuf, dbuflen);
567 #endif
568 if (result < 0)
569 log_error ("send_packet: %m");
570 return result;
571 }
572 #endif /* USE_DLPI_SEND */
573
574 #ifdef USE_DLPI_RECEIVE
575 ssize_t receive_packet (interface, buf, len, from, hfrom)
576 struct interface_info *interface;
577 unsigned char *buf;
578 size_t len;
579 struct sockaddr_in *from;
580 struct hardware *hfrom;
581 {
582 unsigned char dbuf [1536];
583 unsigned char sap [2];
584 unsigned char srcaddr [DLPI_MAXDLADDR];
585 unsigned long srcaddrlen;
586 int saplen;
587 int flags = 0;
588 int length = 0;
589 int offset = 0;
590 int rslt;
591 int bufix = 0;
592
593 #ifdef USE_DLPI_RAW
594 length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
595 #else
596 length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
597 (unsigned long *)NULL, srcaddr, &srcaddrlen,
598 (unsigned long *)NULL, dbuf, sizeof (dbuf));
599 #endif
600
601 if (length <= 0) {
602 return length;
603 }
604
605 #ifndef USE_DLPI_RAW
606 /* Copy sender info */
607 /* XXX: Assumes ethernet, where SAP comes at end of haddr */
608 saplen = -2;
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);
615 } else if (hfrom) {
616 memset (hfrom, '\0', sizeof *hfrom);
617 }
618 #endif
619
620 /* Decode the IP and UDP headers... */
621 bufix = 0;
622 #ifdef USE_DLPI_RAW
623 /* Decode the physical header... */
624 offset = decode_hw_header (interface, dbuf, bufix, hfrom);
625
626 /* If a physical layer checksum failed (dunno of any
627 physical layer that supports this, but WTH), skip this
628 packet. */
629 if (offset < 0) {
630 return 0;
631 }
632 bufix += offset;
633 length -= offset;
634 #endif
635 offset = decode_udp_ip_header (interface, dbuf, bufix,
636 from, (unsigned char *)0, length);
637
638 /* If the IP or UDP checksum was bad, skip the packet... */
639 if (offset < 0) {
640 return 0;
641 }
642
643 bufix += offset;
644 length -= offset;
645
646 /* Copy out the data in the packet... */
647 memcpy (buf, &dbuf [bufix], length);
648 return length;
649 }
650 #endif
651
652 /* Common DLPI routines ...
653 *
654 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
655 *
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.
659 *
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
662 * generic, though.
663 *
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.
668 */
669
670 #define DLPI_MAXWAIT 15 /* Max timeout */
671
672 static void dlpi_makeaddr (physaddr, physaddrlen, sap, saplen, buf)
673 unsigned char *physaddr;
674 int physaddrlen;
675 unsigned char *sap;
676 int saplen;
677 unsigned char *buf;
678 {
679 /*
680 * If the saplen is negative, the SAP goes at the end of the address,
681 * otherwise it goes at the beginning.
682 */
683 if (saplen >= 0) {
684 memcpy ((char *)buf, (char *)sap, saplen);
685 memcpy ((char *)&buf [saplen], (char *)physaddr, physaddrlen);
686 } else {
687 memcpy ((char *)buf, (char *)physaddr, physaddrlen);
688 memcpy ((char *)&buf [physaddrlen], (char *)sap, 0 - saplen);
689 }
690 }
691
692 static void dlpi_parseaddr (buf, physaddr, physaddrlen, sap, saplen)
693 unsigned char *buf;
694 unsigned char *physaddr;
695 int physaddrlen;
696 unsigned char *sap;
697 int saplen;
698 {
699 /*
700 * If the saplen is negative, the SAP is at the end of the address,
701 * otherwise it is at the beginning.
702 */
703 if (saplen >= 0) {
704 memcpy ((char *)sap, (char *)buf, saplen);
705 memcpy ((char *)physaddr, (char *)&buf [saplen], physaddrlen);
706 } else {
707 memcpy ((char *)physaddr, (char *)buf, physaddrlen);
708 memcpy ((char *)sap, (char *)&buf [physaddrlen], 0 - saplen);
709 }
710 }
711
712 /*
713 * Parse an interface name and extract the unit number
714 */
715
716 static int dlpiunit (ifname)
717 char *ifname;
718 {
719 int fd;
720 char *cp, *dp, *ep;
721 int unit;
722
723 if (!ifname) {
724 return 0;
725 }
726
727 /* Advance to the end of the name */
728 cp = ifname;
729 while (*cp) cp++;
730 /* Back up to the start of the first digit */
731 while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
732
733 /* Convert the unit number */
734 unit = 0;
735 while (*cp >= '0' && *cp <= '9') {
736 unit *= 10;
737 unit += (*cp++ - '0');
738 }
739
740 return unit;
741 }
742
743 /*
744 * dlpiopen - open the DLPI device for a given interface name
745 */
746 static int dlpiopen (ifname)
747 char *ifname;
748 {
749 char devname [50];
750 char *cp, *dp, *ep;
751
752 if (!ifname) {
753 return -1;
754 }
755
756 /* Open a DLPI device */
757 if (*ifname == '/') {
758 dp = devname;
759 } else {
760 /* Prepend the device directory */
761 memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
762 dp = &devname [strlen (DLPI_DEVDIR)];
763 }
764
765 /* Find the end of the interface name */
766 ep = cp = ifname;
767 while (*ep)
768 ep++;
769 /* And back up to the first digit (unit number) */
770 while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
771 ep--;
772
773 /* Copy everything up to the unit number */
774 while (cp < ep) {
775 *dp++ = *cp++;
776 }
777 *dp = '\0';
778
779 return open (devname, O_RDWR, 0);
780 }
781
782 /*
783 * dlpiinforeq - request information about the data link provider.
784 */
785
786 static int dlpiinforeq (fd)
787 int fd;
788 {
789 dl_info_req_t info_req;
790 struct strbuf ctl;
791 int flags;
792
793 info_req.dl_primitive = DL_INFO_REQ;
794
795 ctl.maxlen = 0;
796 ctl.len = sizeof (info_req);
797 ctl.buf = (char *)&info_req;
798
799 flags = RS_HIPRI;
800
801 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
802 }
803
804 /*
805 * dlpiphysaddrreq - request the current physical address.
806 */
807 static int dlpiphysaddrreq (fd, addrtype)
808 int fd;
809 unsigned long addrtype;
810 {
811 dl_phys_addr_req_t physaddr_req;
812 struct strbuf ctl;
813 int flags;
814
815 physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
816 physaddr_req.dl_addr_type = addrtype;
817
818 ctl.maxlen = 0;
819 ctl.len = sizeof (physaddr_req);
820 ctl.buf = (char *)&physaddr_req;
821
822 flags = RS_HIPRI;
823
824 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
825 }
826
827 /*
828 * dlpiattachreq - send a request to attach to a specific unit.
829 */
830 static int dlpiattachreq (fd, ppa)
831 unsigned long ppa;
832 int fd;
833 {
834 dl_attach_req_t attach_req;
835 struct strbuf ctl;
836 int flags;
837
838 attach_req.dl_primitive = DL_ATTACH_REQ;
839 attach_req.dl_ppa = ppa;
840
841 ctl.maxlen = 0;
842 ctl.len = sizeof (attach_req);
843 ctl.buf = (char *)&attach_req;
844
845 flags = 0;
846
847 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
848 }
849
850 /*
851 * dlpibindreq - send a request to bind to a specific SAP address.
852 */
853 static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
854 unsigned long sap;
855 unsigned long max_conind;
856 unsigned long service_mode;
857 unsigned long conn_mgmt;
858 unsigned long xidtest;
859 int fd;
860 {
861 dl_bind_req_t bind_req;
862 struct strbuf ctl;
863 int flags;
864
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;
871
872 ctl.maxlen = 0;
873 ctl.len = sizeof (bind_req);
874 ctl.buf = (char *)&bind_req;
875
876 flags = 0;
877
878 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
879 }
880
881 /*
882 * dlpiunbindreq - send a request to unbind.
883 */
884 static int dlpiunbindreq (fd)
885 int fd;
886 {
887 dl_unbind_req_t unbind_req;
888 struct strbuf ctl;
889 int flags;
890
891 unbind_req.dl_primitive = DL_UNBIND_REQ;
892
893 ctl.maxlen = 0;
894 ctl.len = sizeof (unbind_req);
895 ctl.buf = (char *)&unbind_req;
896
897 flags = 0;
898
899 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
900 }
901
902
903 /*
904 * dlpidetachreq - send a request to detach.
905 */
906 static int dlpidetachreq (fd)
907 int fd;
908 {
909 dl_detach_req_t detach_req;
910 struct strbuf ctl;
911 int flags;
912
913 detach_req.dl_primitive = DL_DETACH_REQ;
914
915 ctl.maxlen = 0;
916 ctl.len = sizeof (detach_req);
917 ctl.buf = (char *)&detach_req;
918
919 flags = 0;
920
921 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
922 }
923
924
925 /*
926 * dlpibindack - receive an ack to a dlbindreq.
927 */
928 static int dlpibindack (fd, bufp)
929 char *bufp;
930 int fd;
931 {
932 union DL_primitives *dlp;
933 struct strbuf ctl;
934 int flags;
935
936 ctl.maxlen = DLPI_MAXDLBUF;
937 ctl.len = 0;
938 ctl.buf = bufp;
939
940 if (strgetmsg (fd, &ctl,
941 (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
942 return -1;
943 }
944
945 dlp = (union DL_primitives *)ctl.buf;
946
947 if (!expected (DL_BIND_ACK, dlp, flags) < 0) {
948 return -1;
949 }
950
951 if (ctl.len < sizeof (dl_bind_ack_t)) {
952 /* Returned structure is too short */
953 return -1;
954 }
955
956 return 0;
957 }
958
959 /*
960 * dlpiokack - general acknowledgement reception.
961 */
962 static int dlpiokack (fd, bufp)
963 char *bufp;
964 int fd;
965 {
966 union DL_primitives *dlp;
967 struct strbuf ctl;
968 int flags;
969
970 ctl.maxlen = DLPI_MAXDLBUF;
971 ctl.len = 0;
972 ctl.buf = bufp;
973
974 if (strgetmsg (fd, &ctl,
975 (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
976 return -1;
977 }
978
979 dlp = (union DL_primitives *)ctl.buf;
980
981 if (!expected (DL_OK_ACK, dlp, flags) < 0) {
982 return -1;
983 }
984
985 if (ctl.len < sizeof (dl_ok_ack_t)) {
986 /* Returned structure is too short */
987 return -1;
988 }
989
990 return 0;
991 }
992
993 /*
994 * dlpiinfoack - receive an ack to a dlinforeq.
995 */
996 static int dlpiinfoack (fd, bufp)
997 char *bufp;
998 int fd;
999 {
1000 union DL_primitives *dlp;
1001 struct strbuf ctl;
1002 int flags;
1003
1004 ctl.maxlen = DLPI_MAXDLBUF;
1005 ctl.len = 0;
1006 ctl.buf = bufp;
1007
1008 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1009 "dlpiinfoack") < 0) {
1010 return -1;
1011 }
1012
1013 dlp = (union DL_primitives *) ctl.buf;
1014
1015 if (!expected (DL_INFO_ACK, dlp, flags) < 0) {
1016 return -1;
1017 }
1018
1019 if (ctl.len < sizeof (dl_info_ack_t)) {
1020 /* Returned structure is too short */
1021 return -1;
1022 }
1023
1024 return 0;
1025 }
1026
1027 /*
1028 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1029 */
1030 int dlpiphysaddrack (fd, bufp)
1031 char *bufp;
1032 int fd;
1033 {
1034 union DL_primitives *dlp;
1035 struct strbuf ctl;
1036 int flags;
1037
1038 ctl.maxlen = DLPI_MAXDLBUF;
1039 ctl.len = 0;
1040 ctl.buf = bufp;
1041
1042 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1043 "dlpiphysaddrack") < 0) {
1044 return -1;
1045 }
1046
1047 dlp = (union DL_primitives *)ctl.buf;
1048
1049 if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) {
1050 return -1;
1051 }
1052
1053 if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
1054 /* Returned structure is too short */
1055 return -1;
1056 }
1057
1058 return 0;
1059 }
1060
1061 int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
1062 int fd;
1063 unsigned char *addr;
1064 int addrlen;
1065 unsigned long minpri;
1066 unsigned long maxpri;
1067 unsigned char *dbuf;
1068 int dbuflen;
1069 {
1070 long buf [DLPI_MAXDLBUF];
1071 union DL_primitives *dlp;
1072 struct strbuf ctl, data;
1073
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;
1081
1082 /* Append the destination address */
1083 memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
1084 addr, addrlen);
1085
1086 ctl.maxlen = 0;
1087 ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
1088 ctl.buf = (char *)buf;
1089
1090 data.maxlen = 0;
1091 data.buf = (char *)dbuf;
1092 data.len = dbuflen;
1093
1094 /* Send the packet down the wire... */
1095 return putmsg (fd, &ctl, &data, 0);
1096 }
1097
1098 static int dlpiunitdataind (fd, daddr, daddrlen,
1099 saddr, saddrlen, grpaddr, dbuf, dlen)
1100 int fd;
1101 unsigned char *daddr;
1102 unsigned long *daddrlen;
1103 unsigned char *saddr;
1104 unsigned long *saddrlen;
1105 unsigned long *grpaddr;
1106 unsigned char *dbuf;
1107 int dlen;
1108 {
1109 long buf [DLPI_MAXDLBUF];
1110 union DL_primitives *dlp;
1111 struct strbuf ctl, data;
1112 int flags = 0;
1113 int result;
1114
1115 /* Set up the msg_buf structure... */
1116 dlp = (union DL_primitives *)buf;
1117 dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
1118
1119 ctl.maxlen = DLPI_MAXDLBUF;
1120 ctl.len = 0;
1121 ctl.buf = (char *)buf;
1122
1123 data.maxlen = dlen;
1124 data.len = 0;
1125 data.buf = (char *)dbuf;
1126
1127 result = getmsg (fd, &ctl, &data, &flags);
1128
1129 if (result != 0) {
1130 return -1;
1131 }
1132
1133 if (ctl.len < sizeof (dl_unitdata_ind_t) ||
1134 dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
1135 return -1;
1136 }
1137
1138 if (data.len <= 0) {
1139 return data.len;
1140 }
1141
1142 /* Copy sender info */
1143 if (saddr) {
1144 memcpy (saddr, &buf [dlp -> unitdata_ind.dl_src_addr_offset],
1145 dlp -> unitdata_ind.dl_src_addr_length);
1146 }
1147 if (saddrlen) {
1148 *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
1149 }
1150
1151 /* Copy destination info */
1152 if (daddr) {
1153 memcpy (daddr, &buf [dlp -> unitdata_ind.dl_dest_addr_offset],
1154 dlp -> unitdata_ind.dl_dest_addr_length);
1155 }
1156 if (daddrlen) {
1157 *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
1158 }
1159
1160 if (grpaddr) {
1161 *grpaddr = dlp -> unitdata_ind.dl_group_address;
1162 }
1163
1164 return data.len;
1165 }
1166
1167 /*
1168 * expected - see if we got what we wanted.
1169 */
1170 static int expected (prim, dlp, msgflags)
1171 unsigned long prim;
1172 union DL_primitives *dlp;
1173 int msgflags;
1174 {
1175 if (msgflags != RS_HIPRI) {
1176 /* Message was not M_PCPROTO */
1177 return 0;
1178 }
1179
1180 if (dlp -> dl_primitive != prim) {
1181 /* Incorrect/unexpected return message */
1182 return 0;
1183 }
1184
1185 return 1;
1186 }
1187
1188 /*
1189 * strgetmsg - get a message from a stream, with timeout.
1190 */
1191 static int strgetmsg (fd, ctlp, datap, flagsp, caller)
1192 struct strbuf *ctlp, *datap;
1193 char *caller;
1194 int *flagsp;
1195 int fd;
1196 {
1197 int result;
1198 #ifdef USE_POLL
1199 struct pollfd pfd;
1200 int count;
1201 time_t now;
1202 time_t starttime;
1203 int to_msec;
1204 #endif
1205
1206 #ifdef USE_POLL
1207 pfd.fd = fd;
1208 pfd.events = POLLPRI; /* We're only interested in knowing
1209 * when we can receive the next high
1210 * priority message.
1211 */
1212 pfd.revents = 0;
1213
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);
1218
1219 if (count == 0) {
1220 /* log_fatal ("strgetmsg: timeout"); */
1221 return -1;
1222 } else if (count < 0) {
1223 if (errno == EAGAIN || errno == EINTR) {
1224 time (&now);
1225 continue;
1226 } else {
1227 /* log_fatal ("poll: %m"); */
1228 return -1;
1229 }
1230 } else {
1231 break;
1232 }
1233 }
1234 #else /* defined (USE_POLL) */
1235 /*
1236 * Start timer. Can't use select, since it might return true if there
1237 * were non High-Priority data available on the stream.
1238 */
1239 (void) sigset (SIGALRM, sigalrm);
1240
1241 if (alarm (DLPI_MAXWAIT) < 0) {
1242 /* log_fatal ("alarm: %m"); */
1243 return -1;
1244 }
1245 #endif /* !defined (USE_POLL) */
1246
1247 /*
1248 * Set flags argument and issue getmsg ().
1249 */
1250 *flagsp = 0;
1251 if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
1252 return result;
1253 }
1254
1255 #ifndef USE_POLL
1256 /*
1257 * Stop timer.
1258 */
1259 if (alarm (0) < 0) {
1260 /* log_fatal ("alarm: %m"); */
1261 return -1;
1262 }
1263 #endif
1264
1265 /*
1266 * Check for MOREDATA and/or MORECTL.
1267 */
1268 if (result & (MORECTL|MOREDATA)) {
1269 return -1;
1270 }
1271
1272 /*
1273 * Check for at least sizeof (long) control data portion.
1274 */
1275 if (ctlp -> len < sizeof (long)) {
1276 return -1;
1277 }
1278
1279 return 0;
1280 }
1281
1282 #ifndef USE_POLL
1283 /*
1284 * sigalrm - handle alarms.
1285 */
1286 static void sigalrm (sig)
1287 int sig;
1288 {
1289 fprintf (stderr, "strgetmsg: timeout");
1290 exit (1);
1291 }
1292 #endif /* !defined (USE_POLL) */
1293
1294 int can_unicast_without_arp (ip)
1295 struct interface_info *ip;
1296 {
1297 return 1;
1298 }
1299
1300 int can_receive_unicast_unconfigured (ip)
1301 struct interface_info *ip;
1302 {
1303 return 1;
1304 }
1305
1306 void maybe_setup_fallback ()
1307 {
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,
1313 if_readsocket, 0,
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));
1318 }
1319 }
1320 #endif /* USE_DLPI */