|
|
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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.