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