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