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