Browse Source

[ipv6] Support stateless address autoconfiguration (SLAAC)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
33652880a7
4 changed files with 235 additions and 70 deletions
  1. 21
    6
      src/include/ipxe/ipv6.h
  2. 55
    12
      src/include/ipxe/ndp.h
  3. 47
    0
      src/net/ipv6.c
  4. 112
    52
      src/net/ndp.c

+ 21
- 6
src/include/ipxe/ipv6.h View File

173
 };
173
 };
174
 
174
 
175
 /**
175
 /**
176
- * Construct link-local address (via EUI-64)
176
+ * Construct local IPv6 address via EUI-64
177
  *
177
  *
178
- * @v addr		Address to construct
178
+ * @v addr		Prefix to be completed
179
  * @v netdev		Network device
179
  * @v netdev		Network device
180
  * @ret prefix_len	Prefix length, or negative error
180
  * @ret prefix_len	Prefix length, or negative error
181
  */
181
  */
182
-static inline int ipv6_link_local ( struct in6_addr *addr,
183
-				    struct net_device *netdev ) {
182
+static inline int ipv6_eui64 ( struct in6_addr *addr,
183
+			       struct net_device *netdev ) {
184
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
184
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
185
 	const void *ll_addr = netdev->ll_addr;
185
 	const void *ll_addr = netdev->ll_addr;
186
 	int rc;
186
 	int rc;
187
 
187
 
188
-	memset ( addr, 0, sizeof ( *addr ) );
189
-	addr->s6_addr16[0] = htons ( 0xfe80 );
190
 	if ( ( rc = ll_protocol->eui64 ( ll_addr, &addr->s6_addr[8] ) ) != 0 )
188
 	if ( ( rc = ll_protocol->eui64 ( ll_addr, &addr->s6_addr[8] ) ) != 0 )
191
 		return rc;
189
 		return rc;
192
 	addr->s6_addr[8] ^= 0x02;
190
 	addr->s6_addr[8] ^= 0x02;
193
 	return 64;
191
 	return 64;
194
 }
192
 }
195
 
193
 
194
+/**
195
+ * Construct link-local address via EUI-64
196
+ *
197
+ * @v addr		Address to construct
198
+ * @v netdev		Network device
199
+ * @ret prefix_len	Prefix length, or negative error
200
+ */
201
+static inline int ipv6_link_local ( struct in6_addr *addr,
202
+				    struct net_device *netdev ) {
203
+
204
+	memset ( addr, 0, sizeof ( *addr ) );
205
+	addr->s6_addr16[0] = htons ( 0xfe80 );
206
+	return ipv6_eui64 ( addr, netdev );
207
+}
208
+
196
 /**
209
 /**
197
  * Construct solicited-node multicast address
210
  * Construct solicited-node multicast address
198
  *
211
  *
214
 extern struct net_protocol ipv6_protocol __net_protocol;
227
 extern struct net_protocol ipv6_protocol __net_protocol;
215
 
228
 
216
 extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
229
 extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
230
+extern int ipv6_slaac ( struct net_device *netdev, struct in6_addr *prefix,
231
+			unsigned int prefix_len, struct in6_addr *router );
217
 
232
 
218
 #endif /* _IPXE_IPV6_H */
233
 #endif /* _IPXE_IPV6_H */

+ 55
- 12
src/include/ipxe/ndp.h View File

15
 #include <ipxe/icmpv6.h>
15
 #include <ipxe/icmpv6.h>
16
 #include <ipxe/neighbour.h>
16
 #include <ipxe/neighbour.h>
17
 
17
 
18
-/** An NDP option */
19
-struct ndp_option {
18
+/** An NDP option header */
19
+struct ndp_option_header {
20
 	/** Type */
20
 	/** Type */
21
 	uint8_t type;
21
 	uint8_t type;
22
 	/** Length (in blocks of 8 bytes) */
22
 	/** Length (in blocks of 8 bytes) */
23
 	uint8_t blocks;
23
 	uint8_t blocks;
24
-	/** Value */
25
-	uint8_t value[0];
26
 } __attribute__ (( packed ));
24
 } __attribute__ (( packed ));
27
 
25
 
28
 /** NDP option block size */
26
 /** NDP option block size */
29
 #define NDP_OPTION_BLKSZ 8
27
 #define NDP_OPTION_BLKSZ 8
30
 
28
 
29
+/** NDP source link-layer address option */
30
+#define NDP_OPT_LL_SOURCE 1
31
+
32
+/** NDP target link-layer address option */
33
+#define NDP_OPT_LL_TARGET 2
34
+
35
+/** NDP source or target link-layer address option */
36
+struct ndp_ll_addr_option {
37
+	/** NDP option header */
38
+	struct ndp_option_header header;
39
+	/** Link-layer address */
40
+	uint8_t ll_addr[0];
41
+} __attribute__ (( packed ));
42
+
43
+/** NDP prefix information option */
44
+#define NDP_OPT_PREFIX 3
45
+
46
+/** NDP prefix information */
47
+struct ndp_prefix_information_option {
48
+	/** NDP option header */
49
+	struct ndp_option_header header;
50
+	/** Prefix length */
51
+	uint8_t prefix_len;
52
+	/** Flags */
53
+	uint8_t flags;
54
+	/** Valid lifetime */
55
+	uint32_t valid;
56
+	/** Preferred lifetime */
57
+	uint32_t preferred;
58
+	/** Reserved */
59
+	uint32_t reserved;
60
+	/** Prefix */
61
+	struct in6_addr prefix;
62
+} __attribute__ (( packed ));
63
+
64
+/** NDP on-link flag */
65
+#define NDP_PREFIX_ON_LINK 0x80
66
+
67
+/** NDP autonomous address configuration flag */
68
+#define NDP_PREFIX_AUTONOMOUS 0x40
69
+
70
+/** An NDP option */
71
+union ndp_option {
72
+	/** Option header */
73
+	struct ndp_option_header header;
74
+	/** Source or target link-layer address option */
75
+	struct ndp_ll_addr_option ll_addr;
76
+	/** Prefix information option */
77
+	struct ndp_prefix_information_option prefix;
78
+} __attribute__ (( packed ));
79
+
31
 /** An NDP neighbour solicitation or advertisement header */
80
 /** An NDP neighbour solicitation or advertisement header */
32
 struct ndp_neighbour_header {
81
 struct ndp_neighbour_header {
33
 	/** ICMPv6 header */
82
 	/** ICMPv6 header */
39
 	/** Target address */
88
 	/** Target address */
40
 	struct in6_addr target;
89
 	struct in6_addr target;
41
 	/** Options */
90
 	/** Options */
42
-	struct ndp_option option[0];
91
+	union ndp_option option[0];
43
 } __attribute__ (( packed ));
92
 } __attribute__ (( packed ));
44
 
93
 
45
 /** NDP router flag */
94
 /** NDP router flag */
66
 	/** Retransmission timer */
115
 	/** Retransmission timer */
67
 	uint32_t retransmit;
116
 	uint32_t retransmit;
68
 	/** Options */
117
 	/** Options */
69
-	struct ndp_option option[0];
118
+	union ndp_option option[0];
70
 } __attribute__ (( packed ));
119
 } __attribute__ (( packed ));
71
 
120
 
72
 /** NDP managed address configuration */
121
 /** NDP managed address configuration */
85
 	struct ndp_router_advertisement_header radv;
134
 	struct ndp_router_advertisement_header radv;
86
 } __attribute__ (( packed ));
135
 } __attribute__ (( packed ));
87
 
136
 
88
-/** NDP source link-layer address option */
89
-#define NDP_OPT_LL_SOURCE 1
90
-
91
-/** NDP target link-layer address option */
92
-#define NDP_OPT_LL_TARGET 2
93
-
94
 extern struct neighbour_discovery ndp_discovery;
137
 extern struct neighbour_discovery ndp_discovery;
95
 
138
 
96
 /**
139
 /**

+ 47
- 0
src/net/ipv6.c View File

862
 	.aton = ipv6_sock_aton,
862
 	.aton = ipv6_sock_aton,
863
 };
863
 };
864
 
864
 
865
+/**
866
+ * Perform IPv6 stateless address autoconfiguration (SLAAC)
867
+ *
868
+ * @v netdev		Network device
869
+ * @v prefix		Prefix
870
+ * @v prefix_len	Prefix length
871
+ * @v router		Router address (or NULL)
872
+ * @ret rc		Return status code
873
+ */
874
+int ipv6_slaac ( struct net_device *netdev, struct in6_addr *prefix,
875
+		 unsigned int prefix_len, struct in6_addr *router ) {
876
+	struct ipv6_miniroute *miniroute;
877
+	struct ipv6_miniroute *tmp;
878
+	struct in6_addr address;
879
+	int check_prefix_len;
880
+	int rc;
881
+
882
+	/* Construct local address */
883
+	memcpy ( &address, prefix, sizeof ( address ) );
884
+	check_prefix_len = ipv6_eui64 ( &address, netdev );
885
+	if ( check_prefix_len < 0 ) {
886
+		rc = check_prefix_len;
887
+		DBGC ( netdev, "IPv6 %s could not construct SLAAC address: "
888
+		       "%s\n", netdev->name, strerror ( rc ) );
889
+		return rc;
890
+	}
891
+	if ( check_prefix_len != ( int ) prefix_len ) {
892
+		DBGC ( netdev, "IPv6 %s incorrect SLAAC prefix length %d "
893
+		       "(expected %d)\n", netdev->name, prefix_len,
894
+		       check_prefix_len );
895
+		return -EINVAL;
896
+	}
897
+
898
+	/* Delete any existing SLAAC miniroutes for this prefix */
899
+	list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
900
+		if ( ipv6_is_local ( miniroute, &address ) )
901
+			del_ipv6_miniroute ( miniroute );
902
+	}
903
+
904
+	/* Add miniroute */
905
+	miniroute = add_ipv6_miniroute ( netdev, &address, prefix_len, router );
906
+	if ( ! miniroute )
907
+		return -ENOMEM;
908
+
909
+	return 0;
910
+}
911
+
865
 /**
912
 /**
866
  * Create IPv6 network device
913
  * Create IPv6 network device
867
  *
914
  *

+ 112
- 52
src/net/ndp.c View File

62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
63
 	struct io_buffer *iobuf;
63
 	struct io_buffer *iobuf;
64
 	struct ndp_neighbour_header *neigh;
64
 	struct ndp_neighbour_header *neigh;
65
+	struct ndp_ll_addr_option *ll_addr_opt;
65
 	size_t option_len;
66
 	size_t option_len;
66
 	size_t len;
67
 	size_t len;
67
 	int rc;
68
 	int rc;
68
 
69
 
69
 	/* Allocate and populate buffer */
70
 	/* Allocate and populate buffer */
70
-	option_len = ( ( sizeof ( neigh->option[0] ) +
71
+	option_len = ( ( sizeof ( *ll_addr_opt ) +
71
 			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
72
 			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
72
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
73
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
73
 	len = ( sizeof ( *neigh ) + option_len );
74
 	len = ( sizeof ( *neigh ) + option_len );
80
 	neigh->icmp.type = icmp_type;
81
 	neigh->icmp.type = icmp_type;
81
 	neigh->flags = flags;
82
 	neigh->flags = flags;
82
 	memcpy ( &neigh->target, target, sizeof ( neigh->target ) );
83
 	memcpy ( &neigh->target, target, sizeof ( neigh->target ) );
83
-	neigh->option[0].type = option_type;
84
-	neigh->option[0].blocks = ( option_len / NDP_OPTION_BLKSZ );
85
-	memcpy ( neigh->option[0].value, netdev->ll_addr,
84
+	ll_addr_opt = &neigh->option[0].ll_addr;
85
+	ll_addr_opt->header.type = option_type;
86
+	ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
87
+	memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
86
 		 ll_protocol->ll_addr_len );
88
 		 ll_protocol->ll_addr_len );
87
 	neigh->icmp.chksum = tcpip_chksum ( neigh, len );
89
 	neigh->icmp.chksum = tcpip_chksum ( neigh, len );
88
 
90
 
143
  * @v netdev		Network device
145
  * @v netdev		Network device
144
  * @v sin6_src		Source socket address
146
  * @v sin6_src		Source socket address
145
  * @v ndp		NDP packet
147
  * @v ndp		NDP packet
146
- * @v ll_addr		Source link-layer address
147
- * @v ll_addr_len	Source link-layer address length
148
+ * @v option		NDP option
149
+ * @v len		NDP option length
148
  * @ret rc		Return status code
150
  * @ret rc		Return status code
149
  */
151
  */
150
 static int
152
 static int
151
 ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
153
 ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
152
 					  struct sockaddr_in6 *sin6_src,
154
 					  struct sockaddr_in6 *sin6_src,
153
 					  union ndp_header *ndp,
155
 					  union ndp_header *ndp,
154
-					  const void *ll_addr,
155
-					  size_t ll_addr_len ) {
156
+					  union ndp_option *option,
157
+					  size_t len ) {
156
 	struct ndp_neighbour_header *neigh = &ndp->neigh;
158
 	struct ndp_neighbour_header *neigh = &ndp->neigh;
159
+	struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
157
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
160
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
158
 	int rc;
161
 	int rc;
159
 
162
 
164
 		return 0;
167
 		return 0;
165
 
168
 
166
 	/* Sanity check */
169
 	/* Sanity check */
167
-	if ( ll_addr_len < ll_protocol->ll_addr_len ) {
170
+	if ( offsetof ( typeof ( *ll_addr_opt ),
171
+			ll_addr[ll_protocol->ll_addr_len] ) > len ) {
168
 		DBGC ( netdev, "NDP neighbour solicitation link-layer address "
172
 		DBGC ( netdev, "NDP neighbour solicitation link-layer address "
169
-		       "too short at %zd bytes (min %d bytes)\n",
170
-		       ll_addr_len, ll_protocol->ll_addr_len );
173
+		       "option too short at %zd bytes\n", len );
171
 		return -EINVAL;
174
 		return -EINVAL;
172
 	}
175
 	}
173
 
176
 
174
 	/* Create or update neighbour cache entry */
177
 	/* Create or update neighbour cache entry */
175
 	if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
178
 	if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
176
 				       &sin6_src->sin6_addr,
179
 				       &sin6_src->sin6_addr,
177
-				       ll_addr ) ) != 0 ) {
180
+				       ll_addr_opt->ll_addr ) ) != 0 ) {
178
 		DBGC ( netdev, "NDP could not define %s => %s: %s\n",
181
 		DBGC ( netdev, "NDP could not define %s => %s: %s\n",
179
 		       inet6_ntoa ( &sin6_src->sin6_addr ),
182
 		       inet6_ntoa ( &sin6_src->sin6_addr ),
180
-		       ll_protocol->ntoa ( ll_addr ), strerror ( rc ) );
183
+		       ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
184
+		       strerror ( rc ) );
181
 		return rc;
185
 		return rc;
182
 	}
186
 	}
183
 
187
 
199
  * @v netdev		Network device
203
  * @v netdev		Network device
200
  * @v sin6_src		Source socket address
204
  * @v sin6_src		Source socket address
201
  * @v ndp		NDP packet
205
  * @v ndp		NDP packet
202
- * @v ll_addr		Target link-layer address
203
- * @v ll_addr_len	Target link-layer address length
206
+ * @v option		NDP option
207
+ * @v len		NDP option length
204
  * @ret rc		Return status code
208
  * @ret rc		Return status code
205
  */
209
  */
206
 static int
210
 static int
208
 					   struct sockaddr_in6 *sin6_src
212
 					   struct sockaddr_in6 *sin6_src
209
 						   __unused,
213
 						   __unused,
210
 					   union ndp_header *ndp,
214
 					   union ndp_header *ndp,
211
-					   const void *ll_addr,
212
-					   size_t ll_addr_len ) {
215
+					   union ndp_option *option,
216
+					   size_t len ) {
213
 	struct ndp_neighbour_header *neigh = &ndp->neigh;
217
 	struct ndp_neighbour_header *neigh = &ndp->neigh;
218
+	struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
214
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
219
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
215
 	int rc;
220
 	int rc;
216
 
221
 
217
 	/* Sanity check */
222
 	/* Sanity check */
218
-	if ( ll_addr_len < ll_protocol->ll_addr_len ) {
223
+	if ( offsetof ( typeof ( *ll_addr_opt ),
224
+			ll_addr[ll_protocol->ll_addr_len] ) > len ) {
219
 		DBGC ( netdev, "NDP neighbour advertisement link-layer address "
225
 		DBGC ( netdev, "NDP neighbour advertisement link-layer address "
220
-		       "too short at %zd bytes (min %d bytes)\n",
221
-		       ll_addr_len, ll_protocol->ll_addr_len );
226
+		       "option too short at %zd bytes\n", len );
222
 		return -EINVAL;
227
 		return -EINVAL;
223
 	}
228
 	}
224
 
229
 
225
 	/* Update neighbour cache entry, if any */
230
 	/* Update neighbour cache entry, if any */
226
 	if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
231
 	if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
227
-				       ll_addr ) ) != 0 ) {
232
+				       ll_addr_opt->ll_addr ) ) != 0 ) {
228
 		DBGC ( netdev, "NDP could not update %s => %s: %s\n",
233
 		DBGC ( netdev, "NDP could not update %s => %s: %s\n",
229
 		       inet6_ntoa ( &neigh->target ),
234
 		       inet6_ntoa ( &neigh->target ),
230
-		       ll_protocol->ntoa ( ll_addr ), strerror ( rc ) );
235
+		       ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
236
+		       strerror ( rc ) );
231
 		return rc;
237
 		return rc;
232
 	}
238
 	}
233
 
239
 
240
  * @v netdev		Network device
246
  * @v netdev		Network device
241
  * @v sin6_src		Source socket address
247
  * @v sin6_src		Source socket address
242
  * @v ndp		NDP packet
248
  * @v ndp		NDP packet
243
- * @v ll_addr		Target link-layer address
244
- * @v ll_addr_len	Target link-layer address length
249
+ * @v option		NDP option
250
+ * @v len		NDP option length
245
  * @ret rc		Return status code
251
  * @ret rc		Return status code
246
  */
252
  */
247
 static int
253
 static int
248
 ndp_rx_router_advertisement_ll_source ( struct net_device *netdev,
254
 ndp_rx_router_advertisement_ll_source ( struct net_device *netdev,
249
 					struct sockaddr_in6 *sin6_src,
255
 					struct sockaddr_in6 *sin6_src,
250
 					union ndp_header *ndp __unused,
256
 					union ndp_header *ndp __unused,
251
-					const void *ll_addr,
252
-					size_t ll_addr_len ) {
257
+					union ndp_option *option, size_t len ) {
258
+	struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
253
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
259
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
254
 	int rc;
260
 	int rc;
255
 
261
 
256
 	/* Sanity check */
262
 	/* Sanity check */
257
-	if ( ll_addr_len < ll_protocol->ll_addr_len ) {
263
+	if ( offsetof ( typeof ( *ll_addr_opt ),
264
+			ll_addr[ll_protocol->ll_addr_len] ) > len ) {
258
 		DBGC ( netdev, "NDP router advertisement link-layer address "
265
 		DBGC ( netdev, "NDP router advertisement link-layer address "
259
-		       "too short at %zd bytes (min %d bytes)\n",
260
-		       ll_addr_len, ll_protocol->ll_addr_len );
266
+		       "option too short at %zd bytes\n", len );
261
 		return -EINVAL;
267
 		return -EINVAL;
262
 	}
268
 	}
263
 
269
 
264
 	/* Define neighbour cache entry */
270
 	/* Define neighbour cache entry */
265
 	if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
271
 	if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
266
 				       &sin6_src->sin6_addr,
272
 				       &sin6_src->sin6_addr,
267
-				       ll_addr ) ) != 0 ) {
273
+				       ll_addr_opt->ll_addr ) ) != 0 ) {
268
 		DBGC ( netdev, "NDP could not define %s => %s: %s\n",
274
 		DBGC ( netdev, "NDP could not define %s => %s: %s\n",
269
 		       inet6_ntoa ( &sin6_src->sin6_addr ),
275
 		       inet6_ntoa ( &sin6_src->sin6_addr ),
270
-		       ll_protocol->ntoa ( ll_addr ), strerror ( rc ) );
276
+		       ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
277
+		       strerror ( rc ) );
271
 		return rc;
278
 		return rc;
272
 	}
279
 	}
273
 
280
 
274
 	return 0;
281
 	return 0;
275
 }
282
 }
276
 
283
 
284
+/**
285
+ * Process NDP router advertisement prefix information option
286
+ *
287
+ * @v netdev		Network device
288
+ * @v sin6_src		Source socket address
289
+ * @v ndp		NDP packet
290
+ * @v option		NDP option
291
+ * @v len		NDP option length
292
+ * @ret rc		Return status code
293
+ */
294
+static int
295
+ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
296
+				     struct sockaddr_in6 *sin6_src,
297
+				     union ndp_header *ndp,
298
+				     union ndp_option *option, size_t len ) {
299
+	struct ndp_router_advertisement_header *radv = &ndp->radv;
300
+	struct ndp_prefix_information_option *prefix_opt = &option->prefix;
301
+	struct in6_addr *router = &sin6_src->sin6_addr;
302
+	int rc;
303
+
304
+	/* Sanity check */
305
+	if ( sizeof ( *prefix_opt ) > len ) {
306
+		DBGC ( netdev, "NDP router advertisement prefix option too "
307
+		       "short at %zd bytes\n", len );
308
+		return -EINVAL;
309
+	}
310
+	DBGC ( netdev, "NDP found %sdefault router %s ",
311
+	       ( radv->lifetime ? "" : "non-" ),
312
+	       inet6_ntoa ( &sin6_src->sin6_addr ) );
313
+	DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n",
314
+	       ( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
315
+	       ( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ),
316
+	       inet6_ntoa ( &prefix_opt->prefix ),
317
+	       prefix_opt->prefix_len );
318
+
319
+	/* Perform stateless address autoconfiguration, if applicable */
320
+	if ( ( prefix_opt->flags &
321
+	       ( NDP_PREFIX_ON_LINK | NDP_PREFIX_AUTONOMOUS ) ) ==
322
+	     ( NDP_PREFIX_ON_LINK | NDP_PREFIX_AUTONOMOUS ) ) {
323
+		if ( ( rc = ipv6_slaac ( netdev, &prefix_opt->prefix,
324
+					 prefix_opt->prefix_len,
325
+					 ( radv->lifetime ?
326
+					   router : NULL ) ) ) != 0 ) {
327
+			DBGC ( netdev, "NDP could not autoconfigure prefix %s/"
328
+			       "%d: %s\n", inet6_ntoa ( &prefix_opt->prefix ),
329
+			       prefix_opt->prefix_len, strerror ( rc ) );
330
+			return rc;
331
+		}
332
+	}
333
+
334
+	return 0;
335
+}
336
+
277
 /** An NDP option handler */
337
 /** An NDP option handler */
278
 struct ndp_option_handler {
338
 struct ndp_option_handler {
279
 	/** ICMPv6 type */
339
 	/** ICMPv6 type */
286
 	 * @v netdev		Network device
346
 	 * @v netdev		Network device
287
 	 * @v sin6_src		Source socket address
347
 	 * @v sin6_src		Source socket address
288
 	 * @v ndp		NDP packet
348
 	 * @v ndp		NDP packet
289
-	 * @v value		Option value
290
-	 * @v len		Option length
349
+	 * @v option		NDP option
291
 	 * @ret rc		Return status code
350
 	 * @ret rc		Return status code
292
 	 */
351
 	 */
293
 	int ( * rx ) ( struct net_device *netdev, struct sockaddr_in6 *sin6_src,
352
 	int ( * rx ) ( struct net_device *netdev, struct sockaddr_in6 *sin6_src,
294
-		       union ndp_header *ndp, const void *value, size_t len );
353
+		       union ndp_header *ndp, union ndp_option *option,
354
+		       size_t len );
295
 };
355
 };
296
 
356
 
297
 /** NDP option handlers */
357
 /** NDP option handlers */
311
 		.option_type = NDP_OPT_LL_SOURCE,
371
 		.option_type = NDP_OPT_LL_SOURCE,
312
 		.rx = ndp_rx_router_advertisement_ll_source,
372
 		.rx = ndp_rx_router_advertisement_ll_source,
313
 	},
373
 	},
374
+	{
375
+		.icmp_type = ICMPV6_ROUTER_ADVERTISEMENT,
376
+		.option_type = NDP_OPT_PREFIX,
377
+		.rx = ndp_rx_router_advertisement_prefix,
378
+	},
314
 };
379
 };
315
 
380
 
316
 /**
381
 /**
319
  * @v netdev		Network device
384
  * @v netdev		Network device
320
  * @v sin6_src		Source socket address
385
  * @v sin6_src		Source socket address
321
  * @v ndp		NDP packet
386
  * @v ndp		NDP packet
322
- * @v type		Option type
323
- * @v value		Option value
387
+ * @v option		NDP option
324
  * @v len		Option length
388
  * @v len		Option length
325
  * @ret rc		Return status code
389
  * @ret rc		Return status code
326
  */
390
  */
327
 static int ndp_rx_option ( struct net_device *netdev,
391
 static int ndp_rx_option ( struct net_device *netdev,
328
-			   struct sockaddr_in6 *sin6_src,
329
-			   union ndp_header *ndp, unsigned int type,
330
-			   const void *value, size_t len ) {
392
+			   struct sockaddr_in6 *sin6_src, union ndp_header *ndp,
393
+			   union ndp_option *option, size_t len ) {
331
 	struct ndp_option_handler *handler;
394
 	struct ndp_option_handler *handler;
332
 	unsigned int i;
395
 	unsigned int i;
333
 
396
 
336
 			    sizeof ( ndp_option_handlers[0] ) ) ; i++ ) {
399
 			    sizeof ( ndp_option_handlers[0] ) ) ; i++ ) {
337
 		handler = &ndp_option_handlers[i];
400
 		handler = &ndp_option_handlers[i];
338
 		if ( ( handler->icmp_type == ndp->icmp.type ) &&
401
 		if ( ( handler->icmp_type == ndp->icmp.type ) &&
339
-		     ( handler->option_type == type ) ) {
402
+		     ( handler->option_type == option->header.type ) ) {
340
 			return handler->rx ( netdev, sin6_src, ndp,
403
 			return handler->rx ( netdev, sin6_src, ndp,
341
-					     value, len );
404
+					     option, len );
342
 		}
405
 		}
343
 	}
406
 	}
344
 
407
 
360
 		    struct sockaddr_in6 *sin6_src,
423
 		    struct sockaddr_in6 *sin6_src,
361
 		    size_t offset ) {
424
 		    size_t offset ) {
362
 	union ndp_header *ndp = iobuf->data;
425
 	union ndp_header *ndp = iobuf->data;
363
-	struct ndp_option *option;
426
+	union ndp_option *option;
364
 	size_t remaining;
427
 	size_t remaining;
365
 	size_t option_len;
428
 	size_t option_len;
366
-	size_t option_value_len;
367
 	int rc;
429
 	int rc;
368
 
430
 
369
 	/* Sanity check */
431
 	/* Sanity check */
380
 	while ( remaining ) {
442
 	while ( remaining ) {
381
 
443
 
382
 		/* Sanity check */
444
 		/* Sanity check */
383
-		if ( ( remaining < sizeof ( *option ) ) ||
384
-		     ( option->blocks == 0 ) ||
385
-		     ( remaining < ( option->blocks * NDP_OPTION_BLKSZ ) ) ) {
445
+		if ( ( remaining < sizeof ( option->header ) ) ||
446
+		     ( option->header.blocks == 0 ) ||
447
+		     ( remaining < ( option->header.blocks *
448
+				     NDP_OPTION_BLKSZ ) ) ) {
386
 			DBGC ( netdev, "NDP bad option length:\n" );
449
 			DBGC ( netdev, "NDP bad option length:\n" );
387
 			DBGC_HDA ( netdev, 0, option, remaining );
450
 			DBGC_HDA ( netdev, 0, option, remaining );
388
 			rc = -EINVAL;
451
 			rc = -EINVAL;
389
 			goto done;
452
 			goto done;
390
 		}
453
 		}
391
-		option_len = ( option->blocks * NDP_OPTION_BLKSZ );
392
-		option_value_len = ( option_len - sizeof ( *option ) );
454
+		option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
393
 
455
 
394
 		/* Handle option */
456
 		/* Handle option */
395
-		if ( ( rc = ndp_rx_option ( netdev, sin6_src, ndp,
396
-					    option->type, option->value,
397
-					    option_value_len ) ) != 0 ) {
457
+		if ( ( rc = ndp_rx_option ( netdev, sin6_src, ndp, option,
458
+					    option_len ) ) != 0 )
398
 			goto done;
459
 			goto done;
399
-		}
400
 
460
 
401
 		/* Move to next option */
461
 		/* Move to next option */
402
 		option = ( ( ( void * ) option ) + option_len );
462
 		option = ( ( ( void * ) option ) + option_len );

Loading…
Cancel
Save