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