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