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)
132static 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
145static int dlpiopen(const char *ifname);
146static int dlpiunit (char *ifname);
147static int dlpiinforeq (int fd);
148static int dlpiphysaddrreq (int fd, unsigned long addrtype);
149static int dlpiattachreq (int fd, unsigned long ppa);
150static 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 */
157static int dlpidetachreq (int fd);
158static int dlpiunbindreq (int fd);
159#endif
160static int dlpiokack (int fd, char *bufp);
161static int dlpiinfoack (int fd, char *bufp);
162static int dlpiphysaddrack (int fd, char *bufp);
163static 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 */
168static int dlpiunitdatareq (int fd, unsigned char *addr, int addrlen,
169			    unsigned long minpri, unsigned long maxpri,
170			    unsigned char *data, int datalen);
171static 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 */
180static int expected (unsigned long prim, union DL_primitives *dlp,
181		     int msgflags);
182static 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
189void if_reinitialize_send (info)
190	struct interface_info *info;
191{
192}
193#endif
194
195#ifdef USE_DLPI_RECEIVE
196void 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
206int 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)
312static int
313strioctl (fd, cmd, timeout, len, dp)
314int fd;
315int cmd;
316int timeout;
317int len;
318char *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
337void 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
390void 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
421void 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
509void 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
532ssize_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
634ssize_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
759static 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 */
788static int
789dlpiopen(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
832static 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 */
853static 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 */
876static 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 */
899static 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 */
933static 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 */
957static 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 */
980static 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 */
1014static 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 */
1048static 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 */
1082int 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)
1114int 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
1151static 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 */
1227static 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 */
1248static 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)
1315int can_unicast_without_arp (ip)
1316	struct interface_info *ip;
1317{
1318	return 1;
1319}
1320
1321int can_receive_unicast_unconfigured (ip)
1322	struct interface_info *ip;
1323{
1324	return 1;
1325}
1326
1327int supports_multiple_interfaces (ip)
1328	struct interface_info *ip;
1329{
1330	return 1;
1331}
1332
1333void 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
1350void
1351get_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