Annotation of qemu/roms/ipxe/src/net/ipv6.c, revision 1.1.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.