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