Bläddra i källkod

IP6 support

tags/v0.9.3
Nikhil Chandru Rao 18 år sedan
förälder
incheckning
d1d334b8e1
7 ändrade filer med 743 tillägg och 22 borttagningar
  1. 58
    0
      src/include/gpxe/icmp6.h
  2. 3
    2
      src/include/gpxe/in.h
  3. 41
    6
      src/include/gpxe/ip6.h
  4. 23
    0
      src/include/gpxe/ndp.h
  5. 128
    0
      src/net/icmpv6.c
  6. 309
    14
      src/net/ipv6.c
  7. 181
    0
      src/net/ndp.c

+ 58
- 0
src/include/gpxe/icmp6.h Visa fil

@@ -0,0 +1,58 @@
1
+#ifndef _GPXE_ICMP6_H
2
+#define _GPXE_ICMP6_H
3
+
4
+/** @file
5
+ *
6
+ * ICMP6 protocol
7
+ *
8
+ */
9
+
10
+#include <ip.h>
11
+#include <gpxe/ip6.h>
12
+#include <gpxe/ndp.h>
13
+
14
+#define ICMP6_NSOLICIT 135
15
+#define ICMP6_NADVERT 136
16
+
17
+extern struct tcpip_protocol icmp6_protocol;
18
+
19
+struct icmp6_header {
20
+	uint8_t type;
21
+	uint8_t code;
22
+	uint16_t csum;
23
+	/* Message body */
24
+};
25
+
26
+struct neighbour_solicit {
27
+	uint8_t type;
28
+	uint8_t code;
29
+	uint16_t csum;
30
+	uint32_t reserved;
31
+	struct in6_addr target;
32
+	/* "Compulsory" options */
33
+	uint8_t opt_type;
34
+	uint8_t opt_len;
35
+#warning hack alert
36
+	uint8_t opt_ll_addr[6];
37
+};
38
+
39
+struct neighbour_advert {
40
+	uint8_t type;
41
+	uint8_t code;
42
+	uint16_t csum;
43
+	uint8_t flags;
44
+	uint8_t reserved;
45
+	struct in6_addr target;
46
+	uint8_t opt_type;
47
+	uint8_t opt_len;
48
+#warning hack alert
49
+	uint8_t opt_ll_addr[6];
50
+};
51
+
52
+#define ICMP6_FLAGS_ROUTER 0x80
53
+#define ICMP6_FLAGS_SOLICITED 0x40
54
+#define ICMP6_FLAGS_OVERRIDE 0x20
55
+
56
+int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src, struct in6_addr *dest );
57
+
58
+#endif /* _GPXE_ICMP6_H */

+ 3
- 2
src/include/gpxe/in.h Visa fil

@@ -10,6 +10,7 @@
10 10
 #define IP_IGMP		2
11 11
 #define IP_TCP		6
12 12
 #define IP_UDP		17
13
+#define IP_ICMP6	58
13 14
 
14 15
 /* IP address constants */
15 16
 
@@ -36,7 +37,7 @@ struct in6_addr {
36 37
                 uint8_t u6_addr8[16];
37 38
                 uint16_t u6_addr16[8];
38 39
                 uint32_t u6_addr32[4];
39
-        } in16_u;
40
+        } in6_u;
40 41
 #define s6_addr         in6_u.u6_addr8
41 42
 #define s6_addr16       in6_u.u6_addr16
42 43
 #define s6_addr32       in6_u.u6_addr32
@@ -67,7 +68,7 @@ struct sockaddr_in6 {
67 68
 	 */
68 69
 	sa_family_t sin_family;
69 70
 	/** TCP/IP port (part of struct @c sockaddr_tcpip) */
70
-	uint16_t sin_port;
71
+	uint16_t 	sin_port;
71 72
         uint32_t        sin6_flowinfo;  /* Flow number */
72 73
         struct in6_addr sin6_addr;      /* 128-bit destination address */
73 74
         uint32_t        sin6_scope_id;  /* Scope ID */

+ 41
- 6
src/include/gpxe/ip6.h Visa fil

@@ -8,18 +8,33 @@
8 8
  */
9 9
 
10 10
 #include <ip.h>
11
+#include <gpxe/in.h>
11 12
 
12 13
 /* IP6 constants */
13 14
 
14 15
 #define IP6_VERSION	0x6
15
-#define IP6_HOP_LIMIT	64
16
+#define IP6_HOP_LIMIT	255
16 17
 
17
-/* IP6 header */
18
+/**
19
+ * Packet buffer contents
20
+ * This is duplicated in tcp.h and here. Ideally it should go into pkbuff.h
21
+ */
22
+#define MAX_HDR_LEN	100
23
+#define MAX_PKB_LEN	1500
24
+#define MIN_PKB_LEN	MAX_HDR_LEN + 100 /* To account for padding by LL */
25
+
26
+#define IP6_EQUAL( in6_addr1, in6_addr2 ) \
27
+        ( strncmp ( ( char* ) &( in6_addr1 ), ( char* ) &( in6_addr2 ),\
28
+	sizeof ( struct in6_addr ) ) == 0 )
18 29
 
30
+#define IS_UNSPECIFIED( addr ) \
31
+	( ( (addr).in6_u.u6_addr32[0] == 0x00000000 ) && \
32
+	( (addr).in6_u.u6_addr32[1] == 0x00000000 ) && \
33
+	( (addr).in6_u.u6_addr32[2] == 0x00000000 ) && \
34
+	( (addr).in6_u.u6_addr32[3] == 0x00000000 ) )
35
+/* IP6 header */
19 36
 struct ip6_header {
20
-	uint32_t 	vers:4,
21
-		 	traffic_class:8,
22
-		 	flow_label:20;
37
+	uint32_t 	ver_traffic_class_flow_label;
23 38
 	uint16_t 	payload_len;
24 39
 	uint8_t 	nxt_hdr;
25 40
 	uint8_t 	hop_limit;
@@ -27,12 +42,32 @@ struct ip6_header {
27 42
 	struct in6_addr dest;
28 43
 };
29 44
 
45
+/* IP6 pseudo header */
46
+struct ipv6_pseudo_header {
47
+	struct in6_addr src;
48
+	struct in6_addr dest;
49
+	uint8_t zero_padding;
50
+	uint8_t nxt_hdr;
51
+	uint16_t len;
52
+};
53
+
54
+/* Next header numbers */
55
+#define IP6_HOPBYHOP 		0x00
56
+#define IP6_ROUTING 		0x43
57
+#define IP6_FRAGMENT		0x44
58
+#define IP6_AUTHENTICATION	0x51
59
+#define IP6_DEST_OPTS		0x60
60
+#define IP6_ESP			0x50
61
+#define IP6_ICMP6		0x58
62
+#define IP6_NO_HEADER		0x59
63
+
30 64
 struct pk_buff;
31 65
 struct net_device;
32 66
 struct net_protocol;
33 67
 
34 68
 extern struct net_protocol ipv6_protocol;
69
+extern struct tcpip_net_protocol ipv6_tcpip_protocol;
70
+extern char * inet6_ntoa ( struct in6_addr in6 );
35 71
 
36
-extern int ipv6_tx ( struct pk_buff *pkb, uint16_t trans_proto, struct in6_addr *dest );
37 72
 
38 73
 #endif /* _GPXE_IP6_H */

+ 23
- 0
src/include/gpxe/ndp.h Visa fil

@@ -0,0 +1,23 @@
1
+#include <stdint.h>
2
+#include <byteswap.h>
3
+#include <errno.h>
4
+#include <string.h>
5
+#include <gpxe/icmp6.h>
6
+#include <gpxe/ip6.h>
7
+#include <gpxe/in.h>
8
+#include <gpxe/netdevice.h>
9
+#include <gpxe/pkbuff.h>
10
+#include <gpxe/tcpip.h>
11
+
12
+#define NDP_STATE_INVALID 0
13
+#define NDP_STATE_INCOMPLETE 1
14
+#define NDP_STATE_REACHABLE 2
15
+#define NDP_STATE_DELAY 3
16
+#define NDP_STATE_PROBE 4
17
+#define NDP_STATE_STALE 5
18
+
19
+static struct ndp_entry * ndp_find_entry ( struct in6_addr *in6 );
20
+int ndp_resolve ( struct net_device *netdev, struct in6_addr *src,
21
+		  struct in6_addr *dest, void *dest_ll_addr );
22
+int ndp_process_advert ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
23
+			 struct sockaddr_tcpip *st_dest );

+ 128
- 0
src/net/icmpv6.c Visa fil

@@ -0,0 +1,128 @@
1
+#include <stdint.h>
2
+#include <string.h>
3
+#include <byteswap.h>
4
+#include <errno.h>
5
+#include <gpxe/in.h>
6
+#include <gpxe/ip6.h>
7
+#include <gpxe/if_ether.h>
8
+#include <gpxe/pkbuff.h>
9
+#include <gpxe/ndp.h>
10
+#include <gpxe/icmp6.h>
11
+#include <gpxe/tcpip.h>
12
+#include <gpxe/netdevice.h>
13
+
14
+struct tcpip_protocol icmp6_protocol;
15
+
16
+/**
17
+ * Send neighbour solicitation packet
18
+ *
19
+ * @v netdev	Network device
20
+ * @v src	Source address
21
+ * @v dest	Destination address
22
+ *
23
+ * This function prepares a neighbour solicitation packet and sends it to the
24
+ * network layer.
25
+ */
26
+int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src,
27
+			 struct in6_addr *dest ) {
28
+	union {
29
+		struct sockaddr_in6 sin6;
30
+		struct sockaddr_tcpip st;
31
+	} st_dest;
32
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
33
+	struct neighbour_solicit *nsolicit;
34
+	struct pk_buff *pkb = alloc_pkb ( sizeof ( *nsolicit ) + MIN_PKB_LEN );
35
+	pkb_reserve ( pkb, MAX_HDR_LEN );
36
+	nsolicit = pkb_put ( pkb, sizeof ( *nsolicit ) );
37
+
38
+	/* Fill up the headers */
39
+	memset ( nsolicit, 0, sizeof ( *nsolicit ) );
40
+	nsolicit->type = ICMP6_NSOLICIT;
41
+	nsolicit->code = 0;
42
+	nsolicit->target = *dest;
43
+	nsolicit->opt_type = 1;
44
+	nsolicit->opt_len = ( 2 + ll_protocol->ll_addr_len ) / 8;
45
+	memcpy ( nsolicit->opt_ll_addr, netdev->ll_addr,
46
+				netdev->ll_protocol->ll_addr_len );
47
+	/* Partial checksum */
48
+	nsolicit->csum = 0;
49
+	nsolicit->csum = tcpip_chksum ( nsolicit, sizeof ( *nsolicit ) );
50
+
51
+	/* Solicited multicast address */
52
+	st_dest.sin6.sin_family = AF_INET6;
53
+	st_dest.sin6.sin6_addr.in6_u.u6_addr8[0] = 0xff;
54
+	st_dest.sin6.sin6_addr.in6_u.u6_addr8[2] = 0x02;
55
+	st_dest.sin6.sin6_addr.in6_u.u6_addr16[1] = 0x0000;
56
+	st_dest.sin6.sin6_addr.in6_u.u6_addr32[1] = 0x00000000;
57
+	st_dest.sin6.sin6_addr.in6_u.u6_addr16[4] = 0x0000;
58
+	st_dest.sin6.sin6_addr.in6_u.u6_addr16[5] = 0x0001;
59
+	st_dest.sin6.sin6_addr.in6_u.u6_addr32[3] = dest->in6_u.u6_addr32[3];
60
+	st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff;
61
+	
62
+	/* Send packet over IP6 */
63
+	tcpip_tx ( pkb, &icmp6_protocol, &st_dest.st );
64
+}
65
+
66
+/**
67
+ * Process ICMP6 headers
68
+ *
69
+ * @v pkb	Packet buffer
70
+ * @v st_src	Source address
71
+ * @v st_dest	Destination address
72
+ */
73
+static int icmp6_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
74
+		      struct sockaddr_tcpip *st_dest ) {
75
+	struct icmp6_header *icmp6hdr = pkb->data;
76
+
77
+	/* Sanity check */
78
+	if ( pkb_len ( pkb ) < sizeof ( *icmp6hdr ) ) {
79
+		DBG ( "Packet too short (%d bytes)\n", pkb_len ( pkb ) );
80
+		free_pkb ( pkb );
81
+		return -EINVAL;
82
+	}
83
+
84
+	/* TODO: Verify checksum */
85
+
86
+	/* Process the ICMP header */
87
+	switch ( icmp6hdr->type ) {
88
+	case ICMP6_NADVERT:
89
+		return ndp_process_advert ( pkb, st_src, st_dest );
90
+	}
91
+	return -ENOSYS;
92
+}
93
+
94
+#if 0
95
+void icmp6_test_nadvert (struct net_device *netdev, struct sockaddr_in6 *server_p, char *ll_addr) {
96
+
97
+		struct sockaddr_in6 server;
98
+		memcpy ( &server, server_p, sizeof ( server ) );
99
+                struct pk_buff *rxpkb = alloc_pkb ( 500 );
100
+                pkb_reserve ( rxpkb, MAX_HDR_LEN );
101
+                struct neighbour_advert *nadvert = pkb_put ( rxpkb, sizeof ( *nadvert ) );
102
+                nadvert->type = 136;
103
+                nadvert->code = 0;
104
+                nadvert->flags = ICMP6_FLAGS_SOLICITED;
105
+		nadvert->csum = 0xffff;
106
+		nadvert->target = server.sin6_addr;
107
+                nadvert->opt_type = 2;
108
+                nadvert->opt_len = 1;
109
+                memcpy ( nadvert->opt_ll_addr, ll_addr, 6 );
110
+                struct ip6_header *ip6hdr = pkb_push ( rxpkb, sizeof ( *ip6hdr ) );
111
+                ip6hdr->ver_traffic_class_flow_label = htonl ( 0x60000000 );
112
+		ip6hdr->hop_limit = 255;
113
+		ip6hdr->nxt_hdr = 58;
114
+		ip6hdr->payload_len = htons ( sizeof ( *nadvert ) );
115
+                ip6hdr->src = server.sin6_addr;
116
+                ip6hdr->dest = server.sin6_addr;
117
+		hex_dump ( rxpkb->data, pkb_len ( rxpkb ) );
118
+                net_rx ( rxpkb, netdev, htons ( ETH_P_IPV6 ), ll_addr );
119
+}
120
+#endif
121
+
122
+/** ICMP6 protocol */
123
+struct tcpip_protocol icmp6_protocol __tcpip_protocol = {
124
+	.name = "ICMP6",
125
+	.rx = icmp6_rx,
126
+	.tcpip_proto = IP_ICMP6, // 58
127
+	.csum_offset = 2,
128
+};

+ 309
- 14
src/net/ipv6.c Visa fil

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

+ 181
- 0
src/net/ndp.c Visa fil

@@ -0,0 +1,181 @@
1
+#include <stdint.h>
2
+#include <string.h>
3
+#include <byteswap.h>
4
+#include <errno.h>
5
+#include <gpxe/if_ether.h>
6
+#include <gpxe/pkbuff.h>
7
+#include <gpxe/ndp.h>
8
+#include <gpxe/icmp6.h>
9
+#include <gpxe/ip6.h>
10
+#include <gpxe/netdevice.h>
11
+
12
+/** @file
13
+ *
14
+ * Neighbour Discovery Protocol
15
+ *
16
+ * This file implements address resolution as specified by the neighbour
17
+ * discovery protocol in RFC2461. This protocol is part of the IPv6 protocol
18
+ * family.
19
+ */
20
+
21
+/* A neighbour entry */
22
+struct ndp_entry {
23
+	/** Target IP6 address */
24
+	struct in6_addr in6;
25
+	/** Link layer protocol */
26
+	struct ll_protocol *ll_protocol;
27
+	/** Link-layer address */
28
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
29
+	/** State of the neighbour entry */
30
+	int state;
31
+};
32
+
33
+/** Number of entries in the neighbour cache table */
34
+#define NUM_NDP_ENTRIES 4
35
+
36
+/** The neighbour cache table */
37
+static struct ndp_entry ndp_table[NUM_NDP_ENTRIES];
38
+#define ndp_table_end &ndp_table[NUM_NDP_ENTRIES]
39
+
40
+static unsigned int next_new_ndp_entry = 0;
41
+
42
+/**
43
+ * Find entry in the neighbour cache
44
+ *
45
+ * @v in6	IP6 address
46
+ */
47
+static struct ndp_entry *
48
+ndp_find_entry ( struct in6_addr *in6 ) {
49
+	struct ndp_entry *ndp;
50
+
51
+	for ( ndp = ndp_table ; ndp < ndp_table_end ; ndp++ ) {
52
+		if ( IP6_EQUAL ( ( *in6 ), ndp->in6 ) && 
53
+		     ( ndp->state != NDP_STATE_INVALID ) ) {
54
+			return ndp;
55
+		}
56
+	}
57
+	return NULL;
58
+}
59
+
60
+/**
61
+ * Add NDP entry
62
+ * 
63
+ * @v netdev	Network device
64
+ * @v in6	IP6 address
65
+ * @v ll_addr	Link-layer address
66
+ * @v state	State of the entry - one of the NDP_STATE_XXX values
67
+ */
68
+void add_ndp_entry ( struct net_device *netdev, struct in6_addr *in6,
69
+		     void *ll_addr, int state ) {
70
+	struct ndp_entry *ndp;
71
+	ndp = &ndp_table[next_new_ndp_entry++ % NUM_NDP_ENTRIES];
72
+
73
+	/* Fill up entry */
74
+	ndp->ll_protocol = netdev->ll_protocol;
75
+	memcpy ( &ndp->in6, &( *in6 ), sizeof ( *in6 ) );
76
+	if ( ll_addr ) {
77
+		memcpy ( ndp->ll_addr, ll_addr, netdev->ll_protocol->ll_addr_len );
78
+	} else {
79
+		memset ( ndp->ll_addr, 0, netdev->ll_protocol->ll_addr_len );
80
+	}
81
+	ndp->state = state;
82
+	DBG ( "New neighbour cache entry (%d): IP6 %s => %s %s\n",
83
+	      ( ndp - ndp_table ) / sizeof ( *ndp ),
84
+	      inet6_ntoa ( ndp->in6 ), netdev->ll_protocol->name,
85
+	      netdev->ll_protocol->ntoa ( ndp->ll_addr ) );
86
+}
87
+
88
+/**
89
+ * Resolve the link-layer address
90
+ *
91
+ * @v netdev		Network device
92
+ * @v dest		Destination address
93
+ * @v src		Source address
94
+ * @ret dest_ll_addr	Destination link-layer address or NULL
95
+ * @ret rc		Status
96
+ *
97
+ * This function looks up the neighbour cache for an entry corresponding to the
98
+ * destination address. If it finds a valid entry, it fills up dest_ll_addr and
99
+ * returns 0. Otherwise it sends a neighbour solicitation to the solicited
100
+ * multicast address.
101
+ */
102
+int ndp_resolve ( struct net_device *netdev, struct in6_addr *dest,
103
+		  struct in6_addr *src, void *dest_ll_addr ) {
104
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
105
+	struct ndp_entry *ndp;
106
+	int rc;
107
+
108
+	ndp = ndp_find_entry ( dest );
109
+	/* Check if the entry is valid */
110
+	if ( ndp && ndp->state == NDP_STATE_REACHABLE ) {
111
+		DBG ( "Neighbour cache hit: IP6 %s => %s %s\n",
112
+		      inet6_ntoa ( *dest ), ll_protocol->name,
113
+		      ll_protocol->ntoa ( ndp->ll_addr ) );
114
+		memcpy ( dest_ll_addr, ndp->ll_addr, ll_protocol->ll_addr_len );
115
+		return 0;
116
+	}
117
+
118
+	/* Check if the entry was already created */
119
+	if ( ndp ) {
120
+		DBG ( "Awaiting neighbour advertisement (cache entry %d)\n",
121
+		      ( ( ndp - ndp_table ) / sizeof ( *ndp ) ) );
122
+		/* For test */
123
+//		ndp->state = NDP_STATE_REACHABLE;
124
+//		memcpy ( ndp->ll_addr, netdev->ll_addr, 6 );
125
+//		assert ( ndp->ll_protocol->ll_addr_len == 6 );
126
+//		icmp6_test_nadvert ( netdev, dest, ndp->ll_addr );
127
+//		assert ( ndp->state == NDP_STATE_REACHABLE );
128
+		/* Take it out till here */
129
+		return -ENOENT;
130
+	}
131
+	DBG ( "Neighbour cache miss: IP6 %s\n", inet6_ntoa ( *dest ) );
132
+
133
+	/* Add entry in the neighbour cache */
134
+	add_ndp_entry ( netdev, dest, NULL, NDP_STATE_INCOMPLETE );
135
+
136
+	/* Send neighbour solicitation */
137
+	if ( ( rc = icmp6_send_solicit ( netdev, src, dest ) ) != 0 ) {
138
+		return rc;
139
+	}
140
+	return -ENOENT;
141
+}
142
+
143
+/**
144
+ * Process neighbour advertisement
145
+ *
146
+ * @v pkb	Packet buffer
147
+ * @v st_src	Source address
148
+ * @v st_dest	Destination address 
149
+ */
150
+int ndp_process_advert ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
151
+			   struct sockaddr_tcpip *st_dest ) {
152
+	struct neighbour_advert *nadvert = pkb->data;
153
+	struct ndp_entry *ndp;
154
+
155
+	/* Sanity check */
156
+	if ( pkb_len ( pkb ) < sizeof ( *nadvert ) ) {
157
+		DBG ( "Packet too short (%d bytes)\n", pkb_len ( pkb ) );
158
+		return -EINVAL;
159
+	}
160
+
161
+	assert ( nadvert->code == 0 );
162
+	assert ( nadvert->flags & ICMP6_FLAGS_SOLICITED );
163
+	assert ( nadvert->opt_type == 2 );
164
+
165
+	/* Update the neighbour cache, if entry is present */
166
+	ndp = ndp_find_entry ( &nadvert->target );
167
+	if ( ndp ) {
168
+
169
+	assert ( nadvert->opt_len ==
170
+			( ( 2 + ndp->ll_protocol->ll_addr_len ) / 8 ) );
171
+
172
+		if ( IP6_EQUAL ( ndp->in6, nadvert->target ) ) {
173
+			memcpy ( ndp->ll_addr, nadvert->opt_ll_addr,
174
+				 ndp->ll_protocol->ll_addr_len );
175
+			ndp->state = NDP_STATE_REACHABLE;
176
+			return 0;
177
+		}
178
+	}
179
+	DBG ( "Unsolicited advertisement (dropping packet)\n" );
180
+	return 0;
181
+}

Laddar…
Avbryt
Spara