dhcp_nic.c

00001 /* dhcp_nic.c
00002  *
00003  * Network Interface Configurator for BOTH the ISC DHCP IPv4 client library
00004  * and the DHCPv6 IPv6 client.
00005  *
00006  * Copyright (C) 2006  Red Hat, Inc. All rights reserved.
00007  *
00008  * This copyrighted material is made available to anyone wishing to use,
00009  * modify, copy, or redistribute it subject to the terms and conditions of
00010  * the GNU General Public License v.2.  This program is distributed in the
00011  * hope that it will be useful, but WITHOUT ANY WARRANTY expressed or
00012  * implied, including the implied warranties of MERCHANTABILITY or FITNESS
00013  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
00014  * details.  You should have received a copy of the GNU General Public
00015  * License along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00017  * USA. Any Red Hat trademarks that are incorporated in the source code or
00018  * documentation are not subject to the GNU General Public License and may
00019  * only be used or replicated with the express permission of Red Hat, Inc.
00020  *
00021  * Red Hat Author(s): Jason Vas Dias
00022  *                    David Cantrell
00023  */
00024 #include <sys/types.h>
00025 #include <unistd.h>
00026 #include <sys/wait.h>
00027 #include <sys/mman.h>
00028 #include <dhcp_nic.h>
00029 #include <string.h>
00030 #include <malloc.h>
00031 #include <errno.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 
00035 static
00036 int dhc_log( LIBDHCP_Control *ctl, int priority, char *fmt, ... )
00037 {
00038     if( (ctl==0) || (ctl->eh == 0) )
00039         return 0;
00040     va_list va;
00041     va_start(va,fmt);
00042     int r = ctl->eh(ctl, priority, fmt, va);
00043     va_end(va);
00044     return r;
00045 }
00046 
00047 static
00048 int dhc_log_noctl( LIBDHCP_Error_Handler eh, int log_level, int priority, char *fmt, ... )
00049 {        
00050     LIBDHCP_Control ctl;
00051     if( eh == 0 )
00052         return 0;
00053     ctl.log_level = log_level;
00054     va_list va;
00055     va_start(va,fmt);
00056     int r = eh(&ctl, priority, fmt, va);
00057     va_end(va);
00058     return r;
00059 }
00060 
00061 static int ifup( LIBDHCP_Control *control, NIC_t nic )
00062 {
00063     /* bring interface UP */
00064     uint32_t iff = nic_get_flags(nic);
00065     dhc_log
00066     (   control, LOG_INFO,
00067         "DHCP %s  - bringing link UP - %x %d",
00068         nic_get_name(nic),
00069         iff, iff & (IFF_UP | IFF_RUNNING) 
00070     );
00071     if ( ( iff & (IFF_UP | IFF_RUNNING) ) != (IFF_UP | IFF_RUNNING) ) 
00072     {
00073         nic_set_flags(nic, iff | IFF_UP | IFF_RUNNING );
00074         if ( nic_update(nic) != NIC_OK )
00075         {
00076             dhc_log
00077             (   control, LOG_ERR,
00078                 "DHCP %s - bringing link UP failed.",
00079                 nic_get_name(nic)
00080             );
00081             return 1;
00082         }
00083     }
00084     return 0;
00085 }
00086 
00087 static 
00088 DHCP_nic *dhcp_nic_va
00089 ( 
00090     NLH_t                  nh,
00091     DHCP_Preference        preference,
00092     char                  *ethX,
00093     LIBDHCP_Capability     dhc_cap, 
00094     time_t                 timeout,    
00095     LIBDHCP_Error_Handler  error_handler,
00096     uint8_t                log_level,
00097     va_list                dhclient_va
00098 )
00099 {
00100     DHCP_nic *nic = calloc(1,sizeof(DHCP_nic));
00101     if( nic == 0L )
00102     {
00103         dhc_log_noctl(error_handler, log_level, LOG_FATAL, "dhcp_nic: out of memory");
00104         return 0L;
00105     }
00106 
00107     nic->preference = preference;
00108 
00109     nic->nh = nh;
00110     
00111     NIC_t eth = nic_by_name(nh, ethX);
00112 
00113     if( eth == 0L )
00114     {
00115         dhc_log_noctl(error_handler, log_level, LOG_FATAL, "dhcp_nic: net_get_by_name(%s) failed", ethX);
00116         free(nic);
00117         return 0L;
00118     }
00119 
00120     LIBDHCP_Control *dhc6ctl=0;
00121     DHCPv4_control  *dhc4ctl=0;
00122 
00123     if ( (preference & DHCPv4_DISABLE) == 0 )
00124     {
00125         dhc4ctl =
00126             dhcpv4_control_va
00127             (nh, ethX, dhc_cap, timeout, error_handler, log_level, dhclient_va);
00128         if ( dhc4ctl == 0L )
00129         {
00130             dhc_log_noctl(error_handler, log_level, LOG_FATAL,"dhcp_nic: dhcpv4_control failed");
00131             free(nic);
00132             return 0;
00133         }
00134         nic->dhc4ctl = dhc4ctl;
00135     }
00136 
00137     if ( (preference & DHCPv6_DISABLE) == 0 )
00138     {
00139         dhc6ctl = 
00140             libdhcp_control_new       
00141             (   dhcp6_nic_callback,
00142                 0,  /* NO "capabilities"! */
00143                 timeout, /* timeout */
00144                 0,  /* let do_dhcpv6 worry about arg */
00145                 error_handler, log_level
00146             );
00147 
00148         if ( dhc6ctl == 0L )
00149         {
00150             dhc_log_noctl(error_handler, log_level, LOG_FATAL,"dhcp_nic: libdhcp_control_new failed");
00151             free(nic);
00152             if (dhc4ctl)
00153                 dhcpv4_control_free(dhc4ctl);
00154             return 0;
00155         }
00156 
00157         nic->dhc6ctl = dhc6ctl;
00158     }
00159 
00160     if ( ( dhc6ctl == 0L ) && (dhc4ctl == 0) )
00161     {
00162         dhc_log_noctl(error_handler, log_level, LOG_FATAL, "dhcp_nic: both DISABLE_DHCPv6 and DISABLE_DHCv4 set.");
00163         free(nic);
00164         return 0;
00165     }
00166 
00167     if( error_handler )
00168     {
00169         nic_set_va_logger(nh, (NIC_VA_Error_Handler_t)error_handler, dhc6ctl);
00170         nic_set_loglevel( nh, log_level );
00171     }
00172 
00173     if( ifup(dhc6ctl, eth) != 0 )
00174     {
00175         dhc_log_noctl(error_handler, log_level, LOG_FATAL, "dhcp_nic: ifup(%s) failed", ethX);
00176         if (dhc4ctl)
00177             dhcpv4_control_free(dhc4ctl);
00178         if (dhc6ctl)
00179             libdhcp_control_free(dhc6ctl);
00180         free(nic);
00181         return 0L;
00182     }
00183 
00184     DHCPv4_nic *nic4=0;
00185     DHCPv6_nic *nic6=0;
00186 
00187     if( (preference & DHCPv6_DISABLE) == 0 )
00188     {
00189         /* 
00190          * Ensure the ipv6 kernel module is loaded -
00191          * it gets auto-loaded by first process to do this:
00192          */
00193         int ipv6_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
00194         close(ipv6_sock);
00195     }
00196 
00197     if( timeout > 0 )
00198     {
00199         if ( preference & IPv6_PREFERENCE )
00200         {
00201             if ( (preference & DHCPv6_DISABLE) == 0 )
00202                 nic6 = do_dhcpv6(nic->dhc6ctl, nh, ethX);
00203 
00204             if ( (preference & DHCPv4_DISABLE) == 0 )
00205                 nic4 = do_dhcpv4(nic->dhc4ctl);
00206 
00207         }else
00208         {
00209             if ( (preference & DHCPv4_DISABLE) == 0 )
00210                 nic4 = do_dhcpv4(nic->dhc4ctl);
00211 
00212             if ( (preference & DHCPv6_DISABLE) == 0 )
00213                 nic6 = do_dhcpv6(nic->dhc6ctl, nh, ethX);
00214         }
00215     }else
00216     {
00217         /* User has selected timeout==0, so each client will continue
00218          * trying to obtain a lease indefinitely. This can only work
00219          * in separate processes / threads - threads don't work because
00220          * of the select() used by both clients, so we use processses.
00221          */
00222 
00223         pid_t 
00224             dhc4_pid=-1,
00225             dhc6_pid=-1;
00226         
00227         uint8_t *sma = 
00228             mmap( 0, 16 * 8192, /* 128k - there may be LOTS of DHCPv4 options */ 
00229                   PROT_READ | PROT_WRITE, 
00230                   MAP_SHARED | MAP_ANONYMOUS,
00231                   -1, 0
00232                 );
00233                   
00234         if( sma == 0 )
00235         {
00236             dhc_log_noctl(error_handler, log_level, LOG_FATAL,
00237                           "dhcp_nic: timeout==0 and cannot obtain shared memory area - %d %s.",
00238                           errno, strerror(errno)
00239                          );
00240             if (dhc4ctl)
00241                 dhcpv4_control_free(dhc4ctl);
00242             if (dhc6ctl)
00243                 libdhcp_control_free(dhc6ctl);
00244             free(nic);
00245             return 0L; 
00246         }
00247         
00248         uint8_t 
00249             *dhc4_buf = sma,
00250             *dhc6_buf = sma + (14 * 8192);
00251 
00252 
00253         if( (preference & DHCPv4_DISABLE) == 0) {
00254             if ((dhc4_pid = fork()) == 0 ) {
00255                 nic4 = do_dhcpv4(nic->dhc4ctl);
00256 
00257                 if (nic4 && nic4->lease != 0)
00258                     dhcpv4_pack_lease(nic4->lease, dhc4_buf, (14 * 8192)); 
00259 
00260                 if (dhc4ctl)
00261                     dhcpv4_control_free(dhc4ctl);
00262                 if (dhc6ctl)
00263                     libdhcp_control_free(dhc6ctl);
00264                 free(nic);
00265                 exit(0);
00266             }
00267             if ( dhc4_pid == -1 ) {
00268                 dhc_log_noctl(error_handler, log_level, LOG_FATAL,
00269                           "dhcp_nic: timeout==0 and fork() failed - %d %s.",
00270                           errno, strerror(errno)
00271                          );
00272 
00273                 if (dhc4ctl)
00274                     dhcpv4_control_free(dhc4ctl);
00275                 if (dhc6ctl)
00276                     libdhcp_control_free(dhc6ctl);
00277                 free(nic);
00278                 return 0L; 
00279             }
00280         }
00281 
00282         if( (preference & DHCPv6_DISABLE) == 0) {
00283             if( (dhc6_pid = fork()) == 0 ) {
00284                 nic6 = do_dhcpv6(nic->dhc6ctl, nh, ethX);
00285                 if (nic6 && nic6->lease)
00286                     dhcpv6_pack_lease(nic6->lease, dhc6_buf, (2 * 8192));
00287 
00288                 if (dhc4ctl)
00289                     dhcpv4_control_free(dhc4ctl);
00290                 if (dhc6ctl)
00291                     libdhcp_control_free(dhc6ctl);
00292                 free(nic);
00293                 exit(0);
00294             }
00295 
00296             if( dhc6_pid == -1 ) {
00297                 dhc_log_noctl(error_handler, log_level, LOG_FATAL,
00298                           "dhcp_nic: timeout==0 and fork() failed - %d %s.",
00299                           errno, strerror(errno)
00300                          );
00301                 if (dhc4ctl)
00302                     dhcpv4_control_free(dhc4ctl);
00303                 if (dhc6ctl)
00304                     libdhcp_control_free(dhc6ctl);
00305                 free(nic);
00306                 return 0L; 
00307             }
00308         }
00309 
00310         pid_t wait_pid = 0;
00311         int status, dhc4_status=0, dhc6_status=0;
00312         
00313     dhc_client_wait:
00314         dhc_log_noctl(error_handler, log_level, LOG_DEBUG, "DHCP: wait - %d %d",
00315                       dhc4_status, dhc6_status
00316                      );
00317         if ((dhc4_status == 0 || dhc6_status == 0) ||
00318                 (dhc6_pid == -1 && dhc4_pid == -1))
00319             goto dhc_clients_finished;
00320 
00321         wait_pid = waitpid(-1, &status, 0);
00322 
00323         if( wait_pid == -1 )
00324             goto dhc_client_wait;
00325 
00326         if( wait_pid == dhc4_pid )
00327         {
00328             DHCPv4_lease *lease4 = dhcpv4_unpack_lease( dhc4_buf );
00329 
00330             dhc4_status = dhc4_pid;
00331 
00332             dhc_log_noctl(error_handler, log_level, LOG_DEBUG,
00333                           "DHCPv4 process finished - %p", lease4);
00334 
00335             if ( lease4 )
00336                 nic4 = dhcp4_set_lease( dhc4ctl, lease4 );
00337 
00338             if( dhc6_status == 0 )
00339             {
00340                 if( lease4 && (preference & DHCP_ACCEPT_FIRST_LEASE) )
00341                 {                   
00342                     kill(dhc6_pid, SIGKILL);
00343                     waitpid(dhc6_pid,0,WNOHANG);
00344                 }else
00345                     goto dhc_client_wait;
00346             }       
00347         }else
00348         if( wait_pid == dhc6_pid )
00349         {
00350             DHCPv6_lease *lease6 = dhcpv6_unpack_lease( dhc6_buf );
00351 
00352             dhc6_status = dhc6_pid;
00353 
00354             dhc_log_noctl(error_handler, log_level, LOG_DEBUG,
00355                           "DHCPv6 process finished - %p", lease6);
00356 
00357             if( lease6 )
00358                 nic6 = dhcp6_nic_from_lease(dhc6ctl, nh, lease6, eth);
00359 
00360             if( dhc4_status == 0 )
00361             {
00362                 if( lease6 && (preference & DHCP_ACCEPT_FIRST_LEASE) )
00363                 {
00364                     kill(dhc4_pid, SIGKILL);
00365                     waitpid(dhc4_pid,0,WNOHANG);
00366                 }else
00367                     goto dhc_client_wait;
00368             }
00369         }else
00370             goto dhc_client_wait;
00371 
00372     dhc_clients_finished:
00373         munmap( sma, 16 * 8192 );
00374 
00375     }
00376 
00377 
00378     if (!dhc4ctl) {
00379         nic4 = NULL;
00380         nic->dhc4ctl = NULL;
00381     }
00382     if (nic4 && !dhcp4_process_lease(dhc4ctl)) {
00383         dhc_log_noctl(error_handler, log_level, LOG_ERR,
00384                       "DHCP: empty DHCPv4 lease."
00385                       );
00386         dhcpv4_control_free(dhc4ctl);
00387         dhc4ctl = nic->dhc4ctl = NULL;
00388         nic4 = NULL;
00389     }
00390     if (nic6 && !dhcp6_process_lease(dhc6ctl, nic6)) {
00391         dhc_log_noctl(error_handler, log_level, LOG_ERR,
00392                       "DHCP: empty DHCPv6 lease."
00393                       );
00394         dhcpv6_nic_free(nic6);
00395         nic6 = NULL;
00396         free(dhc6ctl);
00397         nic->dhc6ctl = dhc6ctl = NULL;
00398     }
00399 
00400     if (!nic6 && !nic4) {
00401 #if 0
00402         if (dhc4ctl)
00403             dhcpv4_control_free(dhc4ctl);
00404         if (dhc6ctl)
00405             libdhcp_control_free(dhc6ctl);
00406 #endif
00407         free(nic);
00408         return NULL;
00409     }
00410 
00411     nic->dhcpv4 = (DHCP_config*)nic4;
00412     nic->dhcpv6 = (DHCP_config*)nic6;
00413     return nic;
00414 }
00415 
00416 DHCP_nic *dhcp_nic
00417 ( 
00418     NLH_t nh,
00419     DHCP_Preference preference,
00420     char                  *ethX,
00421     LIBDHCP_Capability     dhc_cap, 
00422     time_t                 timeout,    
00423     LIBDHCP_Error_Handler  error_handler,
00424     uint8_t                log_level,
00425     ...
00426 )
00427 {    
00428     va_list dhclient_va;
00429     va_start(dhclient_va, log_level);
00430     DHCP_nic 
00431         *nic = 
00432         dhcp_nic_va
00433         (   nh,
00434             preference,
00435             ethX,
00436             dhc_cap,
00437             timeout,
00438             error_handler,
00439             log_level,
00440             dhclient_va
00441         );
00442     va_end(dhclient_va);
00443     return nic;
00444 }
00445 
00446 void dhcp_nic_free( DHCP_nic *nic  )
00447 {
00448     if( nic->dhc4ctl )
00449     {
00450         dhcpv4_control_free (  nic->dhc4ctl );
00451         nic->dhc4ctl = 0L;
00452     }
00453     if( nic->dhc6ctl )
00454     {
00455         free(nic->dhc6ctl);
00456         nic->dhc6ctl = 0L;
00457     }
00458     if( nic->dhcpv6 )
00459     {
00460         dhcpv6_nic_free( (DHCPv6_nic*) nic->dhcpv6 );
00461         nic->dhcpv6 = 0L;
00462     }
00463     if (nic->nh)
00464             nic_close(&nic->nh);
00465     free(nic);
00466 }
00467 
00468 NIC_Res_t do_dhcp
00469 ( 
00470     DHCP_Preference preference,
00471     char                  *eth_if_name,
00472     LIBDHCP_Capability     dhc_cap, 
00473     time_t                 timeout,    
00474     LIBDHCP_Error_Handler  error_handler,
00475     uint8_t                log_level,
00476     ... /* extra DHCPv4 dhclient arguments;
00477          * last arg MUST be 0 .
00478          */
00479 )
00480 {
00481     va_list dhclient_va;
00482 
00483     va_start(dhclient_va, log_level);
00484 
00485     NLH_t nh = nic_open(0);
00486 
00487     if ( nh == 0L )
00488     {
00489         dhc_log_noctl(error_handler, log_level, LOG_FATAL, "do_dhcp: nic_open() failed");
00490         nic_close(&nh);
00491         return 0L;
00492     }
00493 
00494     DHCP_nic 
00495         *nic = 
00496         dhcp_nic_va
00497         (   nh,
00498             preference,
00499             eth_if_name,
00500             dhc_cap,
00501             timeout,
00502             error_handler,
00503             log_level,
00504             dhclient_va
00505         );
00506     va_end(dhclient_va);    
00507 
00508     if ( nic == 0L )
00509     {
00510         dhc_log_noctl(error_handler, log_level, LOG_FATAL, "do_dhcp: no leases obtained.");
00511         nic_close(&nh);
00512         return NIC_FAIL;
00513     }
00514         
00515     NIC_Res_t r = dhcp_nic_configure ( nic );
00516 
00517     dhcp_nic_free(nic);
00518     nic_close(&nh);
00519     
00520     return r;
00521 }
00522 
00523 NIC_Res_t
00524 dhcp_nic_configure( DHCP_nic *nic )
00525 {
00526     if (nic == 0)
00527         return NIC_FAIL;
00528 
00529     LIBDHCP_Control *ctl = nic->dhc6ctl;
00530     NIC_Res_t res = NIC_FAIL;    
00531     char order[3] = { 0, 0, 0 };
00532     char res_order[3] = { 0, 0, 0 };
00533     IPaddr_list_t *dns;
00534     char *search_list = 0, sl_len = 0;
00535     int i;
00536     IPaddr_list_node_t *n=0, *nn=0;
00537 
00538     if (nic->dhcpv6) {
00539         if ((!(nic->preference & DHCPv6_DISABLE_RESOLVER)) &&
00540                 !STAILQ_EMPTY(&nic->dhcpv6->dns_list))
00541             res_order[0] = 6;
00542         order[0] = 6;
00543     }
00544     
00545     if (nic->dhcpv4) {
00546         if ((!(nic->preference & DHCPv6_DISABLE_RESOLVER)) &&
00547                 !STAILQ_EMPTY(&nic->dhcpv4->dns_list))
00548             res_order[1] = 4;
00549         order[1] = 4;
00550     }
00551 
00552     sl_len = 2;
00553     search_list = calloc(sl_len, sizeof (char));
00554 
00555     if (!(nic->preference & IPv6_PREFERENCE)) {
00556         char a = order[0];
00557         order[0] = order[1];
00558         order[1] = a;
00559 
00560         a = res_order[0];
00561         res_order[0] = res_order[1];
00562         res_order[1] = res_order[0];
00563     }
00564 
00565     for (i = 0; i < 2; i++) {
00566         if (!order[i])
00567             order[i] = order[i+1];
00568         if (!res_order[i])
00569             res_order[i] = res_order[i+1];
00570     }
00571 
00572     dns = calloc(1, sizeof(IPaddr_list_t));
00573     STAILQ_INIT(dns);
00574 
00575     for (i = 0; res_order[i]; i++) {
00576         switch (res_order[i]) {
00577             case 6:
00578                 if (!nic->dhcpv6) 
00579                     continue;
00580                 STAILQ_FOREACH(n, &(nic->dhcpv6->dns_list), link) {
00581                     nn = calloc(1, sizeof(IPaddr_list_node_t));
00582                     nn->addr = n->addr;
00583                     STAILQ_INSERT_TAIL(dns, nn, link);
00584                 }
00585 
00586                 if (nic->dhcpv6->search_list) {
00587                     sl_len += strlen(nic->dhcpv6->search_list);
00588                     search_list = realloc(search_list, sl_len);
00589                     if (search_list[0])
00590                         strcat(search_list, " ");
00591                     strcat(search_list, nic->dhcpv6->search_list);
00592                 }
00593                 break;
00594             case 4:
00595                 if (!nic->dhcpv4)
00596                     continue;
00597                 STAILQ_FOREACH(n, &(nic->dhcpv4->dns_list), link) {
00598                     nn = calloc(1, sizeof(IPaddr_list_node_t));
00599                     nn->addr = n->addr;
00600                     STAILQ_INSERT_TAIL(dns, nn, link);
00601                 }
00602 
00603                 if (nic->dhcpv4->search_list) {
00604                     sl_len += strlen(nic->dhcpv4->search_list);
00605                     search_list = realloc(search_list, sl_len);
00606                     if (search_list[0])
00607                         strcat(search_list, " ");
00608                     strcat(search_list, nic->dhcpv4->search_list);
00609                 }
00610                 break;
00611         }
00612     }
00613 
00614     for (i = 0; order[i]; i++) {
00615         switch (order[i]) {
00616             case 6:
00617                 if (!nic->dhcpv6) 
00618                     continue;
00619 
00620                 res = nic_configure(nic->nh, nic->dhcpv6->nic,
00621                     (nic->preference & DHCPv6_DISABLE_ADDRESSES) ?
00622                         0 : &nic->dhcpv6->address_list, 
00623                     0,   /* never any dhcpv6 routes ! (use radvd for that.) */
00624                     dns, search_list,
00625                     0    /* dhvpv6 never sets host name */
00626                 );
00627                 if (res == NIC_OK)
00628                     dhc_log(ctl, LOG_INFO, "DHCPv6 interface configuration succeeded.");
00629                 else
00630                     dhc_log(ctl, LOG_ERR, "DHCPv6 interface configuration failed.");
00631                 break;
00632             case 4:
00633                 if (!nic->dhcpv4)
00634                     continue;
00635 
00636                 /* DHCPv4 */
00637                 if (nic->dhc4ctl && dhcpv4_mtu_option(nic->dhc4ctl)) {
00638                     nic_set_mtu(nic->dhcpv4->nic,
00639                         dhcpv4_mtu_option(nic->dhc4ctl));
00640 
00641                     if (nic_update(nic->dhcpv4->nic) != NIC_OK)
00642                         dhc_log(ctl, LOG_ERR, "DHCPv4 MTU set failed."); 
00643                 }
00644                 res=nic_configure(nic->nh, nic->dhcpv4->nic,
00645                         (nic->preference & DHCPv4_DISABLE_ADDRESSES) ?
00646                             0 : &nic->dhcpv4->address_list,
00647                         (nic->preference & DHCPv4_DISABLE_ROUTES) ?
00648                             0 : &nic->dhcpv4->route_list,
00649                         dns, search_list,
00650                         (nic->preference & DHCPv4_DISABLE_HOSTNAME_SET) ?
00651                             0 : nic->dhcpv4->host_name
00652                     );
00653                 if (res == NIC_OK)
00654                     dhc_log(ctl, LOG_INFO, "DHCPv4 interface configuration succeeded.");
00655                 else
00656                     dhc_log(ctl, LOG_ERR, "DHCPv4 interface configuration failed.");
00657                 break;
00658         }
00659     }
00660 
00661     if (!STAILQ_EMPTY(dns)) {
00662         nn = STAILQ_FIRST( dns );
00663         while ((n = nn)) {
00664             nn = STAILQ_NEXT(n, link);
00665             free(n);
00666         }
00667     }
00668     if (dns)
00669         free(dns);
00670     if (search_list)
00671         free(search_list);
00672     return res;
00673 }
00674 
00675 /*
00676  * vim:ts=8:sw=4:sts=4:et
00677  */

Generated on Fri Oct 13 18:20:33 2006 for libdhcp by  doxygen 1.4.7