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