]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/dlpi.c
4700cf51539f23b977620219fb7663d880b0a91f
[thirdparty/dhcp.git] / common / dlpi.c
1 /* dlpi.c
2
3 Data Link Provider Interface (DLPI) network interface code. */
4
5 /*
6 * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
27 *
28 * This software was written for Internet Systems Consortium
29 * by Eric James Negaard, <lmdejn@lmd.ericsson.se>. To learn more about
30 * Internet Systems Consortium, see ``https://www.isc.org''.
31 *
32 * Joost Mulders has also done considerable work in debugging the DLPI API
33 * support on Solaris and getting this code to work properly on a variety
34 * of different Solaris platforms.
35 */
36
37 /*
38 * Based largely in part to the existing NIT code in nit.c.
39 *
40 * This code has been developed and tested on sparc-based machines running
41 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
42 * generic, though.
43 */
44
45 /*
46 * Implementation notes:
47 *
48 * I first tried to write this code to the "vanilla" DLPI 2.0 API.
49 * It worked on a Sun Ultra-1 with a hme interface, but didn't work
50 * on Sun SparcStation 5's with "le" interfaces (the packets sent out
51 * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead
52 * of the expected 0x0800).
53 *
54 * Therefore I added the "DLPI_RAW" code which is a Sun extension to
55 * the DLPI standard. This code works on both of the above machines.
56 * This is configurable in the OS-dependent include file by defining
57 * USE_DLPI_RAW.
58 *
59 * It quickly became apparant that I should also use the "pfmod"
60 * STREAMS module to cut down on the amount of user level packet
61 * processing. I don't know how widely available "pfmod" is, so it's
62 * use is conditionally included. This is configurable in the
63 * OS-dependent include file by defining USE_DLPI_PFMOD.
64 *
65 * A major quirk on the Sun's at least, is that no packets seem to get
66 * sent out the interface until six seconds after the interface is
67 * first "attached" to [per system reboot] (it's actually from when
68 * the interface is attached, not when it is plumbed, so putting a
69 * sleep into the dhclient-script at PREINIT time doesn't help). I
70 * HAVE tried, without success to poll the fd to see when it is ready
71 * for writing. This doesn't help at all. If the sleeps are not done,
72 * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so
73 * I've put them here, when register_send and register_receive are
74 * called (split up into two three-second sleeps between the notices,
75 * so that it doesn't seem like so long when you're watching :-). The
76 * amount of time to sleep is configurable in the OS-dependent include
77 * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds
78 * to sleep.
79 */
80
81 /*
82 * The Open Group Technical Standard can be found here:
83 * http://www.opengroup.org/onlinepubs/009618899/index.htm
84 *
85 * The HP DLPI Programmer's Guide can be found here:
86 * http://docs.hp.com/en/B2355-90139/index.html
87 */
88
89 #include "dhcpd.h"
90
91 #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) || \
92 defined(USE_DLPI_HWADDR)
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 #include <poll.h>
102 #include <errno.h>
103
104 # include <netinet/in_systm.h>
105 # include "includes/netinet/ip.h"
106 # include "includes/netinet/udp.h"
107 # include "includes/netinet/if_ether.h"
108
109 # ifdef USE_DLPI_PFMOD
110 # ifdef USE_DLPI_RAW
111 # define DLPI_MODNAME "DLPI+RAW+PFMOD"
112 # else
113 # define DLPI_MODNAME "DLPI+PFMOD"
114 # endif
115 # else
116 # ifdef USE_DLPI_RAW
117 # define DLPI_MODNAME "DLPI+RAW"
118 # else
119 # define DLPI_MODNAME "DLPI"
120 # endif
121 # endif
122
123 # ifndef ABS
124 # define ABS(x) ((x) >= 0 ? (x) : 0-(x))
125 # endif
126
127 #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
128 static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp));
129 #endif
130
131 #define DLPI_MAXDLBUF 8192 /* Buffer size */
132 #define DLPI_MAXDLADDR 1024 /* Max address size */
133 #define DLPI_DEVDIR "/dev/" /* Device directory */
134
135 static int dlpiopen(const char *ifname);
136 static int dlpiunit PROTO ((char *ifname));
137 static int dlpiinforeq PROTO ((int fd));
138 static int dlpiphysaddrreq PROTO ((int fd, unsigned long addrtype));
139 static int dlpiattachreq PROTO ((int fd, unsigned long ppa));
140 static int dlpibindreq PROTO ((int fd, unsigned long sap, unsigned long max_conind,
141 unsigned long service_mode, unsigned long conn_mgmt,
142 unsigned long xidtest));
143 #if defined(UNUSED_DLPI_INTERFACE)
144 /* These functions are unused at present, but may be used at a later date.
145 * defined out to avoid compiler warnings about unused static functions.
146 */
147 static int dlpidetachreq PROTO ((int fd));
148 static int dlpiunbindreq PROTO ((int fd));
149 #endif
150 static int dlpiokack PROTO ((int fd, char *bufp));
151 static int dlpiinfoack PROTO ((int fd, char *bufp));
152 static int dlpiphysaddrack PROTO ((int fd, char *bufp));
153 static int dlpibindack PROTO ((int fd, char *bufp));
154 #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
155 /* These functions are not used if we're only sourcing the get_hw_addr()
156 * function (for USE_SOCKETS).
157 */
158 static int dlpiunitdatareq PROTO ((int fd, unsigned char *addr,
159 int addrlen, unsigned long minpri,
160 unsigned long maxpri, unsigned char *data,
161 int datalen));
162 static int dlpiunitdataind PROTO ((int fd,
163 unsigned char *dstaddr,
164 unsigned long *dstaddrlen,
165 unsigned char *srcaddr,
166 unsigned long *srcaddrlen,
167 unsigned long *grpaddr,
168 unsigned char *data,
169 int datalen));
170 #endif /* !USE_DLPI_HWADDR: USE_DLPI_SEND || USE_DLPI_RECEIVE */
171 static int expected PROTO ((unsigned long prim, union DL_primitives *dlp,
172 int msgflags));
173 static int strgetmsg PROTO ((int fd, struct strbuf *ctlp,
174 struct strbuf *datap, int *flagsp,
175 char *caller));
176
177 /* Reinitializes the specified interface after an address change. This
178 is not required for packet-filter APIs. */
179
180 #ifdef USE_DLPI_SEND
181 void if_reinitialize_send (info)
182 struct interface_info *info;
183 {
184 }
185 #endif
186
187 #ifdef USE_DLPI_RECEIVE
188 void if_reinitialize_receive (info)
189 struct interface_info *info;
190 {
191 }
192 #endif
193
194 /* Called by get_interface_list for each interface that's discovered.
195 Opens a packet filter for each interface and adds it to the select
196 mask. */
197
198 int if_register_dlpi (info)
199 struct interface_info *info;
200 {
201 int sock;
202 int unit;
203 long buf [DLPI_MAXDLBUF];
204 union DL_primitives *dlp;
205
206 dlp = (union DL_primitives *)buf;
207
208 /* Open a DLPI device */
209 if ((sock = dlpiopen (info -> name)) < 0) {
210 log_fatal ("Can't open DLPI device for %s: %m", info -> name);
211 }
212
213 /*
214 * Submit a DL_INFO_REQ request, to find the dl_mac_type and
215 * dl_provider_style
216 */
217 if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
218 log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
219 } else {
220 switch (dlp -> info_ack.dl_mac_type) {
221 case DL_CSMACD: /* IEEE 802.3 */
222 case DL_ETHER:
223 info -> hw_address.hbuf [0] = HTYPE_ETHER;
224 break;
225 /* adding token ring 5/1999 - mayer@ping.at */
226 case DL_TPR:
227 info -> hw_address.hbuf [0] = HTYPE_IEEE802;
228 break;
229 case DL_FDDI:
230 info -> hw_address.hbuf [0] = HTYPE_FDDI;
231 break;
232 default:
233 log_fatal("%s: unsupported DLPI MAC type %lu", info->name,
234 (unsigned long)dlp->info_ack.dl_mac_type);
235 break;
236 }
237 /*
238 * copy the sap length and broadcast address of this interface
239 * to interface_info. This fixes nothing but seemed nicer than to
240 * assume -2 and ffffff.
241 */
242 info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length;
243 info -> dlpi_broadcast_addr.hlen =
244 dlp -> info_ack.dl_brdcst_addr_length;
245 memcpy (info -> dlpi_broadcast_addr.hbuf,
246 (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset,
247 dlp -> info_ack.dl_brdcst_addr_length);
248 }
249
250 if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
251 /*
252 * Attach to the device. If this fails, the device
253 * does not exist.
254 */
255 unit = dlpiunit (info -> name);
256
257 if (dlpiattachreq (sock, unit) < 0
258 || dlpiokack (sock, (char *)buf) < 0) {
259 log_fatal ("Can't attach DLPI device for %s: %m", info -> name);
260 }
261 }
262
263 /*
264 * Bind to the IP service access point (SAP), connectionless (CLDLS).
265 */
266 if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0
267 || dlpibindack (sock, (char *)buf) < 0) {
268 log_fatal ("Can't bind DLPI device for %s: %m", info -> name);
269 }
270
271 /*
272 * Submit a DL_PHYS_ADDR_REQ request, to find
273 * the hardware address
274 */
275 if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0
276 || dlpiphysaddrack (sock, (char *)buf) < 0) {
277 log_fatal ("Can't get DLPI hardware address for %s: %m",
278 info -> name);
279 }
280
281 info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1;
282 memcpy (&info -> hw_address.hbuf [1],
283 (char *)buf + dlp -> physaddr_ack.dl_addr_offset,
284 dlp -> physaddr_ack.dl_addr_length);
285
286 #ifdef USE_DLPI_RAW
287 if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
288 log_fatal ("Can't set DLPI RAW mode for %s: %m",
289 info -> name);
290 }
291 #endif
292
293 #ifdef USE_DLPI_PFMOD
294 if (ioctl (sock, I_PUSH, "pfmod") < 0) {
295 log_fatal ("Can't push packet filter onto DLPI for %s: %m",
296 info -> name);
297 }
298 #endif
299
300 return sock;
301 }
302
303 #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
304 static int
305 strioctl (fd, cmd, timeout, len, dp)
306 int fd;
307 int cmd;
308 int timeout;
309 int len;
310 char *dp;
311 {
312 struct strioctl sio;
313 int rslt;
314
315 sio.ic_cmd = cmd;
316 sio.ic_timout = timeout;
317 sio.ic_len = len;
318 sio.ic_dp = dp;
319
320 if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
321 return rslt;
322 } else {
323 return sio.ic_len;
324 }
325 }
326 #endif /* USE_DPI_PFMOD || USE_DLPI_RAW */
327
328 #ifdef USE_DLPI_SEND
329 void if_register_send (info)
330 struct interface_info *info;
331 {
332 /* If we're using the DLPI API for sending and receiving,
333 we don't need to register this interface twice. */
334 #ifndef USE_DLPI_RECEIVE
335 # ifdef USE_DLPI_PFMOD
336 struct packetfilt pf;
337 # endif
338
339 info -> wfdesc = if_register_dlpi (info);
340
341 # ifdef USE_DLPI_PFMOD
342 /* Set up an PFMOD filter that rejects everything... */
343 pf.Pf_Priority = 0;
344 pf.Pf_FilterLen = 1;
345 pf.Pf_Filter [0] = ENF_PUSHZERO;
346
347 /* Install the filter */
348 if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM,
349 sizeof (pf), (char *)&pf) < 0) {
350 log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name);
351 }
352
353 # endif /* USE_DLPI_PFMOD */
354 #else /* !defined (USE_DLPI_RECEIVE) */
355 /*
356 * If using DLPI for both send and receive, simply re-use
357 * the read file descriptor that was set up earlier.
358 */
359 info -> wfdesc = info -> rfdesc;
360 #endif
361
362 if (!quiet_interface_discovery)
363 log_info ("Sending on DLPI/%s/%s%s%s",
364 info -> name,
365 print_hw_addr (info -> hw_address.hbuf [0],
366 info -> hw_address.hlen - 1,
367 &info -> hw_address.hbuf [1]),
368 (info -> shared_network ? "/" : ""),
369 (info -> shared_network ?
370 info -> shared_network -> name : ""));
371
372 #ifdef DLPI_FIRST_SEND_WAIT
373 /* See the implementation notes at the beginning of this file */
374 # ifdef USE_DLPI_RECEIVE
375 sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2));
376 # else
377 sleep (DLPI_FIRST_SEND_WAIT);
378 # endif
379 #endif
380 }
381
382 void if_deregister_send (info)
383 struct interface_info *info;
384 {
385 /* If we're using the DLPI API for sending and receiving,
386 we don't need to register this interface twice. */
387 #ifndef USE_DLPI_RECEIVE
388 close (info -> wfdesc);
389 #endif
390 info -> wfdesc = -1;
391
392 if (!quiet_interface_discovery)
393 log_info ("Disabling output on DLPI/%s/%s%s%s",
394 info -> name,
395 print_hw_addr (info -> hw_address.hbuf [0],
396 info -> hw_address.hlen - 1,
397 &info -> hw_address.hbuf [1]),
398 (info -> shared_network ? "/" : ""),
399 (info -> shared_network ?
400 info -> shared_network -> name : ""));
401 }
402 #endif /* USE_DLPI_SEND */
403
404 #ifdef USE_DLPI_RECEIVE
405 /* Packet filter program...
406 XXX Changes to the filter program may require changes to the constant
407 offsets used in if_register_send to patch the NIT program! XXX */
408
409 void if_register_receive (info)
410 struct interface_info *info;
411 {
412 #ifdef USE_DLPI_PFMOD
413 struct packetfilt pf;
414 struct ip iphdr;
415 u_int16_t offset;
416 #endif
417
418 /* Open a DLPI device and hang it on this interface... */
419 info -> rfdesc = if_register_dlpi (info);
420
421 #ifdef USE_DLPI_PFMOD
422 /* Set up the PFMOD filter program. */
423 /* XXX Unlike the BPF filter program, this one won't work if the
424 XXX IP packet is fragmented or if there are options on the IP
425 XXX header. */
426 pf.Pf_Priority = 0;
427 pf.Pf_FilterLen = 0;
428
429 #if defined (USE_DLPI_RAW)
430 # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
431 /*
432 * ethertype == ETHERTYPE_IP
433 */
434 offset = 12;
435 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
436 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
437 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
438 # else
439 # define ETHER_H_PREFIX (0)
440 # endif /* USE_DLPI_RAW */
441 /*
442 * The packets that will be received on this file descriptor
443 * will be IP packets (due to the SAP that was specified in
444 * the dlbind call). There will be no ethernet header.
445 * Therefore, setup the packet filter to check the protocol
446 * field for UDP, and the destination port number equal
447 * to the local port. All offsets are relative to the start
448 * of an IP packet.
449 */
450
451 /*
452 * BOOTPS destination port
453 */
454 offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t);
455 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
456 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
457 pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
458
459 /*
460 * protocol should be udp. this is a byte compare, test for
461 * endianess.
462 */
463 offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr);
464 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
465 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND;
466 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF);
467 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
468 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
469
470 /* Install the filter... */
471 if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
472 sizeof (pf), (char *)&pf) < 0) {
473 log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name);
474 }
475 #endif /* USE_DLPI_PFMOD */
476
477 if (!quiet_interface_discovery)
478 log_info ("Listening on DLPI/%s/%s%s%s",
479 info -> name,
480 print_hw_addr (info -> hw_address.hbuf [0],
481 info -> hw_address.hlen - 1,
482 &info -> hw_address.hbuf [1]),
483 (info -> shared_network ? "/" : ""),
484 (info -> shared_network ?
485 info -> shared_network -> name : ""));
486
487 #ifdef DLPI_FIRST_SEND_WAIT
488 /* See the implementation notes at the beginning of this file */
489 # ifdef USE_DLPI_SEND
490 sleep (DLPI_FIRST_SEND_WAIT / 2);
491 # else
492 sleep (DLPI_FIRST_SEND_WAIT);
493 # endif
494 #endif
495 }
496
497 void if_deregister_receive (info)
498 struct interface_info *info;
499 {
500 /* If we're using the DLPI API for sending and receiving,
501 we don't need to register this interface twice. */
502 #ifndef USE_DLPI_SEND
503 close (info -> rfdesc);
504 #endif
505 info -> rfdesc = -1;
506
507 if (!quiet_interface_discovery)
508 log_info ("Disabling input on DLPI/%s/%s%s%s",
509 info -> name,
510 print_hw_addr (info -> hw_address.hbuf [0],
511 info -> hw_address.hlen - 1,
512 &info -> hw_address.hbuf [1]),
513 (info -> shared_network ? "/" : ""),
514 (info -> shared_network ?
515 info -> shared_network -> name : ""));
516 }
517 #endif /* USE_DLPI_RECEIVE */
518
519 #ifdef USE_DLPI_SEND
520 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
521 struct interface_info *interface;
522 struct packet *packet;
523 struct dhcp_packet *raw;
524 size_t len;
525 struct in_addr from;
526 struct sockaddr_in *to;
527 struct hardware *hto;
528 {
529 #ifdef USE_DLPI_RAW
530 double hh [32];
531 #endif
532 double ih [1536 / sizeof (double)];
533 unsigned char *dbuf = (unsigned char *)ih;
534 unsigned dbuflen;
535 unsigned char dstaddr [DLPI_MAXDLADDR];
536 unsigned addrlen;
537 int result;
538 int fudge;
539
540 if (!strcmp (interface -> name, "fallback"))
541 return send_fallback (interface, packet, raw,
542 len, from, to, hto);
543
544 if (hto == NULL && interface->anycast_mac_addr.hlen)
545 hto = &interface->anycast_mac_addr;
546
547 dbuflen = 0;
548
549 /* Assemble the headers... */
550 #ifdef USE_DLPI_RAW
551 assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto);
552 if (dbuflen > sizeof hh)
553 log_fatal ("send_packet: hh buffer too small.\n");
554 fudge = dbuflen % 4; /* IP header must be word-aligned. */
555 memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen);
556 dbuflen += fudge;
557 #else
558 fudge = 0;
559 #endif
560 assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr,
561 to -> sin_addr.s_addr, to -> sin_port,
562 (unsigned char *)raw, len);
563
564 /* Copy the data into the buffer (yuk). */
565 memcpy (dbuf + dbuflen, raw, len);
566 dbuflen += len;
567
568 #ifdef USE_DLPI_RAW
569 result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
570 #else
571
572 /*
573 * Setup the destination address (DLSAP) in dstaddr
574 *
575 * If sap_length < 0 we must deliver the DLSAP as phys+sap.
576 * If sap_length > 0 we must deliver the DLSAP as sap+phys.
577 *
578 * sap = Service Access Point == ETHERTYPE_IP
579 * sap + datalink address is called DLSAP in dlpi speak.
580 */
581 { /* ENCODE DLSAP */
582 unsigned char phys [DLPI_MAXDLADDR];
583 unsigned char sap [4];
584 int sap_len = interface -> dlpi_sap_length;
585 int phys_len = interface -> hw_address.hlen - 1;
586
587 /* sap = htons (ETHERTYPE_IP) kludge */
588 memset (sap, 0, sizeof (sap));
589 # if (BYTE_ORDER == LITTLE_ENDIAN)
590 sap [0] = 0x00;
591 sap [1] = 0x08;
592 # else
593 sap [0] = 0x08;
594 sap [1] = 0x00;
595 # endif
596
597 if (hto && hto -> hlen == interface -> hw_address.hlen)
598 memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
599 else
600 memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf,
601 interface -> dlpi_broadcast_addr.hlen);
602
603 if (sap_len < 0) {
604 memcpy ( dstaddr, phys, phys_len);
605 memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
606 }
607 else {
608 memcpy ( dstaddr, (void *) sap, sap_len);
609 memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
610 }
611 addrlen = phys_len + ABS (sap_len);
612 } /* ENCODE DLSAP */
613
614 result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
615 0, 0, dbuf, dbuflen);
616 #endif /* USE_DLPI_RAW */
617 if (result < 0)
618 log_error ("send_packet: %m");
619 return result;
620 }
621 #endif /* USE_DLPI_SEND */
622
623 #ifdef USE_DLPI_RECEIVE
624 ssize_t receive_packet (interface, buf, len, from, hfrom)
625 struct interface_info *interface;
626 unsigned char *buf;
627 size_t len;
628 struct sockaddr_in *from;
629 struct hardware *hfrom;
630 {
631 unsigned char dbuf [1536];
632 unsigned char srcaddr [DLPI_MAXDLADDR];
633 unsigned long srcaddrlen;
634 int length = 0;
635 int offset = 0;
636 int bufix = 0;
637 unsigned paylen;
638
639 #ifdef USE_DLPI_RAW
640 length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
641 #else
642 length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
643 (unsigned long *)NULL, srcaddr, &srcaddrlen,
644 (unsigned long *)NULL, dbuf, sizeof (dbuf));
645 #endif
646
647 if (length <= 0) {
648 log_error("receive_packet: %m");
649 return length;
650 }
651
652 # if !defined (USE_DLPI_RAW)
653 /*
654 * Copy the sender's hw address into hfrom
655 * If sap_len < 0 the DLSAP is as phys+sap.
656 * If sap_len > 0 the DLSAP is as sap+phys.
657 *
658 * sap is discarded here.
659 */
660 { /* DECODE DLSAP */
661 int sap_len = interface -> dlpi_sap_length;
662 int phys_len = interface -> hw_address.hlen - 1;
663
664 if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) {
665 hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
666 hfrom -> hlen = interface -> hw_address.hlen;
667
668 if (sap_len < 0) {
669 memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
670 }
671 else {
672 memcpy((char *)&hfrom->hbuf[1], srcaddr + sap_len, phys_len);
673 }
674 }
675 else if (hfrom) {
676 memset (hfrom, '\0', sizeof *hfrom);
677 }
678 } /* DECODE_DLSAP */
679
680 # endif /* !defined (USE_DLPI_RAW) */
681
682 /* Decode the IP and UDP headers... */
683 bufix = 0;
684 #ifdef USE_DLPI_RAW
685 /* Decode the physical header... */
686 offset = decode_hw_header (interface, dbuf, bufix, hfrom);
687
688 /* If a physical layer checksum failed (dunno of any
689 physical layer that supports this, but WTH), skip this
690 packet. */
691 if (offset < 0) {
692 return 0;
693 }
694 bufix += offset;
695 length -= offset;
696 #endif
697 offset = decode_udp_ip_header (interface, dbuf, bufix,
698 from, length, &paylen);
699
700 /*
701 * If the IP or UDP checksum was bad, skip the packet...
702 *
703 * Note: this happens all the time when writing packets via the
704 * fallback socket. The packet received by streams does not have
705 * the IP or UDP checksums filled in, as those are calculated by
706 * the hardware.
707 */
708 if (offset < 0) {
709 return 0;
710 }
711
712 bufix += offset;
713 length -= offset;
714
715 if (length < paylen)
716 log_fatal("Internal inconsistency at %s:%d.", MDL);
717
718 /* Copy out the data in the packet... */
719 memcpy(buf, &dbuf [bufix], paylen);
720 return paylen;
721 }
722 #endif
723
724 /* Common DLPI routines ...
725 *
726 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
727 *
728 * Based largely in part to the example code contained in the document
729 * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
730 * by Neal Nuckolls of SunSoft Internet Engineering.
731 *
732 * This code has been developed and tested on sparc-based machines running
733 * SunOS 5.5.1, with le and hme network interfaces. It should be pretty
734 * generic, though.
735 *
736 * The usual disclaimers apply. This code works for me. Don't blame me
737 * if it makes your machine or network go down in flames. That taken
738 * into consideration, use this code as you wish. If you make usefull
739 * modifications I'd appreciate hearing about it.
740 */
741
742 #define DLPI_MAXWAIT 15 /* Max timeout */
743
744
745 /*
746 * Parse an interface name and extract the unit number
747 */
748
749 static int dlpiunit (ifname)
750 char *ifname;
751 {
752 char *cp;
753 int unit;
754
755 if (!ifname) {
756 return 0;
757 }
758
759 /* Advance to the end of the name */
760 cp = ifname;
761 while (*cp) cp++;
762 /* Back up to the start of the first digit */
763 while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
764
765 /* Convert the unit number */
766 unit = 0;
767 while (*cp >= '0' && *cp <= '9') {
768 unit *= 10;
769 unit += (*cp++ - '0');
770 }
771
772 return unit;
773 }
774
775 /*
776 * dlpiopen - open the DLPI device for a given interface name
777 */
778 static int
779 dlpiopen(const char *ifname) {
780 char devname [50];
781 char *dp;
782 const char *cp, *ep;
783
784 if (!ifname) {
785 return -1;
786 }
787
788 /* Open a DLPI device */
789 if (*ifname == '/') {
790 dp = devname;
791 } else {
792 /* Prepend the device directory */
793 memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
794 dp = &devname [strlen (DLPI_DEVDIR)];
795 }
796
797 /* Find the end of the interface name */
798 ep = cp = ifname;
799 while (*ep)
800 ep++;
801 /* And back up to the first digit (unit number) */
802 while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
803 ep--;
804
805 /* Copy everything up to the unit number */
806 while (cp < ep) {
807 *dp++ = *cp++;
808 }
809 *dp = '\0';
810
811 return open (devname, O_RDWR, 0);
812 }
813
814 /*
815 * dlpiinforeq - request information about the data link provider.
816 */
817
818 static int dlpiinforeq (fd)
819 int fd;
820 {
821 dl_info_req_t info_req;
822 struct strbuf ctl;
823 int flags;
824
825 info_req.dl_primitive = DL_INFO_REQ;
826
827 ctl.maxlen = 0;
828 ctl.len = sizeof (info_req);
829 ctl.buf = (char *)&info_req;
830
831 flags = RS_HIPRI;
832
833 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
834 }
835
836 /*
837 * dlpiphysaddrreq - request the current physical address.
838 */
839 static int dlpiphysaddrreq (fd, addrtype)
840 int fd;
841 unsigned long addrtype;
842 {
843 dl_phys_addr_req_t physaddr_req;
844 struct strbuf ctl;
845 int flags;
846
847 physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
848 physaddr_req.dl_addr_type = addrtype;
849
850 ctl.maxlen = 0;
851 ctl.len = sizeof (physaddr_req);
852 ctl.buf = (char *)&physaddr_req;
853
854 flags = RS_HIPRI;
855
856 return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
857 }
858
859 /*
860 * dlpiattachreq - send a request to attach to a specific unit.
861 */
862 static int dlpiattachreq (fd, ppa)
863 unsigned long ppa;
864 int fd;
865 {
866 dl_attach_req_t attach_req;
867 struct strbuf ctl;
868 int flags;
869
870 attach_req.dl_primitive = DL_ATTACH_REQ;
871 attach_req.dl_ppa = ppa;
872
873 ctl.maxlen = 0;
874 ctl.len = sizeof (attach_req);
875 ctl.buf = (char *)&attach_req;
876
877 flags = 0;
878
879 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
880 }
881
882 /*
883 * dlpibindreq - send a request to bind to a specific SAP address.
884 */
885 static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
886 unsigned long sap;
887 unsigned long max_conind;
888 unsigned long service_mode;
889 unsigned long conn_mgmt;
890 unsigned long xidtest;
891 int fd;
892 {
893 dl_bind_req_t bind_req;
894 struct strbuf ctl;
895 int flags;
896
897 bind_req.dl_primitive = DL_BIND_REQ;
898 bind_req.dl_sap = sap;
899 bind_req.dl_max_conind = max_conind;
900 bind_req.dl_service_mode = service_mode;
901 bind_req.dl_conn_mgmt = conn_mgmt;
902 bind_req.dl_xidtest_flg = xidtest;
903
904 ctl.maxlen = 0;
905 ctl.len = sizeof (bind_req);
906 ctl.buf = (char *)&bind_req;
907
908 flags = 0;
909
910 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
911 }
912
913 #if defined(UNUSED_DLPI_INTERFACE)
914 /*
915 * dlpiunbindreq - send a request to unbind. This function is not actually
916 * used by ISC DHCP, but is included for completeness in case it is
917 * ever required for new work.
918 */
919 static int dlpiunbindreq (fd)
920 int fd;
921 {
922 dl_unbind_req_t unbind_req;
923 struct strbuf ctl;
924 int flags;
925
926 unbind_req.dl_primitive = DL_UNBIND_REQ;
927
928 ctl.maxlen = 0;
929 ctl.len = sizeof (unbind_req);
930 ctl.buf = (char *)&unbind_req;
931
932 flags = 0;
933
934 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
935 }
936
937
938 /*
939 * dlpidetachreq - send a request to detach. This function is not actually
940 * used by ISC DHCP, but is included for completeness in case it is
941 * ever required for new work.
942 */
943 static int dlpidetachreq (fd)
944 int fd;
945 {
946 dl_detach_req_t detach_req;
947 struct strbuf ctl;
948 int flags;
949
950 detach_req.dl_primitive = DL_DETACH_REQ;
951
952 ctl.maxlen = 0;
953 ctl.len = sizeof (detach_req);
954 ctl.buf = (char *)&detach_req;
955
956 flags = 0;
957
958 return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
959 }
960 #endif /* UNUSED_DLPI_INTERFACE */
961
962
963 /*
964 * dlpibindack - receive an ack to a dlbindreq.
965 */
966 static int dlpibindack (fd, bufp)
967 char *bufp;
968 int fd;
969 {
970 union DL_primitives *dlp;
971 struct strbuf ctl;
972 int flags;
973
974 ctl.maxlen = DLPI_MAXDLBUF;
975 ctl.len = 0;
976 ctl.buf = bufp;
977
978 if (strgetmsg (fd, &ctl,
979 (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
980 return -1;
981 }
982
983 dlp = (union DL_primitives *)ctl.buf;
984
985 if (expected (DL_BIND_ACK, dlp, flags) == -1) {
986 return -1;
987 }
988
989 if (ctl.len < sizeof (dl_bind_ack_t)) {
990 /* Returned structure is too short */
991 return -1;
992 }
993
994 return 0;
995 }
996
997 /*
998 * dlpiokack - general acknowledgement reception.
999 */
1000 static int dlpiokack (fd, bufp)
1001 char *bufp;
1002 int fd;
1003 {
1004 union DL_primitives *dlp;
1005 struct strbuf ctl;
1006 int flags;
1007
1008 ctl.maxlen = DLPI_MAXDLBUF;
1009 ctl.len = 0;
1010 ctl.buf = bufp;
1011
1012 if (strgetmsg (fd, &ctl,
1013 (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
1014 return -1;
1015 }
1016
1017 dlp = (union DL_primitives *)ctl.buf;
1018
1019 if (expected (DL_OK_ACK, dlp, flags) == -1) {
1020 return -1;
1021 }
1022
1023 if (ctl.len < sizeof (dl_ok_ack_t)) {
1024 /* Returned structure is too short */
1025 return -1;
1026 }
1027
1028 return 0;
1029 }
1030
1031 /*
1032 * dlpiinfoack - receive an ack to a dlinforeq.
1033 */
1034 static int dlpiinfoack (fd, bufp)
1035 char *bufp;
1036 int fd;
1037 {
1038 union DL_primitives *dlp;
1039 struct strbuf ctl;
1040 int flags;
1041
1042 ctl.maxlen = DLPI_MAXDLBUF;
1043 ctl.len = 0;
1044 ctl.buf = bufp;
1045
1046 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1047 "dlpiinfoack") < 0) {
1048 return -1;
1049 }
1050
1051 dlp = (union DL_primitives *) ctl.buf;
1052
1053 if (expected (DL_INFO_ACK, dlp, flags) == -1) {
1054 return -1;
1055 }
1056
1057 if (ctl.len < sizeof (dl_info_ack_t)) {
1058 /* Returned structure is too short */
1059 return -1;
1060 }
1061
1062 return 0;
1063 }
1064
1065 /*
1066 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1067 */
1068 int dlpiphysaddrack (fd, bufp)
1069 char *bufp;
1070 int fd;
1071 {
1072 union DL_primitives *dlp;
1073 struct strbuf ctl;
1074 int flags;
1075
1076 ctl.maxlen = DLPI_MAXDLBUF;
1077 ctl.len = 0;
1078 ctl.buf = bufp;
1079
1080 if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1081 "dlpiphysaddrack") < 0) {
1082 return -1;
1083 }
1084
1085 dlp = (union DL_primitives *)ctl.buf;
1086
1087 if (expected (DL_PHYS_ADDR_ACK, dlp, flags) == -1) {
1088 return -1;
1089 }
1090
1091 if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
1092 /* Returned structure is too short */
1093 return -1;
1094 }
1095
1096 return 0;
1097 }
1098
1099 #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE)
1100 int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
1101 int fd;
1102 unsigned char *addr;
1103 int addrlen;
1104 unsigned long minpri;
1105 unsigned long maxpri;
1106 unsigned char *dbuf;
1107 int dbuflen;
1108 {
1109 long buf [DLPI_MAXDLBUF];
1110 union DL_primitives *dlp;
1111 struct strbuf ctl, data;
1112
1113 /* Set up the control information... */
1114 dlp = (union DL_primitives *)buf;
1115 dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ;
1116 dlp -> unitdata_req.dl_dest_addr_length = addrlen;
1117 dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
1118 dlp -> unitdata_req.dl_priority.dl_min = minpri;
1119 dlp -> unitdata_req.dl_priority.dl_max = maxpri;
1120
1121 /* Append the destination address */
1122 memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
1123 addr, addrlen);
1124
1125 ctl.maxlen = 0;
1126 ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
1127 ctl.buf = (char *)buf;
1128
1129 data.maxlen = 0;
1130 data.buf = (char *)dbuf;
1131 data.len = dbuflen;
1132
1133 /* Send the packet down the wire... */
1134 return putmsg (fd, &ctl, &data, 0);
1135 }
1136
1137 static int dlpiunitdataind (fd, daddr, daddrlen,
1138 saddr, saddrlen, grpaddr, dbuf, dlen)
1139 int fd;
1140 unsigned char *daddr;
1141 unsigned long *daddrlen;
1142 unsigned char *saddr;
1143 unsigned long *saddrlen;
1144 unsigned long *grpaddr;
1145 unsigned char *dbuf;
1146 int dlen;
1147 {
1148 long buf [DLPI_MAXDLBUF];
1149 union DL_primitives *dlp;
1150 struct strbuf ctl, data;
1151 int flags = 0;
1152 int result;
1153
1154 /* Set up the msg_buf structure... */
1155 dlp = (union DL_primitives *)buf;
1156 dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
1157
1158 ctl.maxlen = DLPI_MAXDLBUF;
1159 ctl.len = 0;
1160 ctl.buf = (char *)buf;
1161
1162 data.maxlen = dlen;
1163 data.len = 0;
1164 data.buf = (char *)dbuf;
1165
1166 result = getmsg (fd, &ctl, &data, &flags);
1167
1168 if (result < 0) {
1169 log_debug("dlpiunitdataind: %m");
1170 return -1;
1171 }
1172
1173 if (ctl.len < sizeof (dl_unitdata_ind_t) ||
1174 dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
1175 return -1;
1176 }
1177
1178 if (data.len <= 0) {
1179 return data.len;
1180 }
1181
1182 /* Copy sender info */
1183 if (saddr) {
1184 memcpy (saddr,
1185 (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset,
1186 dlp -> unitdata_ind.dl_src_addr_length);
1187 }
1188 if (saddrlen) {
1189 *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
1190 }
1191
1192 /* Copy destination info */
1193 if (daddr) {
1194 memcpy (daddr,
1195 (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset,
1196 dlp -> unitdata_ind.dl_dest_addr_length);
1197 }
1198 if (daddrlen) {
1199 *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
1200 }
1201
1202 if (grpaddr) {
1203 *grpaddr = dlp -> unitdata_ind.dl_group_address;
1204 }
1205
1206 return data.len;
1207 }
1208 #endif /* !USE_DLPI_HWADDR: USE_DLPI_RECEIVE || USE_DLPI_SEND */
1209
1210 /*
1211 * expected - see if we got what we wanted.
1212 */
1213 static int expected (prim, dlp, msgflags)
1214 unsigned long prim;
1215 union DL_primitives *dlp;
1216 int msgflags;
1217 {
1218 if (msgflags != RS_HIPRI) {
1219 /* Message was not M_PCPROTO */
1220 return -1;
1221 }
1222
1223 if (dlp->dl_primitive != prim) {
1224 /* Incorrect/unexpected return message */
1225 return -1;
1226 }
1227
1228 return 0;
1229 }
1230
1231 /*
1232 * strgetmsg - get a message from a stream, with timeout.
1233 */
1234 static int strgetmsg (fd, ctlp, datap, flagsp, caller)
1235 struct strbuf *ctlp, *datap;
1236 char *caller;
1237 int *flagsp;
1238 int fd;
1239 {
1240 int result;
1241 struct pollfd pfd;
1242 int count;
1243 time_t now;
1244 time_t starttime;
1245 int to_msec;
1246
1247 pfd.fd = fd;
1248 pfd.events = POLLPRI; /* We're only interested in knowing
1249 * when we can receive the next high
1250 * priority message.
1251 */
1252 pfd.revents = 0;
1253
1254 now = time (&starttime);
1255 while (now <= starttime + DLPI_MAXWAIT) {
1256 to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000;
1257 count = poll (&pfd, 1, to_msec);
1258
1259 if (count == 0) {
1260 /* log_fatal ("strgetmsg: timeout"); */
1261 return -1;
1262 } else if (count < 0) {
1263 if (errno == EAGAIN || errno == EINTR) {
1264 time (&now);
1265 continue;
1266 } else {
1267 /* log_fatal ("poll: %m"); */
1268 return -1;
1269 }
1270 } else {
1271 break;
1272 }
1273 }
1274
1275 /*
1276 * Set flags argument and issue getmsg ().
1277 */
1278 *flagsp = 0;
1279 if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
1280 return result;
1281 }
1282
1283 /*
1284 * Check for MOREDATA and/or MORECTL.
1285 */
1286 if (result & (MORECTL|MOREDATA)) {
1287 return -1;
1288 }
1289
1290 /*
1291 * Check for at least sizeof (long) control data portion.
1292 */
1293 if (ctlp -> len < sizeof (long)) {
1294 return -1;
1295 }
1296
1297 return 0;
1298 }
1299
1300 #if defined(USE_DLPI_SEND)
1301 int can_unicast_without_arp (ip)
1302 struct interface_info *ip;
1303 {
1304 return 1;
1305 }
1306
1307 int can_receive_unicast_unconfigured (ip)
1308 struct interface_info *ip;
1309 {
1310 return 1;
1311 }
1312
1313 int supports_multiple_interfaces (ip)
1314 struct interface_info *ip;
1315 {
1316 return 1;
1317 }
1318
1319 void maybe_setup_fallback ()
1320 {
1321 isc_result_t status;
1322 struct interface_info *fbi = (struct interface_info *)0;
1323 if (setup_fallback (&fbi, MDL)) {
1324 if_register_fallback (fbi);
1325 status = omapi_register_io_object ((omapi_object_t *)fbi,
1326 if_readsocket, 0,
1327 fallback_discard, 0, 0);
1328 if (status != ISC_R_SUCCESS)
1329 log_fatal ("Can't register I/O handle for %s: %s",
1330 fbi -> name, isc_result_totext (status));
1331 interface_dereference (&fbi, MDL);
1332 }
1333 }
1334 #endif /* USE_DLPI_SEND */
1335
1336 void
1337 get_hw_addr(const char *name, struct hardware *hw) {
1338 int sock, unit;
1339 long buf[DLPI_MAXDLBUF];
1340 union DL_primitives *dlp;
1341
1342 dlp = (union DL_primitives *)buf;
1343
1344 /*
1345 * Open a DLPI device.
1346 */
1347 sock = dlpiopen(name);
1348 if (sock < 0) {
1349 log_fatal("Can't open DLPI device for %s: %m", name);
1350 }
1351
1352 /*
1353 * Submit a DL_INFO_REQ request, to find the dl_mac_type and
1354 * dl_provider_style
1355 */
1356 if (dlpiinforeq(sock) < 0) {
1357 log_fatal("Can't request DLPI MAC type for %s: %m", name);
1358 }
1359 if (dlpiinfoack(sock, (char *)buf) < 0) {
1360 log_fatal("Can't get DLPI MAC type for %s: %m", name);
1361 }
1362 switch (dlp->info_ack.dl_mac_type) {
1363 case DL_CSMACD: /* IEEE 802.3 */
1364 case DL_ETHER:
1365 hw->hbuf[0] = HTYPE_ETHER;
1366 break;
1367 case DL_TPR:
1368 hw->hbuf[0] = HTYPE_IEEE802;
1369 break;
1370 case DL_FDDI:
1371 hw->hbuf[0] = HTYPE_FDDI;
1372 break;
1373 default:
1374 log_fatal("%s: unsupported DLPI MAC type %lu", name,
1375 (unsigned long)dlp->info_ack.dl_mac_type);
1376 }
1377
1378 if (dlp->info_ack.dl_provider_style == DL_STYLE2) {
1379 /*
1380 * Attach to the device. If this fails, the device
1381 * does not exist.
1382 */
1383 unit = dlpiunit((char *)name);
1384
1385 if (dlpiattachreq(sock, unit) < 0 ||
1386 dlpiokack(sock, (char *)buf) < 0) {
1387 log_fatal("Can't attach DLPI device for %s: %m",
1388 name);
1389 }
1390 }
1391
1392 /*
1393 * Submit a DL_PHYS_ADDR_REQ request, to find
1394 * the hardware address.
1395 */
1396 if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) {
1397 log_fatal("Can't request DLPI hardware address for %s: %m",
1398 name);
1399 }
1400 if (dlpiphysaddrack(sock, (char *)buf) < 0) {
1401 log_fatal("Can't get DLPI hardware address for %s: %m",
1402 name);
1403 }
1404 if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) {
1405 memcpy(hw->hbuf+1,
1406 (char *)buf + dlp->physaddr_ack.dl_addr_offset,
1407 dlp->physaddr_ack.dl_addr_length);
1408 hw->hlen = dlp->physaddr_ack.dl_addr_length + 1;
1409 } else {
1410 memcpy(hw->hbuf+1,
1411 (char *)buf + dlp->physaddr_ack.dl_addr_offset,
1412 sizeof(hw->hbuf)-1);
1413 hw->hlen = sizeof(hw->hbuf);
1414 }
1415
1416 close(sock);
1417 }
1418 #endif /* USE_DLPI_SEND || USE_DLPI_RECEIVE || USE_DLPI_HWADDR */