common/lpf.c

Go to the documentation of this file.
00001 /* lpf.c
00002 
00003    Linux packet filter code, contributed by Brian Murrel at Interlinx
00004    Support Services in Vancouver, B.C. */
00005 
00006 /*
00007  * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
00009  * Copyright (c) 1996-2003 by Internet Software Consortium
00010  *
00011  * Permission to use, copy, modify, and distribute this software for any
00012  * purpose with or without fee is hereby granted, provided that the above
00013  * copyright notice and this permission notice appear in all copies.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00016  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00017  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00018  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00019  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00020  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00021  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00022  *
00023  *   Internet Systems Consortium, Inc.
00024  *   950 Charter Street
00025  *   Redwood City, CA 94063
00026  *   <info@isc.org>
00027  *   https://www.isc.org/
00028  */
00029 
00030 #include "dhcpd.h"
00031 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
00032 #include <sys/socket.h>
00033 #include <sys/uio.h>
00034 #include <errno.h>
00035 
00036 #include <asm/types.h>
00037 #include <linux/filter.h>
00038 #include <linux/if_ether.h>
00039 #include <linux/if_packet.h>
00040 #include <netinet/in_systm.h>
00041 #include "includes/netinet/ip.h"
00042 #include "includes/netinet/udp.h"
00043 #include "includes/netinet/if_ether.h"
00044 #endif
00045 
00046 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
00047 #include <sys/ioctl.h>
00048 #include <net/if.h>
00049 #include <ifaddrs.h>
00050 
00051 /* Default broadcast address for IPoIB */
00052 static unsigned char default_ib_bcast_addr[20] = {
00053         0x00, 0xff, 0xff, 0xff,
00054         0xff, 0x12, 0x40, 0x1b,
00055         0x00, 0x00, 0x00, 0x00,
00056         0x00, 0x00, 0x00, 0x00,
00057         0xff, 0xff, 0xff, 0xff
00058 };
00059 
00060 #endif
00061 
00062 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
00063 /* Reinitializes the specified interface after an address change.   This
00064    is not required for packet-filter APIs. */
00065 
00066 #ifndef PACKET_AUXDATA
00067 #define PACKET_AUXDATA 8
00068 
00069 struct tpacket_auxdata
00070 {
00071         __u32           tp_status;
00072         __u32           tp_len;
00073         __u32           tp_snaplen;
00074         __u16           tp_mac;
00075         __u16           tp_net;
00076 };
00077 #endif
00078 
00079 #ifdef USE_LPF_SEND
00080 void if_reinitialize_send (info)
00081         struct interface_info *info;
00082 {
00083 }
00084 #endif
00085 
00086 #ifdef USE_LPF_RECEIVE
00087 void if_reinitialize_receive (info)
00088         struct interface_info *info;
00089 {
00090 }
00091 #endif
00092 
00093 /* Called by get_interface_list for each interface that's discovered.
00094    Opens a packet filter for each interface and adds it to the select
00095    mask. */
00096 
00097 int if_register_lpf (info)
00098         struct interface_info *info;
00099 {
00100         int sock;
00101         union {
00102                 struct sockaddr_ll ll;
00103                 struct sockaddr common;
00104         } sa;
00105         struct ifreq ifr;
00106         int type;
00107         int protocol;
00108 
00109         /* Make an LPF socket. */
00110         get_hw_addr(info);
00111 
00112         if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
00113                 type = SOCK_DGRAM;
00114                 protocol = ETHERTYPE_IP;
00115         } else {
00116                 type = SOCK_RAW;
00117                 protocol = ETH_P_ALL;
00118         }
00119 
00120         if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) {
00121                 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
00122                     errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
00123                     errno == EAFNOSUPPORT || errno == EINVAL) {
00124                         log_error ("socket: %m - make sure");
00125                         log_error ("CONFIG_PACKET (Packet socket) %s",
00126                                    "and CONFIG_FILTER");
00127                         log_error ("(Socket Filtering) are enabled %s",
00128                                    "in your kernel");
00129                         log_fatal ("configuration!");
00130                 }
00131                 log_fatal ("Open a socket for LPF: %m");
00132         }
00133 
00134         memset (&ifr, 0, sizeof ifr);
00135         strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name);
00136         ifr.ifr_name[IFNAMSIZ-1] = '\0';
00137         if (ioctl (sock, SIOCGIFINDEX, &ifr))
00138                 log_fatal ("Failed to get interface index: %m");
00139 
00140         /* Bind to the interface name */
00141         memset (&sa, 0, sizeof sa);
00142         sa.ll.sll_family = AF_PACKET;
00143         sa.ll.sll_protocol = htons(protocol);
00144         sa.ll.sll_ifindex = ifr.ifr_ifindex;
00145         if (bind (sock, &sa.common, sizeof sa)) {
00146                 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
00147                     errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
00148                     errno == EAFNOSUPPORT || errno == EINVAL) {
00149                         log_error ("socket: %m - make sure");
00150                         log_error ("CONFIG_PACKET (Packet socket) %s",
00151                                    "and CONFIG_FILTER");
00152                         log_error ("(Socket Filtering) are enabled %s",
00153                                    "in your kernel");
00154                         log_fatal ("configuration!");
00155                 }
00156                 log_fatal ("Bind socket to interface: %m");
00157         }
00158 
00159         return sock;
00160 }
00161 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
00162 
00163 #ifdef USE_LPF_SEND
00164 void if_register_send (info)
00165         struct interface_info *info;
00166 {
00167         int hlen;
00168 
00169         /* If we're using the lpf API for sending and receiving,
00170            we don't need to register this interface twice. */
00171 #ifndef USE_LPF_RECEIVE
00172         info -> wfdesc = if_register_lpf (info);
00173 #else
00174         info -> wfdesc = info -> rfdesc;
00175 #endif
00176         if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND)
00177                 hlen = 9;
00178         else
00179                 hlen = info -> hw_address.hlen;
00180         if (!quiet_interface_discovery)
00181                 log_info ("Sending on   LPF/%s/%s%s%s",
00182                       info -> name,
00183                       print_hw_addr (info -> hw_address.hbuf [0],
00184                                      hlen - 1,
00185                                      &info -> hw_address.hbuf [1]),
00186                       (info -> shared_network ? "/" : ""),
00187                       (info -> shared_network ?
00188                        info -> shared_network -> name : ""));
00189 }
00190 
00191 void if_deregister_send (info)
00192         struct interface_info *info;
00193 {
00194         int hlen = info -> hw_address.hlen;
00195         if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND)
00196                 hlen = 9;
00197 
00198         /* don't need to close twice if we are using lpf for sending and
00199            receiving */
00200 #ifndef USE_LPF_RECEIVE
00201         /* for LPF this is simple, packet filters are removed when sockets
00202            are closed */
00203         close (info -> wfdesc);
00204 #endif
00205         info -> wfdesc = -1;
00206         if (!quiet_interface_discovery)
00207                 log_info ("Disabling output on LPF/%s/%s%s%s",
00208                       info -> name,
00209                       print_hw_addr (info -> hw_address.hbuf [0],
00210                                      hlen - 1,
00211                                      &info -> hw_address.hbuf [1]),
00212                       (info -> shared_network ? "/" : ""),
00213                       (info -> shared_network ?
00214                        info -> shared_network -> name : ""));
00215 }
00216 #endif /* USE_LPF_SEND */
00217 
00218 #ifdef USE_LPF_RECEIVE
00219 /* Defined in bpf.c.   We can't extern these in dhcpd.h without pulling
00220    in bpf includes... */
00221 extern struct sock_filter dhcp_bpf_filter [];
00222 extern int dhcp_bpf_filter_len;
00223 extern struct sock_filter dhcp_ib_bpf_filter [];
00224 extern int dhcp_ib_bpf_filter_len;
00225 
00226 #if defined (HAVE_TR_SUPPORT)
00227 extern struct sock_filter dhcp_bpf_tr_filter [];
00228 extern int dhcp_bpf_tr_filter_len;
00229 static void lpf_tr_filter_setup (struct interface_info *);
00230 #endif
00231 
00232 static void lpf_gen_filter_setup (struct interface_info *);
00233 
00234 void if_register_receive (info)
00235         struct interface_info *info;
00236 {
00237         int val, hlen;
00238 
00239         /* Open a LPF device and hang it on this interface... */
00240         info -> rfdesc = if_register_lpf (info);
00241 
00242         if (info->hw_address.hbuf[0] != HTYPE_INFINIBAND) {
00243                 val = 1;
00244                 if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA,
00245                                 &val, sizeof val) < 0) {
00246                         if (errno != ENOPROTOOPT)
00247                                 log_fatal ("Failed to set auxiliary packet data: %m");
00248                 }
00249                 hlen = info -> hw_address.hlen;
00250         } else
00251                 hlen = 9;
00252 
00253 #if defined (HAVE_TR_SUPPORT)
00254         if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
00255                 lpf_tr_filter_setup (info);
00256         else
00257 #endif
00258                 lpf_gen_filter_setup (info);
00259 
00260         if (!quiet_interface_discovery)
00261                 log_info ("Listening on LPF/%s/%s%s%s",
00262                           info -> name,
00263                           print_hw_addr (info -> hw_address.hbuf [0],
00264                                          hlen - 1,
00265                                          &info -> hw_address.hbuf [1]),
00266                           (info -> shared_network ? "/" : ""),
00267                           (info -> shared_network ?
00268                            info -> shared_network -> name : ""));
00269 }
00270 
00271 void if_deregister_receive (info)
00272         struct interface_info *info;
00273 {
00274         int hlen = info -> hw_address.hlen;
00275         if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND)
00276                 hlen = 9;
00277 
00278         /* for LPF this is simple, packet filters are removed when sockets
00279            are closed */
00280         close (info -> rfdesc);
00281         info -> rfdesc = -1;
00282         if (!quiet_interface_discovery)
00283                 log_info ("Disabling input on LPF/%s/%s%s%s",
00284                           info -> name,
00285                           print_hw_addr (info -> hw_address.hbuf [0],
00286                                          hlen - 1,
00287                                          &info -> hw_address.hbuf [1]),
00288                           (info -> shared_network ? "/" : ""),
00289                           (info -> shared_network ?
00290                            info -> shared_network -> name : ""));
00291 }
00292 
00293 static void lpf_gen_filter_setup (info)
00294         struct interface_info *info;
00295 {
00296         struct sock_fprog p;
00297 
00298         memset(&p, 0, sizeof(p));
00299 
00300         if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
00301                 /* Set up the bpf filter program structure. */
00302                 p.len = dhcp_ib_bpf_filter_len;
00303                 p.filter = dhcp_ib_bpf_filter;
00304 
00305                 /* Patch the server port into the LPF program...
00306                    XXX
00307                    changes to filter program may require changes
00308                    to the insn number(s) used below!
00309                    XXX */
00310                 dhcp_ib_bpf_filter[6].k = ntohs ((short)local_port);
00311         } else {
00312                 /* Set up the bpf filter program structure.
00313                    This is defined in bpf.c */
00314                 p.len = dhcp_bpf_filter_len;
00315                 p.filter = dhcp_bpf_filter;
00316 
00317                 /* Patch the server port into the LPF  program...
00318                    XXX changes to filter program may require changes
00319                    to the insn number(s) used below! XXX */
00320                 dhcp_bpf_filter [8].k = ntohs ((short)local_port);
00321         }
00322 
00323         if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
00324                         sizeof p) < 0) {
00325                 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
00326                     errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
00327                     errno == EAFNOSUPPORT) {
00328                         log_error ("socket: %m - make sure");
00329                         log_error ("CONFIG_PACKET (Packet socket) %s",
00330                                    "and CONFIG_FILTER");
00331                         log_error ("(Socket Filtering) are enabled %s",
00332                                    "in your kernel");
00333                         log_fatal ("configuration!");
00334                 }
00335                 log_fatal ("Can't install packet filter program: %m");
00336         }
00337 }
00338 
00339 #if defined (HAVE_TR_SUPPORT)
00340 static void lpf_tr_filter_setup (info)
00341         struct interface_info *info;
00342 {
00343         struct sock_fprog p;
00344 
00345         memset(&p, 0, sizeof(p));
00346 
00347         /* Set up the bpf filter program structure.    This is defined in
00348            bpf.c */
00349         p.len = dhcp_bpf_tr_filter_len;
00350         p.filter = dhcp_bpf_tr_filter;
00351 
00352         /* Patch the server port into the LPF  program...
00353            XXX changes to filter program may require changes
00354            XXX to the insn number(s) used below!
00355            XXX Token ring filter is null - when/if we have a filter 
00356            XXX that's not, we'll need this code.
00357            XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
00358 
00359         if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
00360                         sizeof p) < 0) {
00361                 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
00362                     errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
00363                     errno == EAFNOSUPPORT) {
00364                         log_error ("socket: %m - make sure");
00365                         log_error ("CONFIG_PACKET (Packet socket) %s",
00366                                    "and CONFIG_FILTER");
00367                         log_error ("(Socket Filtering) are enabled %s",
00368                                    "in your kernel");
00369                         log_fatal ("configuration!");
00370                 }
00371                 log_fatal ("Can't install packet filter program: %m");
00372         }
00373 }
00374 #endif /* HAVE_TR_SUPPORT */
00375 #endif /* USE_LPF_RECEIVE */
00376 
00377 #ifdef USE_LPF_SEND
00378 ssize_t send_packet_ib(interface, packet, raw, len, from, to, hto)
00379         struct interface_info *interface;
00380         struct packet *packet;
00381         struct dhcp_packet *raw;
00382         size_t len;
00383         struct in_addr from;
00384         struct sockaddr_in *to;
00385         struct hardware *hto;
00386 {
00387         unsigned ibufp = 0;
00388         double ih [1536 / sizeof (double)];
00389         unsigned char *buf = (unsigned char *)ih;
00390         ssize_t result;
00391 
00392         union sockunion {
00393                 struct sockaddr sa;
00394                 struct sockaddr_ll sll;
00395                 struct sockaddr_storage ss;
00396         } su;
00397 
00398         assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
00399                                 to->sin_addr.s_addr, to->sin_port,
00400                                 (unsigned char *)raw, len);
00401         memcpy (buf + ibufp, raw, len);
00402 
00403         memset(&su, 0, sizeof(su));
00404         su.sll.sll_family = AF_PACKET;
00405         su.sll.sll_protocol = htons(ETHERTYPE_IP);
00406 
00407         if (!(su.sll.sll_ifindex = if_nametoindex(interface->name))) {
00408                 errno = ENOENT;
00409                 log_error ("send_packet_ib: %m - failed to get if index");
00410                 return -1;
00411         }
00412 
00413         su.sll.sll_hatype = htons(HTYPE_INFINIBAND);
00414         su.sll.sll_halen = sizeof(interface->bcast_addr);
00415         memcpy(&su.sll.sll_addr, interface->bcast_addr, 20);
00416 
00417         result = sendto(interface->wfdesc, buf, ibufp + len, 0,
00418                         &su.sa, sizeof(su));
00419 
00420         if (result < 0)
00421                 log_error ("send_packet_ib: %m");
00422 
00423         return result;
00424 }
00425 
00426 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
00427         struct interface_info *interface;
00428         struct packet *packet;
00429         struct dhcp_packet *raw;
00430         size_t len;
00431         struct in_addr from;
00432         struct sockaddr_in *to;
00433         struct hardware *hto;
00434 {
00435         unsigned hbufp = 0, ibufp = 0;
00436         double hh [16];
00437         double ih [1536 / sizeof (double)];
00438         unsigned char *buf = (unsigned char *)ih;
00439         int result;
00440         int fudge;
00441 
00442         if (!strcmp (interface -> name, "fallback"))
00443                 return send_fallback (interface, packet, raw,
00444                                       len, from, to, hto);
00445 
00446         if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
00447                 return send_packet_ib(interface, packet, raw, len, from,
00448                                       to, hto);
00449         }
00450 
00451         if (hto == NULL && interface->anycast_mac_addr.hlen)
00452                 hto = &interface->anycast_mac_addr;
00453 
00454         /* Assemble the headers... */
00455         assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
00456         fudge = hbufp % 4;      /* IP header must be word-aligned. */
00457         memcpy (buf + fudge, (unsigned char *)hh, hbufp);
00458         ibufp = hbufp + fudge;
00459         assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
00460                                 to -> sin_addr.s_addr, to -> sin_port,
00461                                 (unsigned char *)raw, len);
00462         memcpy (buf + ibufp, raw, len);
00463 
00464         result = write (interface -> wfdesc, buf + fudge, ibufp + len - fudge);
00465         if (result < 0)
00466                 log_error ("send_packet: %m");
00467         return result;
00468 }
00469 #endif /* USE_LPF_SEND */
00470 
00471 #ifdef USE_LPF_RECEIVE
00472 ssize_t receive_packet_ib (interface, buf, len, from, hfrom)
00473         struct interface_info *interface;
00474         unsigned char *buf;
00475         size_t len;
00476         struct sockaddr_in *from;
00477         struct hardware *hfrom;
00478 {
00479         int length = 0;
00480         int offset = 0;
00481         unsigned char ibuf [1536];
00482         unsigned bufix = 0;
00483         unsigned paylen;
00484 
00485         length = read(interface->rfdesc, ibuf, sizeof(ibuf));
00486 
00487         if (length <= 0)
00488                 return length;
00489 
00490         offset = decode_udp_ip_header(interface, ibuf, bufix, from,
00491                                        (unsigned)length, &paylen, 0);
00492 
00493         if (offset < 0)
00494                 return 0;
00495 
00496         bufix += offset;
00497         length -= offset;
00498 
00499         if (length < paylen)
00500                 log_fatal("Internal inconsistency at %s:%d.", MDL);
00501 
00502         /* Copy out the data in the packet... */
00503         memcpy(buf, &ibuf[bufix], paylen);
00504 
00505         return (ssize_t)paylen;
00506 }
00507 
00508 ssize_t receive_packet (interface, buf, len, from, hfrom)
00509         struct interface_info *interface;
00510         unsigned char *buf;
00511         size_t len;
00512         struct sockaddr_in *from;
00513         struct hardware *hfrom;
00514 {
00515         int length = 0;
00516         int offset = 0;
00517         int nocsum = 0;
00518         unsigned char ibuf [1536];
00519         unsigned bufix = 0;
00520         unsigned paylen;
00521         unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
00522         struct iovec iov = {
00523                 .iov_base = ibuf,
00524                 .iov_len = sizeof ibuf,
00525         };
00526         struct msghdr msg = {
00527                 .msg_iov = &iov,
00528                 .msg_iovlen = 1,
00529                 .msg_control = cmsgbuf,
00530                 .msg_controllen = sizeof(cmsgbuf),
00531         };
00532         struct cmsghdr *cmsg;
00533 
00534         if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
00535                 return receive_packet_ib(interface, buf, len, from, hfrom);
00536         }
00537 
00538         length = recvmsg (interface -> rfdesc, &msg, 0);
00539         if (length <= 0)
00540                 return length;
00541 
00542         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
00543                 if (cmsg->cmsg_level == SOL_PACKET &&
00544                     cmsg->cmsg_type == PACKET_AUXDATA) {
00545                         struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
00546                         nocsum = aux->tp_status & TP_STATUS_CSUMNOTREADY;
00547                 }
00548         }
00549 
00550         bufix = 0;
00551         /* Decode the physical header... */
00552         offset = decode_hw_header (interface, ibuf, bufix, hfrom);
00553 
00554         /* If a physical layer checksum failed (dunno of any
00555            physical layer that supports this, but WTH), skip this
00556            packet. */
00557         if (offset < 0) {
00558                 return 0;
00559         }
00560 
00561         bufix += offset;
00562         length -= offset;
00563 
00564         /* Decode the IP and UDP headers... */
00565         offset = decode_udp_ip_header (interface, ibuf, bufix, from,
00566                                        (unsigned)length, &paylen, nocsum);
00567 
00568         /* If the IP or UDP checksum was bad, skip the packet... */
00569         if (offset < 0)
00570                 return 0;
00571 
00572         bufix += offset;
00573         length -= offset;
00574 
00575         if (length < paylen)
00576                 log_fatal("Internal inconsistency at %s:%d.", MDL);
00577 
00578         /* Copy out the data in the packet... */
00579         memcpy(buf, &ibuf[bufix], paylen);
00580         return paylen;
00581 }
00582 
00583 int can_unicast_without_arp (ip)
00584         struct interface_info *ip;
00585 {
00586         return 1;
00587 }
00588 
00589 int can_receive_unicast_unconfigured (ip)
00590         struct interface_info *ip;
00591 {
00592         return 1;
00593 }
00594 
00595 int supports_multiple_interfaces (ip)
00596         struct interface_info *ip;
00597 {
00598         return 1;
00599 }
00600 
00601 void maybe_setup_fallback ()
00602 {
00603         isc_result_t status;
00604         struct interface_info *fbi = (struct interface_info *)0;
00605         if (setup_fallback (&fbi, MDL)) {
00606                 if_register_fallback (fbi);
00607                 status = omapi_register_io_object ((omapi_object_t *)fbi,
00608                                                    if_readsocket, 0,
00609                                                    fallback_discard, 0, 0);
00610                 if (status != ISC_R_SUCCESS)
00611                         log_fatal ("Can't register I/O handle for \"%s\": %s",
00612                                    fbi -> name, isc_result_totext (status));
00613                 interface_dereference (&fbi, MDL);
00614         }
00615 }
00616 #endif
00617 
00618 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
00619 struct sockaddr_ll *
00620 get_ll (struct ifaddrs *ifaddrs, struct ifaddrs **ifa, char *name)
00621 {
00622         for (*ifa = ifaddrs; *ifa != NULL; *ifa = (*ifa)->ifa_next) {
00623                 if ((*ifa)->ifa_addr == NULL)
00624                         continue;
00625 
00626                 if ((*ifa)->ifa_addr->sa_family != AF_PACKET)
00627                         continue;
00628 
00629                 if ((*ifa)->ifa_flags & IFF_LOOPBACK)
00630                         continue;
00631 
00632                 if (strcmp((*ifa)->ifa_name, name) == 0)
00633                         return (struct sockaddr_ll *)(void *)(*ifa)->ifa_addr;
00634         }
00635         *ifa = NULL;
00636         return NULL;
00637 }
00638 
00639 struct sockaddr_ll *
00640 ioctl_get_ll(char *name)
00641 {
00642         int sock;
00643         struct ifreq tmp;
00644         struct sockaddr *sa = NULL;
00645         struct sockaddr_ll *sll = NULL;
00646 
00647         if (strlen(name) >= sizeof(tmp.ifr_name)) {
00648                 log_fatal("Device name too long: \"%s\"", name);
00649         }
00650 
00651         sock = socket(AF_INET, SOCK_DGRAM, 0);
00652         if (sock < 0) {
00653                 log_fatal("Can't create socket for \"%s\": %m", name);
00654         }
00655 
00656         memset(&tmp, 0, sizeof(tmp));
00657         strcpy(tmp.ifr_name, name);
00658         if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
00659                 log_fatal("Error getting hardware address for \"%s\": %m",
00660                           name);
00661         }
00662         close(sock);
00663 
00664         sa = &tmp.ifr_hwaddr;
00665         // needs to be freed outside this function
00666         sll = dmalloc (sizeof (struct sockaddr_ll), MDL);
00667         if (!sll)
00668                 log_fatal("Unable to allocate memory for link layer address");
00669         memcpy(&sll->sll_hatype, &sa->sa_family, sizeof (sll->sll_hatype));
00670         memcpy(sll->sll_addr, sa->sa_data, sizeof (sll->sll_addr));
00671         switch (sll->sll_hatype) {
00672                 case ARPHRD_INFINIBAND:
00673                         /* ioctl limits hardware addresses to 8 bytes */
00674                         sll->sll_halen = 8;
00675                         break;
00676                 default:
00677                         break;
00678         }
00679         return sll;
00680 }
00681 
00682 void
00683 get_hw_addr(struct interface_info *info)
00684 {
00685         struct hardware *hw = &info->hw_address;
00686         char *name = info->name;
00687         struct ifaddrs *ifaddrs = NULL;
00688         struct ifaddrs *ifa = NULL;
00689         struct sockaddr_ll *sll = NULL;
00690         int sll_allocated = 0;
00691         char *dup = NULL;
00692         char *colon = NULL;
00693 
00694         if (getifaddrs(&ifaddrs) == -1)
00695                 log_fatal("Failed to get interfaces");
00696 
00697         if ((sll = get_ll(ifaddrs, &ifa, name)) == NULL) {
00698                 /*
00699                  * We were unable to get link-layer address for name.
00700                  * Fall back to ioctl(SIOCGIFHWADDR).
00701                  */
00702                 sll = ioctl_get_ll(name);
00703                 if (sll != NULL)
00704                         sll_allocated = 1;
00705                 else
00706                         // shouldn't happen
00707                         log_fatal("Unexpected internal error");
00708         }
00709 
00710         switch (sll->sll_hatype) {
00711                 case ARPHRD_ETHER:
00712                         hw->hlen = 7;
00713                         hw->hbuf[0] = HTYPE_ETHER;
00714                         memcpy(&hw->hbuf[1], sll->sll_addr, 6);
00715                         break;
00716                 case ARPHRD_IEEE802:
00717 #ifdef ARPHRD_IEEE802_TR
00718                 case ARPHRD_IEEE802_TR:
00719 #endif /* ARPHRD_IEEE802_TR */
00720                         hw->hlen = 7;
00721                         hw->hbuf[0] = HTYPE_IEEE802;
00722                         memcpy(&hw->hbuf[1], sll->sll_addr, 6);
00723                         break;
00724                 case ARPHRD_FDDI:
00725                         hw->hlen = 7;
00726                         hw->hbuf[0] = HTYPE_FDDI;
00727                         memcpy(&hw->hbuf[1], sll->sll_addr, 6);
00728                         break;
00729                 case ARPHRD_INFINIBAND:
00730                         dup = strdup(name);
00731                         /* Aliased infiniband interface is special case where
00732                          * neither get_ll() nor ioctl_get_ll() get's correct hw
00733                          * address, so we have to truncate the :0 and run
00734                          * get_ll() again for the rest.
00735                         */
00736                         if ((colon = strchr(dup, ':')) != NULL) {
00737                                 *colon = '\0';
00738                                 if ((sll = get_ll(ifaddrs, &ifa, dup)) == NULL)
00739                                         log_fatal("Error getting hardware address for \"%s\": %m", name);
00740                         }
00741                         free (dup);
00742                         /* For Infiniband, save the broadcast address and store
00743                          * the port GUID into the hardware address.
00744                          */
00745                         if (ifa && (ifa->ifa_flags & IFF_BROADCAST)) {
00746                                 struct sockaddr_ll *bll;
00747 
00748                                 bll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
00749                                 memcpy(&info->bcast_addr, bll->sll_addr, 20);
00750                         } else {
00751                                 memcpy(&info->bcast_addr, default_ib_bcast_addr,
00752                                        20);
00753                         }
00754 
00755                         hw->hlen = 1;
00756                         hw->hbuf[0] = HTYPE_INFINIBAND;
00757                         memcpy(&hw->hbuf[1], &sll->sll_addr[sll->sll_halen - 8], 8);
00758                         break;
00759 #if defined(ARPHRD_PPP)
00760                 case ARPHRD_PPP:
00761                         if (local_family != AF_INET6)
00762                                 log_fatal("local_family != AF_INET6 for \"%s\"",
00763                                           name);
00764                         hw->hlen = 0;
00765                         hw->hbuf[0] = HTYPE_RESERVED;
00766                         /* 0xdeadbeef should never occur on the wire,
00767                          * and is a signature that something went wrong.
00768                          */
00769                         hw->hbuf[1] = 0xde;
00770                         hw->hbuf[2] = 0xad;
00771                         hw->hbuf[3] = 0xbe;
00772                         hw->hbuf[4] = 0xef;
00773                         break;
00774 #endif
00775                 default:
00776                         freeifaddrs(ifaddrs);
00777                         log_fatal("Unsupported device type %hu for \"%s\"",
00778                                   sll->sll_hatype, name);
00779         }
00780 
00781         if (sll_allocated)
00782                 dfree(sll, MDL);
00783         freeifaddrs(ifaddrs);
00784 }
00785 #endif

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1