pump.c

00001 /* pump.c
00002  *
00003  * libdhcp pump compatibility API for anaconda -
00004  * only the pump symbols used by anaconda are defined.
00005  *
00006  ******************************************************************************
00007  * Original pump credits:
00008  * 
00009  * There are a bunch of folks who made this code possible. I'm sure I've missed
00010  * some in this list :-(
00011  *
00012  *  Alan Cox <alan@redhat.com>
00013  *  Bruce Beare <bbeare@cisco.com>
00014  *  David Blythe <blythe@routefree.com>
00015  *  Stephen Carville <carville@cpl.net>
00016  *  Guy Delamarter <delamart@pas.rochester.edu>
00017  *  Chris Johnson <cjohnson@mint.net>
00018  *  Michael Johnson <johnsonm@redhat.com>
00019  *  H. J. Lu <hjl@valinux.com>
00020  *  Kristof Petr <Petr@Kristof.CZ>
00021  *  Marco Pietrobono <pietrobo@pietrobo.com>
00022  *  Benjamin Reed <breed@cse.ucsc.edu>
00023  *  George Staikos <staikos@0wned.org>
00024  *  Jay Turner <jturner@redhat.com>
00025  *  Matt Wilson <msw@redhat.com>
00026  *  <aaron@schrab.com>
00027  *  <duanev@io.com>
00028  *  <dunham@cse.msu.edu>
00029  *  <safford@watson.ibm.com>
00030  *  weejock@ferret.lmh.ox.ac.uk
00031  *
00032  *******************************************************************************
00033  *
00034  * Copyright 1999-2001 Red Hat, Inc.
00035  * 
00036  * All Rights Reserved.
00037  * 
00038  * The above copyright notice and this permission notice shall be included in
00039  * all copies or substantial portions of the Software.
00040  * 
00041  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00042  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00043  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00044  * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00045  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00046  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00047  * 
00048  * Except as contained in this notice, the name of Red Hat shall not be
00049  * used in advertising or otherwise to promote the sale, use or other dealings
00050  * in this Software without prior written authorization from Red Hat.
00051  *
00052  ******************************************************************************
00053  *
00054  *  Copyright(C) Jason Vas Dias <jvdias@redhat.com> Red Hat Inc. May 2006
00055  *
00056  *  This program is free software; you can redistribute it and/or modify
00057  *  it under the terms of the GNU General Public License as published by
00058  *  the Free Software Foundation at 
00059  *           http://www.fsf.org/licensing/licenses/gpl.txt
00060  *  and included in this software distribution as the "LICENSE" file.
00061  *
00062  *  This program is distributed in the hope that it will be useful,
00063  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00064  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00065  *  GNU General Public License for more details.
00066  */
00067 
00068 #include <sys/types.h>
00069 #include <unistd.h>
00070 #include <sys/ioctl.h>
00071 #include <sys/queue.h>
00072 #include <errno.h>
00073 #include <string.h>
00074 #include <assert.h>
00075 #include <pump.h>
00076 #include <netlink/netlink.h>
00077 #include <netlink/netlink-kernel.h>
00078 
00079 #include <dhcp4client/dhcp4client.h>
00080 #include <dhcp4client/isc_dhcp/dhcpd.h>
00081 
00082 
00083 enum {
00084     OOM,
00085     DHCP_FAILED,
00086 };
00087 
00088 static char * const pump_errors[] = {
00089     [OOM] = "out of memory",
00090     [DHCP_FAILED] = "DHCP configuration failed",
00091     NULL
00092 };
00093 
00094 char * pumpSetupInterface(struct pumpNetIntf * ifx) 
00095 {
00096     static char buf[512];
00097     NIC_t nic = 0;
00098     IPaddr_t addr = 0;
00099     IProute_t route = 0;
00100     int  err=0;
00101     char *tag="";
00102 
00103     if ( ifx->dhcp_nic )
00104     {
00105         /* do DHCP configuration */
00106         assert(ifx->dhcp_nic->nh);
00107 
00108         int r = dhcp_nic_configure(ifx->dhcp_nic);
00109         
00110         dhcp_nic_free(ifx->dhcp_nic);
00111         ifx->dhcp_nic = 0L;
00112         if ( r < 0 )
00113         {
00114             snprintf(buf, 512, "DHCP configuration failed - %d %s.",
00115                      -r, strerror(-r)
00116                     );
00117             relinquish_timeouts();
00118             return buf;
00119         }    
00120         relinquish_timeouts();
00121         return NULL;
00122     }
00123 
00124     /* do anaconda static configuration */
00125 
00126 
00127     if (!ifx->nh) {
00128         ifx->nh = nic_open( 0 );
00129         if (!ifx->nh) {
00130             err = ENOMEM;
00131             tag = "nic_open";
00132             goto return_emsg;
00133         }
00134     }
00135 
00136     nic = nic_by_name( ifx->nh, ifx->device );
00137     if ( nic == 0 )
00138     {
00139         err = ENODEV;
00140         tag = "get link";
00141         goto return_emsg;
00142     }
00143 
00144     uint32_t flags = nic_get_flags( nic );
00145 
00146     if ( flags & ( IFF_UP | IFF_RUNNING | IFF_BROADCAST ) )
00147         nic_set_flags(nic, flags | IFF_UP | IFF_RUNNING | IFF_BROADCAST);
00148 
00149     if ( ( ifx->set & PUMP_INTFINFO_HAS_MTU ) && ( ifx->mtu ) )
00150         nic_set_mtu(nic, ifx->mtu);
00151 
00152     tag = "set link";
00153     if ( (err = - nic_update ( nic )) > 0 )
00154         goto return_emsg;
00155 
00156     if ( (ifx->ip.sa_family != AF_INET)
00157        &&(ifx->ip.sa_family != AF_INET6)
00158         ) goto return_ok;
00159 
00160     addr = nic_addr( ifx->nh, ifx->ip );
00161     uint8_t prefix = 0;
00162     uint8_t isIPv4 = 0;
00163 
00164     if ( addr == 0L )
00165     {
00166         err = ENOMEM;
00167         tag = "new addr";
00168         goto return_emsg;
00169     }
00170 
00171     if( ifx->netmask.sa_family )
00172         switch( ifx->ip.sa_family )
00173         {
00174         case AF_INET:
00175 
00176             isIPv4 = 1;
00177 
00178             if ( ip_v4_addr( &(ifx->netmask) ) )
00179             {
00180                 nic_addr_set_prefix
00181                 (   addr, 
00182                     prefix = ip_v4_netmask_to_prefix( &(ifx->netmask) )
00183                 );
00184             } 
00185             break;
00186          
00187         case AF_INET6:
00188 
00189             if ( ifx->ipv6_prefixlen )
00190             {
00191                 nic_addr_set_prefix
00192                 (   addr, 
00193                     ifx->ipv6_prefixlen 
00194                 );
00195             }
00196             break;
00197         }
00198     
00199     if ( ifx->broadcast.sa_family )
00200         nic_addr_set_broadcast
00201         (
00202             addr,
00203             ifx->broadcast
00204         );
00205     else
00206     if ( prefix && isIPv4 )     
00207         nic_addr_set_broadcast
00208         (
00209             addr,
00210             ip_v4_broadcast( &(ifx->ip), prefix )
00211         );
00212 
00213     tag = "create addr";
00214 
00215     if( (err = - nic_add_address( nic, addr )) > 0 )
00216         goto return_emsg;    
00217     
00218     /* XXX: do we still need to support pre-2.2 kernels ?
00219      * if so, we may need to add a network route here ...
00220      */
00221 
00222     route = 0;
00223 
00224     if( ifx->gateway.sa_family )
00225     {
00226         tag = "new route";
00227         route = 
00228             nic_route_new
00229             (   ifx->nh,
00230                 nic_get_index(nic),        /* output interface oif     */
00231                 0L,0,                      /* dst=0, len=0: DEFAULT !  */
00232                 &ifx->gateway,             /* gateway ip_addr_t        */
00233                 -1,                        /* -1: default: RTN_UNICAST */
00234                 -1,                        /* -1: default: RTPROT_BOOT */
00235                 -1,                        /* default scope: UNIVERSE  */
00236                 -1,                        /* no priority              */
00237                 -1,                        /* table: default (main)    */
00238                 0L,                        /* no input interface       */ 
00239                 0L,                        /* no src                   */
00240                 0                          /* no src len               */                   
00241             );          
00242 
00243         if( route == 0 )
00244         {
00245             err = ENOMEM;
00246             goto return_emsg;
00247         }
00248 
00249         tag = "create route";
00250 
00251         if((err = - nic_add_route( route )) > 0)
00252             goto return_emsg;
00253     }
00254         
00255 return_ok:
00256     nic_close(&(ifx->nh));
00257     nic_addr_free(addr);
00258     nic_route_free(route);
00259 
00260     relinquish_timeouts();
00261     return NULL;
00262 
00263 return_emsg:
00264     nic_close(&ifx->nh);
00265     nic_addr_free(addr);
00266     nic_route_free(route);
00267 
00268     snprintf(buf,512, "pumpSetupInterface failed: %s - %d: %s.",
00269              tag, err, strerror(err)
00270             );
00271 
00272     relinquish_timeouts();
00273     return buf;
00274 }
00275 
00276 extern int asprintf(char **strp, const char *fmt, ...);
00277 
00278 static void 
00279 ifxDHCPv6( struct pumpNetIntf * ifx )
00280 {
00281     IPaddr_t addr = STAILQ_FIRST( &(ifx->dhcp_nic->dhcpv6->address_list) )->addr;
00282     if( ifx->set & PUMP_INTFINFO_HAS_IP )
00283     {
00284         ifx->ipv6 = nic_ip_addr( addr );
00285         if( (ifx->ipv6_prefixlen = nic_addr_get_prefix( addr )) > 0 )
00286             ifx->set |= PUMP_INTFINFO_HAS_IPV6_PREFIX;
00287         ifx->set |= PUMP_INTFINFO_HAS_IPV6_IP;
00288     }else
00289     {
00290         ifx->ip = nic_ip_addr( addr );
00291         ifx->set |= PUMP_INTFINFO_HAS_IP;
00292         ifx->ipv6_prefixlen = nic_addr_get_prefix( addr );
00293         if ( ifx->ipv6_prefixlen )
00294         {
00295             ifx->network = ip_mask(&ifx->ip, ifx->ipv6_prefixlen);
00296             ifx->set |= PUMP_INTFINFO_HAS_NETWORK;
00297         }
00298     }
00299     if( !STAILQ_EMPTY(&(ifx->dhcp_nic->dhcpv6->dns_list)) )
00300     {
00301         IPaddr_list_node_t *n=0;
00302         STAILQ_FOREACH(n, &(ifx->dhcp_nic->dhcpv6->dns_list), link)
00303         {
00304             if( ifx->numDns >= MAX_DNS_SERVERS )
00305                 break;
00306             ifx->dnsServers[ ifx->numDns++ ] = nic_ip_addr( n->addr );
00307             ifx->set |= PUMP_NETINFO_HAS_DNS;
00308         }
00309     }
00310     if(  (ifx->set & PUMP_NETINFO_HAS_DNS)
00311        && ifx->dhcp_nic->dhcpv6->search_list 
00312       )
00313     {
00314         char *s=ifx->domain;
00315         asprintf
00316             (   &(ifx->domain),
00317                 "%s%s%s", 
00318                 s ? s : "",
00319                 s ? " " : "" ,
00320                 ifx->dhcp_nic->dhcpv6->search_list 
00321             );             
00322         if( s )
00323             free(s);
00324         ifx->set |= PUMP_NETINFO_HAS_DOMAIN;
00325     }
00326 }
00327 
00328 static void
00329 ifxDHCPv4( struct pumpNetIntf *ifx )
00330 {
00331     IPaddr_t addr = STAILQ_FIRST( &(ifx->dhcp_nic->dhcpv4->address_list) )->addr;
00332     if( ifx->set & PUMP_INTFINFO_HAS_IP )
00333     {
00334         ifx->ipv4 = nic_ip_addr( addr );
00335         ifx->set |= PUMP_INTFINFO_HAS_IPV4_IP;
00336     }else
00337     {
00338         ifx->ip = nic_ip_addr( addr );
00339         ifx->set |= PUMP_INTFINFO_HAS_IP;
00340         if ( nic_addr_get_prefix( addr ) )
00341         {
00342             ifx->network = ip_mask(&ifx->ip, nic_addr_get_prefix( addr ) );
00343             ifx->set |= PUMP_INTFINFO_HAS_NETWORK;
00344         }
00345     }
00346     if ( nic_addr_get_prefix( addr ) )
00347     {
00348         ifx->netmask = ip_v4_prefix_to_netmask( nic_addr_get_prefix( addr ) );
00349         ifx->set |= PUMP_INTFINFO_HAS_NETMASK;
00350 
00351         ip_addr_t broadcast = nic_addr_get_broadcast( addr );
00352         if( broadcast.sa_family )
00353         {
00354             ifx->broadcast = broadcast;
00355             ifx->set |= PUMP_INTFINFO_HAS_BROADCAST;
00356         }               
00357     }
00358     if(  ifx->dhcp_nic->dhcpv4 
00359        &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->route_list )) )
00360       )
00361     {
00362         IProute_list_node_t *n;
00363         STAILQ_FOREACH( n, &( ifx->dhcp_nic->dhcpv4->route_list ), link )
00364         {
00365             ip_addr_t dst   = nic_route_get_dst( n->route );
00366             ip_addr_t gw    = nic_route_get_gateway( n->route );
00367             uint8_t dst_len = nic_route_get_dst_len( n->route );
00368             if(  (dst.sa_family == 0)
00369                &&(dst_len == 0)
00370                &&(gw.sa_family == AF_INET)
00371               )
00372             {
00373                 ifx->gateway = gw;
00374                 ifx->set |= PUMP_NETINFO_HAS_GATEWAY;
00375                 break;
00376             }           
00377         }
00378     }
00379     if(   ifx->dhcp_nic->dhc4ctl
00380        && dhcpv4_mtu_option( ifx->dhcp_nic->dhc4ctl )
00381       )
00382     {
00383         ifx->mtu =  dhcpv4_mtu_option( ifx->dhcp_nic->dhc4ctl );
00384         ifx->set |= PUMP_INTFINFO_HAS_MTU;
00385     }
00386     if(  ifx->dhcp_nic->dhcpv4->lease.dhcp4_lease )
00387     {
00388         DHCPv4_lease *lease=ifx->dhcp_nic->dhcpv4->lease.dhcp4_lease;
00389         if ( lease->server_address.s_addr != 0 )
00390         {
00391             ifx->nextServer = ip_addr_in(&(lease->server_address));
00392             ifx->set |= PUMP_INTFINFO_HAS_NEXTSERVER;
00393         }
00394         if ( lease->filename )
00395         {
00396             ifx->bootFile = strdup( lease->filename );
00397             ifx->set |= PUMP_INTFINFO_HAS_BOOTFILE;
00398         }
00399     }
00400 
00401     if( !STAILQ_EMPTY(&(ifx->dhcp_nic->dhcpv4->dns_list)) )
00402     {
00403         IPaddr_list_node_t *n=0;
00404         STAILQ_FOREACH(n, &(ifx->dhcp_nic->dhcpv4->dns_list), link)
00405         {
00406             if( ifx->numDns >= MAX_DNS_SERVERS )
00407                 break;
00408             ifx->dnsServers[ ifx->numDns++ ] = nic_ip_addr( n->addr );
00409             ifx->set |= PUMP_NETINFO_HAS_DNS;
00410         }
00411     }
00412     if(  (ifx->set & PUMP_NETINFO_HAS_DNS)
00413        && ifx->dhcp_nic->dhcpv4->search_list 
00414       )
00415     {
00416         char *s=ifx->domain;
00417         asprintf
00418             (   &(ifx->domain),
00419                 "%s%s%s", 
00420                 s ? s : "",
00421                 s ? " " : "" ,
00422                 ifx->dhcp_nic->dhcpv4->search_list 
00423             );             
00424         if( s )
00425             free(s);
00426         ifx->set |= PUMP_NETINFO_HAS_DOMAIN;
00427     }    
00428     if( ifx->dhcp_nic->dhcpv4->host_name )
00429     {
00430         ifx->set |= PUMP_NETINFO_HAS_HOSTNAME;
00431         if(ifx->hostname)
00432             free(ifx->hostname);
00433         ifx->hostname = strdup( ifx->dhcp_nic->dhcpv4->host_name );
00434     }
00435 }
00436 
00437 char * pumpDhcpClassRun
00438 (   struct pumpNetIntf * ifx,
00439     char * hostname,
00440     char * vendor_class,
00441     DHCP_Preference dhcp_preference ,
00442     LIBDHCP_Capability dhcp_capability ,
00443     time_t timeout,
00444     void (*logger)(void*,int,char*,va_list),
00445     int  log_level
00446 )
00447 {
00448     assert(!ifx->nh);
00449 
00450     if (!(ifx->nh = nic_open(NETLINK_ROUTE)))
00451         return pump_errors[OOM];
00452 
00453     if ( logger )
00454     {
00455         nic_set_va_logger(ifx->nh, (NIC_VA_Error_Handler_t)logger, &ifx);
00456         nic_set_loglevel(ifx->nh, log_level );
00457     }   
00458     ifx->dhcp_nic = 
00459         dhcp_nic
00460         (
00461             ifx->nh,
00462             dhcp_preference,
00463             ifx->device,
00464             dhcp_capability,
00465             timeout,
00466             (LIBDHCP_Error_Handler)logger,
00467             log_level,
00468             "-V", vendor_class,
00469             hostname ? "-H" : 0L, 
00470             hostname ? hostname : 0L,
00471             0L
00472         );
00473     if ( ifx->dhcp_nic )
00474     {  /* fill in the pumpNetIntf structure.
00475         * We'll just use the FIRST configured address as ifx->ip -
00476         * users should realize that a list of addresses may have
00477         * been configured.
00478         */      
00479         if ( ( ifx->dhcp_nic->dhcpv4 && ifx->dhcp_nic->dhcpv6 )
00480            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->address_list )) )
00481            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv6->address_list )) )
00482            )
00483         {
00484             if ( dhcp_preference & IPv6_PREFERENCE )
00485             {
00486                 ifxDHCPv6( ifx );
00487                 ifxDHCPv4( ifx );
00488             }else
00489             {
00490                 ifxDHCPv4( ifx );
00491                 ifxDHCPv6( ifx );
00492             }
00493         }else
00494         if(  ifx->dhcp_nic->dhcpv4 
00495            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->address_list )) )
00496           )
00497         {
00498             ifxDHCPv4( ifx );
00499         }else
00500         if(  ifx->dhcp_nic->dhcpv6 
00501            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv6->address_list )) )
00502           )
00503         {
00504             ifxDHCPv6( ifx );
00505         }       
00506         ifx->nh = NULL;
00507     }else
00508     {
00509         nic_close(&ifx->nh);
00510         return pump_errors[DHCP_FAILED];
00511     }
00512     return NULL;
00513 }
00514 
00515 char * pumpDisableInterface(char * device) 
00516 {
00517     static char buf[512];
00518     struct ifreq req;
00519     int s, e;
00520 
00521     s = socket(AF_INET, SOCK_DGRAM, 0);
00522         
00523     memset(&req,0,sizeof(req));
00524 
00525     strcpy(req.ifr_name, device);
00526     if (ioctl(s, SIOCGIFFLAGS, &req)) {
00527         e = errno;
00528         snprintf(buf, 512,
00529                 "ioctl SIOCGIFFLAGS failed: %d %s\n", 
00530                 e, strerror(e) 
00531                );
00532         close(s);
00533         return  &(buf[0]);
00534     }
00535 
00536     req.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
00537     if (ioctl(s, SIOCSIFFLAGS, &req)) {
00538         e = errno;
00539         snprintf(buf, 512,
00540                 "ioctl SIOCSIFFLAGS failed: %d %s\n", 
00541                 e, strerror(e) 
00542                );
00543         close(s);
00544         return &(buf[0]);
00545     }
00546 
00547     close(s);
00548 
00549     return NULL;
00550 }
00551 
00552 /*
00553  * vim:ts=8:sw=4:sts=4:et
00554  */

Generated on Thu Aug 10 22:16:40 2006 for libdhcp by  doxygen 1.4.7