common/discover.c

Go to the documentation of this file.
00001 /* discover.c
00002 
00003    Find and identify the network interfaces. */
00004 
00005 /*
00006  * Copyright (c) 2013-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004-2009,2011 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1995-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  */
00029 
00030 #include "dhcpd.h"
00031 
00032 #define BSD_COMP                /* needed on Solaris for SIOCGLIFNUM */
00033 #include <sys/ioctl.h>
00034 #include <errno.h>
00035 
00036 #ifdef HAVE_NET_IF6_H
00037 # include <net/if6.h>
00038 #endif
00039 
00040 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
00041 int interfaces_invalidated;
00042 int quiet_interface_discovery;
00043 u_int16_t local_port;
00044 u_int16_t remote_port;
00045 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
00046 int (*dhcp_interface_discovery_hook) (struct interface_info *);
00047 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
00048 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
00049 
00050 struct in_addr limited_broadcast;
00051 
00052 int local_family = AF_INET;
00053 struct in_addr local_address;
00054 
00055 void (*bootp_packet_handler) (struct interface_info *,
00056                               struct dhcp_packet *, unsigned,
00057                               unsigned int,
00058                               struct iaddr, struct hardware *);
00059 
00060 #ifdef DHCPv6
00061 void (*dhcpv6_packet_handler)(struct interface_info *,
00062                               const char *, int,
00063                               int, const struct iaddr *,
00064                               isc_boolean_t);
00065 #endif /* DHCPv6 */
00066 
00067 
00068 omapi_object_type_t *dhcp_type_interface;
00069 #if defined (TRACING)
00070 trace_type_t *interface_trace;
00071 trace_type_t *inpacket_trace;
00072 trace_type_t *outpacket_trace;
00073 #endif
00074 struct interface_info **interface_vector;
00075 int interface_count;
00076 int interface_max;
00077 
00078 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
00079 
00080 isc_result_t interface_setup ()
00081 {
00082         isc_result_t status;
00083         status = omapi_object_type_register (&dhcp_type_interface,
00084                                              "interface",
00085                                              dhcp_interface_set_value,
00086                                              dhcp_interface_get_value,
00087                                              dhcp_interface_destroy,
00088                                              dhcp_interface_signal_handler,
00089                                              dhcp_interface_stuff_values,
00090                                              dhcp_interface_lookup, 
00091                                              dhcp_interface_create,
00092                                              dhcp_interface_remove,
00093                                              0, 0, 0,
00094                                              sizeof (struct interface_info),
00095                                              interface_initialize, RC_MISC);
00096         if (status != ISC_R_SUCCESS)
00097                 log_fatal ("Can't register interface object type: %s",
00098                            isc_result_totext (status));
00099 
00100         return status;
00101 }
00102 
00103 #if defined (TRACING)
00104 void interface_trace_setup ()
00105 {
00106         interface_trace = trace_type_register ("interface", (void *)0,
00107                                                trace_interface_input,
00108                                                trace_interface_stop, MDL);
00109         inpacket_trace = trace_type_register ("inpacket", (void *)0,
00110                                                trace_inpacket_input,
00111                                                trace_inpacket_stop, MDL);
00112         outpacket_trace = trace_type_register ("outpacket", (void *)0,
00113                                                trace_outpacket_input,
00114                                                trace_outpacket_stop, MDL);
00115 }
00116 #endif
00117 
00118 isc_result_t interface_initialize (omapi_object_t *ipo,
00119                                    const char *file, int line)
00120 {
00121         struct interface_info *ip = (struct interface_info *)ipo;
00122         ip -> rfdesc = ip -> wfdesc = -1;
00123         return ISC_R_SUCCESS;
00124 }
00125 
00126 
00127 /* 
00128  * Scanning for Interfaces
00129  * -----------------------
00130  *
00131  * To find interfaces, we create an iterator that abstracts out most 
00132  * of the platform specifics. Use is fairly straightforward:
00133  *
00134  * - begin_iface_scan() starts the process.
00135  * - Use next_iface() until it returns 0.
00136  * - end_iface_scan() performs any necessary cleanup.
00137  *
00138  * We check for errors on each call to next_iface(), which returns a
00139  * description of the error as a string if any occurs.
00140  *
00141  * We currently have code for Solaris and Linux. Other systems need
00142  * to have code written.
00143  *
00144  * NOTE: the long-term goal is to use the interface code from BIND 9.
00145  */
00146 
00147 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS)
00148 
00149 /* HP/UX doesn't define struct lifconf, instead they define struct
00150  * if_laddrconf.  Similarly, 'struct lifreq' and 'struct lifaddrreq'.
00151  */
00152 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
00153 # define lifc_len iflc_len
00154 # define lifc_buf iflc_buf
00155 # define lifc_req iflc_req
00156 # define LIFCONF if_laddrconf
00157 #else
00158 # define ISC_HAVE_LIFC_FAMILY 1
00159 # define ISC_HAVE_LIFC_FLAGS 1
00160 # define LIFCONF lifconf
00161 #endif
00162 
00163 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
00164 # define lifr_addr iflr_addr
00165 # define lifr_name iflr_name
00166 # define lifr_dstaddr iflr_dstaddr
00167 # define lifr_flags iflr_flags
00168 # define sockaddr_storage sockaddr_ext
00169 # define ss_family sa_family
00170 # define LIFREQ if_laddrreq
00171 #else
00172 # define LIFREQ lifreq
00173 #endif
00174 
00175 #ifndef IF_NAMESIZE
00176 # if defined(LIFNAMSIZ)
00177 #  define IF_NAMESIZE   LIFNAMSIZ
00178 # elif defined(IFNAMSIZ)
00179 #  define IF_NAMESIZE   IFNAMSIZ
00180 # else
00181 #  define IF_NAMESIZE   16
00182 # endif
00183 #endif
00184 #elif !defined(__linux) && !defined(HAVE_IFADDRS_H)
00185 # define SIOCGLIFCONF SIOCGIFCONF
00186 # define SIOCGLIFFLAGS SIOCGIFFLAGS
00187 # define LIFREQ ifreq
00188 # define LIFCONF ifconf
00189 # define lifr_name ifr_name
00190 # define lifr_addr ifr_addr
00191 # define lifr_flags ifr_flags
00192 # define lifc_len ifc_len
00193 # define lifc_buf ifc_buf
00194 # define lifc_req ifc_req
00195 #ifdef _AIX
00196 # define ss_family __ss_family
00197 #endif
00198 #endif
00199 
00200 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
00201 /* 
00202  * Solaris support
00203  * ---------------
00204  *
00205  * The SIOCGLIFCONF ioctl() are the extension that you need to use
00206  * on Solaris to get information about IPv6 addresses.
00207  *
00208  * Solaris' extended interface is documented in the if_tcp man page.
00209  */
00210 
00211 /* 
00212  * Structure holding state about the scan.
00213  */
00214 struct iface_conf_list {
00215         int sock;               /* file descriptor used to get information */
00216         int num;                /* total number of interfaces */
00217         struct LIFCONF conf;    /* structure used to get information */
00218         int next;               /* next interface to retrieve when iterating */
00219 };
00220 
00221 /* 
00222  * Structure used to return information about a specific interface.
00223  */
00224 struct iface_info {
00225         char name[IF_NAMESIZE+1];       /* name of the interface, e.g. "bge0" */
00226         struct sockaddr_storage addr;   /* address information */
00227         isc_uint64_t flags;             /* interface flags, e.g. IFF_LOOPBACK */
00228 };
00229 
00230 /* 
00231  * Start a scan of interfaces.
00232  *
00233  * The iface_conf_list structure maintains state for this process.
00234  */
00235 int 
00236 begin_iface_scan(struct iface_conf_list *ifaces) {
00237 #ifdef ISC_PLATFORM_HAVELIFNUM
00238         struct lifnum lifnum;
00239 #else
00240         int lifnum;
00241 #endif
00242 
00243         ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP);
00244         if (ifaces->sock < 0) {
00245                 log_error("Error creating socket to list interfaces; %m");
00246                 return 0;
00247         }
00248 
00249         memset(&lifnum, 0, sizeof(lifnum));
00250 #ifdef ISC_PLATFORM_HAVELIFNUM
00251         lifnum.lifn_family = AF_UNSPEC;
00252 #endif
00253 #ifdef SIOCGLIFNUM
00254         if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
00255                 log_error("Error finding total number of interfaces; %m");
00256                 close(ifaces->sock);
00257                 ifaces->sock = -1;
00258                 return 0;
00259         }
00260 
00261 #ifdef ISC_PLATFORM_HAVELIFNUM
00262         ifaces->num = lifnum.lifn_count;
00263 #else
00264         ifaces->num = lifnum;
00265 #endif
00266 #else
00267         ifaces->num = 64;
00268 #endif /* SIOCGLIFNUM */
00269 
00270         memset(&ifaces->conf, 0, sizeof(ifaces->conf));
00271 #ifdef ISC_HAVE_LIFC_FAMILY
00272         ifaces->conf.lifc_family = AF_UNSPEC;
00273 #endif
00274         ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ);
00275         ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
00276         if (ifaces->conf.lifc_buf == NULL) {
00277                 log_fatal("Out of memory getting interface list.");
00278         }
00279 
00280         if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
00281                 log_error("Error getting interfaces configuration list; %m");
00282                 dfree(ifaces->conf.lifc_buf, MDL);
00283                 close(ifaces->sock);
00284                 ifaces->sock = -1;
00285                 return 0;
00286         }
00287 
00288         ifaces->next = 0;
00289 
00290         return 1;
00291 }
00292 
00293 /*
00294  * Retrieve the next interface.
00295  *
00296  * Returns information in the info structure. 
00297  * Sets err to 1 if there is an error, otherwise 0.
00298  */
00299 int
00300 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
00301         struct LIFREQ *p;
00302         struct LIFREQ tmp;
00303         isc_boolean_t foundif;
00304 #if defined(sun) || defined(__linux)
00305         /* Pointer used to remove interface aliases. */
00306         char *s;
00307 #endif
00308 
00309         do {
00310                 foundif = ISC_FALSE;
00311 
00312                 if (ifaces->next >= ifaces->num) {
00313                         *err = 0;
00314                         return 0;
00315                 }
00316 
00317                 p = ifaces->conf.lifc_req;
00318                 p += ifaces->next;
00319 
00320                 if (strlen(p->lifr_name) >= sizeof(info->name)) {
00321                         *err = 1;
00322                         log_error("Interface name '%s' too long", p->lifr_name);
00323                         return 0;
00324                 }
00325 
00326                 /* Reject if interface address family does not match */
00327                 if (p->lifr_addr.ss_family != local_family) {
00328                         ifaces->next++;
00329                         continue;
00330                 }
00331 
00332                 strcpy(info->name, p->lifr_name);
00333                 memset(&info->addr, 0, sizeof(info->addr));
00334                 memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
00335 
00336 #if defined(sun) || defined(__linux)
00337                 /* interface aliases look like "eth0:1" or "wlan1:3" */
00338                 s = strchr(info->name, ':');
00339                 if (s != NULL) {
00340                         *s = '\0';
00341                 }
00342 #endif /* defined(sun) || defined(__linux) */
00343 
00344                 foundif = ISC_TRUE;
00345         } while ((foundif == ISC_FALSE) ||
00346                  (strncmp(info->name, "dummy", 5) == 0));
00347         
00348         memset(&tmp, 0, sizeof(tmp));
00349         strcpy(tmp.lifr_name, info->name);
00350         if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
00351                 log_error("Error getting interface flags for '%s'; %m", 
00352                           p->lifr_name);
00353                 *err = 1;
00354                 return 0;
00355         }
00356         info->flags = tmp.lifr_flags;
00357 
00358         ifaces->next++;
00359         *err = 0;
00360         return 1;
00361 }
00362 
00363 /*
00364  * End scan of interfaces.
00365  */
00366 void
00367 end_iface_scan(struct iface_conf_list *ifaces) {
00368         dfree(ifaces->conf.lifc_buf, MDL);
00369         close(ifaces->sock);
00370         ifaces->sock = -1;
00371 }
00372 
00373 #else
00374 
00375 /* 
00376  * BSD support
00377  * -----------
00378  *
00379  * FreeBSD, NetBSD, OpenBSD, OS X and Linux all have the getifaddrs()
00380  * function.
00381  *
00382  * The getifaddrs() man page describes the use.
00383  */
00384 
00385 #include <ifaddrs.h>
00386 
00387 /* 
00388  * Structure holding state about the scan.
00389  */
00390 struct iface_conf_list {
00391         struct ifaddrs *head;   /* beginning of the list */
00392         struct ifaddrs *next;   /* current position in the list */
00393 };
00394 
00395 /* 
00396  * Structure used to return information about a specific interface.
00397  */
00398 struct iface_info {
00399         char name[IFNAMSIZ];            /* name of the interface, e.g. "bge0" */
00400         struct sockaddr_storage addr;   /* address information */
00401         isc_uint64_t flags;             /* interface flags, e.g. IFF_LOOPBACK */
00402 };
00403 
00404 /* 
00405  * Start a scan of interfaces.
00406  *
00407  * The iface_conf_list structure maintains state for this process.
00408  */
00409 int 
00410 begin_iface_scan(struct iface_conf_list *ifaces) {
00411         if (getifaddrs(&ifaces->head) != 0) {
00412                 log_error("Error getting interfaces; %m");
00413                 return 0;
00414         }
00415         ifaces->next = ifaces->head;
00416         return 1;
00417 }
00418 
00419 /*
00420  * Retrieve the next interface.
00421  *
00422  * Returns information in the info structure. 
00423  * Sets err to 1 if there is an error, otherwise 0.
00424  */
00425 int
00426 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
00427         size_t sa_len = 0;
00428 
00429         if (ifaces->next == NULL) {
00430                 *err = 0;
00431                 return 0;
00432         }
00433         if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) {
00434                 log_error("Interface name '%s' too long", 
00435                           ifaces->next->ifa_name);
00436                 *err = 1;
00437                 return 0;
00438         }
00439         strcpy(info->name, ifaces->next->ifa_name);
00440 
00441         memset(&info->addr, 0 , sizeof(info->addr));
00442 
00443         if (ifaces->next->ifa_addr != NULL) {
00444 #ifdef HAVE_SA_LEN
00445                 sa_len = ifaces->next->ifa_addr->sa_len;
00446 #else
00447                 if (ifaces->next->ifa_addr->sa_family == AF_INET)
00448                         sa_len = sizeof(struct sockaddr_in);
00449                 else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
00450                         sa_len = sizeof(struct sockaddr_in6);
00451 #endif
00452                 memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
00453         }
00454         info->flags = ifaces->next->ifa_flags;
00455         ifaces->next = ifaces->next->ifa_next;
00456         *err = 0;
00457         return 1;
00458 }
00459 
00460 /*
00461  * End scan of interfaces.
00462  */
00463 void
00464 end_iface_scan(struct iface_conf_list *ifaces) {
00465         freeifaddrs(ifaces->head);
00466         ifaces->head = NULL;
00467         ifaces->next = NULL;
00468 }
00469 #endif 
00470 
00471 /* XXX: perhaps create drealloc() rather than do it manually */
00472 void
00473 add_ipv4_addr_to_interface(struct interface_info *iface, 
00474                            const struct in_addr *addr) {
00475         /*
00476          * We don't expect a lot of addresses per IPv4 interface, so
00477          * we use 4, as our "chunk size" for collecting addresses.
00478          */
00479         if (iface->addresses == NULL) {
00480                 iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
00481                 if (iface->addresses == NULL) {
00482                         log_fatal("Out of memory saving IPv4 address "
00483                                   "on interface.");
00484                 }
00485                 iface->address_count = 0;
00486                 iface->address_max = 4;
00487         } else if (iface->address_count >= iface->address_max) {
00488                 struct in_addr *tmp;
00489                 int new_max;
00490 
00491                 new_max = iface->address_max + 4;
00492                 tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
00493                 if (tmp == NULL) {
00494                         log_fatal("Out of memory saving IPv4 address "
00495                                   "on interface.");
00496                 }
00497                 memcpy(tmp, 
00498                        iface->addresses, 
00499                        iface->address_max * sizeof(struct in_addr));
00500                 dfree(iface->addresses, MDL);
00501                 iface->addresses = tmp;
00502                 iface->address_max = new_max;
00503         }
00504         iface->addresses[iface->address_count++] = *addr;
00505 }
00506 
00507 #ifdef DHCPv6
00508 /* XXX: perhaps create drealloc() rather than do it manually */
00509 void
00510 add_ipv6_addr_to_interface(struct interface_info *iface, 
00511                            const struct in6_addr *addr) {
00512         /*
00513          * Each IPv6 interface will have at least two IPv6 addresses,
00514          * and likely quite a few more. So we use 8, as our "chunk size" for
00515          * collecting addresses.
00516          */
00517         if (iface->v6addresses == NULL) {
00518                 iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
00519                 if (iface->v6addresses == NULL) {
00520                         log_fatal("Out of memory saving IPv6 address "
00521                                   "on interface.");
00522                 }
00523                 iface->v6address_count = 0;
00524                 iface->v6address_max = 8;
00525         } else if (iface->v6address_count >= iface->v6address_max) {
00526                 struct in6_addr *tmp;
00527                 int new_max;
00528 
00529                 new_max = iface->v6address_max + 8;
00530                 tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
00531                 if (tmp == NULL) {
00532                         log_fatal("Out of memory saving IPv6 address "
00533                                   "on interface.");
00534                 }
00535                 memcpy(tmp, 
00536                        iface->v6addresses, 
00537                        iface->v6address_max * sizeof(struct in6_addr));
00538                 dfree(iface->v6addresses, MDL);
00539                 iface->v6addresses = tmp;
00540                 iface->v6address_max = new_max;
00541         }
00542         iface->v6addresses[iface->v6address_count++] = *addr;
00543 }
00544 #endif /* DHCPv6 */
00545 
00546 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
00547    For each interface that's of type INET and not the loopback interface,
00548    register that interface with the network I/O software, figure out what
00549    subnet it's on, and add it to the list of interfaces. */
00550 
00551 void 
00552 discover_interfaces(int state) {
00553         struct iface_conf_list ifaces;
00554         struct iface_info info;
00555         int err;
00556 
00557         struct interface_info *tmp;
00558         struct interface_info *last, *next;
00559 
00560 #ifdef DHCPv6
00561         char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
00562 #endif /* DHCPv6 */
00563 
00564 
00565         struct subnet *subnet;
00566         int ir;
00567         isc_result_t status;
00568         int wifcount = 0;
00569 
00570         static int setup_fallback = 0;
00571 
00572         if (!begin_iface_scan(&ifaces)) {
00573                 log_fatal("Can't get list of interfaces.");
00574         }
00575 
00576         /* If we already have a list of interfaces, and we're running as
00577            a DHCP server, the interfaces were requested. */
00578         if (interfaces && (state == DISCOVER_SERVER ||
00579                            state == DISCOVER_RELAY ||
00580                            state == DISCOVER_REQUESTED))
00581                 ir = 0;
00582         else if (state == DISCOVER_UNCONFIGURED)
00583                 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
00584         else
00585                 ir = INTERFACE_REQUESTED;
00586 
00587         /* Cycle through the list of interfaces looking for IP addresses. */
00588         while (next_iface(&info, &err, &ifaces)) {
00589 
00590                 /* See if we've seen an interface that matches this one. */
00591                 for (tmp = interfaces; tmp; tmp = tmp->next) {
00592                         if (!strcmp(tmp->name, info.name))
00593                                 break;
00594                 }
00595 
00596                 /* Skip non broadcast interfaces (plus loopback and
00597                    point-to-point in case an OS incorrectly marks them
00598                    as broadcast). Also skip down interfaces unless we're
00599                    trying to get a list of configurable interfaces. */
00600                 if ((((local_family == AF_INET &&
00601                     !(info.flags & IFF_BROADCAST)) ||
00602 #ifdef DHCPv6
00603                     (local_family == AF_INET6 &&
00604                     !(info.flags & IFF_MULTICAST)) ||
00605 #endif
00606                       info.flags & IFF_LOOPBACK ||
00607                       info.flags & IFF_POINTOPOINT) && !tmp) ||
00608                     (!(info.flags & IFF_UP) &&
00609                      state != DISCOVER_UNCONFIGURED))
00610                         continue;
00611                 
00612                 /* If there isn't already an interface by this name,
00613                    allocate one. */
00614                 if (tmp == NULL) {
00615                         status = interface_allocate(&tmp, MDL);
00616                         if (status != ISC_R_SUCCESS) {
00617                                 log_fatal("Error allocating interface %s: %s",
00618                                           info.name, isc_result_totext(status));
00619                         }
00620                         strcpy(tmp->name, info.name);
00621                         interface_snorf(tmp, ir);
00622                         interface_dereference(&tmp, MDL);
00623                         tmp = interfaces; /* XXX */
00624                 }
00625 
00626                 if (dhcp_interface_discovery_hook) {
00627                         (*dhcp_interface_discovery_hook)(tmp);
00628                 }
00629 
00630                 if ((info.addr.ss_family == AF_INET) && 
00631                     (local_family == AF_INET)) {
00632                         struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
00633                         struct iaddr addr;
00634 
00635                         /* We don't want the loopback interface. */
00636                         if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
00637                             ((tmp->flags & INTERFACE_AUTOMATIC) &&
00638                              state == DISCOVER_SERVER))
00639                                 continue;
00640 
00641                         /* If the only address we have is 0.0.0.0, we
00642                            shouldn't consider the interface configured. */
00643                         if (a->sin_addr.s_addr != htonl(INADDR_ANY))
00644                                 tmp->configured = 1;
00645 
00646                         add_ipv4_addr_to_interface(tmp, &a->sin_addr);
00647 
00648                         /* invoke the setup hook */
00649                         addr.len = 4;
00650                         memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
00651                         if (dhcp_interface_setup_hook) {
00652                                 (*dhcp_interface_setup_hook)(tmp, &addr);
00653                         }
00654                 }
00655 #ifdef DHCPv6
00656                 else if ((info.addr.ss_family == AF_INET6) && 
00657                          (local_family == AF_INET6)) {
00658                         struct sockaddr_in6 *a = 
00659                                         (struct sockaddr_in6*)&info.addr;
00660                         struct iaddr addr;
00661 
00662                         /* We don't want the loopback interface. */
00663                         if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) && 
00664                             ((tmp->flags & INTERFACE_AUTOMATIC) &&
00665                              state == DISCOVER_SERVER))
00666                             continue;
00667 
00668                         /* If the only address we have is 0.0.0.0, we
00669                            shouldn't consider the interface configured. */
00670                         if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
00671                                 tmp->configured = 1;
00672 
00673                         add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
00674 
00675                         /* invoke the setup hook */
00676                         addr.len = 16;
00677                         memcpy(addr.iabuf, &a->sin6_addr, addr.len);
00678                         if (dhcp_interface_setup_hook) {
00679                                 (*dhcp_interface_setup_hook)(tmp, &addr);
00680                         }
00681                 }
00682 #endif /* DHCPv6 */
00683         }
00684 
00685         if (err) {
00686                 log_fatal("Error getting interface information.");
00687         }
00688 
00689         end_iface_scan(&ifaces);
00690 
00691 
00692         /* Mock-up an 'ifp' structure which is no longer used in the
00693          * new interface-sensing code, but is used in higher layers
00694          * (for example to sense fallback interfaces).
00695          */
00696         for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) {
00697                 if (tmp->ifp == NULL) {
00698                         struct ifreq *tif;
00699 
00700                         tif = (struct ifreq *)dmalloc(sizeof(struct ifreq),
00701                                                       MDL);
00702                         if (tif == NULL)
00703                                 log_fatal("no space for ifp mockup.");
00704                         strcpy(tif->ifr_name, tmp->name);
00705                         tmp->ifp = tif;
00706                 }
00707         }
00708 
00709 
00710         /* If we're just trying to get a list of interfaces that we might
00711            be able to configure, we can quit now. */
00712         if (state == DISCOVER_UNCONFIGURED) {
00713                 return;
00714         }
00715 
00716         /* Weed out the interfaces that did not have IP addresses. */
00717         tmp = last = next = NULL;
00718         if (interfaces)
00719                 interface_reference (&tmp, interfaces, MDL);
00720         while (tmp) {
00721                 if (next)
00722                         interface_dereference (&next, MDL);
00723                 if (tmp -> next)
00724                         interface_reference (&next, tmp -> next, MDL);
00725                 /* skip interfaces that are running already */
00726                 if (tmp -> flags & INTERFACE_RUNNING) {
00727                         interface_dereference(&tmp, MDL);
00728                         if(next)
00729                                 interface_reference(&tmp, next, MDL);
00730                         continue;
00731                 }
00732                 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
00733                     state == DISCOVER_REQUESTED)
00734                         tmp -> flags &= ~(INTERFACE_AUTOMATIC |
00735                                           INTERFACE_REQUESTED);
00736 
00737 #ifdef DHCPv6
00738                 if (!(tmp->flags & INTERFACE_REQUESTED)) {
00739 #else
00740                 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
00741 #endif /* DHCPv6 */
00742                         if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
00743                                 log_fatal ("%s: not found", tmp -> name);
00744                         if (!last) {
00745                                 if (interfaces)
00746                                         interface_dereference (&interfaces,
00747                                                                MDL);
00748                                 if (next)
00749                                 interface_reference (&interfaces, next, MDL);
00750                         } else {
00751                                 interface_dereference (&last -> next, MDL);
00752                                 if (next)
00753                                         interface_reference (&last -> next,
00754                                                              next, MDL);
00755                         }
00756                         if (tmp -> next)
00757                                 interface_dereference (&tmp -> next, MDL);
00758 
00759                         /* Remember the interface in case we need to know
00760                            about it later. */
00761                         if (dummy_interfaces) {
00762                                 interface_reference (&tmp -> next,
00763                                                      dummy_interfaces, MDL);
00764                                 interface_dereference (&dummy_interfaces, MDL);
00765                         }
00766                         interface_reference (&dummy_interfaces, tmp, MDL);
00767                         interface_dereference (&tmp, MDL);
00768                         if (next)
00769                                 interface_reference (&tmp, next, MDL);
00770                         continue;
00771                 }
00772                 last = tmp;
00773 
00774                 /* We must have a subnet declaration for each interface. */
00775                 if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
00776                         log_info("%s", "");
00777                         if (local_family == AF_INET) {
00778                                 log_info("No subnet declaration for %s (%s).",
00779                                           tmp->name, 
00780                                           (tmp->addresses == NULL) ?
00781                                            "no IPv4 addresses" :
00782                                            inet_ntoa(tmp->addresses[0]));
00783 #ifdef DHCPv6
00784                         } else {
00785                                 if (tmp->v6addresses != NULL) {
00786                                         inet_ntop(AF_INET6, 
00787                                                   &tmp->v6addresses[0],
00788                                                   abuf,
00789                                                   sizeof(abuf));
00790                                 } else {
00791                                         strcpy(abuf, "no IPv6 addresses");
00792                                 }
00793                                 log_info("No subnet6 declaration for %s (%s).",
00794                                           tmp->name,
00795                                           abuf);
00796 #endif /* DHCPv6 */
00797                         }
00798                         if (supports_multiple_interfaces(tmp)) {
00799                                 log_info ("** Ignoring requests on %s.  %s",
00800                                            tmp -> name, "If this is not what");
00801                                 log_info ("   you want, please write %s",
00802 #ifdef DHCPv6
00803                                            (local_family != AF_INET) ?
00804                                            "a subnet6 declaration" :
00805 #endif
00806                                            "a subnet declaration");
00807                                 log_info ("   in your dhcpd.conf file %s",
00808                                            "for the network segment");
00809                                 log_info ("   to %s %s %s",
00810                                            "which interface",
00811                                            tmp -> name, "is attached. **");
00812                                 log_info ("%s", "");
00813                                 goto next;
00814                         } else {
00815                                 log_error ("You must write a %s",
00816 #ifdef DHCPv6
00817                                            (local_family != AF_INET) ?
00818                                            "subnet6 declaration for this" :
00819 #endif
00820                                            "subnet declaration for this");
00821                                 log_error ("subnet.   You cannot prevent %s",
00822                                            "the DHCP server");
00823                                 log_error ("from listening on this subnet %s",
00824                                            "because your");
00825                                 log_fatal ("operating system does not %s.",
00826                                            "support this capability");
00827                         }
00828                 }
00829 
00830                 /* Find subnets that don't have valid interface
00831                    addresses... */
00832                 for (subnet = (tmp -> shared_network
00833                                ? tmp -> shared_network -> subnets
00834                                : (struct subnet *)0);
00835                      subnet; subnet = subnet -> next_sibling) {
00836                         /* Set the interface address for this subnet
00837                            to the first address we found. */
00838                         if (subnet->interface_address.len == 0) {
00839                                 if (tmp->address_count > 0) {
00840                                         subnet->interface_address.len = 4;
00841                                         memcpy(subnet->interface_address.iabuf,
00842                                                &tmp->addresses[0].s_addr, 4);
00843                                 } else if (tmp->v6address_count > 0) {
00844                                         subnet->interface_address.len = 16;
00845                                         memcpy(subnet->interface_address.iabuf,
00846                                                &tmp->v6addresses[0].s6_addr, 
00847                                                16);
00848                                 } else {
00849                                         /* XXX: should be one */
00850                                         log_error("%s missing an interface "
00851                                                   "address", tmp->name);
00852                                         continue;
00853                                 }
00854                         }
00855                 }
00856 
00857                 /* Flag the index as not having been set, so that the
00858                    interface registerer can set it or not as it chooses. */
00859                 tmp -> index = -1;
00860 
00861                 /* Register the interface... */
00862                 if (local_family == AF_INET) {
00863                         if_register_receive(tmp);
00864                         if_register_send(tmp);
00865 #ifdef DHCPv6
00866                 } else {
00867                         if ((state == DISCOVER_SERVER) ||
00868                             (state == DISCOVER_RELAY)) {
00869                                 if_register6(tmp, 1);
00870                         } else {
00871                                 if_register_linklocal6(tmp);
00872                         }
00873 #endif /* DHCPv6 */
00874                 }
00875 
00876                 interface_stash (tmp);
00877                 wifcount++;
00878 #if defined (F_SETFD)
00879                 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
00880                         log_error ("Can't set close-on-exec on %s: %m",
00881                                    tmp -> name);
00882                 if (tmp -> rfdesc != tmp -> wfdesc) {
00883                         if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
00884                                 log_error ("Can't set close-on-exec on %s: %m",
00885                                            tmp -> name);
00886                 }
00887 #endif
00888               next:
00889                 interface_dereference (&tmp, MDL);
00890                 if (next)
00891                         interface_reference (&tmp, next, MDL);
00892         }
00893 
00894         /*
00895          * Now register all the remaining interfaces as protocols.
00896          * We register with omapi to allow for control of the interface,
00897          * we've already registered the fd or socket with the socket
00898          * manager as part of if_register_receive().
00899          */
00900         for (tmp = interfaces; tmp; tmp = tmp -> next) {
00901                 /* not if it's been registered before */
00902                 if (tmp -> flags & INTERFACE_RUNNING)
00903                         continue;
00904                 if (tmp -> rfdesc == -1)
00905                         continue;
00906                 switch (local_family) {
00907 #ifdef DHCPv6 
00908                 case AF_INET6:
00909                         status = omapi_register_io_object((omapi_object_t *)tmp,
00910                                                           if_readsocket, 
00911                                                           0, got_one_v6, 0, 0);
00912                         break;
00913 #endif /* DHCPv6 */
00914                 case AF_INET:
00915                 default:
00916                         status = omapi_register_io_object((omapi_object_t *)tmp,
00917                                                           if_readsocket, 
00918                                                           0, got_one, 0, 0);
00919                         break;
00920                 }
00921 
00922                 if (status != ISC_R_SUCCESS)
00923                         log_fatal ("Can't register I/O handle for %s: %s",
00924                                    tmp -> name, isc_result_totext (status));
00925 
00926 #if defined(DHCPv6)
00927                 /* Only register the first interface for V6, since
00928                  * servers and relays all use the same socket.
00929                  * XXX: This has some messy side effects if we start
00930                  * dynamically adding and removing interfaces, but
00931                  * we're well beyond that point in terms of mess.
00932                  */
00933                 if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) &&
00934                     (local_family == AF_INET6))
00935                         break;
00936 #endif
00937         } /* for (tmp = interfaces; ... */
00938 
00939         if (state == DISCOVER_SERVER && wifcount == 0) {
00940                 log_info ("%s", "");
00941                 log_fatal ("Not configured to listen on any interfaces!");
00942         }
00943 
00944         if ((local_family == AF_INET) && !setup_fallback) {
00945                 setup_fallback = 1;
00946                 maybe_setup_fallback();
00947         }
00948 
00949 #if defined (F_SETFD)
00950         if (fallback_interface) {
00951             if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
00952                 log_error ("Can't set close-on-exec on fallback: %m");
00953             if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
00954                 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
00955                     log_error ("Can't set close-on-exec on fallback: %m");
00956             }
00957         }
00958 #endif /* F_SETFD */
00959 }
00960 
00961 int if_readsocket (h)
00962         omapi_object_t *h;
00963 {
00964         struct interface_info *ip;
00965 
00966         if (h -> type != dhcp_type_interface)
00967                 return -1;
00968         ip = (struct interface_info *)h;
00969         return ip -> rfdesc;
00970 }
00971 
00972 int setup_fallback (struct interface_info **fp, const char *file, int line)
00973 {
00974         isc_result_t status;
00975 
00976         status = interface_allocate (&fallback_interface, file, line);
00977         if (status != ISC_R_SUCCESS)
00978                 log_fatal ("Error allocating fallback interface: %s",
00979                            isc_result_totext (status));
00980         strcpy (fallback_interface -> name, "fallback");
00981         if (dhcp_interface_setup_hook)
00982                 (*dhcp_interface_setup_hook) (fallback_interface,
00983                                               (struct iaddr *)0);
00984         status = interface_reference (fp, fallback_interface, file, line);
00985 
00986         fallback_interface -> index = -1;
00987         interface_stash (fallback_interface);
00988         return status == ISC_R_SUCCESS;
00989 }
00990 
00991 void reinitialize_interfaces ()
00992 {
00993         struct interface_info *ip;
00994 
00995         for (ip = interfaces; ip; ip = ip -> next) {
00996                 if_reinitialize_receive (ip);
00997                 if_reinitialize_send (ip);
00998         }
00999 
01000         if (fallback_interface)
01001                 if_reinitialize_send (fallback_interface);
01002 
01003         interfaces_invalidated = 1;
01004 }
01005 
01006 isc_result_t got_one (h)
01007         omapi_object_t *h;
01008 {
01009         struct sockaddr_in from;
01010         struct hardware hfrom;
01011         struct iaddr ifrom;
01012         int result;
01013         union {
01014                 unsigned char packbuf [4095]; /* Packet input buffer.
01015                                                  Must be as large as largest
01016                                                  possible MTU. */
01017                 struct dhcp_packet packet;
01018         } u;
01019         struct interface_info *ip;
01020 
01021         if (h -> type != dhcp_type_interface)
01022                 return DHCP_R_INVALIDARG;
01023         ip = (struct interface_info *)h;
01024 
01025       again:
01026         if ((result =
01027              receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
01028                 log_error ("receive_packet failed on %s: %m", ip -> name);
01029                 return ISC_R_UNEXPECTED;
01030         }
01031         if (result == 0)
01032                 return ISC_R_UNEXPECTED;
01033 
01034         /*
01035          * If we didn't at least get the fixed portion of the BOOTP
01036          * packet, drop the packet.
01037          * Previously we allowed packets with no sname or filename
01038          * as we were aware of at least one client that did.  But
01039          * a bug caused short packets to not work and nobody has
01040          * complained, it seems rational to tighten up that
01041          * restriction.
01042          */
01043         if (result < DHCP_FIXED_NON_UDP)
01044                 return ISC_R_UNEXPECTED;
01045 
01046 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
01047         {
01048                 /* We retrieve the ifindex from the unused hfrom variable */
01049                 unsigned int ifindex;
01050 
01051                 memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex));
01052 
01053                 /*
01054                  * Seek forward from the first interface to find the matching
01055                  * source interface by interface index.
01056                  */
01057                 ip = interfaces;
01058                 while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex))
01059                         ip = ip->next;
01060                 if (ip == NULL)
01061                         return ISC_R_NOTFOUND;
01062         }
01063 #endif
01064 
01065         if (bootp_packet_handler) {
01066                 ifrom.len = 4;
01067                 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
01068 
01069                 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
01070                                          from.sin_port, ifrom, &hfrom);
01071         }
01072 
01073         /* If there is buffered data, read again.    This is for, e.g.,
01074            bpf, which may return two packets at once. */
01075         if (ip -> rbuf_offset != ip -> rbuf_len)
01076                 goto again;
01077         return ISC_R_SUCCESS;
01078 }
01079 
01080 #ifdef DHCPv6
01081 isc_result_t
01082 got_one_v6(omapi_object_t *h) {
01083         struct sockaddr_in6 from;
01084         struct in6_addr to;
01085         struct iaddr ifrom;
01086         int result;
01087         char buf[65536];        /* maximum size for a UDP packet is 65536 */
01088         struct interface_info *ip;
01089         int is_unicast;
01090         unsigned int if_idx = 0;
01091 
01092         if (h->type != dhcp_type_interface) {
01093                 return DHCP_R_INVALIDARG;
01094         }
01095         ip = (struct interface_info *)h;
01096 
01097         result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
01098                                  &from, &to, &if_idx);
01099         if (result < 0) {
01100                 log_error("receive_packet6() failed on %s: %m", ip->name);
01101                 return ISC_R_UNEXPECTED;
01102         }
01103 
01104         /* 0 is 'any' interface. */
01105         if (if_idx == 0)
01106                 return ISC_R_NOTFOUND;
01107 
01108         if (dhcpv6_packet_handler != NULL) {
01109                 /*
01110                  * If a packet is not multicast, we assume it is unicast.
01111                  */
01112                 if (IN6_IS_ADDR_MULTICAST(&to)) { 
01113                         is_unicast = ISC_FALSE;
01114                 } else {
01115                         is_unicast = ISC_TRUE;
01116                 }
01117 
01118                 ifrom.len = 16;
01119                 memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
01120 
01121                 /* Seek forward to find the matching source interface. */
01122                 ip = interfaces;
01123                 while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
01124                         ip = ip->next;
01125 
01126                 if (ip == NULL)
01127                         return ISC_R_NOTFOUND;
01128 
01129                 (*dhcpv6_packet_handler)(ip, buf, 
01130                                          result, from.sin6_port, 
01131                                          &ifrom, is_unicast);
01132         }
01133 
01134         return ISC_R_SUCCESS;
01135 }
01136 #endif /* DHCPv6 */
01137 
01138 isc_result_t dhcp_interface_set_value  (omapi_object_t *h,
01139                                         omapi_object_t *id,
01140                                         omapi_data_string_t *name,
01141                                         omapi_typed_data_t *value)
01142 {
01143         struct interface_info *interface;
01144         isc_result_t status;
01145 
01146         if (h -> type != dhcp_type_interface)
01147                 return DHCP_R_INVALIDARG;
01148         interface = (struct interface_info *)h;
01149 
01150         if (!omapi_ds_strcmp (name, "name")) {
01151                 if ((value -> type == omapi_datatype_data ||
01152                      value -> type == omapi_datatype_string) &&
01153                     value -> u.buffer.len < sizeof interface -> name) {
01154                         memcpy (interface -> name,
01155                                 value -> u.buffer.value,
01156                                 value -> u.buffer.len);
01157                         interface -> name [value -> u.buffer.len] = 0;
01158                 } else
01159                         return DHCP_R_INVALIDARG;
01160                 return ISC_R_SUCCESS;
01161         }
01162 
01163         /* Try to find some inner object that can take the value. */
01164         if (h -> inner && h -> inner -> type -> set_value) {
01165                 status = ((*(h -> inner -> type -> set_value))
01166                           (h -> inner, id, name, value));
01167                 if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
01168                         return status;
01169         }
01170                           
01171         return ISC_R_NOTFOUND;
01172 }
01173 
01174 
01175 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
01176                                        omapi_object_t *id,
01177                                        omapi_data_string_t *name,
01178                                        omapi_value_t **value)
01179 {
01180         return ISC_R_NOTIMPLEMENTED;
01181 }
01182 
01183 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
01184                                          const char *file, int line)
01185 {
01186         struct interface_info *interface;
01187 
01188         if (h -> type != dhcp_type_interface)
01189                 return DHCP_R_INVALIDARG;
01190         interface = (struct interface_info *)h;
01191 
01192         if (interface -> ifp) {
01193                 dfree (interface -> ifp, file, line);
01194                 interface -> ifp = 0;
01195         }
01196         if (interface -> next)
01197                 interface_dereference (&interface -> next, file, line);
01198         if (interface -> rbuf) {
01199                 dfree (interface -> rbuf, file, line);
01200                 interface -> rbuf = (unsigned char *)0;
01201         }
01202         if (interface -> client)
01203                 interface -> client = (struct client_state *)0;
01204 
01205         if (interface -> shared_network)
01206                 omapi_object_dereference ((omapi_object_t **)
01207                                           &interface -> shared_network, MDL);
01208 
01209         return ISC_R_SUCCESS;
01210 }
01211 
01212 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
01213                                             const char *name, va_list ap)
01214 {
01215         struct interface_info *ip, *interface;
01216         isc_result_t status;
01217 
01218         if (h -> type != dhcp_type_interface)
01219                 return DHCP_R_INVALIDARG;
01220         interface = (struct interface_info *)h;
01221 
01222         /* If it's an update signal, see if the interface is dead right
01223            now, or isn't known at all, and if that's the case, revive it. */
01224         if (!strcmp (name, "update")) {
01225                 for (ip = dummy_interfaces; ip; ip = ip -> next)
01226                         if (ip == interface)
01227                                 break;
01228                 if (ip && dhcp_interface_startup_hook)
01229                         return (*dhcp_interface_startup_hook) (ip);
01230 
01231                 for (ip = interfaces; ip; ip = ip -> next)
01232                         if (ip == interface)
01233                                 break;
01234                 if (!ip && dhcp_interface_startup_hook)
01235                         return (*dhcp_interface_startup_hook) (ip);
01236         }
01237 
01238         /* Try to find some inner object that can take the value. */
01239         if (h -> inner && h -> inner -> type -> signal_handler) {
01240                 status = ((*(h -> inner -> type -> signal_handler))
01241                           (h -> inner, name, ap));
01242                 if (status == ISC_R_SUCCESS)
01243                         return status;
01244         }
01245         return ISC_R_NOTFOUND;
01246 }
01247 
01248 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
01249                                           omapi_object_t *id,
01250                                           omapi_object_t *h)
01251 {
01252         struct interface_info *interface;
01253         isc_result_t status;
01254 
01255         if (h -> type != dhcp_type_interface)
01256                 return DHCP_R_INVALIDARG;
01257         interface = (struct interface_info *)h;
01258 
01259         /* Write out all the values. */
01260 
01261         status = omapi_connection_put_name (c, "state");
01262         if (status != ISC_R_SUCCESS)
01263                 return status;
01264         if ((interface->flags & INTERFACE_REQUESTED) != 0)
01265             status = omapi_connection_put_string (c, "up");
01266         else
01267             status = omapi_connection_put_string (c, "down");
01268         if (status != ISC_R_SUCCESS)
01269                 return status;
01270 
01271         /* Write out the inner object, if any. */
01272         if (h -> inner && h -> inner -> type -> stuff_values) {
01273                 status = ((*(h -> inner -> type -> stuff_values))
01274                           (c, id, h -> inner));
01275                 if (status == ISC_R_SUCCESS)
01276                         return status;
01277         }
01278 
01279         return ISC_R_SUCCESS;
01280 }
01281 
01282 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
01283                                     omapi_object_t *id,
01284                                     omapi_object_t *ref)
01285 {
01286         omapi_value_t *tv = (omapi_value_t *)0;
01287         isc_result_t status;
01288         struct interface_info *interface;
01289 
01290         if (!ref)
01291                 return DHCP_R_NOKEYS;
01292 
01293         /* First see if we were sent a handle. */
01294         status = omapi_get_value_str (ref, id, "handle", &tv);
01295         if (status == ISC_R_SUCCESS) {
01296                 status = omapi_handle_td_lookup (ip, tv -> value);
01297 
01298                 omapi_value_dereference (&tv, MDL);
01299                 if (status != ISC_R_SUCCESS)
01300                         return status;
01301 
01302                 /* Don't return the object if the type is wrong. */
01303                 if ((*ip) -> type != dhcp_type_interface) {
01304                         omapi_object_dereference (ip, MDL);
01305                         return DHCP_R_INVALIDARG;
01306                 }
01307         }
01308 
01309         /* Now look for an interface name. */
01310         status = omapi_get_value_str (ref, id, "name", &tv);
01311         if (status == ISC_R_SUCCESS) {
01312                 char *s;
01313                 unsigned len;
01314                 for (interface = interfaces; interface;
01315                      interface = interface -> next) {
01316                     s = memchr (interface -> name, 0, IFNAMSIZ);
01317                     if (s)
01318                             len = s - &interface -> name [0];
01319                     else
01320                             len = IFNAMSIZ;
01321                     if ((tv -> value -> u.buffer.len == len &&
01322                          !memcmp (interface -> name,
01323                                   (char *)tv -> value -> u.buffer.value,
01324                                   len)))
01325                             break;
01326                 }
01327                 if (!interface) {
01328                     for (interface = dummy_interfaces;
01329                          interface; interface = interface -> next) {
01330                             s = memchr (interface -> name, 0, IFNAMSIZ);
01331                             if (s)
01332                                     len = s - &interface -> name [0];
01333                             else
01334                                     len = IFNAMSIZ;
01335                             if ((tv -> value -> u.buffer.len == len &&
01336                                  !memcmp (interface -> name,
01337                                           (char *)
01338                                           tv -> value -> u.buffer.value,
01339                                           len)))
01340                                     break;
01341                     }
01342                 }
01343 
01344                 omapi_value_dereference (&tv, MDL);
01345                 if (*ip && *ip != (omapi_object_t *)interface) {
01346                         omapi_object_dereference (ip, MDL);
01347                         return DHCP_R_KEYCONFLICT;
01348                 } else if (!interface) {
01349                         if (*ip)
01350                                 omapi_object_dereference (ip, MDL);
01351                         return ISC_R_NOTFOUND;
01352                 } else if (!*ip)
01353                         omapi_object_reference (ip,
01354                                                 (omapi_object_t *)interface,
01355                                                 MDL);
01356         }
01357 
01358         /* If we get to here without finding an interface, no valid key was
01359            specified. */
01360         if (!*ip)
01361                 return DHCP_R_NOKEYS;
01362         return ISC_R_SUCCESS;
01363 }
01364 
01365 /* actually just go discover the interface */
01366 isc_result_t dhcp_interface_create (omapi_object_t **lp,
01367                                     omapi_object_t *id)
01368 {
01369         struct interface_info *hp;
01370         isc_result_t status;
01371         
01372         hp = (struct interface_info *)0;
01373         status = interface_allocate (&hp, MDL);
01374         if (status != ISC_R_SUCCESS)
01375                 return status;
01376         hp -> flags = INTERFACE_REQUESTED;
01377         status = interface_reference ((struct interface_info **)lp, hp, MDL);
01378         interface_dereference (&hp, MDL);
01379         return status;
01380 }
01381 
01382 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
01383                                     omapi_object_t *id)
01384 {
01385         struct interface_info *interface, *ip, *last;
01386 
01387         interface = (struct interface_info *)lp;
01388 
01389         /* remove from interfaces */
01390         last = 0;
01391         for (ip = interfaces; ip; ip = ip -> next) {
01392                 if (ip == interface) {
01393                         if (last) {
01394                                 interface_dereference (&last -> next, MDL);
01395                                 if (ip -> next)
01396                                         interface_reference (&last -> next,
01397                                                              ip -> next, MDL);
01398                         } else {
01399                                 interface_dereference (&interfaces, MDL);
01400                                 if (ip -> next)
01401                                         interface_reference (&interfaces,
01402                                                              ip -> next, MDL);
01403                         }
01404                         if (ip -> next)
01405                                 interface_dereference (&ip -> next, MDL);
01406                         break;
01407                 }
01408                 last = ip;
01409         }
01410         if (!ip)
01411                 return ISC_R_NOTFOUND;
01412 
01413         /* add the interface to the dummy_interface list */
01414         if (dummy_interfaces) {
01415                 interface_reference (&interface -> next,
01416                                      dummy_interfaces, MDL);
01417                 interface_dereference (&dummy_interfaces, MDL);
01418         }
01419         interface_reference (&dummy_interfaces, interface, MDL);
01420 
01421         /* do a DHCPRELEASE */
01422         if (dhcp_interface_shutdown_hook)
01423                 (*dhcp_interface_shutdown_hook) (interface);
01424 
01425         /* remove the io object */
01426         omapi_unregister_io_object ((omapi_object_t *)interface);
01427 
01428         switch(local_family) {
01429 #ifdef DHCPv6
01430         case AF_INET6:
01431                 if_deregister6(interface);
01432                 break;
01433 #endif /* DHCPv6 */
01434         case AF_INET:
01435         default:
01436                 if_deregister_send(interface);
01437                 if_deregister_receive(interface);
01438                 break;
01439         }
01440 
01441         return ISC_R_SUCCESS;
01442 }
01443 
01444 void interface_stash (struct interface_info *tptr)
01445 {
01446         struct interface_info **vec;
01447         int delta;
01448 
01449         /* If the registerer didn't assign an index, assign one now. */
01450         if (tptr -> index == -1) {
01451                 tptr -> index = interface_count++;
01452                 while (tptr -> index < interface_max &&
01453                        interface_vector [tptr -> index])
01454                         tptr -> index = interface_count++;
01455         }
01456 
01457         if (interface_max <= tptr -> index) {
01458                 delta = tptr -> index - interface_max + 10;
01459                 vec = dmalloc ((interface_max + delta) *
01460                                sizeof (struct interface_info *), MDL);
01461                 if (!vec)
01462                         return;
01463                 memset (&vec [interface_max], 0,
01464                         (sizeof (struct interface_info *)) * delta);
01465                 interface_max += delta;
01466                 if (interface_vector) {
01467                     memcpy (vec, interface_vector,
01468                             (interface_count *
01469                              sizeof (struct interface_info *)));
01470                     dfree (interface_vector, MDL);
01471                 }
01472                 interface_vector = vec;
01473         }
01474         interface_reference (&interface_vector [tptr -> index], tptr, MDL);
01475         if (tptr -> index >= interface_count)
01476                 interface_count = tptr -> index + 1;
01477 #if defined (TRACING)
01478         trace_interface_register (interface_trace, tptr);
01479 #endif
01480 }
01481 
01482 void interface_snorf (struct interface_info *tmp, int ir)
01483 {
01484         tmp -> circuit_id = (u_int8_t *)tmp -> name;
01485         tmp -> circuit_id_len = strlen (tmp -> name);
01486         tmp -> remote_id = 0;
01487         tmp -> remote_id_len = 0;
01488         tmp -> flags = ir;
01489         if (interfaces) {
01490                 interface_reference (&tmp -> next,
01491                                      interfaces, MDL);
01492                 interface_dereference (&interfaces, MDL);
01493         }
01494         interface_reference (&interfaces, tmp, MDL);
01495 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1