ソースを参照

[ipv6] Extract link layer addresses from router advertisements

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10年前
コミット
2dca2e6ade
3個のファイルの変更188行の追加54行の削除
  1. 5
    2
      src/include/ipxe/icmpv6.h
  2. 39
    5
      src/include/ipxe/ndp.h
  3. 144
    47
      src/net/ndp.c

+ 5
- 2
src/include/ipxe/icmpv6.h ファイルの表示

@@ -46,11 +46,14 @@ struct icmpv6_handler {
46 46
 /** ICMPv6 echo reply */
47 47
 #define ICMPV6_ECHO_REPLY 129
48 48
 
49
+/** ICMPv6 router advertisement */
50
+#define ICMPV6_ROUTER_ADVERTISEMENT 134
51
+
49 52
 /** ICMPv6 neighbour solicitation */
50
-#define ICMPV6_NDP_NEIGHBOUR_SOLICITATION 135
53
+#define ICMPV6_NEIGHBOUR_SOLICITATION 135
51 54
 
52 55
 /** ICMPv6 neighbour advertisement */
53
-#define ICMPV6_NDP_NEIGHBOUR_ADVERTISEMENT 136
56
+#define ICMPV6_NEIGHBOUR_ADVERTISEMENT 136
54 57
 
55 58
 extern struct tcpip_protocol icmpv6_protocol __tcpip_protocol;
56 59
 

+ 39
- 5
src/include/ipxe/ndp.h ファイルの表示

@@ -28,8 +28,8 @@ struct ndp_option {
28 28
 /** NDP option block size */
29 29
 #define NDP_OPTION_BLKSZ 8
30 30
 
31
-/** An NDP header */
32
-struct ndp_header {
31
+/** An NDP neighbour solicitation or advertisement header */
32
+struct ndp_neighbour_header {
33 33
 	/** ICMPv6 header */
34 34
 	struct icmp_header icmp;
35 35
 	/** Flags */
@@ -43,13 +43,47 @@ struct ndp_header {
43 43
 } __attribute__ (( packed ));
44 44
 
45 45
 /** NDP router flag */
46
-#define NDP_ROUTER 0x80
46
+#define NDP_NEIGHBOUR_ROUTER 0x80
47 47
 
48 48
 /** NDP solicited flag */
49
-#define NDP_SOLICITED 0x40
49
+#define NDP_NEIGHBOUR_SOLICITED 0x40
50 50
 
51 51
 /** NDP override flag */
52
-#define NDP_OVERRIDE 0x20
52
+#define NDP_NEIGHBOUR_OVERRIDE 0x20
53
+
54
+/** An NDP router advertisement header */
55
+struct ndp_router_advertisement_header {
56
+	/** ICMPv6 header */
57
+	struct icmp_header icmp;
58
+	/** Current hop limit */
59
+	uint8_t hop_limit;
60
+	/** Flags */
61
+	uint8_t flags;
62
+	/** Router lifetime */
63
+	uint16_t lifetime;
64
+	/** Reachable time */
65
+	uint32_t reachable;
66
+	/** Retransmission timer */
67
+	uint32_t retransmit;
68
+	/** Options */
69
+	struct ndp_option option[0];
70
+} __attribute__ (( packed ));
71
+
72
+/** NDP managed address configuration */
73
+#define NDP_ROUTER_MANAGED 0x80
74
+
75
+/** NDP other configuration */
76
+#define NDP_ROUTER_OTHER 0x40
77
+
78
+/** An NDP header */
79
+union ndp_header {
80
+	/** ICMPv6 header */
81
+	struct icmp_header icmp;
82
+	/** Neighbour solicitation or advertisement header */
83
+	struct ndp_neighbour_header neigh;
84
+	/** Router advertisement header */
85
+	struct ndp_router_advertisement_header radv;
86
+} __attribute__ (( packed ));
53 87
 
54 88
 /** NDP source link-layer address option */
55 89
 #define NDP_OPT_LL_SOURCE 1

+ 144
- 47
src/net/ndp.c ファイルの表示

@@ -61,34 +61,34 @@ static int ndp_tx_neighbour ( struct net_device *netdev,
61 61
 		( ( struct sockaddr_tcpip * ) sin6_dest );
62 62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
63 63
 	struct io_buffer *iobuf;
64
-	struct ndp_header *ndp;
64
+	struct ndp_neighbour_header *neigh;
65 65
 	size_t option_len;
66 66
 	size_t len;
67 67
 	int rc;
68 68
 
69 69
 	/* Allocate and populate buffer */
70
-	option_len = ( ( sizeof ( ndp->option[0] ) + ll_protocol->ll_addr_len +
71
-			 NDP_OPTION_BLKSZ - 1 ) &
70
+	option_len = ( ( sizeof ( neigh->option[0] ) +
71
+			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
72 72
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
73
-	len = ( sizeof ( *ndp ) + option_len );
73
+	len = ( sizeof ( *neigh ) + option_len );
74 74
 	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
75 75
 	if ( ! iobuf )
76 76
 		return -ENOMEM;
77 77
 	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
78
-	ndp = iob_put ( iobuf, len );
79
-	memset ( ndp, 0, len );
80
-	ndp->icmp.type = icmp_type;
81
-	ndp->flags = flags;
82
-	memcpy ( &ndp->target, target, sizeof ( ndp->target ) );
83
-	ndp->option[0].type = option_type;
84
-	ndp->option[0].blocks = ( option_len / NDP_OPTION_BLKSZ );
85
-	memcpy ( ndp->option[0].value, netdev->ll_addr,
78
+	neigh = iob_put ( iobuf, len );
79
+	memset ( neigh, 0, len );
80
+	neigh->icmp.type = icmp_type;
81
+	neigh->flags = flags;
82
+	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,
86 86
 		 ll_protocol->ll_addr_len );
87
-	ndp->icmp.chksum = tcpip_chksum ( ndp, len );
87
+	neigh->icmp.chksum = tcpip_chksum ( neigh, len );
88 88
 
89 89
 	/* Transmit packet */
90 90
 	if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
91
-			       netdev, &ndp->icmp.chksum ) ) != 0 ) {
91
+			       netdev, &neigh->icmp.chksum ) ) != 0 ) {
92 92
 		DBGC ( netdev, "NDP could not transmit packet: %s\n",
93 93
 		       strerror ( rc ) );
94 94
 		return rc;
@@ -127,7 +127,7 @@ static int ndp_tx_request ( struct net_device *netdev,
127 127
 
128 128
 	/* Transmit neighbour discovery packet */
129 129
 	return ndp_tx_neighbour ( netdev, &sin6_src, &sin6_dest, net_dest,
130
-				  ICMPV6_NDP_NEIGHBOUR_SOLICITATION, 0,
130
+				  ICMPV6_NEIGHBOUR_SOLICITATION, 0,
131 131
 				  NDP_OPT_LL_SOURCE );
132 132
 }
133 133
 
@@ -147,18 +147,20 @@ struct neighbour_discovery ndp_discovery = {
147 147
  * @v ll_addr_len	Source link-layer address length
148 148
  * @ret rc		Return status code
149 149
  */
150
-static int ndp_rx_neighbour_solicitation ( struct net_device *netdev,
151
-					   struct sockaddr_in6 *sin6_src,
152
-					   struct ndp_header *ndp __unused,
153
-					   const void *ll_addr,
154
-					   size_t ll_addr_len ) {
150
+static int
151
+ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
152
+					  struct sockaddr_in6 *sin6_src,
153
+					  union ndp_header *ndp,
154
+					  const void *ll_addr,
155
+					  size_t ll_addr_len ) {
156
+	struct ndp_neighbour_header *neigh = &ndp->neigh;
155 157
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
156 158
 	int rc;
157 159
 
158 160
 	/* Silently ignore neighbour solicitations for addresses we do
159 161
 	 * not own.
160 162
 	 */
161
-	if ( ! ipv6_has_addr ( netdev, &ndp->target ) )
163
+	if ( ! ipv6_has_addr ( netdev, &neigh->target ) )
162 164
 		return 0;
163 165
 
164 166
 	/* Sanity check */
@@ -180,9 +182,10 @@ static int ndp_rx_neighbour_solicitation ( struct net_device *netdev,
180 182
 	}
181 183
 
182 184
 	/* Send neighbour advertisement */
183
-	if ( ( rc = ndp_tx_neighbour ( netdev, NULL, sin6_src, &ndp->target,
184
-				       ICMPV6_NDP_NEIGHBOUR_ADVERTISEMENT,
185
-				       ( NDP_SOLICITED | NDP_OVERRIDE ),
185
+	if ( ( rc = ndp_tx_neighbour ( netdev, NULL, sin6_src, &neigh->target,
186
+				       ICMPV6_NEIGHBOUR_ADVERTISEMENT,
187
+				       ( NDP_NEIGHBOUR_SOLICITED |
188
+					 NDP_NEIGHBOUR_OVERRIDE ),
186 189
 				       NDP_OPT_LL_TARGET ) ) != 0 ) {
187 190
 		return rc;
188 191
 	}
@@ -201,10 +204,13 @@ static int ndp_rx_neighbour_solicitation ( struct net_device *netdev,
201 204
  * @ret rc		Return status code
202 205
  */
203 206
 static int
204
-ndp_rx_neighbour_advertisement ( struct net_device *netdev,
205
-				 struct sockaddr_in6 *sin6_src __unused,
206
-				 struct ndp_header *ndp, const void *ll_addr,
207
-				 size_t ll_addr_len ) {
207
+ndp_rx_neighbour_advertisement_ll_target ( struct net_device *netdev,
208
+					   struct sockaddr_in6 *sin6_src
209
+						   __unused,
210
+					   union ndp_header *ndp,
211
+					   const void *ll_addr,
212
+					   size_t ll_addr_len ) {
213
+	struct ndp_neighbour_header *neigh = &ndp->neigh;
208 214
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
209 215
 	int rc;
210 216
 
@@ -217,10 +223,50 @@ ndp_rx_neighbour_advertisement ( struct net_device *netdev,
217 223
 	}
218 224
 
219 225
 	/* Update neighbour cache entry, if any */
220
-	if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &ndp->target,
226
+	if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
221 227
 				       ll_addr ) ) != 0 ) {
222 228
 		DBGC ( netdev, "NDP could not update %s => %s: %s\n",
223
-		       inet6_ntoa ( &ndp->target ),
229
+		       inet6_ntoa ( &neigh->target ),
230
+		       ll_protocol->ntoa ( ll_addr ), strerror ( rc ) );
231
+		return rc;
232
+	}
233
+
234
+	return 0;
235
+}
236
+
237
+/**
238
+ * Process NDP router advertisement source link-layer address option
239
+ *
240
+ * @v netdev		Network device
241
+ * @v sin6_src		Source socket address
242
+ * @v ndp		NDP packet
243
+ * @v ll_addr		Target link-layer address
244
+ * @v ll_addr_len	Target link-layer address length
245
+ * @ret rc		Return status code
246
+ */
247
+static int
248
+ndp_rx_router_advertisement_ll_source ( struct net_device *netdev,
249
+					struct sockaddr_in6 *sin6_src,
250
+					union ndp_header *ndp __unused,
251
+					const void *ll_addr,
252
+					size_t ll_addr_len ) {
253
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
254
+	int rc;
255
+
256
+	/* Sanity check */
257
+	if ( ll_addr_len < ll_protocol->ll_addr_len ) {
258
+		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 );
261
+		return -EINVAL;
262
+	}
263
+
264
+	/* Define neighbour cache entry */
265
+	if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
266
+				       &sin6_src->sin6_addr,
267
+				       ll_addr ) ) != 0 ) {
268
+		DBGC ( netdev, "NDP could not define %s => %s: %s\n",
269
+		       inet6_ntoa ( &sin6_src->sin6_addr ),
224 270
 		       ll_protocol->ntoa ( ll_addr ), strerror ( rc ) );
225 271
 		return rc;
226 272
 	}
@@ -245,20 +291,25 @@ struct ndp_option_handler {
245 291
 	 * @ret rc		Return status code
246 292
 	 */
247 293
 	int ( * rx ) ( struct net_device *netdev, struct sockaddr_in6 *sin6_src,
248
-		       struct ndp_header *ndp, const void *value, size_t len );
294
+		       union ndp_header *ndp, const void *value, size_t len );
249 295
 };
250 296
 
251 297
 /** NDP option handlers */
252 298
 static struct ndp_option_handler ndp_option_handlers[] = {
253 299
 	{
254
-		.icmp_type = ICMPV6_NDP_NEIGHBOUR_SOLICITATION,
300
+		.icmp_type = ICMPV6_NEIGHBOUR_SOLICITATION,
255 301
 		.option_type = NDP_OPT_LL_SOURCE,
256
-		.rx = ndp_rx_neighbour_solicitation,
302
+		.rx = ndp_rx_neighbour_solicitation_ll_source,
257 303
 	},
258 304
 	{
259
-		.icmp_type = ICMPV6_NDP_NEIGHBOUR_ADVERTISEMENT,
305
+		.icmp_type = ICMPV6_NEIGHBOUR_ADVERTISEMENT,
260 306
 		.option_type = NDP_OPT_LL_TARGET,
261
-		.rx = ndp_rx_neighbour_advertisement,
307
+		.rx = ndp_rx_neighbour_advertisement_ll_target,
308
+	},
309
+	{
310
+		.icmp_type = ICMPV6_ROUTER_ADVERTISEMENT,
311
+		.option_type = NDP_OPT_LL_SOURCE,
312
+		.rx = ndp_rx_router_advertisement_ll_source,
262 313
 	},
263 314
 };
264 315
 
@@ -275,7 +326,7 @@ static struct ndp_option_handler ndp_option_handlers[] = {
275 326
  */
276 327
 static int ndp_rx_option ( struct net_device *netdev,
277 328
 			   struct sockaddr_in6 *sin6_src,
278
-			   struct ndp_header *ndp, unsigned int type,
329
+			   union ndp_header *ndp, unsigned int type,
279 330
 			   const void *value, size_t len ) {
280 331
 	struct ndp_option_handler *handler;
281 332
 	unsigned int i;
@@ -301,14 +352,14 @@ static int ndp_rx_option ( struct net_device *netdev,
301 352
  * @v iobuf		I/O buffer
302 353
  * @v netdev		Network device
303 354
  * @v sin6_src		Source socket address
304
- * @v sin6_dest		Destination socket address
355
+ * @v offset		Offset to NDP options
305 356
  * @ret rc		Return status code
306 357
  */
307 358
 static int ndp_rx ( struct io_buffer *iobuf,
308 359
 		    struct net_device *netdev,
309 360
 		    struct sockaddr_in6 *sin6_src,
310
-		    struct sockaddr_in6 *sin6_dest __unused ) {
311
-	struct ndp_header *ndp = iobuf->data;
361
+		    size_t offset ) {
362
+	union ndp_header *ndp = iobuf->data;
312 363
 	struct ndp_option *option;
313 364
 	size_t remaining;
314 365
 	size_t option_len;
@@ -316,16 +367,16 @@ static int ndp_rx ( struct io_buffer *iobuf,
316 367
 	int rc;
317 368
 
318 369
 	/* Sanity check */
319
-	if ( iob_len ( iobuf ) < sizeof ( *ndp ) ) {
370
+	if ( iob_len ( iobuf ) < offset ) {
320 371
 		DBGC ( netdev, "NDP packet too short at %zd bytes (min %zd "
321
-		       "bytes)\n", iob_len ( iobuf ), sizeof ( *ndp ) );
372
+		       "bytes)\n", iob_len ( iobuf ), offset );
322 373
 		rc = -EINVAL;
323 374
 		goto done;
324 375
 	}
325 376
 
326 377
 	/* Search for option */
327
-	option = ndp->option;
328
-	remaining = ( iob_len ( iobuf ) - offsetof ( typeof ( *ndp ), option ));
378
+	option = ( ( ( void * ) ndp ) + offset );
379
+	remaining = ( iob_len ( iobuf ) - offset );
329 380
 	while ( remaining ) {
330 381
 
331 382
 		/* Sanity check */
@@ -360,14 +411,60 @@ static int ndp_rx ( struct io_buffer *iobuf,
360 411
 	return rc;
361 412
 }
362 413
 
414
+/**
415
+ * Process received NDP neighbour solicitation or advertisement
416
+ *
417
+ * @v iobuf		I/O buffer
418
+ * @v netdev		Network device
419
+ * @v sin6_src		Source socket address
420
+ * @v sin6_dest		Destination socket address
421
+ * @ret rc		Return status code
422
+ */
423
+static int ndp_rx_neighbour ( struct io_buffer *iobuf,
424
+			      struct net_device *netdev,
425
+			      struct sockaddr_in6 *sin6_src,
426
+			      struct sockaddr_in6 *sin6_dest __unused ) {
427
+	union ndp_header *ndp = iobuf->data;
428
+	struct ndp_neighbour_header *neigh = &ndp->neigh;
429
+
430
+	return ndp_rx ( iobuf, netdev, sin6_src,
431
+			offsetof ( typeof ( *neigh ), option ) );
432
+}
433
+
434
+/**
435
+ * Process received NDP router advertisement
436
+ *
437
+ * @v iobuf		I/O buffer
438
+ * @v netdev		Network device
439
+ * @v sin6_src		Source socket address
440
+ * @v sin6_dest		Destination socket address
441
+ * @ret rc		Return status code
442
+ */
443
+static int
444
+ndp_rx_router_advertisement ( struct io_buffer *iobuf,
445
+			      struct net_device *netdev,
446
+			      struct sockaddr_in6 *sin6_src,
447
+			      struct sockaddr_in6 *sin6_dest __unused ) {
448
+	union ndp_header *ndp = iobuf->data;
449
+	struct ndp_router_advertisement_header *radv = &ndp->radv;
450
+
451
+	return ndp_rx ( iobuf, netdev, sin6_src,
452
+			offsetof ( typeof ( *radv ), option ) );
453
+}
454
+
455
+
363 456
 /** NDP ICMPv6 handlers */
364 457
 struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
365 458
 	{
366
-		.type = ICMPV6_NDP_NEIGHBOUR_SOLICITATION,
367
-		.rx = ndp_rx,
459
+		.type = ICMPV6_NEIGHBOUR_SOLICITATION,
460
+		.rx = ndp_rx_neighbour,
461
+	},
462
+	{
463
+		.type = ICMPV6_NEIGHBOUR_ADVERTISEMENT,
464
+		.rx = ndp_rx_neighbour,
368 465
 	},
369 466
 	{
370
-		.type = ICMPV6_NDP_NEIGHBOUR_ADVERTISEMENT,
371
-		.rx = ndp_rx,
467
+		.type = ICMPV6_ROUTER_ADVERTISEMENT,
468
+		.rx = ndp_rx_router_advertisement,
372 469
 	},
373 470
 };

読み込み中…
キャンセル
保存