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) 2006  Red Hat, Inc. All rights reserved.
00055  *
00056  * This copyrighted material is made available to anyone wishing to use,
00057  * modify, copy, or redistribute it subject to the terms and conditions of
00058  * the GNU General Public License v.2.  This program is distributed in the
00059  * hope that it will be useful, but WITHOUT ANY WARRANTY expressed or
00060  * implied, including the implied warranties of MERCHANTABILITY or FITNESS
00061  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
00062  * details.  You should have received a copy of the GNU General Public
00063  * License along with this program; if not, write to the Free Software
00064  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00065  * USA. Any Red Hat trademarks that are incorporated in the source code or
00066  * documentation are not subject to the GNU General Public License and may
00067  * only be used or replicated with the express permission of Red Hat, Inc.
00068  *
00069  * Red Hat Author(s): Jason Vas Dias
00070  *                    David Cantrell
00071  */
00072 
00073 #include <sys/types.h>
00074 #include <unistd.h>
00075 #include <sys/ioctl.h>
00076 #include <sys/queue.h>
00077 #include <errno.h>
00078 #include <string.h>
00079 #include <assert.h>
00080 #include <pump.h>
00081 #include <netlink/netlink.h>
00082 #include <netlink/netlink-kernel.h>
00083 
00084 #include <dhcp4client/dhcp4client.h>
00085 #include <dhcp4client/isc_dhcp/dhcpd.h>
00086 
00087 enum {
00088     OOM,
00089     DHCP_FAILED,
00090 };
00091 
00092 static char * const pump_errors[] = {
00093     [OOM] = "out of memory",
00094     [DHCP_FAILED] = "DHCP configuration failed",
00095     NULL
00096 };
00097 
00098 char * pumpSetupInterface(struct pumpNetIntf * ifx) 
00099 {
00100     static char buf[512];
00101     NIC_t nic = 0;
00102     IPaddr_t addr = 0;
00103     IProute_t route = 0;
00104     int  err=0;
00105     char *tag="";
00106 
00107     if ( ifx->dhcp_nic )
00108     {
00109         /* do DHCP configuration */
00110         assert(ifx->dhcp_nic->nh);
00111 
00112         int r = dhcp_nic_configure(ifx->dhcp_nic);
00113         
00114         dhcp_nic_free(ifx->dhcp_nic);
00115         ifx->dhcp_nic = 0L;
00116         if ( r < 0 )
00117         {
00118             snprintf(buf, 512, "DHCP configuration failed - %d %s.",
00119                      -r, strerror(-r)
00120                     );
00121             relinquish_timeouts();
00122             return buf;
00123         }    
00124         relinquish_timeouts();
00125         return NULL;
00126     }
00127 
00128     /* do anaconda static configuration */
00129     if (!ifx->nh) {
00130         ifx->nh = nic_open( 0 );
00131         if (!ifx->nh) {
00132             err = ENOMEM;
00133             tag = "nic_open";
00134             goto return_emsg;
00135         }
00136     }
00137 
00138     nic = nic_by_name( ifx->nh, ifx->device );
00139     if ( nic == 0 )
00140     {
00141         err = ENODEV;
00142         tag = "get link";
00143         nic_close(&ifx->nh);
00144         goto return_emsg;
00145     }
00146 
00147     uint32_t flags = nic_get_flags( nic );
00148 
00149     if ( flags & ( IFF_UP | IFF_RUNNING | IFF_BROADCAST ) )
00150         nic_set_flags(nic, flags | IFF_UP | IFF_RUNNING | IFF_BROADCAST);
00151 
00152     if ( ( ifx->set & PUMP_INTFINFO_HAS_MTU ) && ( ifx->mtu ) )
00153         nic_set_mtu(nic, ifx->mtu);
00154 
00155     tag = "set link";
00156     if ( (err = - nic_update ( nic )) > 0 )
00157     {
00158         nic_close(&ifx->nh);
00159         goto return_emsg;
00160     }
00161 
00162     if ( (ifx->ip.sa_family != AF_INET) && (ifx->ip.sa_family != AF_INET6) )
00163     {
00164         nic_close(&ifx->nh);
00165         return NULL;
00166     }
00167 
00168     addr = nic_addr( ifx->nh, ifx->ip );
00169     uint8_t prefix = 0;
00170     uint8_t isIPv4 = 0;
00171 
00172     if ( addr == 0L )
00173     {
00174         err = ENOMEM;
00175         tag = "new addr";
00176         nic_close(&ifx->nh);
00177         goto return_emsg;
00178     }
00179 
00180     if( ifx->netmask.sa_family )
00181         switch( ifx->ip.sa_family )
00182         {
00183         case AF_INET:
00184 
00185             isIPv4 = 1;
00186 
00187             if ( ip_v4_addr( &(ifx->netmask) ) )
00188             {
00189                 nic_addr_set_prefix
00190                 (   addr, 
00191                     prefix = ip_v4_netmask_to_prefix( &(ifx->netmask) )
00192                 );
00193             } 
00194             break;
00195          
00196         case AF_INET6:
00197 
00198             if ( ifx->ipv6_prefixlen )
00199             {
00200                 nic_addr_set_prefix
00201                 (   addr, 
00202                     ifx->ipv6_prefixlen 
00203                 );
00204             }
00205             break;
00206         }
00207 
00208     if ( ifx->broadcast.sa_family ) {
00209         nic_addr_set_broadcast
00210         (
00211             addr,
00212             ifx->broadcast
00213         );
00214     } else if ( prefix && isIPv4 ) {
00215         nic_addr_set_broadcast
00216         (
00217             addr,
00218             ip_v4_broadcast( &(ifx->ip), prefix )
00219         );
00220     }
00221 
00222     tag = "create addr";
00223 
00224     if( (err = - nic_add_address( nic, addr )) > 0 )
00225     {
00226         nic_addr_free(addr);
00227         nic_close(&ifx->nh);
00228         goto return_emsg;
00229     }
00230     
00231     /* XXX: do we still need to support pre-2.2 kernels ?
00232      * if so, we may need to add a network route here ...
00233      */
00234 
00235     route = 0;
00236 
00237     if( ifx->gateway.sa_family )
00238     {
00239         tag = "new route";
00240         route = 
00241             nic_route_new
00242             (   ifx->nh,
00243                 nic_get_index(nic),        /* output interface oif     */
00244                 0L,0,                      /* dst=0, len=0: DEFAULT !  */
00245                 &ifx->gateway,             /* gateway ip_addr_t        */
00246                 -1,                        /* -1: default: RTN_UNICAST */
00247                 -1,                        /* -1: default: RTPROT_BOOT */
00248                 -1,                        /* default scope: UNIVERSE  */
00249                 -1,                        /* no priority              */
00250                 -1,                        /* table: default (main)    */
00251                 0L,                        /* no input interface       */ 
00252                 0L,                        /* no src                   */
00253                 0                          /* no src len               */                   
00254             );          
00255 
00256         if( route == 0 )
00257         {
00258             err = ENOMEM;
00259             nic_addr_free(addr);
00260             nic_close(&ifx->nh);
00261             goto return_emsg;
00262         }
00263 
00264         tag = "create route";
00265 
00266         if((err = - nic_add_route( route )) > 0)
00267         {
00268             nic_route_free(route);
00269             nic_addr_free(addr);
00270             nic_close(&ifx->nh);
00271             goto return_emsg;
00272         }
00273     }
00274 
00275     nic_route_free(route);
00276     nic_addr_free(addr);        
00277     nic_close(&ifx->nh);
00278     return NULL;
00279 
00280 return_emsg:
00281     snprintf(buf,512, "pumpSetupInterface failed: %s - %d: %s.",
00282              tag, err, strerror(err)
00283             );
00284     return buf;
00285 }
00286 
00287 extern int asprintf(char **strp, const char *fmt, ...);
00288 
00289 static void 
00290 ifxDHCPv6( struct pumpNetIntf * ifx )
00291 {
00292     IPaddr_t addr = STAILQ_FIRST( &(ifx->dhcp_nic->dhcpv6->address_list) )->addr;
00293     if( ifx->set & PUMP_INTFINFO_HAS_IP )
00294     {
00295         ifx->ipv6 = nic_ip_addr( addr );
00296         if( (ifx->ipv6_prefixlen = nic_addr_get_prefix( addr )) > 0 )
00297             ifx->set |= PUMP_INTFINFO_HAS_IPV6_PREFIX;
00298         ifx->set |= PUMP_INTFINFO_HAS_IPV6_IP;
00299     }else
00300     {
00301         ifx->ip = nic_ip_addr( addr );
00302         ifx->set |= PUMP_INTFINFO_HAS_IP;
00303         ifx->ipv6_prefixlen = nic_addr_get_prefix( addr );
00304         if ( ifx->ipv6_prefixlen )
00305         {
00306             ifx->network = ip_mask(&ifx->ip, ifx->ipv6_prefixlen);
00307             ifx->set |= PUMP_INTFINFO_HAS_NETWORK;
00308         }
00309     }
00310     if( !STAILQ_EMPTY(&(ifx->dhcp_nic->dhcpv6->dns_list)) )
00311     {
00312         IPaddr_list_node_t *n=0;
00313         STAILQ_FOREACH(n, &(ifx->dhcp_nic->dhcpv6->dns_list), link)
00314         {
00315             if( ifx->numDns >= MAX_DNS_SERVERS )
00316                 break;
00317             ifx->dnsServers[ ifx->numDns++ ] = nic_ip_addr( n->addr );
00318             ifx->set |= PUMP_NETINFO_HAS_DNS;
00319         }
00320     }
00321     if(  (ifx->set & PUMP_NETINFO_HAS_DNS)
00322        && ifx->dhcp_nic->dhcpv6->search_list 
00323       )
00324     {
00325         char *s=ifx->domain;
00326         asprintf
00327             (   &(ifx->domain),
00328                 "%s%s%s", 
00329                 s ? s : "",
00330                 s ? " " : "" ,
00331                 ifx->dhcp_nic->dhcpv6->search_list 
00332             );             
00333         if( s )
00334             free(s);
00335         ifx->set |= PUMP_NETINFO_HAS_DOMAIN;
00336     }
00337 }
00338 
00339 static void
00340 ifxDHCPv4( struct pumpNetIntf *ifx )
00341 {
00342     IPaddr_t addr = STAILQ_FIRST( &(ifx->dhcp_nic->dhcpv4->address_list) )->addr;
00343     if( ifx->set & PUMP_INTFINFO_HAS_IP )
00344     {
00345         ifx->ipv4 = nic_ip_addr( addr );
00346         ifx->set |= PUMP_INTFINFO_HAS_IPV4_IP;
00347     }else
00348     {
00349         ifx->ip = nic_ip_addr( addr );
00350         ifx->set |= PUMP_INTFINFO_HAS_IP;
00351         if ( nic_addr_get_prefix( addr ) )
00352         {
00353             ifx->network = ip_mask(&ifx->ip, nic_addr_get_prefix( addr ) );
00354             ifx->set |= PUMP_INTFINFO_HAS_NETWORK;
00355         }
00356     }
00357     if ( nic_addr_get_prefix( addr ) )
00358     {
00359         ifx->netmask = ip_v4_prefix_to_netmask( nic_addr_get_prefix( addr ) );
00360         ifx->set |= PUMP_INTFINFO_HAS_NETMASK;
00361 
00362         ip_addr_t broadcast = nic_addr_get_broadcast( addr );
00363         if( broadcast.sa_family )
00364         {
00365             ifx->broadcast = broadcast;
00366             ifx->set |= PUMP_INTFINFO_HAS_BROADCAST;
00367         }               
00368     }
00369     if(  ifx->dhcp_nic->dhcpv4 
00370        &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->route_list )) )
00371       )
00372     {
00373         IProute_list_node_t *n;
00374         STAILQ_FOREACH( n, &( ifx->dhcp_nic->dhcpv4->route_list ), link )
00375         {
00376             ip_addr_t dst   = nic_route_get_dst( n->route );
00377             ip_addr_t gw    = nic_route_get_gateway( n->route );
00378             uint8_t dst_len = nic_route_get_dst_len( n->route );
00379             if(  (dst.sa_family == 0)
00380                &&(dst_len == 0)
00381                &&(gw.sa_family == AF_INET)
00382               )
00383             {
00384                 ifx->gateway = gw;
00385                 ifx->set |= PUMP_NETINFO_HAS_GATEWAY;
00386                 break;
00387             }           
00388         }
00389     }
00390     if(   ifx->dhcp_nic->dhc4ctl
00391        && dhcpv4_mtu_option( ifx->dhcp_nic->dhc4ctl )
00392       )
00393     {
00394         ifx->mtu =  dhcpv4_mtu_option( ifx->dhcp_nic->dhc4ctl );
00395         ifx->set |= PUMP_INTFINFO_HAS_MTU;
00396     }
00397     if(  ifx->dhcp_nic->dhcpv4->lease.dhcp4_lease )
00398     {
00399         DHCPv4_lease *lease=ifx->dhcp_nic->dhcpv4->lease.dhcp4_lease;
00400         if ( lease->server_address.s_addr != 0 )
00401         {
00402             ifx->nextServer = ip_addr_in(&(lease->server_address));
00403             ifx->set |= PUMP_INTFINFO_HAS_NEXTSERVER;
00404         }
00405         if ( lease->filename )
00406         {
00407             ifx->bootFile = strdup( lease->filename );
00408             ifx->set |= PUMP_INTFINFO_HAS_BOOTFILE;
00409         }
00410     }
00411 
00412     if( !STAILQ_EMPTY(&(ifx->dhcp_nic->dhcpv4->dns_list)) )
00413     {
00414         IPaddr_list_node_t *n=0;
00415         STAILQ_FOREACH(n, &(ifx->dhcp_nic->dhcpv4->dns_list), link)
00416         {
00417             if( ifx->numDns >= MAX_DNS_SERVERS )
00418                 break;
00419             ifx->dnsServers[ ifx->numDns++ ] = nic_ip_addr( n->addr );
00420             ifx->set |= PUMP_NETINFO_HAS_DNS;
00421         }
00422     }
00423     if(  (ifx->set & PUMP_NETINFO_HAS_DNS)
00424        && ifx->dhcp_nic->dhcpv4->search_list 
00425       )
00426     {
00427         char *s=ifx->domain;
00428         asprintf
00429             (   &(ifx->domain),
00430                 "%s%s%s", 
00431                 s ? s : "",
00432                 s ? " " : "" ,
00433                 ifx->dhcp_nic->dhcpv4->search_list 
00434             );             
00435         if( s )
00436             free(s);
00437         ifx->set |= PUMP_NETINFO_HAS_DOMAIN;
00438     }    
00439     if( ifx->dhcp_nic->dhcpv4->host_name )
00440     {
00441         ifx->set |= PUMP_NETINFO_HAS_HOSTNAME;
00442         if(ifx->hostname)
00443             free(ifx->hostname);
00444         ifx->hostname = strdup( ifx->dhcp_nic->dhcpv4->host_name );
00445     }
00446 }
00447 
00448 char * pumpDhcpClassRun
00449 (   struct pumpNetIntf * ifx,
00450     char * hostname,
00451     char * vendor_class,
00452     DHCP_Preference dhcp_preference ,
00453     LIBDHCP_Capability dhcp_capability ,
00454     time_t timeout,
00455     void (*logger)(void*,int,char*,va_list),
00456     int  log_level
00457 )
00458 {
00459     char *disret;
00460     disret = pumpDisableInterface(ifx->device);
00461     if (disret != NULL)
00462         return disret;
00463 
00464     assert(!ifx->nh);
00465 
00466     if (!(ifx->nh = nic_open(NETLINK_ROUTE)))
00467         return pump_errors[OOM];
00468 
00469     if ( logger )
00470     {
00471         nic_set_va_logger(ifx->nh, (NIC_VA_Error_Handler_t)logger, &ifx);
00472         nic_set_loglevel(ifx->nh, log_level );
00473     }   
00474     ifx->dhcp_nic = 
00475         dhcp_nic
00476         (
00477             ifx->nh,
00478             dhcp_preference,
00479             ifx->device,
00480             dhcp_capability,
00481             timeout,
00482             (LIBDHCP_Error_Handler)logger,
00483             log_level,
00484             "-V", vendor_class,
00485             hostname ? "-H" : 0L, 
00486             hostname ? hostname : 0L,
00487             0L
00488         );
00489     if ( ifx->dhcp_nic )
00490     {  /* fill in the pumpNetIntf structure.
00491         * We'll just use the FIRST configured address as ifx->ip -
00492         * users should realize that a list of addresses may have
00493         * been configured.
00494         */      
00495         if ( ( ifx->dhcp_nic->dhcpv4 && ifx->dhcp_nic->dhcpv6 )
00496            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->address_list )) )
00497            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv6->address_list )) )
00498            )
00499         {
00500             if ( dhcp_preference & IPv6_PREFERENCE )
00501             {
00502                 ifxDHCPv6( ifx );
00503                 ifxDHCPv4( ifx );
00504             }else
00505             {
00506                 ifxDHCPv4( ifx );
00507                 ifxDHCPv6( ifx );
00508             }
00509         }else
00510         if(  ifx->dhcp_nic->dhcpv4 
00511            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv4->address_list )) )
00512           )
00513         {
00514             ifxDHCPv4( ifx );
00515         }else
00516         if(  ifx->dhcp_nic->dhcpv6 
00517            &&( !STAILQ_EMPTY( &( ifx->dhcp_nic->dhcpv6->address_list )) )
00518           )
00519         {
00520             ifxDHCPv6( ifx );
00521         }       
00522         ifx->nh = NULL;
00523     }else
00524     {
00525         nic_close(&ifx->nh);
00526         return pump_errors[DHCP_FAILED];
00527     }
00528     return NULL;
00529 }
00530 
00531 char * pumpDisableInterface(char * device) 
00532 {
00533     static char buf[512];
00534     struct ifreq req;
00535     int s, e;
00536 
00537     s = socket(AF_INET, SOCK_DGRAM, 0);
00538         
00539     memset(&req,0,sizeof(req));
00540 
00541     strcpy(req.ifr_name, device);
00542     if (ioctl(s, SIOCGIFFLAGS, &req)) {
00543         e = errno;
00544         snprintf(buf, 512,
00545                 "ioctl SIOCGIFFLAGS failed: %d %s\n", 
00546                 e, strerror(e) 
00547                );
00548         close(s);
00549         return  &(buf[0]);
00550     }
00551 
00552     req.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
00553     if (ioctl(s, SIOCSIFFLAGS, &req)) {
00554         e = errno;
00555         snprintf(buf, 512,
00556                 "ioctl SIOCSIFFLAGS failed: %d %s\n", 
00557                 e, strerror(e) 
00558                );
00559         close(s);
00560         return &(buf[0]);
00561     }
00562 
00563     close(s);
00564 
00565     return NULL;
00566 }
00567 
00568 /*
00569  * vim:ts=8:sw=4:sts=4:et
00570  */

Generated on Mon Aug 14 17:25:56 2006 for libdhcp by  doxygen 1.4.7