ipv4.c

Go to the documentation of this file.
00001 #include <string.h>
00002 #include <stdint.h>
00003 #include <stdlib.h>
00004 #include <stdio.h>
00005 #include <errno.h>
00006 #include <byteswap.h>
00007 #include <gpxe/list.h>
00008 #include <gpxe/in.h>
00009 #include <gpxe/arp.h>
00010 #include <gpxe/if_ether.h>
00011 #include <gpxe/iobuf.h>
00012 #include <gpxe/netdevice.h>
00013 #include <gpxe/ip.h>
00014 #include <gpxe/tcpip.h>
00015 #include <gpxe/dhcp.h>
00016 #include <gpxe/settings.h>
00017 
00018 /** @file
00019  *
00020  * IPv4 protocol
00021  *
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER );
00025 
00026 /* Unique IP datagram identification number */
00027 static uint16_t next_ident = 0;
00028 
00029 struct net_protocol ipv4_protocol;
00030 
00031 /** List of IPv4 miniroutes */
00032 struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
00033 
00034 /** List of fragment reassembly buffers */
00035 static LIST_HEAD ( frag_buffers );
00036 
00037 /**
00038  * Add IPv4 minirouting table entry
00039  *
00040  * @v netdev            Network device
00041  * @v address           IPv4 address
00042  * @v netmask           Subnet mask
00043  * @v gateway           Gateway address (if any)
00044  * @ret miniroute       Routing table entry, or NULL
00045  */
00046 static struct ipv4_miniroute * __malloc
00047 add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
00048                      struct in_addr netmask, struct in_addr gateway ) {
00049         struct ipv4_miniroute *miniroute;
00050 
00051         DBG ( "IPv4 add %s", inet_ntoa ( address ) );
00052         DBG ( "/%s ", inet_ntoa ( netmask ) );
00053         if ( gateway.s_addr )
00054                 DBG ( "gw %s ", inet_ntoa ( gateway ) );
00055         DBG ( "via %s\n", netdev->name );
00056 
00057         /* Allocate and populate miniroute structure */
00058         miniroute = malloc ( sizeof ( *miniroute ) );
00059         if ( ! miniroute ) {
00060                 DBG ( "IPv4 could not add miniroute\n" );
00061                 return NULL;
00062         }
00063 
00064         /* Record routing information */
00065         miniroute->netdev = netdev_get ( netdev );
00066         miniroute->address = address;
00067         miniroute->netmask = netmask;
00068         miniroute->gateway = gateway;
00069                 
00070         /* Add to end of list if we have a gateway, otherwise
00071          * to start of list.
00072          */
00073         if ( gateway.s_addr ) {
00074                 list_add_tail ( &miniroute->list, &ipv4_miniroutes );
00075         } else {
00076                 list_add ( &miniroute->list, &ipv4_miniroutes );
00077         }
00078 
00079         return miniroute;
00080 }
00081 
00082 /**
00083  * Delete IPv4 minirouting table entry
00084  *
00085  * @v miniroute         Routing table entry
00086  */
00087 static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
00088 
00089         DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
00090         DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
00091         if ( miniroute->gateway.s_addr )
00092                 DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
00093         DBG ( "via %s\n", miniroute->netdev->name );
00094 
00095         netdev_put ( miniroute->netdev );
00096         list_del ( &miniroute->list );
00097         free ( miniroute );
00098 }
00099 
00100 /**
00101  * Perform IPv4 routing
00102  *
00103  * @v dest              Final destination address
00104  * @ret dest            Next hop destination address
00105  * @ret miniroute       Routing table entry to use, or NULL if no route
00106  *
00107  * If the route requires use of a gateway, the next hop destination
00108  * address will be overwritten with the gateway address.
00109  */
00110 static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
00111         struct ipv4_miniroute *miniroute;
00112         int local;
00113         int has_gw;
00114 
00115         /* Never attempt to route the broadcast address */
00116         if ( dest->s_addr == INADDR_BROADCAST )
00117                 return NULL;
00118 
00119         /* Find first usable route in routing table */
00120         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
00121                 if ( ! netdev_is_open ( miniroute->netdev ) )
00122                         continue;
00123                 local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
00124                             & miniroute->netmask.s_addr ) == 0 );
00125                 has_gw = ( miniroute->gateway.s_addr );
00126                 if ( local || has_gw ) {
00127                         if ( ! local )
00128                                 *dest = miniroute->gateway;
00129                         return miniroute;
00130                 }
00131         }
00132 
00133         return NULL;
00134 }
00135 
00136 /**
00137  * Fragment reassembly counter timeout
00138  *
00139  * @v timer     Retry timer
00140  * @v over      If asserted, the timer is greater than @c MAX_TIMEOUT 
00141  */
00142 static void ipv4_frag_expired ( struct retry_timer *timer __unused,
00143                                 int over ) {
00144         if ( over ) {
00145                 DBG ( "Fragment reassembly timeout" );
00146                 /* Free the fragment buffer */
00147         }
00148 }
00149 
00150 /**
00151  * Free fragment buffer
00152  *
00153  * @v fragbug   Fragment buffer
00154  */
00155 static void free_fragbuf ( struct frag_buffer *fragbuf ) {
00156         free ( fragbuf );
00157 }
00158 
00159 /**
00160  * Fragment reassembler
00161  *
00162  * @v iobuf             I/O buffer, fragment of the datagram
00163  * @ret frag_iob        Reassembled packet, or NULL
00164  */
00165 static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
00166         struct iphdr *iphdr = iobuf->data;
00167         struct frag_buffer *fragbuf;
00168         
00169         /**
00170          * Check if the fragment belongs to any fragment series
00171          */
00172         list_for_each_entry ( fragbuf, &frag_buffers, list ) {
00173                 if ( fragbuf->ident == iphdr->ident &&
00174                      fragbuf->src.s_addr == iphdr->src.s_addr ) {
00175                         /**
00176                          * Check if the packet is the expected fragment
00177                          * 
00178                          * The offset of the new packet must be equal to the
00179                          * length of the data accumulated so far (the length of
00180                          * the reassembled I/O buffer
00181                          */
00182                         if ( iob_len ( fragbuf->frag_iob ) == 
00183                               ( iphdr->frags & IP_MASK_OFFSET ) ) {
00184                                 /**
00185                                  * Append the contents of the fragment to the
00186                                  * reassembled I/O buffer
00187                                  */
00188                                 iob_pull ( iobuf, sizeof ( *iphdr ) );
00189                                 memcpy ( iob_put ( fragbuf->frag_iob,
00190                                                         iob_len ( iobuf ) ),
00191                                          iobuf->data, iob_len ( iobuf ) );
00192                                 free_iob ( iobuf );
00193 
00194                                 /** Check if the fragment series is over */
00195                                 if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
00196                                         iobuf = fragbuf->frag_iob;
00197                                         free_fragbuf ( fragbuf );
00198                                         return iobuf;
00199                                 }
00200 
00201                         } else {
00202                                 /* Discard the fragment series */
00203                                 free_fragbuf ( fragbuf );
00204                                 free_iob ( iobuf );
00205                         }
00206                         return NULL;
00207                 }
00208         }
00209         
00210         /** Check if the fragment is the first in the fragment series */
00211         if ( iphdr->frags & IP_MASK_MOREFRAGS &&
00212                         ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
00213         
00214                 /** Create a new fragment buffer */
00215                 fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
00216                 fragbuf->ident = iphdr->ident;
00217                 fragbuf->src = iphdr->src;
00218 
00219                 /* Set up the reassembly I/O buffer */
00220                 fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE );
00221                 iob_pull ( iobuf, sizeof ( *iphdr ) );
00222                 memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ),
00223                          iobuf->data, iob_len ( iobuf ) );
00224                 free_iob ( iobuf );
00225 
00226                 /* Set the reassembly timer */
00227                 fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT;
00228                 fragbuf->frag_timer.expired = ipv4_frag_expired;
00229                 start_timer ( &fragbuf->frag_timer );
00230 
00231                 /* Add the fragment buffer to the list of fragment buffers */
00232                 list_add ( &fragbuf->list, &frag_buffers );
00233         }
00234         
00235         return NULL;
00236 }
00237 
00238 /**
00239  * Add IPv4 pseudo-header checksum to existing checksum
00240  *
00241  * @v iobuf             I/O buffer
00242  * @v csum              Existing checksum
00243  * @ret csum            Updated checksum
00244  */
00245 static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
00246         struct ipv4_pseudo_header pshdr;
00247         struct iphdr *iphdr = iobuf->data;
00248         size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
00249 
00250         /* Build pseudo-header */
00251         pshdr.src = iphdr->src;
00252         pshdr.dest = iphdr->dest;
00253         pshdr.zero_padding = 0x00;
00254         pshdr.protocol = iphdr->protocol;
00255         pshdr.len = htons ( iob_len ( iobuf ) - hdrlen );
00256 
00257         /* Update the checksum value */
00258         return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
00259 }
00260 
00261 /**
00262  * Determine link-layer address
00263  *
00264  * @v dest              IPv4 destination address
00265  * @v src               IPv4 source address
00266  * @v netdev            Network device
00267  * @v ll_dest           Link-layer destination address buffer
00268  * @ret rc              Return status code
00269  */
00270 static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
00271                           struct net_device *netdev, uint8_t *ll_dest ) {
00272         struct ll_protocol *ll_protocol = netdev->ll_protocol;
00273 
00274         if ( dest.s_addr == INADDR_BROADCAST ) {
00275                 /* Broadcast address */
00276                 memcpy ( ll_dest, netdev->ll_broadcast,
00277                          ll_protocol->ll_addr_len );
00278                 return 0;
00279         } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
00280                 return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
00281         } else {
00282                 /* Unicast address: resolve via ARP */
00283                 return arp_resolve ( netdev, &ipv4_protocol, &dest,
00284                                      &src, ll_dest );
00285         }
00286 }
00287 
00288 /**
00289  * Transmit IP packet
00290  *
00291  * @v iobuf             I/O buffer
00292  * @v tcpip             Transport-layer protocol
00293  * @v st_src            Source network-layer address
00294  * @v st_dest           Destination network-layer address
00295  * @v netdev            Network device to use if no route found, or NULL
00296  * @v trans_csum        Transport-layer checksum to complete, or NULL
00297  * @ret rc              Status
00298  *
00299  * This function expects a transport-layer segment and prepends the IP header
00300  */
00301 static int ipv4_tx ( struct io_buffer *iobuf,
00302                      struct tcpip_protocol *tcpip_protocol,
00303                      struct sockaddr_tcpip *st_src,
00304                      struct sockaddr_tcpip *st_dest,
00305                      struct net_device *netdev,
00306                      uint16_t *trans_csum ) {
00307         struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
00308         struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
00309         struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
00310         struct ipv4_miniroute *miniroute;
00311         struct in_addr next_hop;
00312         uint8_t ll_dest[MAX_LL_ADDR_LEN];
00313         int rc;
00314 
00315         /* Fill up the IP header, except source address */
00316         memset ( iphdr, 0, sizeof ( *iphdr ) );
00317         iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
00318         iphdr->service = IP_TOS;
00319         iphdr->len = htons ( iob_len ( iobuf ) );       
00320         iphdr->ident = htons ( ++next_ident );
00321         iphdr->ttl = IP_TTL;
00322         iphdr->protocol = tcpip_protocol->tcpip_proto;
00323         iphdr->dest = sin_dest->sin_addr;
00324 
00325         /* Use routing table to identify next hop and transmitting netdev */
00326         next_hop = iphdr->dest;
00327         if ( sin_src )
00328                 iphdr->src = sin_src->sin_addr;
00329         if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
00330              ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
00331              ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
00332                 iphdr->src = miniroute->address;
00333                 netdev = miniroute->netdev;
00334         }
00335         if ( ! netdev ) {
00336                 DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
00337                 rc = -ENETUNREACH;
00338                 goto err;
00339         }
00340 
00341         /* Determine link-layer destination address */
00342         if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
00343                                    ll_dest ) ) != 0 ) {
00344                 DBG ( "IPv4 has no link-layer address for %s: %s\n",
00345                       inet_ntoa ( next_hop ), strerror ( rc ) );
00346                 goto err;
00347         }
00348 
00349         /* Fix up checksums */
00350         if ( trans_csum )
00351                 *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
00352         iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
00353 
00354         /* Print IP4 header for debugging */
00355         DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
00356         DBG ( "%s len %d proto %d id %04x csum %04x\n",
00357               inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
00358               ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
00359 
00360         /* Hand off to link layer */
00361         if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest ) ) != 0 ) {
00362                 DBG ( "IPv4 could not transmit packet via %s: %s\n",
00363                       netdev->name, strerror ( rc ) );
00364                 return rc;
00365         }
00366 
00367         return 0;
00368 
00369  err:
00370         free_iob ( iobuf );
00371         return rc;
00372 }
00373 
00374 /**
00375  * Process incoming packets
00376  *
00377  * @v iobuf     I/O buffer
00378  * @v netdev    Network device
00379  * @v ll_source Link-layer destination source
00380  *
00381  * This function expects an IP4 network datagram. It processes the headers 
00382  * and sends it to the transport layer.
00383  */
00384 static int ipv4_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
00385                      const void *ll_source __unused ) {
00386         struct iphdr *iphdr = iobuf->data;
00387         size_t hdrlen;
00388         size_t len;
00389         union {
00390                 struct sockaddr_in sin;
00391                 struct sockaddr_tcpip st;
00392         } src, dest;
00393         uint16_t csum;
00394         uint16_t pshdr_csum;
00395         int rc;
00396 
00397         /* Sanity check the IPv4 header */
00398         if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
00399                 DBG ( "IPv4 packet too short at %zd bytes (min %zd bytes)\n",
00400                       iob_len ( iobuf ), sizeof ( *iphdr ) );
00401                 goto err;
00402         }
00403         if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
00404                 DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
00405                 goto err;
00406         }
00407         hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
00408         if ( hdrlen < sizeof ( *iphdr ) ) {
00409                 DBG ( "IPv4 header too short at %zd bytes (min %zd bytes)\n",
00410                       hdrlen, sizeof ( *iphdr ) );
00411                 goto err;
00412         }
00413         if ( hdrlen > iob_len ( iobuf ) ) {
00414                 DBG ( "IPv4 header too long at %zd bytes "
00415                       "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
00416                 goto err;
00417         }
00418         if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
00419                 DBG ( "IPv4 checksum incorrect (is %04x including checksum "
00420                       "field, should be 0000)\n", csum );
00421                 goto err;
00422         }
00423         len = ntohs ( iphdr->len );
00424         if ( len < hdrlen ) {
00425                 DBG ( "IPv4 length too short at %zd bytes "
00426                       "(header is %zd bytes)\n", len, hdrlen );
00427                 goto err;
00428         }
00429         if ( len > iob_len ( iobuf ) ) {
00430                 DBG ( "IPv4 length too long at %zd bytes "
00431                       "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
00432                 goto err;
00433         }
00434 
00435         /* Print IPv4 header for debugging */
00436         DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
00437         DBG ( "%s len %d proto %d id %04x csum %04x\n",
00438               inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
00439               ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
00440 
00441         /* Truncate packet to correct length, calculate pseudo-header
00442          * checksum and then strip off the IPv4 header.
00443          */
00444         iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
00445         pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
00446         iob_pull ( iobuf, hdrlen );
00447 
00448         /* Fragment reassembly */
00449         if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
00450              ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
00451                 /* Pass the fragment to ipv4_reassemble() which either
00452                  * returns a fully reassembled I/O buffer or NULL.
00453                  */
00454                 iobuf = ipv4_reassemble ( iobuf );
00455                 if ( ! iobuf )
00456                         return 0;
00457         }
00458 
00459         /* Construct socket addresses and hand off to transport layer */
00460         memset ( &src, 0, sizeof ( src ) );
00461         src.sin.sin_family = AF_INET;
00462         src.sin.sin_addr = iphdr->src;
00463         memset ( &dest, 0, sizeof ( dest ) );
00464         dest.sin.sin_family = AF_INET;
00465         dest.sin.sin_addr = iphdr->dest;
00466         if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st,
00467                                &dest.st, pshdr_csum ) ) != 0 ) {
00468                 DBG ( "IPv4 received packet rejected by stack: %s\n",
00469                       strerror ( rc ) );
00470                 return rc;
00471         }
00472 
00473         return 0;
00474 
00475  err:
00476         free_iob ( iobuf );
00477         return -EINVAL;
00478 }
00479 
00480 /** 
00481  * Check existence of IPv4 address for ARP
00482  *
00483  * @v netdev            Network device
00484  * @v net_addr          Network-layer address
00485  * @ret rc              Return status code
00486  */
00487 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
00488         const struct in_addr *address = net_addr;
00489         struct ipv4_miniroute *miniroute;
00490 
00491         list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
00492                 if ( ( miniroute->netdev == netdev ) &&
00493                      ( miniroute->address.s_addr == address->s_addr ) ) {
00494                         /* Found matching address */
00495                         return 0;
00496                 }
00497         }
00498         return -ENOENT;
00499 }
00500 
00501 /**
00502  * Convert IPv4 address to dotted-quad notation
00503  *
00504  * @v in        IP address
00505  * @ret string  IP address in dotted-quad notation
00506  */
00507 char * inet_ntoa ( struct in_addr in ) {
00508         static char buf[16]; /* "xxx.xxx.xxx.xxx" */
00509         uint8_t *bytes = ( uint8_t * ) &in;
00510         
00511         sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
00512         return buf;
00513 }
00514 
00515 /**
00516  * Transcribe IP address
00517  *
00518  * @v net_addr  IP address
00519  * @ret string  IP address in dotted-quad notation
00520  *
00521  */
00522 static const char * ipv4_ntoa ( const void *net_addr ) {
00523         return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
00524 }
00525 
00526 /** IPv4 protocol */
00527 struct net_protocol ipv4_protocol __net_protocol = {
00528         .name = "IP",
00529         .net_proto = htons ( ETH_P_IP ),
00530         .net_addr_len = sizeof ( struct in_addr ),
00531         .rx = ipv4_rx,
00532         .ntoa = ipv4_ntoa,
00533 };
00534 
00535 /** IPv4 TCPIP net protocol */
00536 struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
00537         .name = "IPv4",
00538         .sa_family = AF_INET,
00539         .tx = ipv4_tx,
00540 };
00541 
00542 /** IPv4 ARP protocol */
00543 struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
00544         .net_protocol = &ipv4_protocol,
00545         .check = ipv4_arp_check,
00546 };
00547 
00548 /******************************************************************************
00549  *
00550  * Settings
00551  *
00552  ******************************************************************************
00553  */
00554 
00555 /** IPv4 address setting */
00556 struct setting ip_setting __setting = {
00557         .name = "ip",
00558         .description = "IPv4 address",
00559         .tag = DHCP_EB_YIADDR,
00560         .type = &setting_type_ipv4,
00561 };
00562 
00563 /** IPv4 subnet mask setting */
00564 struct setting netmask_setting __setting = {
00565         .name = "netmask",
00566         .description = "IPv4 subnet mask",
00567         .tag = DHCP_SUBNET_MASK,
00568         .type = &setting_type_ipv4,
00569 };
00570 
00571 /** Default gateway setting */
00572 struct setting gateway_setting __setting = {
00573         .name = "gateway",
00574         .description = "Default gateway",
00575         .tag = DHCP_ROUTERS,
00576         .type = &setting_type_ipv4,
00577 };
00578 
00579 /**
00580  * Create IPv4 routing table based on configured settings
00581  *
00582  * @ret rc              Return status code
00583  */
00584 static int ipv4_create_routes ( void ) {
00585         struct ipv4_miniroute *miniroute;
00586         struct ipv4_miniroute *tmp;
00587         struct net_device *netdev;
00588         struct settings *settings;
00589         struct in_addr address = { 0 };
00590         struct in_addr netmask = { 0 };
00591         struct in_addr gateway = { 0 };
00592 
00593         /* Delete all existing routes */
00594         list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
00595                 del_ipv4_miniroute ( miniroute );
00596 
00597         /* Create a route for each configured network device */
00598         for_each_netdev ( netdev ) {
00599                 settings = netdev_settings ( netdev );
00600                 /* Get IPv4 address */
00601                 address.s_addr = 0;
00602                 fetch_ipv4_setting ( settings, &ip_setting, &address );
00603                 if ( ! address.s_addr )
00604                         continue;
00605                 /* Get subnet mask */
00606                 fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
00607                 /* Calculate default netmask, if necessary */
00608                 if ( ! netmask.s_addr ) {
00609                         if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
00610                                 netmask.s_addr = htonl ( IN_CLASSA_NET );
00611                         } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
00612                                 netmask.s_addr = htonl ( IN_CLASSB_NET );
00613                         } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
00614                                 netmask.s_addr = htonl ( IN_CLASSC_NET );
00615                         }
00616                 }
00617                 /* Get default gateway, if present */
00618                 fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
00619                 /* Configure route */
00620                 miniroute = add_ipv4_miniroute ( netdev, address,
00621                                                  netmask, gateway );
00622                 if ( ! miniroute )
00623                         return -ENOMEM;
00624         }
00625 
00626         return 0;
00627 }
00628 
00629 /** IPv4 settings applicator */
00630 struct settings_applicator ipv4_settings_applicator __settings_applicator = {
00631         .apply = ipv4_create_routes,
00632 };
00633 
00634 /* Drag in ICMP */
00635 REQUIRE_OBJECT ( icmp );

Generated on Tue Apr 6 20:01:10 2010 for gPXE by  doxygen 1.5.7.1