Browse Source

[ipv6] Extract link layer addresses from router advertisements

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
2dca2e6ade
3 changed files with 188 additions and 54 deletions
  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 View File

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

+ 39
- 5
src/include/ipxe/ndp.h View File

28
 /** NDP option block size */
28
 /** NDP option block size */
29
 #define NDP_OPTION_BLKSZ 8
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
 	/** ICMPv6 header */
33
 	/** ICMPv6 header */
34
 	struct icmp_header icmp;
34
 	struct icmp_header icmp;
35
 	/** Flags */
35
 	/** Flags */
43
 } __attribute__ (( packed ));
43
 } __attribute__ (( packed ));
44
 
44
 
45
 /** NDP router flag */
45
 /** NDP router flag */
46
-#define NDP_ROUTER 0x80
46
+#define NDP_NEIGHBOUR_ROUTER 0x80
47
 
47
 
48
 /** NDP solicited flag */
48
 /** NDP solicited flag */
49
-#define NDP_SOLICITED 0x40
49
+#define NDP_NEIGHBOUR_SOLICITED 0x40
50
 
50
 
51
 /** NDP override flag */
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
 /** NDP source link-layer address option */
88
 /** NDP source link-layer address option */
55
 #define NDP_OPT_LL_SOURCE 1
89
 #define NDP_OPT_LL_SOURCE 1

+ 144
- 47
src/net/ndp.c View File

61
 		( ( struct sockaddr_tcpip * ) sin6_dest );
61
 		( ( struct sockaddr_tcpip * ) sin6_dest );
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_header *ndp;
64
+	struct ndp_neighbour_header *neigh;
65
 	size_t option_len;
65
 	size_t option_len;
66
 	size_t len;
66
 	size_t len;
67
 	int rc;
67
 	int rc;
68
 
68
 
69
 	/* Allocate and populate buffer */
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
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
72
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
73
-	len = ( sizeof ( *ndp ) + option_len );
73
+	len = ( sizeof ( *neigh ) + option_len );
74
 	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
74
 	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
75
 	if ( ! iobuf )
75
 	if ( ! iobuf )
76
 		return -ENOMEM;
76
 		return -ENOMEM;
77
 	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
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
 		 ll_protocol->ll_addr_len );
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
 	/* Transmit packet */
89
 	/* Transmit packet */
90
 	if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
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
 		DBGC ( netdev, "NDP could not transmit packet: %s\n",
92
 		DBGC ( netdev, "NDP could not transmit packet: %s\n",
93
 		       strerror ( rc ) );
93
 		       strerror ( rc ) );
94
 		return rc;
94
 		return rc;
127
 
127
 
128
 	/* Transmit neighbour discovery packet */
128
 	/* Transmit neighbour discovery packet */
129
 	return ndp_tx_neighbour ( netdev, &sin6_src, &sin6_dest, net_dest,
129
 	return ndp_tx_neighbour ( netdev, &sin6_src, &sin6_dest, net_dest,
130
-				  ICMPV6_NDP_NEIGHBOUR_SOLICITATION, 0,
130
+				  ICMPV6_NEIGHBOUR_SOLICITATION, 0,
131
 				  NDP_OPT_LL_SOURCE );
131
 				  NDP_OPT_LL_SOURCE );
132
 }
132
 }
133
 
133
 
147
  * @v ll_addr_len	Source link-layer address length
147
  * @v ll_addr_len	Source link-layer address length
148
  * @ret rc		Return status code
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
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
157
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
156
 	int rc;
158
 	int rc;
157
 
159
 
158
 	/* Silently ignore neighbour solicitations for addresses we do
160
 	/* Silently ignore neighbour solicitations for addresses we do
159
 	 * not own.
161
 	 * not own.
160
 	 */
162
 	 */
161
-	if ( ! ipv6_has_addr ( netdev, &ndp->target ) )
163
+	if ( ! ipv6_has_addr ( netdev, &neigh->target ) )
162
 		return 0;
164
 		return 0;
163
 
165
 
164
 	/* Sanity check */
166
 	/* Sanity check */
180
 	}
182
 	}
181
 
183
 
182
 	/* Send neighbour advertisement */
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
 				       NDP_OPT_LL_TARGET ) ) != 0 ) {
189
 				       NDP_OPT_LL_TARGET ) ) != 0 ) {
187
 		return rc;
190
 		return rc;
188
 	}
191
 	}
201
  * @ret rc		Return status code
204
  * @ret rc		Return status code
202
  */
205
  */
203
 static int
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
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
214
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
209
 	int rc;
215
 	int rc;
210
 
216
 
217
 	}
223
 	}
218
 
224
 
219
 	/* Update neighbour cache entry, if any */
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
 				       ll_addr ) ) != 0 ) {
227
 				       ll_addr ) ) != 0 ) {
222
 		DBGC ( netdev, "NDP could not update %s => %s: %s\n",
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
 		       ll_protocol->ntoa ( ll_addr ), strerror ( rc ) );
270
 		       ll_protocol->ntoa ( ll_addr ), strerror ( rc ) );
225
 		return rc;
271
 		return rc;
226
 	}
272
 	}
245
 	 * @ret rc		Return status code
291
 	 * @ret rc		Return status code
246
 	 */
292
 	 */
247
 	int ( * rx ) ( struct net_device *netdev, struct sockaddr_in6 *sin6_src,
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
 /** NDP option handlers */
297
 /** NDP option handlers */
252
 static struct ndp_option_handler ndp_option_handlers[] = {
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
 		.option_type = NDP_OPT_LL_SOURCE,
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
 		.option_type = NDP_OPT_LL_TARGET,
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
  */
326
  */
276
 static int ndp_rx_option ( struct net_device *netdev,
327
 static int ndp_rx_option ( struct net_device *netdev,
277
 			   struct sockaddr_in6 *sin6_src,
328
 			   struct sockaddr_in6 *sin6_src,
278
-			   struct ndp_header *ndp, unsigned int type,
329
+			   union ndp_header *ndp, unsigned int type,
279
 			   const void *value, size_t len ) {
330
 			   const void *value, size_t len ) {
280
 	struct ndp_option_handler *handler;
331
 	struct ndp_option_handler *handler;
281
 	unsigned int i;
332
 	unsigned int i;
301
  * @v iobuf		I/O buffer
352
  * @v iobuf		I/O buffer
302
  * @v netdev		Network device
353
  * @v netdev		Network device
303
  * @v sin6_src		Source socket address
354
  * @v sin6_src		Source socket address
304
- * @v sin6_dest		Destination socket address
355
+ * @v offset		Offset to NDP options
305
  * @ret rc		Return status code
356
  * @ret rc		Return status code
306
  */
357
  */
307
 static int ndp_rx ( struct io_buffer *iobuf,
358
 static int ndp_rx ( struct io_buffer *iobuf,
308
 		    struct net_device *netdev,
359
 		    struct net_device *netdev,
309
 		    struct sockaddr_in6 *sin6_src,
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
 	struct ndp_option *option;
363
 	struct ndp_option *option;
313
 	size_t remaining;
364
 	size_t remaining;
314
 	size_t option_len;
365
 	size_t option_len;
316
 	int rc;
367
 	int rc;
317
 
368
 
318
 	/* Sanity check */
369
 	/* Sanity check */
319
-	if ( iob_len ( iobuf ) < sizeof ( *ndp ) ) {
370
+	if ( iob_len ( iobuf ) < offset ) {
320
 		DBGC ( netdev, "NDP packet too short at %zd bytes (min %zd "
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
 		rc = -EINVAL;
373
 		rc = -EINVAL;
323
 		goto done;
374
 		goto done;
324
 	}
375
 	}
325
 
376
 
326
 	/* Search for option */
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
 	while ( remaining ) {
380
 	while ( remaining ) {
330
 
381
 
331
 		/* Sanity check */
382
 		/* Sanity check */
360
 	return rc;
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
 /** NDP ICMPv6 handlers */
456
 /** NDP ICMPv6 handlers */
364
 struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
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
 };

Loading…
Cancel
Save