Annotation of qemu/roms/ipxe/src/net/ipv4.c, revision 1.1

1.1     ! root        1: #include <string.h>
        !             2: #include <stdint.h>
        !             3: #include <stdlib.h>
        !             4: #include <stdio.h>
        !             5: #include <errno.h>
        !             6: #include <byteswap.h>
        !             7: #include <ipxe/list.h>
        !             8: #include <ipxe/in.h>
        !             9: #include <ipxe/arp.h>
        !            10: #include <ipxe/if_ether.h>
        !            11: #include <ipxe/iobuf.h>
        !            12: #include <ipxe/netdevice.h>
        !            13: #include <ipxe/ip.h>
        !            14: #include <ipxe/tcpip.h>
        !            15: #include <ipxe/dhcp.h>
        !            16: #include <ipxe/settings.h>
        !            17: 
        !            18: /** @file
        !            19:  *
        !            20:  * IPv4 protocol
        !            21:  *
        !            22:  */
        !            23: 
        !            24: FILE_LICENCE ( GPL2_OR_LATER );
        !            25: 
        !            26: /* Unique IP datagram identification number */
        !            27: static uint16_t next_ident = 0;
        !            28: 
        !            29: /** List of IPv4 miniroutes */
        !            30: struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
        !            31: 
        !            32: /** List of fragment reassembly buffers */
        !            33: static LIST_HEAD ( frag_buffers );
        !            34: 
        !            35: /**
        !            36:  * Add IPv4 minirouting table entry
        !            37:  *
        !            38:  * @v netdev           Network device
        !            39:  * @v address          IPv4 address
        !            40:  * @v netmask          Subnet mask
        !            41:  * @v gateway          Gateway address (if any)
        !            42:  * @ret miniroute      Routing table entry, or NULL
        !            43:  */
        !            44: static struct ipv4_miniroute * __malloc
        !            45: add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
        !            46:                     struct in_addr netmask, struct in_addr gateway ) {
        !            47:        struct ipv4_miniroute *miniroute;
        !            48: 
        !            49:        DBG ( "IPv4 add %s", inet_ntoa ( address ) );
        !            50:        DBG ( "/%s ", inet_ntoa ( netmask ) );
        !            51:        if ( gateway.s_addr )
        !            52:                DBG ( "gw %s ", inet_ntoa ( gateway ) );
        !            53:        DBG ( "via %s\n", netdev->name );
        !            54: 
        !            55:        /* Allocate and populate miniroute structure */
        !            56:        miniroute = malloc ( sizeof ( *miniroute ) );
        !            57:        if ( ! miniroute ) {
        !            58:                DBG ( "IPv4 could not add miniroute\n" );
        !            59:                return NULL;
        !            60:        }
        !            61: 
        !            62:        /* Record routing information */
        !            63:        miniroute->netdev = netdev_get ( netdev );
        !            64:        miniroute->address = address;
        !            65:        miniroute->netmask = netmask;
        !            66:        miniroute->gateway = gateway;
        !            67:                
        !            68:        /* Add to end of list if we have a gateway, otherwise
        !            69:         * to start of list.
        !            70:         */
        !            71:        if ( gateway.s_addr ) {
        !            72:                list_add_tail ( &miniroute->list, &ipv4_miniroutes );
        !            73:        } else {
        !            74:                list_add ( &miniroute->list, &ipv4_miniroutes );
        !            75:        }
        !            76: 
        !            77:        return miniroute;
        !            78: }
        !            79: 
        !            80: /**
        !            81:  * Delete IPv4 minirouting table entry
        !            82:  *
        !            83:  * @v miniroute                Routing table entry
        !            84:  */
        !            85: static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
        !            86: 
        !            87:        DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
        !            88:        DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
        !            89:        if ( miniroute->gateway.s_addr )
        !            90:                DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
        !            91:        DBG ( "via %s\n", miniroute->netdev->name );
        !            92: 
        !            93:        netdev_put ( miniroute->netdev );
        !            94:        list_del ( &miniroute->list );
        !            95:        free ( miniroute );
        !            96: }
        !            97: 
        !            98: /**
        !            99:  * Perform IPv4 routing
        !           100:  *
        !           101:  * @v dest             Final destination address
        !           102:  * @ret dest           Next hop destination address
        !           103:  * @ret miniroute      Routing table entry to use, or NULL if no route
        !           104:  *
        !           105:  * If the route requires use of a gateway, the next hop destination
        !           106:  * address will be overwritten with the gateway address.
        !           107:  */
        !           108: static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
        !           109:        struct ipv4_miniroute *miniroute;
        !           110:        int local;
        !           111:        int has_gw;
        !           112: 
        !           113:        /* Never attempt to route the broadcast address */
        !           114:        if ( dest->s_addr == INADDR_BROADCAST )
        !           115:                return NULL;
        !           116: 
        !           117:        /* Find first usable route in routing table */
        !           118:        list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
        !           119:                if ( ! netdev_is_open ( miniroute->netdev ) )
        !           120:                        continue;
        !           121:                local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
        !           122:                            & miniroute->netmask.s_addr ) == 0 );
        !           123:                has_gw = ( miniroute->gateway.s_addr );
        !           124:                if ( local || has_gw ) {
        !           125:                        if ( ! local )
        !           126:                                *dest = miniroute->gateway;
        !           127:                        return miniroute;
        !           128:                }
        !           129:        }
        !           130: 
        !           131:        return NULL;
        !           132: }
        !           133: 
        !           134: /**
        !           135:  * Fragment reassembly counter timeout
        !           136:  *
        !           137:  * @v timer    Retry timer
        !           138:  * @v over     If asserted, the timer is greater than @c MAX_TIMEOUT 
        !           139:  */
        !           140: static void ipv4_frag_expired ( struct retry_timer *timer __unused,
        !           141:                                int over ) {
        !           142:        if ( over ) {
        !           143:                DBG ( "Fragment reassembly timeout" );
        !           144:                /* Free the fragment buffer */
        !           145:        }
        !           146: }
        !           147: 
        !           148: /**
        !           149:  * Free fragment buffer
        !           150:  *
        !           151:  * @v fragbug  Fragment buffer
        !           152:  */
        !           153: static void free_fragbuf ( struct frag_buffer *fragbuf ) {
        !           154:        free ( fragbuf );
        !           155: }
        !           156: 
        !           157: /**
        !           158:  * Fragment reassembler
        !           159:  *
        !           160:  * @v iobuf            I/O buffer, fragment of the datagram
        !           161:  * @ret frag_iob       Reassembled packet, or NULL
        !           162:  */
        !           163: static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
        !           164:        struct iphdr *iphdr = iobuf->data;
        !           165:        struct frag_buffer *fragbuf;
        !           166:        
        !           167:        /**
        !           168:         * Check if the fragment belongs to any fragment series
        !           169:         */
        !           170:        list_for_each_entry ( fragbuf, &frag_buffers, list ) {
        !           171:                if ( fragbuf->ident == iphdr->ident &&
        !           172:                     fragbuf->src.s_addr == iphdr->src.s_addr ) {
        !           173:                        /**
        !           174:                         * Check if the packet is the expected fragment
        !           175:                         * 
        !           176:                         * The offset of the new packet must be equal to the
        !           177:                         * length of the data accumulated so far (the length of
        !           178:                         * the reassembled I/O buffer
        !           179:                         */
        !           180:                        if ( iob_len ( fragbuf->frag_iob ) == 
        !           181:                              ( iphdr->frags & IP_MASK_OFFSET ) ) {
        !           182:                                /**
        !           183:                                 * Append the contents of the fragment to the
        !           184:                                 * reassembled I/O buffer
        !           185:                                 */
        !           186:                                iob_pull ( iobuf, sizeof ( *iphdr ) );
        !           187:                                memcpy ( iob_put ( fragbuf->frag_iob,
        !           188:                                                        iob_len ( iobuf ) ),
        !           189:                                         iobuf->data, iob_len ( iobuf ) );
        !           190:                                free_iob ( iobuf );
        !           191: 
        !           192:                                /** Check if the fragment series is over */
        !           193:                                if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
        !           194:                                        iobuf = fragbuf->frag_iob;
        !           195:                                        free_fragbuf ( fragbuf );
        !           196:                                        return iobuf;
        !           197:                                }
        !           198: 
        !           199:                        } else {
        !           200:                                /* Discard the fragment series */
        !           201:                                free_fragbuf ( fragbuf );
        !           202:                                free_iob ( iobuf );
        !           203:                        }
        !           204:                        return NULL;
        !           205:                }
        !           206:        }
        !           207:        
        !           208:        /** Check if the fragment is the first in the fragment series */
        !           209:        if ( iphdr->frags & IP_MASK_MOREFRAGS &&
        !           210:                        ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
        !           211:        
        !           212:                /** Create a new fragment buffer */
        !           213:                fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
        !           214:                fragbuf->ident = iphdr->ident;
        !           215:                fragbuf->src = iphdr->src;
        !           216: 
        !           217:                /* Set up the reassembly I/O buffer */
        !           218:                fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE );
        !           219:                iob_pull ( iobuf, sizeof ( *iphdr ) );
        !           220:                memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ),
        !           221:                         iobuf->data, iob_len ( iobuf ) );
        !           222:                free_iob ( iobuf );
        !           223: 
        !           224:                /* Set the reassembly timer */
        !           225:                timer_init ( &fragbuf->frag_timer, ipv4_frag_expired, NULL );
        !           226:                start_timer_fixed ( &fragbuf->frag_timer, IP_FRAG_TIMEOUT );
        !           227: 
        !           228:                /* Add the fragment buffer to the list of fragment buffers */
        !           229:                list_add ( &fragbuf->list, &frag_buffers );
        !           230:        }
        !           231:        
        !           232:        return NULL;
        !           233: }
        !           234: 
        !           235: /**
        !           236:  * Add IPv4 pseudo-header checksum to existing checksum
        !           237:  *
        !           238:  * @v iobuf            I/O buffer
        !           239:  * @v csum             Existing checksum
        !           240:  * @ret csum           Updated checksum
        !           241:  */
        !           242: static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
        !           243:        struct ipv4_pseudo_header pshdr;
        !           244:        struct iphdr *iphdr = iobuf->data;
        !           245:        size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
        !           246: 
        !           247:        /* Build pseudo-header */
        !           248:        pshdr.src = iphdr->src;
        !           249:        pshdr.dest = iphdr->dest;
        !           250:        pshdr.zero_padding = 0x00;
        !           251:        pshdr.protocol = iphdr->protocol;
        !           252:        pshdr.len = htons ( iob_len ( iobuf ) - hdrlen );
        !           253: 
        !           254:        /* Update the checksum value */
        !           255:        return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
        !           256: }
        !           257: 
        !           258: /**
        !           259:  * Determine link-layer address
        !           260:  *
        !           261:  * @v dest             IPv4 destination address
        !           262:  * @v src              IPv4 source address
        !           263:  * @v netdev           Network device
        !           264:  * @v ll_dest          Link-layer destination address buffer
        !           265:  * @ret rc             Return status code
        !           266:  */
        !           267: static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
        !           268:                          struct net_device *netdev, uint8_t *ll_dest ) {
        !           269:        struct ll_protocol *ll_protocol = netdev->ll_protocol;
        !           270: 
        !           271:        if ( dest.s_addr == INADDR_BROADCAST ) {
        !           272:                /* Broadcast address */
        !           273:                memcpy ( ll_dest, netdev->ll_broadcast,
        !           274:                         ll_protocol->ll_addr_len );
        !           275:                return 0;
        !           276:        } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
        !           277:                return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
        !           278:        } else {
        !           279:                /* Unicast address: resolve via ARP */
        !           280:                return arp_resolve ( netdev, &ipv4_protocol, &dest,
        !           281:                                     &src, ll_dest );
        !           282:        }
        !           283: }
        !           284: 
        !           285: /**
        !           286:  * Transmit IP packet
        !           287:  *
        !           288:  * @v iobuf            I/O buffer
        !           289:  * @v tcpip            Transport-layer protocol
        !           290:  * @v st_src           Source network-layer address
        !           291:  * @v st_dest          Destination network-layer address
        !           292:  * @v netdev           Network device to use if no route found, or NULL
        !           293:  * @v trans_csum       Transport-layer checksum to complete, or NULL
        !           294:  * @ret rc             Status
        !           295:  *
        !           296:  * This function expects a transport-layer segment and prepends the IP header
        !           297:  */
        !           298: static int ipv4_tx ( struct io_buffer *iobuf,
        !           299:                     struct tcpip_protocol *tcpip_protocol,
        !           300:                     struct sockaddr_tcpip *st_src,
        !           301:                     struct sockaddr_tcpip *st_dest,
        !           302:                     struct net_device *netdev,
        !           303:                     uint16_t *trans_csum ) {
        !           304:        struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
        !           305:        struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
        !           306:        struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
        !           307:        struct ipv4_miniroute *miniroute;
        !           308:        struct in_addr next_hop;
        !           309:        uint8_t ll_dest[MAX_LL_ADDR_LEN];
        !           310:        int rc;
        !           311: 
        !           312:        /* Fill up the IP header, except source address */
        !           313:        memset ( iphdr, 0, sizeof ( *iphdr ) );
        !           314:        iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
        !           315:        iphdr->service = IP_TOS;
        !           316:        iphdr->len = htons ( iob_len ( iobuf ) );       
        !           317:        iphdr->ident = htons ( ++next_ident );
        !           318:        iphdr->ttl = IP_TTL;
        !           319:        iphdr->protocol = tcpip_protocol->tcpip_proto;
        !           320:        iphdr->dest = sin_dest->sin_addr;
        !           321: 
        !           322:        /* Use routing table to identify next hop and transmitting netdev */
        !           323:        next_hop = iphdr->dest;
        !           324:        if ( sin_src )
        !           325:                iphdr->src = sin_src->sin_addr;
        !           326:        if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
        !           327:             ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
        !           328:             ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
        !           329:                iphdr->src = miniroute->address;
        !           330:                netdev = miniroute->netdev;
        !           331:        }
        !           332:        if ( ! netdev ) {
        !           333:                DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
        !           334:                rc = -ENETUNREACH;
        !           335:                goto err;
        !           336:        }
        !           337: 
        !           338:        /* Determine link-layer destination address */
        !           339:        if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
        !           340:                                   ll_dest ) ) != 0 ) {
        !           341:                DBG ( "IPv4 has no link-layer address for %s: %s\n",
        !           342:                      inet_ntoa ( next_hop ), strerror ( rc ) );
        !           343:                goto err;
        !           344:        }
        !           345: 
        !           346:        /* Fix up checksums */
        !           347:        if ( trans_csum )
        !           348:                *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
        !           349:        iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
        !           350: 
        !           351:        /* Print IP4 header for debugging */
        !           352:        DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
        !           353:        DBG ( "%s len %d proto %d id %04x csum %04x\n",
        !           354:              inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
        !           355:              ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
        !           356: 
        !           357:        /* Hand off to link layer */
        !           358:        if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
        !           359:                             netdev->ll_addr ) ) != 0 ) {
        !           360:                DBG ( "IPv4 could not transmit packet via %s: %s\n",
        !           361:                      netdev->name, strerror ( rc ) );
        !           362:                return rc;
        !           363:        }
        !           364: 
        !           365:        return 0;
        !           366: 
        !           367:  err:
        !           368:        free_iob ( iobuf );
        !           369:        return rc;
        !           370: }
        !           371: 
        !           372: /**
        !           373:  * Process incoming packets
        !           374:  *
        !           375:  * @v iobuf    I/O buffer
        !           376:  * @v netdev   Network device
        !           377:  * @v ll_dest  Link-layer destination address
        !           378:  * @v ll_source        Link-layer destination source
        !           379:  *
        !           380:  * This function expects an IP4 network datagram. It processes the headers 
        !           381:  * and sends it to the transport layer.
        !           382:  */
        !           383: static int ipv4_rx ( struct io_buffer *iobuf,
        !           384:                     struct net_device *netdev __unused,
        !           385:                     const void *ll_dest __unused,
        !           386:                     const void *ll_source __unused ) {
        !           387:        struct iphdr *iphdr = iobuf->data;
        !           388:        size_t hdrlen;
        !           389:        size_t len;
        !           390:        union {
        !           391:                struct sockaddr_in sin;
        !           392:                struct sockaddr_tcpip st;
        !           393:        } src, dest;
        !           394:        uint16_t csum;
        !           395:        uint16_t pshdr_csum;
        !           396:        int rc;
        !           397: 
        !           398:        /* Sanity check the IPv4 header */
        !           399:        if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
        !           400:                DBG ( "IPv4 packet too short at %zd bytes (min %zd bytes)\n",
        !           401:                      iob_len ( iobuf ), sizeof ( *iphdr ) );
        !           402:                goto err;
        !           403:        }
        !           404:        if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
        !           405:                DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
        !           406:                goto err;
        !           407:        }
        !           408:        hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
        !           409:        if ( hdrlen < sizeof ( *iphdr ) ) {
        !           410:                DBG ( "IPv4 header too short at %zd bytes (min %zd bytes)\n",
        !           411:                      hdrlen, sizeof ( *iphdr ) );
        !           412:                goto err;
        !           413:        }
        !           414:        if ( hdrlen > iob_len ( iobuf ) ) {
        !           415:                DBG ( "IPv4 header too long at %zd bytes "
        !           416:                      "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
        !           417:                goto err;
        !           418:        }
        !           419:        if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
        !           420:                DBG ( "IPv4 checksum incorrect (is %04x including checksum "
        !           421:                      "field, should be 0000)\n", csum );
        !           422:                goto err;
        !           423:        }
        !           424:        len = ntohs ( iphdr->len );
        !           425:        if ( len < hdrlen ) {
        !           426:                DBG ( "IPv4 length too short at %zd bytes "
        !           427:                      "(header is %zd bytes)\n", len, hdrlen );
        !           428:                goto err;
        !           429:        }
        !           430:        if ( len > iob_len ( iobuf ) ) {
        !           431:                DBG ( "IPv4 length too long at %zd bytes "
        !           432:                      "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
        !           433:                goto err;
        !           434:        }
        !           435: 
        !           436:        /* Print IPv4 header for debugging */
        !           437:        DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
        !           438:        DBG ( "%s len %d proto %d id %04x csum %04x\n",
        !           439:              inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
        !           440:              ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
        !           441: 
        !           442:        /* Truncate packet to correct length, calculate pseudo-header
        !           443:         * checksum and then strip off the IPv4 header.
        !           444:         */
        !           445:        iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
        !           446:        pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
        !           447:        iob_pull ( iobuf, hdrlen );
        !           448: 
        !           449:        /* Fragment reassembly */
        !           450:        if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
        !           451:             ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
        !           452:                /* Pass the fragment to ipv4_reassemble() which either
        !           453:                 * returns a fully reassembled I/O buffer or NULL.
        !           454:                 */
        !           455:                iobuf = ipv4_reassemble ( iobuf );
        !           456:                if ( ! iobuf )
        !           457:                        return 0;
        !           458:        }
        !           459: 
        !           460:        /* Construct socket addresses and hand off to transport layer */
        !           461:        memset ( &src, 0, sizeof ( src ) );
        !           462:        src.sin.sin_family = AF_INET;
        !           463:        src.sin.sin_addr = iphdr->src;
        !           464:        memset ( &dest, 0, sizeof ( dest ) );
        !           465:        dest.sin.sin_family = AF_INET;
        !           466:        dest.sin.sin_addr = iphdr->dest;
        !           467:        if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st,
        !           468:                               &dest.st, pshdr_csum ) ) != 0 ) {
        !           469:                DBG ( "IPv4 received packet rejected by stack: %s\n",
        !           470:                      strerror ( rc ) );
        !           471:                return rc;
        !           472:        }
        !           473: 
        !           474:        return 0;
        !           475: 
        !           476:  err:
        !           477:        free_iob ( iobuf );
        !           478:        return -EINVAL;
        !           479: }
        !           480: 
        !           481: /** 
        !           482:  * Check existence of IPv4 address for ARP
        !           483:  *
        !           484:  * @v netdev           Network device
        !           485:  * @v net_addr         Network-layer address
        !           486:  * @ret rc             Return status code
        !           487:  */
        !           488: static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
        !           489:        const struct in_addr *address = net_addr;
        !           490:        struct ipv4_miniroute *miniroute;
        !           491: 
        !           492:        list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
        !           493:                if ( ( miniroute->netdev == netdev ) &&
        !           494:                     ( miniroute->address.s_addr == address->s_addr ) ) {
        !           495:                        /* Found matching address */
        !           496:                        return 0;
        !           497:                }
        !           498:        }
        !           499:        return -ENOENT;
        !           500: }
        !           501: 
        !           502: /**
        !           503:  * Convert IPv4 address to dotted-quad notation
        !           504:  *
        !           505:  * @v in       IP address
        !           506:  * @ret string IP address in dotted-quad notation
        !           507:  */
        !           508: char * inet_ntoa ( struct in_addr in ) {
        !           509:        static char buf[16]; /* "xxx.xxx.xxx.xxx" */
        !           510:        uint8_t *bytes = ( uint8_t * ) &in;
        !           511:        
        !           512:        sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
        !           513:        return buf;
        !           514: }
        !           515: 
        !           516: /**
        !           517:  * Transcribe IP address
        !           518:  *
        !           519:  * @v net_addr IP address
        !           520:  * @ret string IP address in dotted-quad notation
        !           521:  *
        !           522:  */
        !           523: static const char * ipv4_ntoa ( const void *net_addr ) {
        !           524:        return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
        !           525: }
        !           526: 
        !           527: /** IPv4 protocol */
        !           528: struct net_protocol ipv4_protocol __net_protocol = {
        !           529:        .name = "IP",
        !           530:        .net_proto = htons ( ETH_P_IP ),
        !           531:        .net_addr_len = sizeof ( struct in_addr ),
        !           532:        .rx = ipv4_rx,
        !           533:        .ntoa = ipv4_ntoa,
        !           534: };
        !           535: 
        !           536: /** IPv4 TCPIP net protocol */
        !           537: struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
        !           538:        .name = "IPv4",
        !           539:        .sa_family = AF_INET,
        !           540:        .tx = ipv4_tx,
        !           541: };
        !           542: 
        !           543: /** IPv4 ARP protocol */
        !           544: struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
        !           545:        .net_protocol = &ipv4_protocol,
        !           546:        .check = ipv4_arp_check,
        !           547: };
        !           548: 
        !           549: /******************************************************************************
        !           550:  *
        !           551:  * Settings
        !           552:  *
        !           553:  ******************************************************************************
        !           554:  */
        !           555: 
        !           556: /** IPv4 address setting */
        !           557: struct setting ip_setting __setting ( SETTING_IPv4 ) = {
        !           558:        .name = "ip",
        !           559:        .description = "IP address",
        !           560:        .tag = DHCP_EB_YIADDR,
        !           561:        .type = &setting_type_ipv4,
        !           562: };
        !           563: 
        !           564: /** IPv4 subnet mask setting */
        !           565: struct setting netmask_setting __setting ( SETTING_IPv4 ) = {
        !           566:        .name = "netmask",
        !           567:        .description = "Subnet mask",
        !           568:        .tag = DHCP_SUBNET_MASK,
        !           569:        .type = &setting_type_ipv4,
        !           570: };
        !           571: 
        !           572: /** Default gateway setting */
        !           573: struct setting gateway_setting __setting ( SETTING_IPv4 ) = {
        !           574:        .name = "gateway",
        !           575:        .description = "Default gateway",
        !           576:        .tag = DHCP_ROUTERS,
        !           577:        .type = &setting_type_ipv4,
        !           578: };
        !           579: 
        !           580: /**
        !           581:  * Create IPv4 routing table based on configured settings
        !           582:  *
        !           583:  * @ret rc             Return status code
        !           584:  */
        !           585: static int ipv4_create_routes ( void ) {
        !           586:        struct ipv4_miniroute *miniroute;
        !           587:        struct ipv4_miniroute *tmp;
        !           588:        struct net_device *netdev;
        !           589:        struct settings *settings;
        !           590:        struct in_addr address = { 0 };
        !           591:        struct in_addr netmask = { 0 };
        !           592:        struct in_addr gateway = { 0 };
        !           593: 
        !           594:        /* Delete all existing routes */
        !           595:        list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
        !           596:                del_ipv4_miniroute ( miniroute );
        !           597: 
        !           598:        /* Create a route for each configured network device */
        !           599:        for_each_netdev ( netdev ) {
        !           600:                settings = netdev_settings ( netdev );
        !           601:                /* Get IPv4 address */
        !           602:                address.s_addr = 0;
        !           603:                fetch_ipv4_setting ( settings, &ip_setting, &address );
        !           604:                if ( ! address.s_addr )
        !           605:                        continue;
        !           606:                /* Get subnet mask */
        !           607:                fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
        !           608:                /* Calculate default netmask, if necessary */
        !           609:                if ( ! netmask.s_addr ) {
        !           610:                        if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
        !           611:                                netmask.s_addr = htonl ( IN_CLASSA_NET );
        !           612:                        } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
        !           613:                                netmask.s_addr = htonl ( IN_CLASSB_NET );
        !           614:                        } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
        !           615:                                netmask.s_addr = htonl ( IN_CLASSC_NET );
        !           616:                        }
        !           617:                }
        !           618:                /* Get default gateway, if present */
        !           619:                fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
        !           620:                /* Configure route */
        !           621:                miniroute = add_ipv4_miniroute ( netdev, address,
        !           622:                                                 netmask, gateway );
        !           623:                if ( ! miniroute )
        !           624:                        return -ENOMEM;
        !           625:        }
        !           626: 
        !           627:        return 0;
        !           628: }
        !           629: 
        !           630: /** IPv4 settings applicator */
        !           631: struct settings_applicator ipv4_settings_applicator __settings_applicator = {
        !           632:        .apply = ipv4_create_routes,
        !           633: };
        !           634: 
        !           635: /* Drag in ICMP */
        !           636: REQUIRE_OBJECT ( icmp );

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.