xref: /netbsd-src/external/mpl/dhcp/dist/common/dlpi.c (revision f407d9293b6650aa8c33d6a995f797bb6aaefd90)
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