浏览代码

[ipv6] Support stateless address autoconfiguration (SLAAC)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 年前
父节点
当前提交
33652880a7
共有 4 个文件被更改,包括 235 次插入70 次删除
  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 查看文件

@@ -173,26 +173,39 @@ struct ipv6_miniroute {
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 179
  * @v netdev		Network device
180 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 184
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
185 185
 	const void *ll_addr = netdev->ll_addr;
186 186
 	int rc;
187 187
 
188
-	memset ( addr, 0, sizeof ( *addr ) );
189
-	addr->s6_addr16[0] = htons ( 0xfe80 );
190 188
 	if ( ( rc = ll_protocol->eui64 ( ll_addr, &addr->s6_addr[8] ) ) != 0 )
191 189
 		return rc;
192 190
 	addr->s6_addr[8] ^= 0x02;
193 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 210
  * Construct solicited-node multicast address
198 211
  *
@@ -214,5 +227,7 @@ extern struct list_head ipv6_miniroutes;
214 227
 extern struct net_protocol ipv6_protocol __net_protocol;
215 228
 
216 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 233
 #endif /* _IPXE_IPV6_H */

+ 55
- 12
src/include/ipxe/ndp.h 查看文件

@@ -15,19 +15,68 @@ FILE_LICENCE ( GPL2_OR_LATER );
15 15
 #include <ipxe/icmpv6.h>
16 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 20
 	/** Type */
21 21
 	uint8_t type;
22 22
 	/** Length (in blocks of 8 bytes) */
23 23
 	uint8_t blocks;
24
-	/** Value */
25
-	uint8_t value[0];
26 24
 } __attribute__ (( packed ));
27 25
 
28 26
 /** NDP option block size */
29 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 80
 /** An NDP neighbour solicitation or advertisement header */
32 81
 struct ndp_neighbour_header {
33 82
 	/** ICMPv6 header */
@@ -39,7 +88,7 @@ struct ndp_neighbour_header {
39 88
 	/** Target address */
40 89
 	struct in6_addr target;
41 90
 	/** Options */
42
-	struct ndp_option option[0];
91
+	union ndp_option option[0];
43 92
 } __attribute__ (( packed ));
44 93
 
45 94
 /** NDP router flag */
@@ -66,7 +115,7 @@ struct ndp_router_advertisement_header {
66 115
 	/** Retransmission timer */
67 116
 	uint32_t retransmit;
68 117
 	/** Options */
69
-	struct ndp_option option[0];
118
+	union ndp_option option[0];
70 119
 } __attribute__ (( packed ));
71 120
 
72 121
 /** NDP managed address configuration */
@@ -85,12 +134,6 @@ union ndp_header {
85 134
 	struct ndp_router_advertisement_header radv;
86 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 137
 extern struct neighbour_discovery ndp_discovery;
95 138
 
96 139
 /**

+ 47
- 0
src/net/ipv6.c 查看文件

@@ -862,6 +862,53 @@ struct sockaddr_converter ipv6_sockaddr_converter __sockaddr_converter = {
862 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 913
  * Create IPv6 network device
867 914
  *

+ 112
- 52
src/net/ndp.c 查看文件

@@ -62,12 +62,13 @@ static int ndp_tx_neighbour ( struct net_device *netdev,
62 62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
63 63
 	struct io_buffer *iobuf;
64 64
 	struct ndp_neighbour_header *neigh;
65
+	struct ndp_ll_addr_option *ll_addr_opt;
65 66
 	size_t option_len;
66 67
 	size_t len;
67 68
 	int rc;
68 69
 
69 70
 	/* Allocate and populate buffer */
70
-	option_len = ( ( sizeof ( neigh->option[0] ) +
71
+	option_len = ( ( sizeof ( *ll_addr_opt ) +
71 72
 			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
72 73
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
73 74
 	len = ( sizeof ( *neigh ) + option_len );
@@ -80,9 +81,10 @@ static int ndp_tx_neighbour ( struct net_device *netdev,
80 81
 	neigh->icmp.type = icmp_type;
81 82
 	neigh->flags = flags;
82 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 88
 		 ll_protocol->ll_addr_len );
87 89
 	neigh->icmp.chksum = tcpip_chksum ( neigh, len );
88 90
 
@@ -143,17 +145,18 @@ struct neighbour_discovery ndp_discovery = {
143 145
  * @v netdev		Network device
144 146
  * @v sin6_src		Source socket address
145 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 150
  * @ret rc		Return status code
149 151
  */
150 152
 static int
151 153
 ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
152 154
 					  struct sockaddr_in6 *sin6_src,
153 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 158
 	struct ndp_neighbour_header *neigh = &ndp->neigh;
159
+	struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
157 160
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
158 161
 	int rc;
159 162
 
@@ -164,20 +167,21 @@ ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
164 167
 		return 0;
165 168
 
166 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 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 174
 		return -EINVAL;
172 175
 	}
173 176
 
174 177
 	/* Create or update neighbour cache entry */
175 178
 	if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
176 179
 				       &sin6_src->sin6_addr,
177
-				       ll_addr ) ) != 0 ) {
180
+				       ll_addr_opt->ll_addr ) ) != 0 ) {
178 181
 		DBGC ( netdev, "NDP could not define %s => %s: %s\n",
179 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 185
 		return rc;
182 186
 	}
183 187
 
@@ -199,8 +203,8 @@ ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
199 203
  * @v netdev		Network device
200 204
  * @v sin6_src		Source socket address
201 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 208
  * @ret rc		Return status code
205 209
  */
206 210
 static int
@@ -208,26 +212,28 @@ ndp_rx_neighbour_advertisement_ll_target ( struct net_device *netdev,
208 212
 					   struct sockaddr_in6 *sin6_src
209 213
 						   __unused,
210 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 217
 	struct ndp_neighbour_header *neigh = &ndp->neigh;
218
+	struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
214 219
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
215 220
 	int rc;
216 221
 
217 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 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 227
 		return -EINVAL;
223 228
 	}
224 229
 
225 230
 	/* Update neighbour cache entry, if any */
226 231
 	if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
227
-				       ll_addr ) ) != 0 ) {
232
+				       ll_addr_opt->ll_addr ) ) != 0 ) {
228 233
 		DBGC ( netdev, "NDP could not update %s => %s: %s\n",
229 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 237
 		return rc;
232 238
 	}
233 239
 
@@ -240,40 +246,94 @@ ndp_rx_neighbour_advertisement_ll_target ( struct net_device *netdev,
240 246
  * @v netdev		Network device
241 247
  * @v sin6_src		Source socket address
242 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 251
  * @ret rc		Return status code
246 252
  */
247 253
 static int
248 254
 ndp_rx_router_advertisement_ll_source ( struct net_device *netdev,
249 255
 					struct sockaddr_in6 *sin6_src,
250 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 259
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
254 260
 	int rc;
255 261
 
256 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 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 267
 		return -EINVAL;
262 268
 	}
263 269
 
264 270
 	/* Define neighbour cache entry */
265 271
 	if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
266 272
 				       &sin6_src->sin6_addr,
267
-				       ll_addr ) ) != 0 ) {
273
+				       ll_addr_opt->ll_addr ) ) != 0 ) {
268 274
 		DBGC ( netdev, "NDP could not define %s => %s: %s\n",
269 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 278
 		return rc;
272 279
 	}
273 280
 
274 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 337
 /** An NDP option handler */
278 338
 struct ndp_option_handler {
279 339
 	/** ICMPv6 type */
@@ -286,12 +346,12 @@ struct ndp_option_handler {
286 346
 	 * @v netdev		Network device
287 347
 	 * @v sin6_src		Source socket address
288 348
 	 * @v ndp		NDP packet
289
-	 * @v value		Option value
290
-	 * @v len		Option length
349
+	 * @v option		NDP option
291 350
 	 * @ret rc		Return status code
292 351
 	 */
293 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 357
 /** NDP option handlers */
@@ -311,6 +371,11 @@ static struct ndp_option_handler ndp_option_handlers[] = {
311 371
 		.option_type = NDP_OPT_LL_SOURCE,
312 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,15 +384,13 @@ static struct ndp_option_handler ndp_option_handlers[] = {
319 384
  * @v netdev		Network device
320 385
  * @v sin6_src		Source socket address
321 386
  * @v ndp		NDP packet
322
- * @v type		Option type
323
- * @v value		Option value
387
+ * @v option		NDP option
324 388
  * @v len		Option length
325 389
  * @ret rc		Return status code
326 390
  */
327 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 394
 	struct ndp_option_handler *handler;
332 395
 	unsigned int i;
333 396
 
@@ -336,9 +399,9 @@ static int ndp_rx_option ( struct net_device *netdev,
336 399
 			    sizeof ( ndp_option_handlers[0] ) ) ; i++ ) {
337 400
 		handler = &ndp_option_handlers[i];
338 401
 		if ( ( handler->icmp_type == ndp->icmp.type ) &&
339
-		     ( handler->option_type == type ) ) {
402
+		     ( handler->option_type == option->header.type ) ) {
340 403
 			return handler->rx ( netdev, sin6_src, ndp,
341
-					     value, len );
404
+					     option, len );
342 405
 		}
343 406
 	}
344 407
 
@@ -360,10 +423,9 @@ static int ndp_rx ( struct io_buffer *iobuf,
360 423
 		    struct sockaddr_in6 *sin6_src,
361 424
 		    size_t offset ) {
362 425
 	union ndp_header *ndp = iobuf->data;
363
-	struct ndp_option *option;
426
+	union ndp_option *option;
364 427
 	size_t remaining;
365 428
 	size_t option_len;
366
-	size_t option_value_len;
367 429
 	int rc;
368 430
 
369 431
 	/* Sanity check */
@@ -380,23 +442,21 @@ static int ndp_rx ( struct io_buffer *iobuf,
380 442
 	while ( remaining ) {
381 443
 
382 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 449
 			DBGC ( netdev, "NDP bad option length:\n" );
387 450
 			DBGC_HDA ( netdev, 0, option, remaining );
388 451
 			rc = -EINVAL;
389 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 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 459
 			goto done;
399
-		}
400 460
 
401 461
 		/* Move to next option */
402 462
 		option = ( ( ( void * ) option ) + option_len );

正在加载...
取消
保存