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