3
Data Link Provider Interface (DLPI) network interface code. */
6
* Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
7
* Copyright (c) 1996-2003 by Internet Software Consortium
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.
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.
21
* Internet Systems Consortium, Inc.
23
* Redwood City, CA 94063
27
* This software was written for Internet Systems Consortium
28
* by Eric James Negaard, <lmdejn@lmd.ericsson.se>. To learn more about
29
* Internet Systems Consortium, see ``http://www.isc.org''.
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.
37
* Based largely in part to the existing NIT code in nit.c.
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
45
* Implementation notes:
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).
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
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.
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
81
* The Open Group Technical Standard can be found here:
82
* http://www.opengroup.org/onlinepubs/009618899/index.htm
84
* The HP DLPI Programmer's Guide can be found here:
85
* http://docs.hp.com/en/B2355-90139/index.html
90
#if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
92
# include <sys/ioctl.h>
93
# include <sys/time.h>
94
# include <sys/dlpi.h>
96
# ifdef USE_DLPI_PFMOD
97
# include <sys/pfmod.h>
102
# include <netinet/in_systm.h>
103
# include "includes/netinet/ip.h"
104
# include "includes/netinet/udp.h"
105
# include "includes/netinet/if_ether.h"
107
# ifdef USE_DLPI_PFMOD
109
# define DLPI_MODNAME "DLPI+RAW+PFMOD"
111
# define DLPI_MODNAME "DLPI+PFMOD"
115
# define DLPI_MODNAME "DLPI+RAW"
117
# define DLPI_MODNAME "DLPI"
122
# define ABS(x) ((x) >= 0 ? (x) : 0-(x))
125
#if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
126
static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp));
129
#define DLPI_MAXDLBUF 8192 /* Buffer size */
130
#define DLPI_MAXDLADDR 1024 /* Max address size */
131
#define DLPI_DEVDIR "/dev/" /* Device directory */
133
static int dlpiopen(const char *ifname);
134
static int dlpiunit PROTO ((char *ifname));
135
static int dlpiinforeq PROTO ((int fd));
136
static int dlpiphysaddrreq PROTO ((int fd, unsigned long addrtype));
137
static int dlpiattachreq PROTO ((int fd, unsigned long ppa));
138
static int dlpibindreq PROTO ((int fd, unsigned long sap, unsigned long max_conind,
139
unsigned long service_mode, unsigned long conn_mgmt,
140
unsigned long xidtest));
141
#if defined(UNUSED_DLPI_INTERFACE)
142
/* These functions are unused at present, but may be used at a later date.
143
* defined out to avoid compiler warnings about unused static functions.
145
static int dlpidetachreq PROTO ((int fd));
146
static int dlpiunbindreq PROTO ((int fd));
148
static int dlpiokack PROTO ((int fd, char *bufp));
149
static int dlpiinfoack PROTO ((int fd, char *bufp));
150
static int dlpiphysaddrack PROTO ((int fd, char *bufp));
151
static int dlpibindack PROTO ((int fd, char *bufp));
152
static int dlpiunitdatareq PROTO ((int fd, unsigned char *addr,
153
int addrlen, unsigned long minpri,
154
unsigned long maxpri, unsigned char *data,
156
static int dlpiunitdataind PROTO ((int fd,
157
unsigned char *dstaddr,
158
unsigned long *dstaddrlen,
159
unsigned char *srcaddr,
160
unsigned long *srcaddrlen,
161
unsigned long *grpaddr,
165
static int expected PROTO ((unsigned long prim, union DL_primitives *dlp,
167
static int strgetmsg PROTO ((int fd, struct strbuf *ctlp,
168
struct strbuf *datap, int *flagsp,
171
/* Reinitializes the specified interface after an address change. This
172
is not required for packet-filter APIs. */
175
void if_reinitialize_send (info)
176
struct interface_info *info;
181
#ifdef USE_DLPI_RECEIVE
182
void if_reinitialize_receive (info)
183
struct interface_info *info;
188
/* Called by get_interface_list for each interface that's discovered.
189
Opens a packet filter for each interface and adds it to the select
192
int if_register_dlpi (info)
193
struct interface_info *info;
197
long buf [DLPI_MAXDLBUF];
198
union DL_primitives *dlp;
200
dlp = (union DL_primitives *)buf;
202
/* Open a DLPI device */
203
if ((sock = dlpiopen (info -> name)) < 0) {
204
log_fatal ("Can't open DLPI device for %s: %m", info -> name);
209
* Submit a DL_INFO_REQ request, to find the dl_mac_type and
212
if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
213
log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
215
switch (dlp -> info_ack.dl_mac_type) {
216
case DL_CSMACD: /* IEEE 802.3 */
218
info -> hw_address.hbuf [0] = HTYPE_ETHER;
220
/* adding token ring 5/1999 - mayer@ping.at */
222
info -> hw_address.hbuf [0] = HTYPE_IEEE802;
225
info -> hw_address.hbuf [0] = HTYPE_FDDI;
228
log_fatal("%s: unsupported DLPI MAC type %lu", info->name,
229
(unsigned long)dlp->info_ack.dl_mac_type);
233
* copy the sap length and broadcast address of this interface
234
* to interface_info. This fixes nothing but seemed nicer than to
235
* assume -2 and ffffff.
237
info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length;
238
info -> dlpi_broadcast_addr.hlen =
239
dlp -> info_ack.dl_brdcst_addr_length;
240
memcpy (info -> dlpi_broadcast_addr.hbuf,
241
(char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset,
242
dlp -> info_ack.dl_brdcst_addr_length);
245
if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
247
* Attach to the device. If this fails, the device
250
unit = dlpiunit (info -> name);
252
if (dlpiattachreq (sock, unit) < 0
253
|| dlpiokack (sock, (char *)buf) < 0) {
254
log_fatal ("Can't attach DLPI device for %s: %m", info -> name);
259
* Bind to the IP service access point (SAP), connectionless (CLDLS).
261
if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0
262
|| dlpibindack (sock, (char *)buf) < 0) {
263
log_fatal ("Can't bind DLPI device for %s: %m", info -> name);
267
* Submit a DL_PHYS_ADDR_REQ request, to find
268
* the hardware address
270
if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0
271
|| dlpiphysaddrack (sock, (char *)buf) < 0) {
272
log_fatal ("Can't get DLPI hardware address for %s: %m",
276
info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1;
277
memcpy (&info -> hw_address.hbuf [1],
278
(char *)buf + dlp -> physaddr_ack.dl_addr_offset,
279
dlp -> physaddr_ack.dl_addr_length);
282
if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
283
log_fatal ("Can't set DLPI RAW mode for %s: %m",
288
#ifdef USE_DLPI_PFMOD
289
if (ioctl (sock, I_PUSH, "pfmod") < 0) {
290
log_fatal ("Can't push packet filter onto DLPI for %s: %m",
295
get_hw_addr(info->name, &info->hw_address);
300
#if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
302
strioctl (fd, cmd, timeout, len, dp)
313
sio.ic_timout = timeout;
317
if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
323
#endif /* USE_DPI_PFMOD || USE_DLPI_RAW */
326
void if_register_send (info)
327
struct interface_info *info;
329
/* If we're using the DLPI API for sending and receiving,
330
we don't need to register this interface twice. */
331
#ifndef USE_DLPI_RECEIVE
332
# ifdef USE_DLPI_PFMOD
333
struct packetfilt pf;
336
info -> wfdesc = if_register_dlpi (info);
338
# ifdef USE_DLPI_PFMOD
339
/* Set up an PFMOD filter that rejects everything... */
342
pf.Pf_Filter [0] = ENF_PUSHZERO;
344
/* Install the filter */
345
if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM,
346
sizeof (pf), (char *)&pf) < 0) {
347
log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name);
350
# endif /* USE_DLPI_PFMOD */
351
#else /* !defined (USE_DLPI_RECEIVE) */
353
* If using DLPI for both send and receive, simply re-use
354
* the read file descriptor that was set up earlier.
356
info -> wfdesc = info -> rfdesc;
359
if (!quiet_interface_discovery)
360
log_info ("Sending on DLPI/%s/%s%s%s",
362
print_hw_addr (info -> hw_address.hbuf [0],
363
info -> hw_address.hlen - 1,
364
&info -> hw_address.hbuf [1]),
365
(info -> shared_network ? "/" : ""),
366
(info -> shared_network ?
367
info -> shared_network -> name : ""));
369
#ifdef DLPI_FIRST_SEND_WAIT
370
/* See the implementation notes at the beginning of this file */
371
# ifdef USE_DLPI_RECEIVE
372
sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2));
374
sleep (DLPI_FIRST_SEND_WAIT);
379
void if_deregister_send (info)
380
struct interface_info *info;
382
/* If we're using the DLPI API for sending and receiving,
383
we don't need to register this interface twice. */
384
#ifndef USE_DLPI_RECEIVE
385
close (info -> wfdesc);
389
if (!quiet_interface_discovery)
390
log_info ("Disabling output on DLPI/%s/%s%s%s",
392
print_hw_addr (info -> hw_address.hbuf [0],
393
info -> hw_address.hlen - 1,
394
&info -> hw_address.hbuf [1]),
395
(info -> shared_network ? "/" : ""),
396
(info -> shared_network ?
397
info -> shared_network -> name : ""));
399
#endif /* USE_DLPI_SEND */
401
#ifdef USE_DLPI_RECEIVE
402
/* Packet filter program...
403
XXX Changes to the filter program may require changes to the constant
404
offsets used in if_register_send to patch the NIT program! XXX */
406
void if_register_receive (info)
407
struct interface_info *info;
409
#ifdef USE_DLPI_PFMOD
410
struct packetfilt pf;
415
/* Open a DLPI device and hang it on this interface... */
416
info -> rfdesc = if_register_dlpi (info);
418
#ifdef USE_DLPI_PFMOD
419
/* Set up the PFMOD filter program. */
420
/* XXX Unlike the BPF filter program, this one won't work if the
421
XXX IP packet is fragmented or if there are options on the IP
426
#if defined (USE_DLPI_RAW)
427
# define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
429
* ethertype == ETHERTYPE_IP
432
pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
433
pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
434
pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
436
# define ETHER_H_PREFIX (0)
437
# endif /* USE_DLPI_RAW */
439
* The packets that will be received on this file descriptor
440
* will be IP packets (due to the SAP that was specified in
441
* the dlbind call). There will be no ethernet header.
442
* Therefore, setup the packet filter to check the protocol
443
* field for UDP, and the destination port number equal
444
* to the local port. All offsets are relative to the start
449
* BOOTPS destination port
451
offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t);
452
pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
453
pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
454
pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
457
* protocol should be udp. this is a byte compare, test for
460
offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr);
461
pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
462
pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND;
463
pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF);
464
pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
465
pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
467
/* Install the filter... */
468
if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
469
sizeof (pf), (char *)&pf) < 0) {
470
log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name);
472
#endif /* USE_DLPI_PFMOD */
474
if (!quiet_interface_discovery)
475
log_info ("Listening on DLPI/%s/%s%s%s",
477
print_hw_addr (info -> hw_address.hbuf [0],
478
info -> hw_address.hlen - 1,
479
&info -> hw_address.hbuf [1]),
480
(info -> shared_network ? "/" : ""),
481
(info -> shared_network ?
482
info -> shared_network -> name : ""));
484
#ifdef DLPI_FIRST_SEND_WAIT
485
/* See the implementation notes at the beginning of this file */
486
# ifdef USE_DLPI_SEND
487
sleep (DLPI_FIRST_SEND_WAIT / 2);
489
sleep (DLPI_FIRST_SEND_WAIT);
494
void if_deregister_receive (info)
495
struct interface_info *info;
497
/* If we're using the DLPI API for sending and receiving,
498
we don't need to register this interface twice. */
499
#ifndef USE_DLPI_SEND
500
close (info -> rfdesc);
504
if (!quiet_interface_discovery)
505
log_info ("Disabling input on DLPI/%s/%s%s%s",
507
print_hw_addr (info -> hw_address.hbuf [0],
508
info -> hw_address.hlen - 1,
509
&info -> hw_address.hbuf [1]),
510
(info -> shared_network ? "/" : ""),
511
(info -> shared_network ?
512
info -> shared_network -> name : ""));
514
#endif /* USE_DLPI_RECEIVE */
517
ssize_t send_packet (interface, packet, raw, len, from, to, hto)
518
struct interface_info *interface;
519
struct packet *packet;
520
struct dhcp_packet *raw;
523
struct sockaddr_in *to;
524
struct hardware *hto;
529
double ih [1536 / sizeof (double)];
530
unsigned char *dbuf = (unsigned char *)ih;
532
unsigned char dstaddr [DLPI_MAXDLADDR];
537
if (!strcmp (interface -> name, "fallback"))
538
return send_fallback (interface, packet, raw,
543
/* Assemble the headers... */
545
assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto);
546
if (dbuflen > sizeof hh)
547
log_fatal ("send_packet: hh buffer too small.\n");
548
fudge = dbuflen % 4; /* IP header must be word-aligned. */
549
memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen);
554
assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr,
555
to -> sin_addr.s_addr, to -> sin_port,
556
(unsigned char *)raw, len);
558
/* Copy the data into the buffer (yuk). */
559
memcpy (dbuf + dbuflen, raw, len);
563
result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
567
* Setup the destination address (DLSAP) in dstaddr
569
* If sap_length < 0 we must deliver the DLSAP as phys+sap.
570
* If sap_length > 0 we must deliver the DLSAP as sap+phys.
572
* sap = Service Access Point == ETHERTYPE_IP
573
* sap + datalink address is called DLSAP in dlpi speak.
576
unsigned char phys [DLPI_MAXDLADDR];
577
unsigned char sap [4];
578
int sap_len = interface -> dlpi_sap_length;
579
int phys_len = interface -> hw_address.hlen - 1;
581
/* sap = htons (ETHERTYPE_IP) kludge */
582
memset (sap, 0, sizeof (sap));
583
# if (BYTE_ORDER == LITTLE_ENDIAN)
591
if (hto && hto -> hlen == interface -> hw_address.hlen)
592
memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
594
memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf,
595
interface -> dlpi_broadcast_addr.hlen);
598
memcpy ( dstaddr, phys, phys_len);
599
memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
602
memcpy ( dstaddr, (void *) sap, sap_len);
603
memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
605
addrlen = phys_len + ABS (sap_len);
608
result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
609
0, 0, dbuf, dbuflen);
610
#endif /* USE_DLPI_RAW */
612
log_error ("send_packet: %m");
615
#endif /* USE_DLPI_SEND */
617
#ifdef USE_DLPI_RECEIVE
618
ssize_t receive_packet (interface, buf, len, from, hfrom)
619
struct interface_info *interface;
622
struct sockaddr_in *from;
623
struct hardware *hfrom;
625
unsigned char dbuf [1536];
626
unsigned char srcaddr [DLPI_MAXDLADDR];
627
unsigned long srcaddrlen;
634
length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
636
length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
637
(unsigned long *)NULL, srcaddr, &srcaddrlen,
638
(unsigned long *)NULL, dbuf, sizeof (dbuf));
645
# if !defined (USE_DLPI_RAW)
647
* Copy the sender's hw address into hfrom
648
* If sap_len < 0 the DLSAP is as phys+sap.
649
* If sap_len > 0 the DLSAP is as sap+phys.
651
* sap is discarded here.
654
int sap_len = interface -> dlpi_sap_length;
655
int phys_len = interface -> hw_address.hlen - 1;
657
if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) {
658
hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
659
hfrom -> hlen = interface -> hw_address.hlen;
662
memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
665
memcpy ((char *) &hfrom -> hbuf [1], (char *) &srcaddr [phys_len],
670
memset (hfrom, '\0', sizeof *hfrom);
674
# endif /* !defined (USE_DLPI_RAW) */
676
/* Decode the IP and UDP headers... */
679
/* Decode the physical header... */
680
offset = decode_hw_header (interface, dbuf, bufix, hfrom);
682
/* If a physical layer checksum failed (dunno of any
683
physical layer that supports this, but WTH), skip this
691
offset = decode_udp_ip_header (interface, dbuf, bufix,
692
from, length, &paylen);
694
/* If the IP or UDP checksum was bad, skip the packet... */
703
log_fatal("Internal inconsistency at %s:%d.", MDL);
705
/* Copy out the data in the packet... */
706
memcpy(buf, &dbuf [bufix], paylen);
711
/* Common DLPI routines ...
713
* Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
715
* Based largely in part to the example code contained in the document
716
* "How to Use the STREAMS Data Link Provider Interface (DLPI)", written
717
* by Neal Nuckolls of SunSoft Internet Engineering.
719
* This code has been developed and tested on sparc-based machines running
720
* SunOS 5.5.1, with le and hme network interfaces. It should be pretty
723
* The usual disclaimers apply. This code works for me. Don't blame me
724
* if it makes your machine or network go down in flames. That taken
725
* into consideration, use this code as you wish. If you make usefull
726
* modifications I'd appreciate hearing about it.
729
#define DLPI_MAXWAIT 15 /* Max timeout */
733
* Parse an interface name and extract the unit number
736
static int dlpiunit (ifname)
746
/* Advance to the end of the name */
749
/* Back up to the start of the first digit */
750
while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--;
752
/* Convert the unit number */
754
while (*cp >= '0' && *cp <= '9') {
756
unit += (*cp++ - '0');
763
* dlpiopen - open the DLPI device for a given interface name
766
dlpiopen(const char *ifname) {
775
/* Open a DLPI device */
776
if (*ifname == '/') {
779
/* Prepend the device directory */
780
memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR));
781
dp = &devname [strlen (DLPI_DEVDIR)];
784
/* Find the end of the interface name */
788
/* And back up to the first digit (unit number) */
789
while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':')
792
/* Copy everything up to the unit number */
798
return open (devname, O_RDWR, 0);
802
* dlpiinforeq - request information about the data link provider.
805
static int dlpiinforeq (fd)
808
dl_info_req_t info_req;
812
info_req.dl_primitive = DL_INFO_REQ;
815
ctl.len = sizeof (info_req);
816
ctl.buf = (char *)&info_req;
820
return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
824
* dlpiphysaddrreq - request the current physical address.
826
static int dlpiphysaddrreq (fd, addrtype)
828
unsigned long addrtype;
830
dl_phys_addr_req_t physaddr_req;
834
physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ;
835
physaddr_req.dl_addr_type = addrtype;
838
ctl.len = sizeof (physaddr_req);
839
ctl.buf = (char *)&physaddr_req;
843
return putmsg (fd, &ctl, (struct strbuf *)NULL, flags);
847
* dlpiattachreq - send a request to attach to a specific unit.
849
static int dlpiattachreq (fd, ppa)
853
dl_attach_req_t attach_req;
857
attach_req.dl_primitive = DL_ATTACH_REQ;
858
attach_req.dl_ppa = ppa;
861
ctl.len = sizeof (attach_req);
862
ctl.buf = (char *)&attach_req;
866
return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
870
* dlpibindreq - send a request to bind to a specific SAP address.
872
static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
874
unsigned long max_conind;
875
unsigned long service_mode;
876
unsigned long conn_mgmt;
877
unsigned long xidtest;
880
dl_bind_req_t bind_req;
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;
892
ctl.len = sizeof (bind_req);
893
ctl.buf = (char *)&bind_req;
897
return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
900
#if defined(UNUSED_DLPI_INTERFACE)
902
* dlpiunbindreq - send a request to unbind. This function is not actually
903
* used by ISC DHCP, but is included for completeness in case it is
904
* ever required for new work.
906
static int dlpiunbindreq (fd)
909
dl_unbind_req_t unbind_req;
913
unbind_req.dl_primitive = DL_UNBIND_REQ;
916
ctl.len = sizeof (unbind_req);
917
ctl.buf = (char *)&unbind_req;
921
return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
926
* dlpidetachreq - send a request to detach. This function is not actually
927
* used by ISC DHCP, but is included for completeness in case it is
928
* ever required for new work.
930
static int dlpidetachreq (fd)
933
dl_detach_req_t detach_req;
937
detach_req.dl_primitive = DL_DETACH_REQ;
940
ctl.len = sizeof (detach_req);
941
ctl.buf = (char *)&detach_req;
945
return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
947
#endif /* UNUSED_DLPI_INTERFACE */
951
* dlpibindack - receive an ack to a dlbindreq.
953
static int dlpibindack (fd, bufp)
957
union DL_primitives *dlp;
961
ctl.maxlen = DLPI_MAXDLBUF;
965
if (strgetmsg (fd, &ctl,
966
(struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
970
dlp = (union DL_primitives *)ctl.buf;
972
if (!expected (DL_BIND_ACK, dlp, flags) < 0) {
976
if (ctl.len < sizeof (dl_bind_ack_t)) {
977
/* Returned structure is too short */
985
* dlpiokack - general acknowledgement reception.
987
static int dlpiokack (fd, bufp)
991
union DL_primitives *dlp;
995
ctl.maxlen = DLPI_MAXDLBUF;
999
if (strgetmsg (fd, &ctl,
1000
(struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
1004
dlp = (union DL_primitives *)ctl.buf;
1006
if (!expected (DL_OK_ACK, dlp, flags) < 0) {
1010
if (ctl.len < sizeof (dl_ok_ack_t)) {
1011
/* Returned structure is too short */
1019
* dlpiinfoack - receive an ack to a dlinforeq.
1021
static int dlpiinfoack (fd, bufp)
1025
union DL_primitives *dlp;
1029
ctl.maxlen = DLPI_MAXDLBUF;
1033
if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1034
"dlpiinfoack") < 0) {
1038
dlp = (union DL_primitives *) ctl.buf;
1040
if (!expected (DL_INFO_ACK, dlp, flags) < 0) {
1044
if (ctl.len < sizeof (dl_info_ack_t)) {
1045
/* Returned structure is too short */
1053
* dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
1055
int dlpiphysaddrack (fd, bufp)
1059
union DL_primitives *dlp;
1063
ctl.maxlen = DLPI_MAXDLBUF;
1067
if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
1068
"dlpiphysaddrack") < 0) {
1072
dlp = (union DL_primitives *)ctl.buf;
1074
if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) {
1078
if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
1079
/* Returned structure is too short */
1086
int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
1088
unsigned char *addr;
1090
unsigned long minpri;
1091
unsigned long maxpri;
1092
unsigned char *dbuf;
1095
long buf [DLPI_MAXDLBUF];
1096
union DL_primitives *dlp;
1097
struct strbuf ctl, data;
1099
/* Set up the control information... */
1100
dlp = (union DL_primitives *)buf;
1101
dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ;
1102
dlp -> unitdata_req.dl_dest_addr_length = addrlen;
1103
dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
1104
dlp -> unitdata_req.dl_priority.dl_min = minpri;
1105
dlp -> unitdata_req.dl_priority.dl_max = maxpri;
1107
/* Append the destination address */
1108
memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
1112
ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
1113
ctl.buf = (char *)buf;
1116
data.buf = (char *)dbuf;
1119
/* Send the packet down the wire... */
1120
return putmsg (fd, &ctl, &data, 0);
1123
static int dlpiunitdataind (fd, daddr, daddrlen,
1124
saddr, saddrlen, grpaddr, dbuf, dlen)
1126
unsigned char *daddr;
1127
unsigned long *daddrlen;
1128
unsigned char *saddr;
1129
unsigned long *saddrlen;
1130
unsigned long *grpaddr;
1131
unsigned char *dbuf;
1134
long buf [DLPI_MAXDLBUF];
1135
union DL_primitives *dlp;
1136
struct strbuf ctl, data;
1140
/* Set up the msg_buf structure... */
1141
dlp = (union DL_primitives *)buf;
1142
dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
1144
ctl.maxlen = DLPI_MAXDLBUF;
1146
ctl.buf = (char *)buf;
1150
data.buf = (char *)dbuf;
1152
result = getmsg (fd, &ctl, &data, &flags);
1158
if (ctl.len < sizeof (dl_unitdata_ind_t) ||
1159
dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
1163
if (data.len <= 0) {
1167
/* Copy sender info */
1170
(char *)buf + dlp -> unitdata_ind.dl_src_addr_offset,
1171
dlp -> unitdata_ind.dl_src_addr_length);
1174
*saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
1177
/* Copy destination info */
1180
(char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset,
1181
dlp -> unitdata_ind.dl_dest_addr_length);
1184
*daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
1188
*grpaddr = dlp -> unitdata_ind.dl_group_address;
1195
* expected - see if we got what we wanted.
1197
static int expected (prim, dlp, msgflags)
1199
union DL_primitives *dlp;
1202
if (msgflags != RS_HIPRI) {
1203
/* Message was not M_PCPROTO */
1207
if (dlp -> dl_primitive != prim) {
1208
/* Incorrect/unexpected return message */
1216
* strgetmsg - get a message from a stream, with timeout.
1218
static int strgetmsg (fd, ctlp, datap, flagsp, caller)
1219
struct strbuf *ctlp, *datap;
1232
pfd.events = POLLPRI; /* We're only interested in knowing
1233
* when we can receive the next high
1238
now = time (&starttime);
1239
while (now <= starttime + DLPI_MAXWAIT) {
1240
to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000;
1241
count = poll (&pfd, 1, to_msec);
1244
/* log_fatal ("strgetmsg: timeout"); */
1246
} else if (count < 0) {
1247
if (errno == EAGAIN || errno == EINTR) {
1251
/* log_fatal ("poll: %m"); */
1260
* Set flags argument and issue getmsg ().
1263
if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
1268
* Check for MOREDATA and/or MORECTL.
1270
if (result & (MORECTL|MOREDATA)) {
1275
* Check for at least sizeof (long) control data portion.
1277
if (ctlp -> len < sizeof (long)) {
1284
int can_unicast_without_arp (ip)
1285
struct interface_info *ip;
1290
int can_receive_unicast_unconfigured (ip)
1291
struct interface_info *ip;
1296
int supports_multiple_interfaces (ip)
1297
struct interface_info *ip;
1302
void maybe_setup_fallback ()
1304
isc_result_t status;
1305
struct interface_info *fbi = (struct interface_info *)0;
1306
if (setup_fallback (&fbi, MDL)) {
1307
if_register_fallback (fbi);
1308
status = omapi_register_io_object ((omapi_object_t *)fbi,
1310
fallback_discard, 0, 0);
1311
if (status != ISC_R_SUCCESS)
1312
log_fatal ("Can't register I/O handle for %s: %s",
1313
fbi -> name, isc_result_totext (status));
1314
interface_dereference (&fbi, MDL);
1319
get_hw_addr(const char *name, struct hardware *hw) {
1321
long buf[DLPI_MAXDLBUF];
1322
union DL_primitives *dlp;
1324
dlp = (union DL_primitives *)buf;
1327
* Open a DLPI device.
1329
sock = dlpiopen(name);
1331
log_fatal("Can't open DLPI device for %s: %m", name);
1335
* Submit a DL_INFO_REQ request, to find the dl_mac_type and
1338
if (dlpiinforeq(sock) < 0) {
1339
log_fatal("Can't request DLPI MAC type for %s: %m", name);
1341
if (dlpiinfoack(sock, (char *)buf) < 0) {
1342
log_fatal("Can't get DLPI MAC type for %s: %m", name);
1344
switch (dlp->info_ack.dl_mac_type) {
1345
case DL_CSMACD: /* IEEE 802.3 */
1347
hw->hbuf[0] = HTYPE_ETHER;
1350
hw->hbuf[0] = HTYPE_IEEE802;
1353
hw->hbuf[0] = HTYPE_FDDI;
1356
log_fatal("%s: unsupported DLPI MAC type %lu", name,
1357
(unsigned long)dlp->info_ack.dl_mac_type);
1361
* Submit a DL_PHYS_ADDR_REQ request, to find
1362
* the hardware address.
1364
if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) {
1365
log_fatal("Can't request DLPI hardware address for %s: %m",
1368
if (dlpiphysaddrack(sock, (char *)buf) < 0) {
1369
log_fatal("Can't get DLPI hardware address for %s: %m",
1372
if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) {
1374
(char *)buf + dlp->physaddr_ack.dl_addr_offset,
1375
dlp->physaddr_ack.dl_addr_length);
1376
hw->hlen = dlp->physaddr_ack.dl_addr_length + 1;
1379
(char *)buf + dlp->physaddr_ack.dl_addr_offset,
1380
sizeof(hw->hbuf)-1);
1381
hw->hlen = sizeof(hw->hbuf);
1386
#endif /* USE_DLPI */