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