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