ISC DHCP  4.3.0
A reference DHCPv4 and DHCPv6 implementation
lpf.c
Go to the documentation of this file.
1 /* lpf.c
2 
3  Linux packet filter code, contributed by Brian Murrel at Interlinx
4  Support Services in Vancouver, B.C. */
5 
6 /*
7  * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1996-2003 by Internet Software Consortium
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Internet Systems Consortium, Inc.
24  * 950 Charter Street
25  * Redwood City, CA 94063
26  * <info@isc.org>
27  * https://www.isc.org/
28  */
29 
30 #include "dhcpd.h"
31 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
32 #include <sys/socket.h>
33 #include <sys/uio.h>
34 #include <errno.h>
35 
36 #include <asm/types.h>
37 #include <linux/filter.h>
38 #include <linux/if_ether.h>
39 #include <linux/if_packet.h>
40 #include <netinet/in_systm.h>
41 #include "includes/netinet/ip.h"
42 #include "includes/netinet/udp.h"
44 #endif
45 
46 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
47 #include <sys/ioctl.h>
48 #include <net/if.h>
49 #include <ifaddrs.h>
50 
51 /* Default broadcast address for IPoIB */
52 static unsigned char default_ib_bcast_addr[20] = {
53  0x00, 0xff, 0xff, 0xff,
54  0xff, 0x12, 0x40, 0x1b,
55  0x00, 0x00, 0x00, 0x00,
56  0x00, 0x00, 0x00, 0x00,
57  0xff, 0xff, 0xff, 0xff
58 };
59 
60 #endif
61 
62 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
63 /* Reinitializes the specified interface after an address change. This
64  is not required for packet-filter APIs. */
65 
66 #ifndef PACKET_AUXDATA
67 #define PACKET_AUXDATA 8
68 
69 struct tpacket_auxdata
70 {
71  __u32 tp_status;
72  __u32 tp_len;
73  __u32 tp_snaplen;
74  __u16 tp_mac;
75  __u16 tp_net;
76 };
77 #endif
78 
79 #ifdef USE_LPF_SEND
80 void if_reinitialize_send (info)
81  struct interface_info *info;
82 {
83 }
84 #endif
85 
86 #ifdef USE_LPF_RECEIVE
87 void if_reinitialize_receive (info)
88  struct interface_info *info;
89 {
90 }
91 #endif
92 
93 /* Called by get_interface_list for each interface that's discovered.
94  Opens a packet filter for each interface and adds it to the select
95  mask. */
96 
97 int if_register_lpf (info)
98  struct interface_info *info;
99 {
100  int sock;
101  union {
102  struct sockaddr_ll ll;
103  struct sockaddr common;
104  } sa;
105  struct ifreq ifr;
106  int type;
107  int protocol;
108 
109  /* Make an LPF socket. */
110  get_hw_addr(info);
111 
112  if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
113  type = SOCK_DGRAM;
114  protocol = ETHERTYPE_IP;
115  } else {
116  type = SOCK_RAW;
117  protocol = ETH_P_ALL;
118  }
119 
120  if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) {
121  if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
122  errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
123  errno == EAFNOSUPPORT || errno == EINVAL) {
124  log_error ("socket: %m - make sure");
125  log_error ("CONFIG_PACKET (Packet socket) %s",
126  "and CONFIG_FILTER");
127  log_error ("(Socket Filtering) are enabled %s",
128  "in your kernel");
129  log_fatal ("configuration!");
130  }
131  log_fatal ("Open a socket for LPF: %m");
132  }
133 
134  memset (&ifr, 0, sizeof ifr);
135  strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name);
136  ifr.ifr_name[IFNAMSIZ-1] = '\0';
137  if (ioctl (sock, SIOCGIFINDEX, &ifr))
138  log_fatal ("Failed to get interface index: %m");
139 
140  /* Bind to the interface name */
141  memset (&sa, 0, sizeof sa);
142  sa.ll.sll_family = AF_PACKET;
143  sa.ll.sll_protocol = htons(protocol);
144  sa.ll.sll_ifindex = ifr.ifr_ifindex;
145  if (bind (sock, &sa.common, sizeof sa)) {
146  if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
147  errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
148  errno == EAFNOSUPPORT || errno == EINVAL) {
149  log_error ("socket: %m - make sure");
150  log_error ("CONFIG_PACKET (Packet socket) %s",
151  "and CONFIG_FILTER");
152  log_error ("(Socket Filtering) are enabled %s",
153  "in your kernel");
154  log_fatal ("configuration!");
155  }
156  log_fatal ("Bind socket to interface: %m");
157  }
158 
159  return sock;
160 }
161 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
162 
163 #ifdef USE_LPF_SEND
164 void if_register_send (info)
165  struct interface_info *info;
166 {
167  int hlen;
168 
169  /* If we're using the lpf API for sending and receiving,
170  we don't need to register this interface twice. */
171 #ifndef USE_LPF_RECEIVE
172  info -> wfdesc = if_register_lpf (info);
173 #else
174  info -> wfdesc = info -> rfdesc;
175 #endif
176  if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND)
177  hlen = 9;
178  else
179  hlen = info -> hw_address.hlen;
181  log_info ("Sending on LPF/%s/%s%s%s",
182  info -> name,
183  print_hw_addr (info -> hw_address.hbuf [0],
184  hlen - 1,
185  &info -> hw_address.hbuf [1]),
186  (info -> shared_network ? "/" : ""),
187  (info -> shared_network ?
188  info -> shared_network -> name : ""));
189 }
190 
191 void if_deregister_send (info)
192  struct interface_info *info;
193 {
194  int hlen = info -> hw_address.hlen;
195  if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND)
196  hlen = 9;
197 
198  /* don't need to close twice if we are using lpf for sending and
199  receiving */
200 #ifndef USE_LPF_RECEIVE
201  /* for LPF this is simple, packet filters are removed when sockets
202  are closed */
203  close (info -> wfdesc);
204 #endif
205  info -> wfdesc = -1;
207  log_info ("Disabling output on LPF/%s/%s%s%s",
208  info -> name,
209  print_hw_addr (info -> hw_address.hbuf [0],
210  hlen - 1,
211  &info -> hw_address.hbuf [1]),
212  (info -> shared_network ? "/" : ""),
213  (info -> shared_network ?
214  info -> shared_network -> name : ""));
215 }
216 #endif /* USE_LPF_SEND */
217 
218 #ifdef USE_LPF_RECEIVE
219 /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
220  in bpf includes... */
221 extern struct sock_filter dhcp_bpf_filter [];
222 extern int dhcp_bpf_filter_len;
223 extern struct sock_filter dhcp_ib_bpf_filter [];
224 extern int dhcp_ib_bpf_filter_len;
225 
226 #if defined (HAVE_TR_SUPPORT)
227 extern struct sock_filter dhcp_bpf_tr_filter [];
228 extern int dhcp_bpf_tr_filter_len;
229 static void lpf_tr_filter_setup (struct interface_info *);
230 #endif
231 
232 static void lpf_gen_filter_setup (struct interface_info *);
233 
234 void if_register_receive (info)
235  struct interface_info *info;
236 {
237  int val, hlen;
238 
239  /* Open a LPF device and hang it on this interface... */
240  info -> rfdesc = if_register_lpf (info);
241 
242  if (info->hw_address.hbuf[0] != HTYPE_INFINIBAND) {
243  val = 1;
244  if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA,
245  &val, sizeof val) < 0) {
246  if (errno != ENOPROTOOPT)
247  log_fatal ("Failed to set auxiliary packet data: %m");
248  }
249  hlen = info -> hw_address.hlen;
250  } else
251  hlen = 9;
252 
253 #if defined (HAVE_TR_SUPPORT)
254  if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
255  lpf_tr_filter_setup (info);
256  else
257 #endif
258  lpf_gen_filter_setup (info);
259 
261  log_info ("Listening on LPF/%s/%s%s%s",
262  info -> name,
263  print_hw_addr (info -> hw_address.hbuf [0],
264  hlen - 1,
265  &info -> hw_address.hbuf [1]),
266  (info -> shared_network ? "/" : ""),
267  (info -> shared_network ?
268  info -> shared_network -> name : ""));
269 }
270 
271 void if_deregister_receive (info)
272  struct interface_info *info;
273 {
274  int hlen = info -> hw_address.hlen;
275  if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND)
276  hlen = 9;
277 
278  /* for LPF this is simple, packet filters are removed when sockets
279  are closed */
280  close (info -> rfdesc);
281  info -> rfdesc = -1;
283  log_info ("Disabling input on LPF/%s/%s%s%s",
284  info -> name,
285  print_hw_addr (info -> hw_address.hbuf [0],
286  hlen - 1,
287  &info -> hw_address.hbuf [1]),
288  (info -> shared_network ? "/" : ""),
289  (info -> shared_network ?
290  info -> shared_network -> name : ""));
291 }
292 
293 static void lpf_gen_filter_setup (info)
294  struct interface_info *info;
295 {
296  struct sock_fprog p;
297 
298  memset(&p, 0, sizeof(p));
299 
300  if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
301  /* Set up the bpf filter program structure. */
302  p.len = dhcp_ib_bpf_filter_len;
303  p.filter = dhcp_ib_bpf_filter;
304 
305  /* Patch the server port into the LPF program...
306  XXX
307  changes to filter program may require changes
308  to the insn number(s) used below!
309  XXX */
310  dhcp_ib_bpf_filter[6].k = ntohs ((short)local_port);
311  } else {
312  /* Set up the bpf filter program structure.
313  This is defined in bpf.c */
314  p.len = dhcp_bpf_filter_len;
315  p.filter = dhcp_bpf_filter;
316 
317  /* Patch the server port into the LPF program...
318  XXX changes to filter program may require changes
319  to the insn number(s) used below! XXX */
320  dhcp_bpf_filter [8].k = ntohs ((short)local_port);
321  }
322 
323  if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
324  sizeof p) < 0) {
325  if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
326  errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
327  errno == EAFNOSUPPORT) {
328  log_error ("socket: %m - make sure");
329  log_error ("CONFIG_PACKET (Packet socket) %s",
330  "and CONFIG_FILTER");
331  log_error ("(Socket Filtering) are enabled %s",
332  "in your kernel");
333  log_fatal ("configuration!");
334  }
335  log_fatal ("Can't install packet filter program: %m");
336  }
337 }
338 
339 #if defined (HAVE_TR_SUPPORT)
340 static void lpf_tr_filter_setup (info)
341  struct interface_info *info;
342 {
343  struct sock_fprog p;
344 
345  memset(&p, 0, sizeof(p));
346 
347  /* Set up the bpf filter program structure. This is defined in
348  bpf.c */
349  p.len = dhcp_bpf_tr_filter_len;
350  p.filter = dhcp_bpf_tr_filter;
351 
352  /* Patch the server port into the LPF program...
353  XXX changes to filter program may require changes
354  XXX to the insn number(s) used below!
355  XXX Token ring filter is null - when/if we have a filter
356  XXX that's not, we'll need this code.
357  XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
358 
359  if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
360  sizeof p) < 0) {
361  if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
362  errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
363  errno == EAFNOSUPPORT) {
364  log_error ("socket: %m - make sure");
365  log_error ("CONFIG_PACKET (Packet socket) %s",
366  "and CONFIG_FILTER");
367  log_error ("(Socket Filtering) are enabled %s",
368  "in your kernel");
369  log_fatal ("configuration!");
370  }
371  log_fatal ("Can't install packet filter program: %m");
372  }
373 }
374 #endif /* HAVE_TR_SUPPORT */
375 #endif /* USE_LPF_RECEIVE */
376 
377 #ifdef USE_LPF_SEND
378 ssize_t send_packet_ib(interface, packet, raw, len, from, to, hto)
379  struct interface_info *interface;
380  struct packet *packet;
381  struct dhcp_packet *raw;
382  size_t len;
383  struct in_addr from;
384  struct sockaddr_in *to;
385  struct hardware *hto;
386 {
387  unsigned ibufp = 0;
388  double ih [1536 / sizeof (double)];
389  unsigned char *buf = (unsigned char *)ih;
390  ssize_t result;
391 
392  union sockunion {
393  struct sockaddr sa;
394  struct sockaddr_ll sll;
395  struct sockaddr_storage ss;
396  } su;
397 
398  assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
399  to->sin_addr.s_addr, to->sin_port,
400  (unsigned char *)raw, len);
401  memcpy (buf + ibufp, raw, len);
402 
403  memset(&su, 0, sizeof(su));
404  su.sll.sll_family = AF_PACKET;
405  su.sll.sll_protocol = htons(ETHERTYPE_IP);
406 
407  if (!(su.sll.sll_ifindex = if_nametoindex(interface->name))) {
408  errno = ENOENT;
409  log_error ("send_packet_ib: %m - failed to get if index");
410  return -1;
411  }
412 
413  su.sll.sll_hatype = htons(HTYPE_INFINIBAND);
414  su.sll.sll_halen = sizeof(interface->bcast_addr);
415  memcpy(&su.sll.sll_addr, interface->bcast_addr, 20);
416 
417  result = sendto(interface->wfdesc, buf, ibufp + len, 0,
418  &su.sa, sizeof(su));
419 
420  if (result < 0)
421  log_error ("send_packet_ib: %m");
422 
423  return result;
424 }
425 
426 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
427  struct interface_info *interface;
428  struct packet *packet;
429  struct dhcp_packet *raw;
430  size_t len;
431  struct in_addr from;
432  struct sockaddr_in *to;
433  struct hardware *hto;
434 {
435  unsigned hbufp = 0, ibufp = 0;
436  double hh [16];
437  double ih [1536 / sizeof (double)];
438  unsigned char *buf = (unsigned char *)ih;
439  int result;
440  int fudge;
441 
442  if (!strcmp (interface -> name, "fallback"))
443  return send_fallback (interface, packet, raw,
444  len, from, to, hto);
445 
446  if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
447  return send_packet_ib(interface, packet, raw, len, from,
448  to, hto);
449  }
450 
451  if (hto == NULL && interface->anycast_mac_addr.hlen)
452  hto = &interface->anycast_mac_addr;
453 
454  /* Assemble the headers... */
455  assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
456  fudge = hbufp % 4; /* IP header must be word-aligned. */
457  memcpy (buf + fudge, (unsigned char *)hh, hbufp);
458  ibufp = hbufp + fudge;
459  assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
460  to -> sin_addr.s_addr, to -> sin_port,
461  (unsigned char *)raw, len);
462  memcpy (buf + ibufp, raw, len);
463 
464  result = write (interface -> wfdesc, buf + fudge, ibufp + len - fudge);
465  if (result < 0)
466  log_error ("send_packet: %m");
467  return result;
468 }
469 #endif /* USE_LPF_SEND */
470 
471 #ifdef USE_LPF_RECEIVE
472 ssize_t receive_packet_ib (interface, buf, len, from, hfrom)
473  struct interface_info *interface;
474  unsigned char *buf;
475  size_t len;
476  struct sockaddr_in *from;
477  struct hardware *hfrom;
478 {
479  int length = 0;
480  int offset = 0;
481  unsigned char ibuf [1536];
482  unsigned bufix = 0;
483  unsigned paylen;
484 
485  length = read(interface->rfdesc, ibuf, sizeof(ibuf));
486 
487  if (length <= 0)
488  return length;
489 
490  offset = decode_udp_ip_header(interface, ibuf, bufix, from,
491  (unsigned)length, &paylen, 0);
492 
493  if (offset < 0)
494  return 0;
495 
496  bufix += offset;
497  length -= offset;
498 
499  if (length < paylen)
500  log_fatal("Internal inconsistency at %s:%d.", MDL);
501 
502  /* Copy out the data in the packet... */
503  memcpy(buf, &ibuf[bufix], paylen);
504 
505  return (ssize_t)paylen;
506 }
507 
508 ssize_t receive_packet (interface, buf, len, from, hfrom)
509  struct interface_info *interface;
510  unsigned char *buf;
511  size_t len;
512  struct sockaddr_in *from;
513  struct hardware *hfrom;
514 {
515  int length = 0;
516  int offset = 0;
517  int nocsum = 0;
518  unsigned char ibuf [1536];
519  unsigned bufix = 0;
520  unsigned paylen;
521  unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
522  struct iovec iov = {
523  .iov_base = ibuf,
524  .iov_len = sizeof ibuf,
525  };
526  struct msghdr msg = {
527  .msg_iov = &iov,
528  .msg_iovlen = 1,
529  .msg_control = cmsgbuf,
530  .msg_controllen = sizeof(cmsgbuf),
531  };
532  struct cmsghdr *cmsg;
533 
534  if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
535  return receive_packet_ib(interface, buf, len, from, hfrom);
536  }
537 
538  length = recvmsg (interface -> rfdesc, &msg, 0);
539  if (length <= 0)
540  return length;
541 
542  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
543  if (cmsg->cmsg_level == SOL_PACKET &&
544  cmsg->cmsg_type == PACKET_AUXDATA) {
545  struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
546  nocsum = aux->tp_status & TP_STATUS_CSUMNOTREADY;
547  }
548  }
549 
550  bufix = 0;
551  /* Decode the physical header... */
552  offset = decode_hw_header (interface, ibuf, bufix, hfrom);
553 
554  /* If a physical layer checksum failed (dunno of any
555  physical layer that supports this, but WTH), skip this
556  packet. */
557  if (offset < 0) {
558  return 0;
559  }
560 
561  bufix += offset;
562  length -= offset;
563 
564  /* Decode the IP and UDP headers... */
565  offset = decode_udp_ip_header (interface, ibuf, bufix, from,
566  (unsigned)length, &paylen, nocsum);
567 
568  /* If the IP or UDP checksum was bad, skip the packet... */
569  if (offset < 0)
570  return 0;
571 
572  bufix += offset;
573  length -= offset;
574 
575  if (length < paylen)
576  log_fatal("Internal inconsistency at %s:%d.", MDL);
577 
578  /* Copy out the data in the packet... */
579  memcpy(buf, &ibuf[bufix], paylen);
580  return paylen;
581 }
582 
584  struct interface_info *ip;
585 {
586  return 1;
587 }
588 
590  struct interface_info *ip;
591 {
592  return 1;
593 }
594 
596  struct interface_info *ip;
597 {
598  return 1;
599 }
600 
601 void maybe_setup_fallback ()
602 {
603  isc_result_t status;
604  struct interface_info *fbi = (struct interface_info *)0;
605  if (setup_fallback (&fbi, MDL)) {
606  if_register_fallback (fbi);
607  status = omapi_register_io_object ((omapi_object_t *)fbi,
608  if_readsocket, 0,
609  fallback_discard, 0, 0);
610  if (status != ISC_R_SUCCESS)
611  log_fatal ("Can't register I/O handle for \"%s\": %s",
612  fbi -> name, isc_result_totext (status));
613  interface_dereference (&fbi, MDL);
614  }
615 }
616 #endif
617 
618 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
619 struct sockaddr_ll *
620 get_ll (struct ifaddrs *ifaddrs, struct ifaddrs **ifa, char *name)
621 {
622  for (*ifa = ifaddrs; *ifa != NULL; *ifa = (*ifa)->ifa_next) {
623  if ((*ifa)->ifa_addr == NULL)
624  continue;
625 
626  if ((*ifa)->ifa_addr->sa_family != AF_PACKET)
627  continue;
628 
629  if ((*ifa)->ifa_flags & IFF_LOOPBACK)
630  continue;
631 
632  if (strcmp((*ifa)->ifa_name, name) == 0)
633  return (struct sockaddr_ll *)(void *)(*ifa)->ifa_addr;
634  }
635  *ifa = NULL;
636  return NULL;
637 }
638 
639 struct sockaddr_ll *
640 ioctl_get_ll(char *name)
641 {
642  int sock;
643  struct ifreq tmp;
644  struct sockaddr *sa = NULL;
645  struct sockaddr_ll *sll = NULL;
646 
647  if (strlen(name) >= sizeof(tmp.ifr_name)) {
648  log_fatal("Device name too long: \"%s\"", name);
649  }
650 
651  sock = socket(AF_INET, SOCK_DGRAM, 0);
652  if (sock < 0) {
653  log_fatal("Can't create socket for \"%s\": %m", name);
654  }
655 
656  memset(&tmp, 0, sizeof(tmp));
657  strcpy(tmp.ifr_name, name);
658  if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
659  log_fatal("Error getting hardware address for \"%s\": %m",
660  name);
661  }
662  close(sock);
663 
664  sa = &tmp.ifr_hwaddr;
665  // needs to be freed outside this function
666  sll = dmalloc (sizeof (struct sockaddr_ll), MDL);
667  if (!sll)
668  log_fatal("Unable to allocate memory for link layer address");
669  memcpy(&sll->sll_hatype, &sa->sa_family, sizeof (sll->sll_hatype));
670  memcpy(sll->sll_addr, sa->sa_data, sizeof (sll->sll_addr));
671  switch (sll->sll_hatype) {
672  case ARPHRD_INFINIBAND:
673  /* ioctl limits hardware addresses to 8 bytes */
674  sll->sll_halen = 8;
675  break;
676  default:
677  break;
678  }
679  return sll;
680 }
681 
682 void
683 get_hw_addr(struct interface_info *info)
684 {
685  struct hardware *hw = &info->hw_address;
686  char *name = info->name;
687  struct ifaddrs *ifaddrs = NULL;
688  struct ifaddrs *ifa = NULL;
689  struct sockaddr_ll *sll = NULL;
690  int sll_allocated = 0;
691  char *dup = NULL;
692  char *colon = NULL;
693 
694  if (getifaddrs(&ifaddrs) == -1)
695  log_fatal("Failed to get interfaces");
696 
697  if ((sll = get_ll(ifaddrs, &ifa, name)) == NULL) {
698  /*
699  * We were unable to get link-layer address for name.
700  * Fall back to ioctl(SIOCGIFHWADDR).
701  */
702  sll = ioctl_get_ll(name);
703  if (sll != NULL)
704  sll_allocated = 1;
705  else
706  // shouldn't happen
707  log_fatal("Unexpected internal error");
708  }
709 
710  switch (sll->sll_hatype) {
711  case ARPHRD_ETHER:
712  hw->hlen = 7;
713  hw->hbuf[0] = HTYPE_ETHER;
714  memcpy(&hw->hbuf[1], sll->sll_addr, 6);
715  break;
716  case ARPHRD_IEEE802:
717 #ifdef ARPHRD_IEEE802_TR
718  case ARPHRD_IEEE802_TR:
719 #endif /* ARPHRD_IEEE802_TR */
720  hw->hlen = 7;
721  hw->hbuf[0] = HTYPE_IEEE802;
722  memcpy(&hw->hbuf[1], sll->sll_addr, 6);
723  break;
724  case ARPHRD_FDDI:
725  hw->hlen = 7;
726  hw->hbuf[0] = HTYPE_FDDI;
727  memcpy(&hw->hbuf[1], sll->sll_addr, 6);
728  break;
729  case ARPHRD_INFINIBAND:
730  dup = strdup(name);
731  /* Aliased infiniband interface is special case where
732  * neither get_ll() nor ioctl_get_ll() get's correct hw
733  * address, so we have to truncate the :0 and run
734  * get_ll() again for the rest.
735  */
736  if ((colon = strchr(dup, ':')) != NULL) {
737  *colon = '\0';
738  if ((sll = get_ll(ifaddrs, &ifa, dup)) == NULL)
739  log_fatal("Error getting hardware address for \"%s\": %m", name);
740  }
741  free (dup);
742  /* For Infiniband, save the broadcast address and store
743  * the port GUID into the hardware address.
744  */
745  if (ifa && (ifa->ifa_flags & IFF_BROADCAST)) {
746  struct sockaddr_ll *bll;
747 
748  bll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
749  memcpy(&info->bcast_addr, bll->sll_addr, 20);
750  } else {
751  memcpy(&info->bcast_addr, default_ib_bcast_addr,
752  20);
753  }
754 
755  hw->hlen = 1;
756  hw->hbuf[0] = HTYPE_INFINIBAND;
757  memcpy(&hw->hbuf[1], &sll->sll_addr[sll->sll_halen - 8], 8);
758  break;
759 #if defined(ARPHRD_PPP)
760  case ARPHRD_PPP:
761  if (local_family != AF_INET6)
762  log_fatal("local_family != AF_INET6 for \"%s\"",
763  name);
764  hw->hlen = 0;
765  hw->hbuf[0] = HTYPE_RESERVED;
766  /* 0xdeadbeef should never occur on the wire,
767  * and is a signature that something went wrong.
768  */
769  hw->hbuf[1] = 0xde;
770  hw->hbuf[2] = 0xad;
771  hw->hbuf[3] = 0xbe;
772  hw->hbuf[4] = 0xef;
773  break;
774 #endif
775  default:
776  freeifaddrs(ifaddrs);
777  log_fatal("Unsupported device type %hu for \"%s\"",
778  sll->sll_hatype, name);
779  }
780 
781  if (sll_allocated)
782  dfree(sll, MDL);
783  freeifaddrs(ifaddrs);
784 }
785 #endif
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:440
int if_readsocket(omapi_object_t *h)
Definition: discover.c:961
char name[IFNAMSIZ]
Definition: dhcpd.h:1267
void if_reinitialize_send(struct interface_info *)
void * dmalloc(unsigned, const char *, int)
Definition: alloc.c:56
ssize_t decode_udp_ip_header(struct interface_info *, unsigned char *, unsigned, struct sockaddr_in *, unsigned, unsigned *, int)
#define HTYPE_RESERVED
Definition: dhcp.h:84
#define MDL
Definition: omapip.h:568
int can_receive_unicast_unconfigured(struct interface_info *)
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition: discover.c:972
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
#define HTYPE_INFINIBAND
Definition: dhcp.h:79
u_int16_t local_port
Definition: dhclient.c:87
Definition: dhcpd.h:369
void assemble_hw_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
int if_register_lpf(struct interface_info *)
u_int8_t bcast_addr[20]
Definition: dhcpd.h:1246
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 *)
void dfree(void *, const char *, int)
Definition: alloc.c:131
struct hardware hw_address
Definition: dhcpd.h:1245
int int log_info(const char *,...) __attribute__((__format__(__printf__
int local_family
Definition: discover.c:52
int quiet_interface_discovery
Definition: discover.c:42
#define HTYPE_FDDI
Definition: dhcp.h:78
void if_register_fallback(struct interface_info *)
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:441
struct hardware anycast_mac_addr
Definition: dhcpd.h:1296
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 *)