|
|
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.