~ubuntu-branches/ubuntu/oneiric/isc-dhcp/oneiric-security

« back to all changes in this revision

Viewing changes to common/dlpi.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Pollock
  • Date: 2009-09-02 22:34:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090902223425-nypo7bkftxffq41m
Tags: upstream-4.1.0
ImportĀ upstreamĀ versionĀ 4.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* dlpi.c
 
2
 
 
3
   Data Link Provider Interface (DLPI) network interface code. */
 
4
 
 
5
/*
 
6
 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
 
7
 * Copyright (c) 1996-2003 by Internet Software Consortium
 
8
 *
 
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.
 
12
 *
 
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.
 
20
 *
 
21
 *   Internet Systems Consortium, Inc.
 
22
 *   950 Charter Street
 
23
 *   Redwood City, CA 94063
 
24
 *   <info@isc.org>
 
25
 *   http://www.isc.org/
 
26
 *
 
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''.
 
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.
 
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
 
 
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
 
 
88
#include "dhcpd.h"
 
89
 
 
90
#if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
 
91
 
 
92
# include <sys/ioctl.h>
 
93
# include <sys/time.h>
 
94
# include <sys/dlpi.h>
 
95
# include <stropts.h>
 
96
# ifdef USE_DLPI_PFMOD
 
97
#  include <sys/pfmod.h>
 
98
# endif
 
99
#include <poll.h>
 
100
#include <errno.h>
 
101
 
 
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"
 
106
 
 
107
# ifdef USE_DLPI_PFMOD
 
108
#  ifdef USE_DLPI_RAW
 
109
#   define DLPI_MODNAME "DLPI+RAW+PFMOD"
 
110
#  else
 
111
#   define DLPI_MODNAME "DLPI+PFMOD"
 
112
#  endif
 
113
# else
 
114
#  ifdef USE_DLPI_RAW
 
115
#   define DLPI_MODNAME "DLPI+RAW"
 
116
#  else
 
117
#   define DLPI_MODNAME "DLPI"
 
118
#  endif
 
119
# endif
 
120
 
 
121
# ifndef ABS
 
122
#  define ABS(x) ((x) >= 0 ? (x) : 0-(x))
 
123
# endif
 
124
 
 
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));
 
127
#endif
 
128
 
 
129
#define DLPI_MAXDLBUF           8192    /* Buffer size */
 
130
#define DLPI_MAXDLADDR          1024    /* Max address size */
 
131
#define DLPI_DEVDIR             "/dev/" /* Device directory */
 
132
 
 
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.
 
144
 */
 
145
static int dlpidetachreq PROTO ((int fd));
 
146
static int dlpiunbindreq PROTO ((int fd));
 
147
#endif
 
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,
 
155
                                   int datalen));
 
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,
 
162
                                   unsigned char *data,
 
163
                                   int datalen));
 
164
 
 
165
static int      expected PROTO ((unsigned long prim, union DL_primitives *dlp,
 
166
                                  int msgflags));
 
167
static int      strgetmsg PROTO ((int fd, struct strbuf *ctlp,
 
168
                                  struct strbuf *datap, int *flagsp,
 
169
                                  char *caller));
 
170
 
 
171
/* Reinitializes the specified interface after an address change.   This
 
172
   is not required for packet-filter APIs. */
 
173
 
 
174
#ifdef USE_DLPI_SEND
 
175
void if_reinitialize_send (info)
 
176
        struct interface_info *info;
 
177
{
 
178
}
 
179
#endif
 
180
 
 
181
#ifdef USE_DLPI_RECEIVE
 
182
void if_reinitialize_receive (info)
 
183
        struct interface_info *info;
 
184
{
 
185
}
 
186
#endif
 
187
 
 
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
 
190
   mask. */
 
191
 
 
192
int if_register_dlpi (info)
 
193
        struct interface_info *info;
 
194
{
 
195
        int sock;
 
196
        int unit;
 
197
        long buf [DLPI_MAXDLBUF];
 
198
        union DL_primitives *dlp;
 
199
 
 
200
        dlp = (union DL_primitives *)buf;
 
201
 
 
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);
 
205
        }
 
206
 
 
207
 
 
208
        /*
 
209
         * Submit a DL_INFO_REQ request, to find the dl_mac_type and 
 
210
         * dl_provider_style
 
211
         */
 
212
        if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
 
213
            log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
 
214
        } else {
 
215
            switch (dlp -> info_ack.dl_mac_type) {
 
216
              case DL_CSMACD: /* IEEE 802.3 */
 
217
              case DL_ETHER:
 
218
                info -> hw_address.hbuf [0] = HTYPE_ETHER;
 
219
                break;
 
220
              /* adding token ring 5/1999 - mayer@ping.at  */ 
 
221
              case DL_TPR:
 
222
                info -> hw_address.hbuf [0] = HTYPE_IEEE802;
 
223
                break;
 
224
              case DL_FDDI:
 
225
                info -> hw_address.hbuf [0] = HTYPE_FDDI;
 
226
                break;
 
227
              default:
 
228
                log_fatal("%s: unsupported DLPI MAC type %lu", info->name,
 
229
                          (unsigned long)dlp->info_ack.dl_mac_type);
 
230
                break;
 
231
            }
 
232
            /*
 
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.
 
236
             */
 
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);
 
243
        }
 
244
 
 
245
        if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
 
246
            /*
 
247
             * Attach to the device.  If this fails, the device
 
248
             * does not exist.
 
249
             */
 
250
            unit = dlpiunit (info -> name);
 
251
        
 
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);
 
255
            }
 
256
        }
 
257
 
 
258
        /*
 
259
         * Bind to the IP service access point (SAP), connectionless (CLDLS).
 
260
         */
 
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);
 
264
        }
 
265
 
 
266
        /*
 
267
         * Submit a DL_PHYS_ADDR_REQ request, to find
 
268
         * the hardware address
 
269
         */
 
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",
 
273
                   info -> name);
 
274
        }
 
275
 
 
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);
 
280
 
 
281
#ifdef USE_DLPI_RAW
 
282
        if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) {
 
283
            log_fatal ("Can't set DLPI RAW mode for %s: %m",
 
284
                   info -> name);
 
285
        }
 
286
#endif
 
287
 
 
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",
 
291
                   info -> name);
 
292
        }
 
293
#endif
 
294
 
 
295
        get_hw_addr(info->name, &info->hw_address);
 
296
 
 
297
        return sock;
 
298
}
 
299
 
 
300
#if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW)
 
301
static int
 
302
strioctl (fd, cmd, timeout, len, dp)
 
303
int fd;
 
304
int cmd;
 
305
int timeout;
 
306
int len;
 
307
char *dp;
 
308
{
 
309
    struct strioctl sio;
 
310
    int rslt;
 
311
 
 
312
    sio.ic_cmd = cmd;
 
313
    sio.ic_timout = timeout;
 
314
    sio.ic_len = len;
 
315
    sio.ic_dp = dp;
 
316
 
 
317
    if ((rslt = ioctl (fd, I_STR, &sio)) < 0) {
 
318
        return rslt;
 
319
    } else {
 
320
        return sio.ic_len;
 
321
    }
 
322
}
 
323
#endif /* USE_DPI_PFMOD || USE_DLPI_RAW */
 
324
 
 
325
#ifdef USE_DLPI_SEND
 
326
void if_register_send (info)
 
327
        struct interface_info *info;
 
328
{
 
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;
 
334
# endif
 
335
 
 
336
        info -> wfdesc = if_register_dlpi (info);
 
337
 
 
338
# ifdef USE_DLPI_PFMOD
 
339
        /* Set up an PFMOD filter that rejects everything... */
 
340
        pf.Pf_Priority = 0;
 
341
        pf.Pf_FilterLen = 1;
 
342
        pf.Pf_Filter [0] = ENF_PUSHZERO;
 
343
 
 
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);
 
348
        }
 
349
 
 
350
# endif /* USE_DLPI_PFMOD */
 
351
#else /* !defined (USE_DLPI_RECEIVE) */
 
352
        /*
 
353
         * If using DLPI for both send and receive, simply re-use
 
354
         * the read file descriptor that was set up earlier.
 
355
         */
 
356
        info -> wfdesc = info -> rfdesc;
 
357
#endif
 
358
 
 
359
        if (!quiet_interface_discovery)
 
360
                log_info ("Sending on   DLPI/%s/%s%s%s",
 
361
                      info -> name,
 
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 : ""));
 
368
 
 
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));
 
373
# else
 
374
        sleep (DLPI_FIRST_SEND_WAIT);
 
375
# endif
 
376
#endif
 
377
}
 
378
 
 
379
void if_deregister_send (info)
 
380
        struct interface_info *info;
 
381
{
 
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);
 
386
#endif
 
387
        info -> wfdesc = -1;
 
388
 
 
389
        if (!quiet_interface_discovery)
 
390
                log_info ("Disabling output on DLPI/%s/%s%s%s",
 
391
                      info -> name,
 
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 : ""));
 
398
}
 
399
#endif /* USE_DLPI_SEND */
 
400
 
 
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 */
 
405
 
 
406
void if_register_receive (info)
 
407
        struct interface_info *info;
 
408
{
 
409
#ifdef USE_DLPI_PFMOD
 
410
        struct packetfilt pf;
 
411
        struct ip iphdr;
 
412
        u_int16_t offset;
 
413
#endif
 
414
 
 
415
        /* Open a DLPI device and hang it on this interface... */
 
416
        info -> rfdesc = if_register_dlpi (info);
 
417
 
 
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
 
422
           XXX header. */
 
423
        pf.Pf_Priority = 0;
 
424
        pf.Pf_FilterLen = 0;
 
425
 
 
426
#if defined (USE_DLPI_RAW)
 
427
# define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
 
428
    /*
 
429
     * ethertype == ETHERTYPE_IP
 
430
     */
 
431
    offset = 12;
 
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);
 
435
# else
 
436
# define ETHER_H_PREFIX (0)
 
437
# endif /* USE_DLPI_RAW */
 
438
        /*
 
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
 
445
         * of an IP packet.
 
446
         */
 
447
 
 
448
        /*
 
449
         * BOOTPS destination port
 
450
         */
 
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;
 
455
 
 
456
        /*
 
457
         * protocol should be udp. this is a byte compare, test for
 
458
         * endianess.
 
459
         */
 
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);
 
466
 
 
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);
 
471
        }
 
472
#endif /* USE_DLPI_PFMOD */
 
473
 
 
474
        if (!quiet_interface_discovery)
 
475
                log_info ("Listening on DLPI/%s/%s%s%s",
 
476
                      info -> name,
 
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 : ""));
 
483
 
 
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);
 
488
# else
 
489
        sleep (DLPI_FIRST_SEND_WAIT);
 
490
# endif
 
491
#endif
 
492
}
 
493
 
 
494
void if_deregister_receive (info)
 
495
        struct interface_info *info;
 
496
{
 
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);
 
501
#endif
 
502
        info -> rfdesc = -1;
 
503
 
 
504
        if (!quiet_interface_discovery)
 
505
                log_info ("Disabling input on DLPI/%s/%s%s%s",
 
506
                      info -> name,
 
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 : ""));
 
513
}
 
514
#endif /* USE_DLPI_RECEIVE */
 
515
 
 
516
#ifdef USE_DLPI_SEND
 
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;
 
521
        size_t len;
 
522
        struct in_addr from;
 
523
        struct sockaddr_in *to;
 
524
        struct hardware *hto;
 
525
{
 
526
#ifdef USE_DLPI_RAW
 
527
        double hh [32];
 
528
#endif
 
529
        double ih [1536 / sizeof (double)];
 
530
        unsigned char *dbuf = (unsigned char *)ih;
 
531
        unsigned dbuflen;
 
532
        unsigned char dstaddr [DLPI_MAXDLADDR];
 
533
        unsigned addrlen;
 
534
        int result;
 
535
        int fudge;
 
536
 
 
537
        if (!strcmp (interface -> name, "fallback"))
 
538
                return send_fallback (interface, packet, raw,
 
539
                                      len, from, to, hto);
 
540
 
 
541
        dbuflen = 0;
 
542
 
 
543
        /* Assemble the headers... */
 
544
#ifdef USE_DLPI_RAW
 
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);
 
550
        dbuflen += fudge;
 
551
#else
 
552
        fudge = 0;
 
553
#endif
 
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);
 
557
 
 
558
        /* Copy the data into the buffer (yuk). */
 
559
        memcpy (dbuf + dbuflen, raw, len);
 
560
        dbuflen += len;
 
561
 
 
562
#ifdef USE_DLPI_RAW
 
563
        result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
 
564
#else
 
565
 
 
566
        /*
 
567
         * Setup the destination address (DLSAP) in dstaddr 
 
568
         *
 
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.
 
571
         *
 
572
         * sap = Service Access Point == ETHERTYPE_IP
 
573
         * sap + datalink address is called DLSAP in dlpi speak.
 
574
         */
 
575
        { /* ENCODE DLSAP */
 
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;
 
580
 
 
581
          /* sap = htons (ETHERTYPE_IP) kludge */
 
582
          memset (sap, 0, sizeof (sap));
 
583
# if (BYTE_ORDER == LITTLE_ENDIAN)
 
584
          sap [0] = 0x00;
 
585
          sap [1] = 0x08;
 
586
# else
 
587
          sap [0] = 0x08;
 
588
          sap [1] = 0x00;
 
589
# endif
 
590
 
 
591
        if (hto && hto -> hlen == interface -> hw_address.hlen)
 
592
             memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
 
593
          else 
 
594
             memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, 
 
595
              interface -> dlpi_broadcast_addr.hlen);
 
596
           
 
597
          if (sap_len < 0) { 
 
598
             memcpy ( dstaddr, phys, phys_len);
 
599
             memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
 
600
          }
 
601
          else {
 
602
             memcpy ( dstaddr, (void *) sap, sap_len);
 
603
             memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
 
604
          }
 
605
        addrlen = phys_len + ABS (sap_len);
 
606
      } /* ENCODE DLSAP */
 
607
 
 
608
        result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
 
609
                                  0, 0, dbuf, dbuflen);
 
610
#endif /* USE_DLPI_RAW */
 
611
        if (result < 0)
 
612
                log_error ("send_packet: %m");
 
613
        return result;
 
614
}
 
615
#endif /* USE_DLPI_SEND */
 
616
 
 
617
#ifdef USE_DLPI_RECEIVE
 
618
ssize_t receive_packet (interface, buf, len, from, hfrom)
 
619
        struct interface_info *interface;
 
620
        unsigned char *buf;
 
621
        size_t len;
 
622
        struct sockaddr_in *from;
 
623
        struct hardware *hfrom;
 
624
{
 
625
        unsigned char dbuf [1536];
 
626
        unsigned char srcaddr [DLPI_MAXDLADDR];
 
627
        unsigned long srcaddrlen;
 
628
        int length = 0;
 
629
        int offset = 0;
 
630
        int bufix = 0;
 
631
        unsigned paylen;
 
632
        
 
633
#ifdef USE_DLPI_RAW
 
634
        length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
 
635
#else   
 
636
        length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL,
 
637
                                  (unsigned long *)NULL, srcaddr, &srcaddrlen,
 
638
                                  (unsigned long *)NULL, dbuf, sizeof (dbuf));
 
639
#endif
 
640
 
 
641
        if (length <= 0) {
 
642
            return length;
 
643
        }
 
644
 
 
645
# if !defined (USE_DLPI_RAW)
 
646
        /*
 
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.
 
650
         *
 
651
         * sap is discarded here.
 
652
         */
 
653
        { /* DECODE DLSAP */
 
654
          int sap_len = interface -> dlpi_sap_length;
 
655
          int phys_len = interface -> hw_address.hlen - 1;
 
656
 
 
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;
 
660
            
 
661
            if (sap_len < 0) {
 
662
              memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
 
663
            }
 
664
            else {
 
665
              memcpy ((char *) &hfrom -> hbuf [1], (char *) &srcaddr [phys_len],
 
666
                phys_len);
 
667
            }
 
668
          } 
 
669
          else if (hfrom) {
 
670
            memset (hfrom, '\0', sizeof *hfrom);
 
671
          }
 
672
        } /* DECODE_DLSAP */
 
673
 
 
674
# endif /* !defined (USE_DLPI_RAW) */
 
675
 
 
676
        /* Decode the IP and UDP headers... */
 
677
        bufix = 0;
 
678
#ifdef USE_DLPI_RAW
 
679
        /* Decode the physical header... */
 
680
        offset = decode_hw_header (interface, dbuf, bufix, hfrom);
 
681
 
 
682
        /* If a physical layer checksum failed (dunno of any
 
683
           physical layer that supports this, but WTH), skip this
 
684
           packet. */
 
685
        if (offset < 0) {
 
686
                return 0;
 
687
        }
 
688
        bufix += offset;
 
689
        length -= offset;
 
690
#endif
 
691
        offset = decode_udp_ip_header (interface, dbuf, bufix,
 
692
                                       from, length, &paylen);
 
693
 
 
694
        /* If the IP or UDP checksum was bad, skip the packet... */
 
695
        if (offset < 0) {
 
696
            return 0;
 
697
        }
 
698
 
 
699
        bufix += offset;
 
700
        length -= offset;
 
701
 
 
702
        if (length < paylen)
 
703
                log_fatal("Internal inconsistency at %s:%d.", MDL);
 
704
 
 
705
        /* Copy out the data in the packet... */
 
706
        memcpy(buf, &dbuf [bufix], paylen);
 
707
        return paylen;
 
708
}
 
709
#endif
 
710
 
 
711
/* Common DLPI routines ...
 
712
 *
 
713
 * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se>
 
714
 *
 
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.
 
718
 * 
 
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
 
721
 * generic, though.
 
722
 * 
 
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.
 
727
 */
 
728
 
 
729
#define DLPI_MAXWAIT            15      /* Max timeout */
 
730
 
 
731
 
 
732
/*
 
733
 * Parse an interface name and extract the unit number
 
734
 */
 
735
 
 
736
static int dlpiunit (ifname)
 
737
        char *ifname;
 
738
{
 
739
        char *cp;
 
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
 */
 
765
static int
 
766
dlpiopen(const char *ifname) {
 
767
        char devname [50];
 
768
        char *dp;
 
769
        const char *cp, *ep;
 
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
 
 
805
static 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
 */
 
826
static 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
 */
 
849
static 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
 */
 
872
static 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
#if defined(UNUSED_DLPI_INTERFACE)
 
901
/*
 
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.
 
905
 */
 
906
static int dlpiunbindreq (fd)
 
907
        int fd;
 
908
{
 
909
        dl_unbind_req_t unbind_req;
 
910
        struct strbuf ctl;
 
911
        int flags;
 
912
        
 
913
        unbind_req.dl_primitive = DL_UNBIND_REQ;
 
914
        
 
915
        ctl.maxlen = 0;
 
916
        ctl.len = sizeof (unbind_req);
 
917
        ctl.buf = (char *)&unbind_req;
 
918
        
 
919
        flags = 0;
 
920
        
 
921
        return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
 
922
}
 
923
 
 
924
 
 
925
/*
 
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.
 
929
 */
 
930
static int dlpidetachreq (fd)
 
931
        int fd;
 
932
{
 
933
        dl_detach_req_t detach_req;
 
934
        struct strbuf ctl;
 
935
        int flags;
 
936
        
 
937
        detach_req.dl_primitive = DL_DETACH_REQ;
 
938
        
 
939
        ctl.maxlen = 0;
 
940
        ctl.len = sizeof (detach_req);
 
941
        ctl.buf = (char *)&detach_req;
 
942
        
 
943
        flags = 0;
 
944
        
 
945
        return putmsg (fd, &ctl, (struct strbuf*)NULL, flags);
 
946
}
 
947
#endif /* UNUSED_DLPI_INTERFACE */
 
948
 
 
949
 
 
950
/*
 
951
 * dlpibindack - receive an ack to a dlbindreq.
 
952
 */
 
953
static int dlpibindack (fd, bufp)
 
954
        char *bufp;
 
955
        int fd;
 
956
{
 
957
        union DL_primitives *dlp;
 
958
        struct strbuf ctl;
 
959
        int flags;
 
960
        
 
961
        ctl.maxlen = DLPI_MAXDLBUF;
 
962
        ctl.len = 0;
 
963
        ctl.buf = bufp;
 
964
 
 
965
        if (strgetmsg (fd, &ctl,
 
966
                       (struct strbuf*)NULL, &flags, "dlpibindack") < 0) {
 
967
                return -1;
 
968
        }
 
969
        
 
970
        dlp = (union DL_primitives *)ctl.buf;
 
971
        
 
972
        if (!expected (DL_BIND_ACK, dlp, flags) < 0) {
 
973
                return -1;
 
974
        }
 
975
        
 
976
        if (ctl.len < sizeof (dl_bind_ack_t)) {
 
977
                /* Returned structure is too short */
 
978
                return -1;
 
979
        }
 
980
 
 
981
        return 0;
 
982
}
 
983
 
 
984
/*
 
985
 * dlpiokack - general acknowledgement reception.
 
986
 */
 
987
static int dlpiokack (fd, bufp)
 
988
        char *bufp;
 
989
        int fd;
 
990
{
 
991
        union DL_primitives *dlp;
 
992
        struct strbuf ctl;
 
993
        int flags;
 
994
        
 
995
        ctl.maxlen = DLPI_MAXDLBUF;
 
996
        ctl.len = 0;
 
997
        ctl.buf = bufp;
 
998
        
 
999
        if (strgetmsg (fd, &ctl,
 
1000
                       (struct strbuf*)NULL, &flags, "dlpiokack") < 0) {
 
1001
                return -1;
 
1002
        }
 
1003
        
 
1004
        dlp = (union DL_primitives *)ctl.buf;
 
1005
        
 
1006
        if (!expected (DL_OK_ACK, dlp, flags) < 0) {
 
1007
                return -1;
 
1008
        }
 
1009
        
 
1010
        if (ctl.len < sizeof (dl_ok_ack_t)) {
 
1011
                /* Returned structure is too short */
 
1012
                return -1;
 
1013
        }
 
1014
        
 
1015
        return 0;
 
1016
}
 
1017
 
 
1018
/*
 
1019
 * dlpiinfoack - receive an ack to a dlinforeq.
 
1020
 */
 
1021
static int dlpiinfoack (fd, bufp)
 
1022
        char *bufp;
 
1023
        int fd;
 
1024
{
 
1025
        union DL_primitives *dlp;
 
1026
        struct strbuf ctl;
 
1027
        int flags;
 
1028
        
 
1029
        ctl.maxlen = DLPI_MAXDLBUF;
 
1030
        ctl.len = 0;
 
1031
        ctl.buf = bufp;
 
1032
        
 
1033
        if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
 
1034
                       "dlpiinfoack") < 0) {
 
1035
                return -1;
 
1036
        }
 
1037
        
 
1038
        dlp = (union DL_primitives *) ctl.buf;
 
1039
        
 
1040
        if (!expected (DL_INFO_ACK, dlp, flags) < 0) {
 
1041
                return -1;
 
1042
        }
 
1043
        
 
1044
        if (ctl.len < sizeof (dl_info_ack_t)) {
 
1045
                /* Returned structure is too short */
 
1046
                return -1;
 
1047
        }
 
1048
        
 
1049
        return 0;
 
1050
}
 
1051
 
 
1052
/*
 
1053
 * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq.
 
1054
 */
 
1055
int dlpiphysaddrack (fd, bufp)
 
1056
        char *bufp;
 
1057
        int fd;
 
1058
{
 
1059
        union DL_primitives *dlp;
 
1060
        struct strbuf ctl;
 
1061
        int flags;
 
1062
        
 
1063
        ctl.maxlen = DLPI_MAXDLBUF;
 
1064
        ctl.len = 0;
 
1065
        ctl.buf = bufp;
 
1066
        
 
1067
        if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags,
 
1068
                       "dlpiphysaddrack") < 0) {
 
1069
                return -1;
 
1070
        }
 
1071
 
 
1072
        dlp = (union DL_primitives *)ctl.buf;
 
1073
        
 
1074
        if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) {
 
1075
                return -1;
 
1076
        }
 
1077
 
 
1078
        if (ctl.len < sizeof (dl_phys_addr_ack_t)) {
 
1079
                /* Returned structure is too short */
 
1080
                return -1;
 
1081
        }
 
1082
        
 
1083
        return 0;
 
1084
}
 
1085
 
 
1086
int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen)
 
1087
        int fd;
 
1088
        unsigned char *addr;
 
1089
        int addrlen;
 
1090
        unsigned long minpri;
 
1091
        unsigned long maxpri;
 
1092
        unsigned char *dbuf;
 
1093
        int dbuflen;
 
1094
{
 
1095
        long buf [DLPI_MAXDLBUF];
 
1096
        union DL_primitives *dlp;
 
1097
        struct strbuf ctl, data;
 
1098
        
 
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;
 
1106
 
 
1107
        /* Append the destination address */
 
1108
        memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset,
 
1109
                addr, addrlen);
 
1110
        
 
1111
        ctl.maxlen = 0;
 
1112
        ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen;
 
1113
        ctl.buf = (char *)buf;
 
1114
 
 
1115
        data.maxlen = 0;
 
1116
        data.buf = (char *)dbuf;
 
1117
        data.len = dbuflen;
 
1118
 
 
1119
        /* Send the packet down the wire... */
 
1120
        return putmsg (fd, &ctl, &data, 0);
 
1121
}
 
1122
 
 
1123
static int dlpiunitdataind (fd, daddr, daddrlen,
 
1124
                            saddr, saddrlen, grpaddr, dbuf, dlen)
 
1125
        int fd;
 
1126
        unsigned char *daddr;
 
1127
        unsigned long *daddrlen;
 
1128
        unsigned char *saddr;
 
1129
        unsigned long *saddrlen;
 
1130
        unsigned long *grpaddr;
 
1131
        unsigned char *dbuf;
 
1132
        int dlen;
 
1133
{
 
1134
        long buf [DLPI_MAXDLBUF];
 
1135
        union DL_primitives *dlp;
 
1136
        struct strbuf ctl, data;
 
1137
        int flags = 0;
 
1138
        int result;
 
1139
 
 
1140
        /* Set up the msg_buf structure... */
 
1141
        dlp = (union DL_primitives *)buf;
 
1142
        dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND;
 
1143
 
 
1144
        ctl.maxlen = DLPI_MAXDLBUF;
 
1145
        ctl.len = 0;
 
1146
        ctl.buf = (char *)buf;
 
1147
        
 
1148
        data.maxlen = dlen;
 
1149
        data.len = 0;
 
1150
        data.buf = (char *)dbuf;
 
1151
        
 
1152
        result = getmsg (fd, &ctl, &data, &flags);
 
1153
        
 
1154
        if (result != 0) {
 
1155
                return -1;
 
1156
        }
 
1157
        
 
1158
        if (ctl.len < sizeof (dl_unitdata_ind_t) ||
 
1159
            dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) {
 
1160
                return -1;
 
1161
        }
 
1162
        
 
1163
        if (data.len <= 0) {
 
1164
                return data.len;
 
1165
        }
 
1166
 
 
1167
        /* Copy sender info */
 
1168
        if (saddr) {
 
1169
                memcpy (saddr,
 
1170
                        (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset,
 
1171
                        dlp -> unitdata_ind.dl_src_addr_length);
 
1172
        }
 
1173
        if (saddrlen) {
 
1174
                *saddrlen = dlp -> unitdata_ind.dl_src_addr_length;
 
1175
        }
 
1176
 
 
1177
        /* Copy destination info */
 
1178
        if (daddr) {
 
1179
                memcpy (daddr,
 
1180
                        (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset,
 
1181
                        dlp -> unitdata_ind.dl_dest_addr_length);
 
1182
        }
 
1183
        if (daddrlen) {
 
1184
                *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length;
 
1185
        }
 
1186
        
 
1187
        if (grpaddr) {
 
1188
                *grpaddr = dlp -> unitdata_ind.dl_group_address;
 
1189
        }
 
1190
        
 
1191
        return data.len;
 
1192
}
 
1193
 
 
1194
/*
 
1195
 * expected - see if we got what we wanted.
 
1196
 */
 
1197
static int expected (prim, dlp, msgflags)
 
1198
        unsigned long prim;
 
1199
        union DL_primitives *dlp;
 
1200
        int msgflags;
 
1201
{
 
1202
        if (msgflags != RS_HIPRI) {
 
1203
                /* Message was not M_PCPROTO */
 
1204
                return 0;
 
1205
        }
 
1206
 
 
1207
        if (dlp -> dl_primitive != prim) {
 
1208
                /* Incorrect/unexpected return message */
 
1209
                return 0;
 
1210
        }
 
1211
        
 
1212
        return 1;
 
1213
}
 
1214
 
 
1215
/*
 
1216
 * strgetmsg - get a message from a stream, with timeout.
 
1217
 */
 
1218
static int strgetmsg (fd, ctlp, datap, flagsp, caller)
 
1219
        struct strbuf *ctlp, *datap;
 
1220
        char *caller;
 
1221
        int *flagsp;
 
1222
        int fd;
 
1223
{
 
1224
        int result;
 
1225
        struct pollfd pfd;
 
1226
        int count;
 
1227
        time_t now;
 
1228
        time_t starttime;
 
1229
        int to_msec;
 
1230
        
 
1231
        pfd.fd = fd;
 
1232
        pfd.events = POLLPRI;   /* We're only interested in knowing
 
1233
                                 * when we can receive the next high
 
1234
                                 * priority message.
 
1235
                                 */
 
1236
        pfd.revents = 0;
 
1237
 
 
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);
 
1242
                
 
1243
                if (count == 0) {
 
1244
                        /* log_fatal ("strgetmsg: timeout"); */
 
1245
                        return -1;
 
1246
                } else if (count < 0) {
 
1247
                        if (errno == EAGAIN || errno == EINTR) {
 
1248
                                time (&now);
 
1249
                                continue;
 
1250
                        } else {
 
1251
                                /* log_fatal ("poll: %m"); */
 
1252
                                return -1;
 
1253
                        }
 
1254
                } else {
 
1255
                        break;
 
1256
                }
 
1257
        }
 
1258
 
 
1259
        /*
 
1260
         * Set flags argument and issue getmsg ().
 
1261
         */
 
1262
        *flagsp = 0;
 
1263
        if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) {
 
1264
                return result;
 
1265
        }
 
1266
 
 
1267
        /*
 
1268
         * Check for MOREDATA and/or MORECTL.
 
1269
         */
 
1270
        if (result & (MORECTL|MOREDATA)) {
 
1271
                return -1;
 
1272
        }
 
1273
 
 
1274
        /*
 
1275
         * Check for at least sizeof (long) control data portion.
 
1276
         */
 
1277
        if (ctlp -> len < sizeof (long)) {
 
1278
                return -1;
 
1279
        }
 
1280
 
 
1281
        return 0;
 
1282
}
 
1283
 
 
1284
int can_unicast_without_arp (ip)
 
1285
        struct interface_info *ip;
 
1286
{
 
1287
        return 1;
 
1288
}
 
1289
 
 
1290
int can_receive_unicast_unconfigured (ip)
 
1291
        struct interface_info *ip;
 
1292
{
 
1293
        return 1;
 
1294
}
 
1295
 
 
1296
int supports_multiple_interfaces (ip)
 
1297
        struct interface_info *ip;
 
1298
{
 
1299
        return 1;
 
1300
}
 
1301
 
 
1302
void maybe_setup_fallback ()
 
1303
{
 
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,
 
1309
                                                   if_readsocket, 0,
 
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);
 
1315
        }
 
1316
}
 
1317
 
 
1318
void 
 
1319
get_hw_addr(const char *name, struct hardware *hw) {
 
1320
        int sock;
 
1321
        long buf[DLPI_MAXDLBUF];
 
1322
        union DL_primitives *dlp;
 
1323
 
 
1324
        dlp = (union DL_primitives *)buf;
 
1325
 
 
1326
        /* 
 
1327
         * Open a DLPI device.
 
1328
         */
 
1329
        sock = dlpiopen(name);
 
1330
        if (sock < 0) {
 
1331
                log_fatal("Can't open DLPI device for %s: %m", name);
 
1332
        }
 
1333
 
 
1334
        /*
 
1335
         * Submit a DL_INFO_REQ request, to find the dl_mac_type and 
 
1336
         * dl_provider_style
 
1337
         */
 
1338
        if (dlpiinforeq(sock) < 0) {
 
1339
            log_fatal("Can't request DLPI MAC type for %s: %m", name);
 
1340
        }
 
1341
        if (dlpiinfoack(sock, (char *)buf) < 0) {
 
1342
            log_fatal("Can't get DLPI MAC type for %s: %m", name);
 
1343
        }
 
1344
        switch (dlp->info_ack.dl_mac_type) {
 
1345
                case DL_CSMACD: /* IEEE 802.3 */
 
1346
                case DL_ETHER:
 
1347
                        hw->hbuf[0] = HTYPE_ETHER;
 
1348
                        break;
 
1349
                case DL_TPR:
 
1350
                        hw->hbuf[0] = HTYPE_IEEE802;
 
1351
                        break;
 
1352
                case DL_FDDI:
 
1353
                        hw->hbuf[0] = HTYPE_FDDI;
 
1354
                        break;
 
1355
                default:
 
1356
                        log_fatal("%s: unsupported DLPI MAC type %lu", name,
 
1357
                                  (unsigned long)dlp->info_ack.dl_mac_type);
 
1358
        }
 
1359
 
 
1360
        /*
 
1361
         * Submit a DL_PHYS_ADDR_REQ request, to find
 
1362
         * the hardware address.
 
1363
         */
 
1364
        if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) {
 
1365
                log_fatal("Can't request DLPI hardware address for %s: %m",
 
1366
                          name);
 
1367
        }
 
1368
        if (dlpiphysaddrack(sock, (char *)buf) < 0) {
 
1369
                log_fatal("Can't get DLPI hardware address for %s: %m",
 
1370
                          name);
 
1371
        }
 
1372
        if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) {
 
1373
                memcpy(hw->hbuf+1, 
 
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;
 
1377
        } else {
 
1378
                memcpy(hw->hbuf+1, 
 
1379
                       (char *)buf + dlp->physaddr_ack.dl_addr_offset,
 
1380
                       sizeof(hw->hbuf)-1);
 
1381
                hw->hlen = sizeof(hw->hbuf);
 
1382
        }
 
1383
 
 
1384
        close(sock);
 
1385
}
 
1386
#endif /* USE_DLPI */