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

1.1     ! root        1: #include <errno.h>
        !             2: #include <stdint.h>
        !             3: #include <string.h>
        !             4: #include <stdlib.h>
        !             5: #include <stdio.h>
        !             6: #include <byteswap.h>
        !             7: #include <ipxe/in.h>
        !             8: #include <ipxe/ip6.h>
        !             9: #include <ipxe/ndp.h>
        !            10: #include <ipxe/list.h>
        !            11: #include <ipxe/icmp6.h>
        !            12: #include <ipxe/tcpip.h>
        !            13: #include <ipxe/socket.h>
        !            14: #include <ipxe/iobuf.h>
        !            15: #include <ipxe/netdevice.h>
        !            16: #include <ipxe/if_ether.h>
        !            17: 
        !            18: /* Unspecified IP6 address */
        !            19: static struct in6_addr ip6_none = {
        !            20:         .in6_u.u6_addr32 = { 0,0,0,0 }
        !            21: };
        !            22: 
        !            23: /** An IPv6 routing table entry */
        !            24: struct ipv6_miniroute {
        !            25:        /* List of miniroutes */
        !            26:        struct list_head list;
        !            27: 
        !            28:        /* Network device */
        !            29:        struct net_device *netdev;
        !            30: 
        !            31:        /* Destination prefix */
        !            32:        struct in6_addr prefix;
        !            33:        /* Prefix length */
        !            34:        int prefix_len;
        !            35:        /* IPv6 address of interface */
        !            36:        struct in6_addr address;
        !            37:        /* Gateway address */
        !            38:        struct in6_addr gateway;
        !            39: };
        !            40: 
        !            41: /** List of IPv6 miniroutes */
        !            42: static LIST_HEAD ( miniroutes );
        !            43: 
        !            44: /**
        !            45:  * Add IPv6 minirouting table entry
        !            46:  *
        !            47:  * @v netdev           Network device
        !            48:  * @v prefix           Destination prefix
        !            49:  * @v address          Address of the interface
        !            50:  * @v gateway          Gateway address (or ::0 for no gateway)
        !            51:  * @ret miniroute      Routing table entry, or NULL
        !            52:  */
        !            53: static struct ipv6_miniroute * __malloc 
        !            54: add_ipv6_miniroute ( struct net_device *netdev, struct in6_addr prefix,
        !            55:                     int prefix_len, struct in6_addr address,
        !            56:                     struct in6_addr gateway ) {
        !            57:        struct ipv6_miniroute *miniroute;
        !            58:        
        !            59:        miniroute = malloc ( sizeof ( *miniroute ) );
        !            60:        if ( miniroute ) {
        !            61:                /* Record routing information */
        !            62:                miniroute->netdev = netdev_get ( netdev );
        !            63:                miniroute->prefix = prefix;
        !            64:                miniroute->prefix_len = prefix_len;
        !            65:                miniroute->address = address;
        !            66:                miniroute->gateway = gateway;
        !            67:                
        !            68:                /* Add miniroute to list of miniroutes */
        !            69:                if ( !IP6_EQUAL ( gateway, ip6_none ) ) {
        !            70:                        list_add_tail ( &miniroute->list, &miniroutes );
        !            71:                } else {
        !            72:                        list_add ( &miniroute->list, &miniroutes );
        !            73:                }
        !            74:        }
        !            75: 
        !            76:        return miniroute;
        !            77: }
        !            78: 
        !            79: /**
        !            80:  * Delete IPv6 minirouting table entry
        !            81:  *
        !            82:  * @v miniroute                Routing table entry
        !            83:  */
        !            84: static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) {
        !            85:        netdev_put ( miniroute->netdev );
        !            86:        list_del ( &miniroute->list );
        !            87:        free ( miniroute );
        !            88: }
        !            89: 
        !            90: /**
        !            91:  * Add IPv6 interface
        !            92:  *
        !            93:  * @v netdev   Network device
        !            94:  * @v prefix   Destination prefix
        !            95:  * @v address  Address of the interface
        !            96:  * @v gateway  Gateway address (or ::0 for no gateway)
        !            97:  */
        !            98: int add_ipv6_address ( struct net_device *netdev, struct in6_addr prefix,
        !            99:                       int prefix_len, struct in6_addr address,
        !           100:                       struct in6_addr gateway ) {
        !           101:        struct ipv6_miniroute *miniroute;
        !           102: 
        !           103:        /* Clear any existing address for this net device */
        !           104:        del_ipv6_address ( netdev );
        !           105: 
        !           106:        /* Add new miniroute */
        !           107:        miniroute = add_ipv6_miniroute ( netdev, prefix, prefix_len, address,
        !           108:                                         gateway );
        !           109:        if ( ! miniroute )
        !           110:                return -ENOMEM;
        !           111: 
        !           112:        return 0;
        !           113: }
        !           114: 
        !           115: /**
        !           116:  * Remove IPv6 interface
        !           117:  *
        !           118:  * @v netdev   Network device
        !           119:  */
        !           120: void del_ipv6_address ( struct net_device *netdev ) {
        !           121:        struct ipv6_miniroute *miniroute;
        !           122: 
        !           123:        list_for_each_entry ( miniroute, &miniroutes, list ) {
        !           124:                if ( miniroute->netdev == netdev ) {
        !           125:                        del_ipv6_miniroute ( miniroute );
        !           126:                        break;
        !           127:                }
        !           128:        }
        !           129: }
        !           130: 
        !           131: /**
        !           132:  * Calculate TCPIP checksum
        !           133:  *
        !           134:  * @v iobuf    I/O buffer
        !           135:  * @v tcpip    TCP/IP protocol
        !           136:  *
        !           137:  * This function constructs the pseudo header and completes the checksum in the
        !           138:  * upper layer header.
        !           139:  */
        !           140: static uint16_t ipv6_tx_csum ( struct io_buffer *iobuf, uint16_t csum ) {
        !           141:        struct ip6_header *ip6hdr = iobuf->data;
        !           142:        struct ipv6_pseudo_header pshdr;
        !           143: 
        !           144:        /* Calculate pseudo header */
        !           145:        memset ( &pshdr, 0, sizeof ( pshdr ) );
        !           146:        pshdr.src = ip6hdr->src;
        !           147:        pshdr.dest = ip6hdr->dest;
        !           148:        pshdr.len = htons ( iob_len ( iobuf ) - sizeof ( *ip6hdr ) );
        !           149:        pshdr.nxt_hdr = ip6hdr->nxt_hdr;
        !           150: 
        !           151:        /* Update checksum value */
        !           152:        return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
        !           153: }
        !           154: 
        !           155: /**
        !           156:  * Dump IP6 header for debugging
        !           157:  *
        !           158:  * ip6hdr      IPv6 header
        !           159:  */
        !           160: void ipv6_dump ( struct ip6_header *ip6hdr ) {
        !           161:        DBG ( "IP6 %p src %s dest %s nxt_hdr %d len %d\n", ip6hdr,
        !           162:              inet6_ntoa ( ip6hdr->src ), inet6_ntoa ( ip6hdr->dest ),
        !           163:              ip6hdr->nxt_hdr, ntohs ( ip6hdr->payload_len ) );
        !           164: }
        !           165: 
        !           166: /**
        !           167:  * Transmit IP6 packet
        !           168:  *
        !           169:  * iobuf               I/O buffer
        !           170:  * tcpip       TCP/IP protocol
        !           171:  * st_dest     Destination socket address
        !           172:  *
        !           173:  * This function prepends the IPv6 headers to the payload an transmits it.
        !           174:  */
        !           175: static int ipv6_tx ( struct io_buffer *iobuf,
        !           176:                     struct tcpip_protocol *tcpip,
        !           177:                     struct sockaddr_tcpip *st_src __unused,
        !           178:                     struct sockaddr_tcpip *st_dest,
        !           179:                     struct net_device *netdev,
        !           180:                     uint16_t *trans_csum ) {
        !           181:        struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest;
        !           182:        struct in6_addr next_hop;
        !           183:        struct ipv6_miniroute *miniroute;
        !           184:        uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
        !           185:        const uint8_t *ll_dest = ll_dest_buf;
        !           186:        int rc;
        !           187: 
        !           188:        /* Construct the IPv6 packet */
        !           189:        struct ip6_header *ip6hdr = iob_push ( iobuf, sizeof ( *ip6hdr ) );
        !           190:        memset ( ip6hdr, 0, sizeof ( *ip6hdr) );
        !           191:        ip6hdr->ver_traffic_class_flow_label = htonl ( 0x60000000 );//IP6_VERSION;
        !           192:        ip6hdr->payload_len = htons ( iob_len ( iobuf ) - sizeof ( *ip6hdr ) );
        !           193:        ip6hdr->nxt_hdr = tcpip->tcpip_proto;
        !           194:        ip6hdr->hop_limit = IP6_HOP_LIMIT; // 255
        !           195: 
        !           196:        /* Determine the next hop address and interface
        !           197:         *
        !           198:         * TODO: Implement the routing table.
        !           199:         */
        !           200:        next_hop = dest->sin6_addr;
        !           201:        list_for_each_entry ( miniroute, &miniroutes, list ) {
        !           202:                if ( ( memcmp ( &ip6hdr->dest, &miniroute->prefix,
        !           203:                                        miniroute->prefix_len ) == 0 ) ||
        !           204:                     ( IP6_EQUAL ( miniroute->gateway, ip6_none ) ) ) {
        !           205:                        netdev = miniroute->netdev;
        !           206:                        ip6hdr->src = miniroute->address;
        !           207:                        if ( ! ( IS_UNSPECIFIED ( miniroute->gateway ) ) ) {
        !           208:                                next_hop = miniroute->gateway;
        !           209:                        }
        !           210:                        break;
        !           211:                }
        !           212:        }
        !           213:        /* No network interface identified */
        !           214:        if ( !netdev ) {
        !           215:                DBG ( "No route to host %s\n", inet6_ntoa ( ip6hdr->dest ) );
        !           216:                rc = -ENETUNREACH;
        !           217:                goto err;
        !           218:        }
        !           219: 
        !           220:        /* Complete the transport layer checksum */
        !           221:        if ( trans_csum )
        !           222:                *trans_csum = ipv6_tx_csum ( iobuf, *trans_csum );
        !           223: 
        !           224:        /* Print IPv6 header */
        !           225:        ipv6_dump ( ip6hdr );
        !           226:        
        !           227:        /* Resolve link layer address */
        !           228:        if ( next_hop.in6_u.u6_addr8[0] == 0xff ) {
        !           229:                ll_dest_buf[0] = 0x33;
        !           230:                ll_dest_buf[1] = 0x33;
        !           231:                ll_dest_buf[2] = next_hop.in6_u.u6_addr8[12];
        !           232:                ll_dest_buf[3] = next_hop.in6_u.u6_addr8[13];
        !           233:                ll_dest_buf[4] = next_hop.in6_u.u6_addr8[14];
        !           234:                ll_dest_buf[5] = next_hop.in6_u.u6_addr8[15];
        !           235:        } else {
        !           236:                /* Unicast address needs to be resolved by NDP */
        !           237:                if ( ( rc = ndp_resolve ( netdev, &next_hop, &ip6hdr->src,
        !           238:                                          ll_dest_buf ) ) != 0 ) {
        !           239:                        DBG ( "No entry for %s\n", inet6_ntoa ( next_hop ) );
        !           240:                        goto err;
        !           241:                }
        !           242:        }
        !           243: 
        !           244:        /* Transmit packet */
        !           245:        return net_tx ( iobuf, netdev, &ipv6_protocol, ll_dest,
        !           246:                        netdev->ll_addr );
        !           247: 
        !           248:   err:
        !           249:        free_iob ( iobuf );
        !           250:        return rc;
        !           251: }
        !           252: 
        !           253: /**
        !           254:  * Process next IP6 header
        !           255:  *
        !           256:  * @v iobuf    I/O buffer
        !           257:  * @v nxt_hdr  Next header number
        !           258:  * @v src      Source socket address
        !           259:  * @v dest     Destination socket address
        !           260:  *
        !           261:  * Refer http://www.iana.org/assignments/ipv6-parameters for the numbers
        !           262:  */
        !           263: static int ipv6_process_nxt_hdr ( struct io_buffer *iobuf, uint8_t nxt_hdr,
        !           264:                struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest ) {
        !           265:        switch ( nxt_hdr ) {
        !           266:        case IP6_HOPBYHOP: 
        !           267:        case IP6_ROUTING: 
        !           268:        case IP6_FRAGMENT: 
        !           269:        case IP6_AUTHENTICATION: 
        !           270:        case IP6_DEST_OPTS: 
        !           271:        case IP6_ESP: 
        !           272:                DBG ( "Function not implemented for header %d\n", nxt_hdr );
        !           273:                return -ENOSYS;
        !           274:        case IP6_ICMP6: 
        !           275:                break;
        !           276:        case IP6_NO_HEADER: 
        !           277:                DBG ( "No next header\n" );
        !           278:                return 0;
        !           279:        }
        !           280:        /* Next header is not a IPv6 extension header */
        !           281:        return tcpip_rx ( iobuf, nxt_hdr, src, dest, 0 /* fixme */ );
        !           282: }
        !           283: 
        !           284: /**
        !           285:  * Process incoming IP6 packets
        !           286:  *
        !           287:  * @v iobuf            I/O buffer
        !           288:  * @v netdev           Network device
        !           289:  * @v ll_dest          Link-layer destination address
        !           290:  * @v ll_source                Link-layer source address
        !           291:  *
        !           292:  * This function processes a IPv6 packet
        !           293:  */
        !           294: static int ipv6_rx ( struct io_buffer *iobuf,
        !           295:                     __unused struct net_device *netdev,
        !           296:                     __unused const void *ll_dest,
        !           297:                     __unused const void *ll_source ) {
        !           298: 
        !           299:        struct ip6_header *ip6hdr = iobuf->data;
        !           300:        union {
        !           301:                struct sockaddr_in6 sin6;
        !           302:                struct sockaddr_tcpip st;
        !           303:        } src, dest;
        !           304: 
        !           305:        /* Sanity check */
        !           306:        if ( iob_len ( iobuf ) < sizeof ( *ip6hdr ) ) {
        !           307:                DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) );
        !           308:                goto drop;
        !           309:        }
        !           310: 
        !           311:        /* TODO: Verify checksum */
        !           312: 
        !           313:        /* Print IP6 header for debugging */
        !           314:        ipv6_dump ( ip6hdr );
        !           315: 
        !           316:        /* Check header version */
        !           317:        if ( ( ip6hdr->ver_traffic_class_flow_label & 0xf0000000 ) != 0x60000000 ) {
        !           318:                DBG ( "Invalid protocol version\n" );
        !           319:                goto drop;
        !           320:        }
        !           321: 
        !           322:        /* Check the payload length */
        !           323:        if ( ntohs ( ip6hdr->payload_len ) > iob_len ( iobuf ) ) {
        !           324:                DBG ( "Inconsistent packet length (%d bytes)\n",
        !           325:                        ip6hdr->payload_len );
        !           326:                goto drop;
        !           327:        }
        !           328: 
        !           329:        /* Ignore the traffic class and flow control values */
        !           330: 
        !           331:        /* Construct socket address */
        !           332:        memset ( &src, 0, sizeof ( src ) );
        !           333:        src.sin6.sin_family = AF_INET6;
        !           334:        src.sin6.sin6_addr = ip6hdr->src;
        !           335:        memset ( &dest, 0, sizeof ( dest ) );
        !           336:        dest.sin6.sin_family = AF_INET6;
        !           337:        dest.sin6.sin6_addr = ip6hdr->dest;
        !           338: 
        !           339:        /* Strip header */
        !           340:        iob_unput ( iobuf, iob_len ( iobuf ) - ntohs ( ip6hdr->payload_len ) -
        !           341:                                                        sizeof ( *ip6hdr ) );
        !           342:        iob_pull ( iobuf, sizeof ( *ip6hdr ) );
        !           343: 
        !           344:        /* Send it to the transport layer */
        !           345:        return ipv6_process_nxt_hdr ( iobuf, ip6hdr->nxt_hdr, &src.st, &dest.st );
        !           346: 
        !           347:   drop:
        !           348:        DBG ( "Packet dropped\n" );
        !           349:        free_iob ( iobuf );
        !           350:        return -1;
        !           351: }
        !           352: 
        !           353: /**
        !           354:  * Print a IP6 address as xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
        !           355:  */
        !           356: char * inet6_ntoa ( struct in6_addr in6 ) {
        !           357:        static char buf[40];
        !           358:        uint16_t *bytes = ( uint16_t* ) &in6;
        !           359:        sprintf ( buf, "%x:%x:%x:%x:%x:%x:%x:%x", bytes[0], bytes[1], bytes[2],
        !           360:                        bytes[3], bytes[4], bytes[5], bytes[6], bytes[7] );
        !           361:        return buf;
        !           362: }
        !           363: 
        !           364: static const char * ipv6_ntoa ( const void *net_addr ) {
        !           365:        return inet6_ntoa ( * ( ( struct in6_addr * ) net_addr ) );
        !           366: }
        !           367: 
        !           368: /** IPv6 protocol */
        !           369: struct net_protocol ipv6_protocol __net_protocol = {
        !           370:        .name = "IPv6",
        !           371:        .net_proto = htons ( ETH_P_IPV6 ),
        !           372:        .net_addr_len = sizeof ( struct in6_addr ),
        !           373:        .rx = ipv6_rx,
        !           374:        .ntoa = ipv6_ntoa,
        !           375: };
        !           376: 
        !           377: /** IPv6 TCPIP net protocol */
        !           378: struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol = {
        !           379:        .name = "IPv6",
        !           380:        .sa_family = AF_INET6,
        !           381:        .tx = ipv6_tx,
        !           382: };

unix.superglobalmegacorp.com

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