Browse Source

[ipv6] Add ndp_tx_router_solicitation() to send router solicitations

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
b15dbc9cc6
5 changed files with 95 additions and 37 deletions
  1. 3
    0
      src/include/ipxe/icmpv6.h
  2. 12
    4
      src/include/ipxe/ipv6.h
  3. 14
    0
      src/include/ipxe/ndp.h
  4. 1
    0
      src/net/ipv6.c
  5. 65
    33
      src/net/ndp.c

+ 3
- 0
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 solicitation */
50
+#define ICMPV6_ROUTER_SOLICITATION 133
51
+
49
 /** ICMPv6 router advertisement */
52
 /** ICMPv6 router advertisement */
50
 #define ICMPV6_ROUTER_ADVERTISEMENT 134
53
 #define ICMPV6_ROUTER_ADVERTISEMENT 134
51
 
54
 

+ 12
- 4
src/include/ipxe/ipv6.h View File

194
 /**
194
 /**
195
  * Construct link-local address via EUI-64
195
  * Construct link-local address via EUI-64
196
  *
196
  *
197
- * @v addr		Address to construct
197
+ * @v addr		Zeroed address to construct
198
  * @v netdev		Network device
198
  * @v netdev		Network device
199
  * @ret prefix_len	Prefix length, or negative error
199
  * @ret prefix_len	Prefix length, or negative error
200
  */
200
  */
201
 static inline int ipv6_link_local ( struct in6_addr *addr,
201
 static inline int ipv6_link_local ( struct in6_addr *addr,
202
 				    struct net_device *netdev ) {
202
 				    struct net_device *netdev ) {
203
 
203
 
204
-	memset ( addr, 0, sizeof ( *addr ) );
205
 	addr->s6_addr16[0] = htons ( 0xfe80 );
204
 	addr->s6_addr16[0] = htons ( 0xfe80 );
206
 	return ipv6_eui64 ( addr, netdev );
205
 	return ipv6_eui64 ( addr, netdev );
207
 }
206
 }
209
 /**
208
 /**
210
  * Construct solicited-node multicast address
209
  * Construct solicited-node multicast address
211
  *
210
  *
212
- * @v addr		Address to construct
211
+ * @v addr		Zeroed address to construct
213
  * @v unicast		Unicast address
212
  * @v unicast		Unicast address
214
  */
213
  */
215
 static inline void ipv6_solicited_node ( struct in6_addr *addr,
214
 static inline void ipv6_solicited_node ( struct in6_addr *addr,
216
 					 const struct in6_addr *unicast ) {
215
 					 const struct in6_addr *unicast ) {
217
 
216
 
218
-	memset ( addr, 0, sizeof ( *addr ) );
219
 	addr->s6_addr16[0] = htons ( 0xff02 );
217
 	addr->s6_addr16[0] = htons ( 0xff02 );
220
 	addr->s6_addr[11] = 1;
218
 	addr->s6_addr[11] = 1;
221
 	addr->s6_addr[12] = 0xff;
219
 	addr->s6_addr[12] = 0xff;
222
 	memcpy ( &addr->s6_addr[13], &unicast->s6_addr[13], 3 );
220
 	memcpy ( &addr->s6_addr[13], &unicast->s6_addr[13], 3 );
223
 }
221
 }
224
 
222
 
223
+/**
224
+ * Construct all-routers multicast address
225
+ *
226
+ * @v addr		Zeroed address to construct
227
+ */
228
+static inline void ipv6_all_routers ( struct in6_addr *addr ) {
229
+	addr->s6_addr16[0] = htons ( 0xff02 );
230
+	addr->s6_addr[15] = 2;
231
+}
232
+
225
 extern struct list_head ipv6_miniroutes;
233
 extern struct list_head ipv6_miniroutes;
226
 
234
 
227
 extern struct net_protocol ipv6_protocol __net_protocol;
235
 extern struct net_protocol ipv6_protocol __net_protocol;

+ 14
- 0
src/include/ipxe/ndp.h View File

124
 /** NDP other configuration */
124
 /** NDP other configuration */
125
 #define NDP_ROUTER_OTHER 0x40
125
 #define NDP_ROUTER_OTHER 0x40
126
 
126
 
127
+/** An NDP router solicitation header */
128
+struct ndp_router_solicitation_header {
129
+	/** ICMPv6 header */
130
+	struct icmp_header icmp;
131
+	/** Reserved */
132
+	uint32_t reserved;
133
+	/** Options */
134
+	union ndp_option option[0];
135
+} __attribute__ (( packed ));
136
+
127
 /** An NDP header */
137
 /** An NDP header */
128
 union ndp_header {
138
 union ndp_header {
129
 	/** ICMPv6 header */
139
 	/** ICMPv6 header */
130
 	struct icmp_header icmp;
140
 	struct icmp_header icmp;
131
 	/** Neighbour solicitation or advertisement header */
141
 	/** Neighbour solicitation or advertisement header */
132
 	struct ndp_neighbour_header neigh;
142
 	struct ndp_neighbour_header neigh;
143
+	/** Router solicitation header */
144
+	struct ndp_router_solicitation_header rsol;
133
 	/** Router advertisement header */
145
 	/** Router advertisement header */
134
 	struct ndp_router_advertisement_header radv;
146
 	struct ndp_router_advertisement_header radv;
135
 } __attribute__ (( packed ));
147
 } __attribute__ (( packed ));
154
 			      &ndp_discovery, net_source, ll_source );
166
 			      &ndp_discovery, net_source, ll_source );
155
 }
167
 }
156
 
168
 
169
+extern int ndp_tx_router_solicitation ( struct net_device *netdev );
170
+
157
 #endif /* _IPXE_NDP_H */
171
 #endif /* _IPXE_NDP_H */

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

926
 	int rc;
926
 	int rc;
927
 
927
 
928
 	/* Construct link-local address from EUI-64 as per RFC 2464 */
928
 	/* Construct link-local address from EUI-64 as per RFC 2464 */
929
+	memset ( &address, 0, sizeof ( address ) );
929
 	prefix_len = ipv6_link_local ( &address, netdev );
930
 	prefix_len = ipv6_link_local ( &address, netdev );
930
 	if ( prefix_len < 0 ) {
931
 	if ( prefix_len < 0 ) {
931
 		rc = prefix_len;
932
 		rc = prefix_len;

+ 65
- 33
src/net/ndp.c View File

37
  */
37
  */
38
 
38
 
39
 /**
39
 /**
40
- * Transmit NDP neighbour solicitation/advertisement packet
40
+ * Transmit NDP packet with link-layer address option
41
  *
41
  *
42
  * @v netdev		Network device
42
  * @v netdev		Network device
43
  * @v sin6_src		Source socket address
43
  * @v sin6_src		Source socket address
44
  * @v sin6_dest		Destination socket address
44
  * @v sin6_dest		Destination socket address
45
- * @v target		Neighbour target address
46
- * @v icmp_type		ICMPv6 type
47
- * @v flags		NDP flags
45
+ * @v data		NDP header
46
+ * @v len		Size of NDP header
48
  * @v option_type	NDP option type
47
  * @v option_type	NDP option type
49
  * @ret rc		Return status code
48
  * @ret rc		Return status code
50
  */
49
  */
51
-static int ndp_tx_neighbour ( struct net_device *netdev,
52
-			      struct sockaddr_in6 *sin6_src,
53
-			      struct sockaddr_in6 *sin6_dest,
54
-			      const struct in6_addr *target,
55
-			      unsigned int icmp_type,
56
-			      unsigned int flags,
57
-			      unsigned int option_type ) {
50
+static int ndp_tx_ll_addr ( struct net_device *netdev,
51
+			    struct sockaddr_in6 *sin6_src,
52
+			    struct sockaddr_in6 *sin6_dest,
53
+			    const void *data, size_t len,
54
+			    unsigned int option_type ) {
58
 	struct sockaddr_tcpip *st_src =
55
 	struct sockaddr_tcpip *st_src =
59
 		( ( struct sockaddr_tcpip * ) sin6_src );
56
 		( ( struct sockaddr_tcpip * ) sin6_src );
60
 	struct sockaddr_tcpip *st_dest =
57
 	struct sockaddr_tcpip *st_dest =
61
 		( ( struct sockaddr_tcpip * ) sin6_dest );
58
 		( ( struct sockaddr_tcpip * ) sin6_dest );
62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
59
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
63
 	struct io_buffer *iobuf;
60
 	struct io_buffer *iobuf;
64
-	struct ndp_neighbour_header *neigh;
65
 	struct ndp_ll_addr_option *ll_addr_opt;
61
 	struct ndp_ll_addr_option *ll_addr_opt;
62
+	union ndp_header *ndp;
66
 	size_t option_len;
63
 	size_t option_len;
67
-	size_t len;
68
 	int rc;
64
 	int rc;
69
 
65
 
70
 	/* Allocate and populate buffer */
66
 	/* Allocate and populate buffer */
71
 	option_len = ( ( sizeof ( *ll_addr_opt ) +
67
 	option_len = ( ( sizeof ( *ll_addr_opt ) +
72
 			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
68
 			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
73
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
69
 		       ~( NDP_OPTION_BLKSZ - 1 ) );
74
-	len = ( sizeof ( *neigh ) + option_len );
75
-	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
70
+	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len + option_len );
76
 	if ( ! iobuf )
71
 	if ( ! iobuf )
77
 		return -ENOMEM;
72
 		return -ENOMEM;
78
 	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
73
 	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
79
-	neigh = iob_put ( iobuf, len );
80
-	memset ( neigh, 0, len );
81
-	neigh->icmp.type = icmp_type;
82
-	neigh->flags = flags;
83
-	memcpy ( &neigh->target, target, sizeof ( neigh->target ) );
84
-	ll_addr_opt = &neigh->option[0].ll_addr;
74
+	memcpy ( iob_put ( iobuf, len ), data, len );
75
+	ll_addr_opt = iob_put ( iobuf, option_len );
85
 	ll_addr_opt->header.type = option_type;
76
 	ll_addr_opt->header.type = option_type;
86
 	ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
77
 	ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
87
 	memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
78
 	memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
88
 		 ll_protocol->ll_addr_len );
79
 		 ll_protocol->ll_addr_len );
89
-	neigh->icmp.chksum = tcpip_chksum ( neigh, len );
80
+	ndp = iobuf->data;
81
+	ndp->icmp.chksum = tcpip_chksum ( ndp, ( len + option_len ) );
90
 
82
 
91
 	/* Transmit packet */
83
 	/* Transmit packet */
92
 	if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
84
 	if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
93
-			       netdev, &neigh->icmp.chksum ) ) != 0 ) {
85
+			       netdev, &ndp->icmp.chksum ) ) != 0 ) {
94
 		DBGC ( netdev, "NDP could not transmit packet: %s\n",
86
 		DBGC ( netdev, "NDP could not transmit packet: %s\n",
95
 		       strerror ( rc ) );
87
 		       strerror ( rc ) );
96
 		return rc;
88
 		return rc;
113
 			    const void *net_dest, const void *net_source ) {
105
 			    const void *net_dest, const void *net_source ) {
114
 	struct sockaddr_in6 sin6_src;
106
 	struct sockaddr_in6 sin6_src;
115
 	struct sockaddr_in6 sin6_dest;
107
 	struct sockaddr_in6 sin6_dest;
108
+	struct ndp_neighbour_header neigh;
109
+	int rc;
116
 
110
 
117
 	/* Construct source address */
111
 	/* Construct source address */
118
 	memset ( &sin6_src, 0, sizeof ( sin6_src ) );
112
 	memset ( &sin6_src, 0, sizeof ( sin6_src ) );
127
 	sin6_dest.sin6_scope_id = netdev->index;
121
 	sin6_dest.sin6_scope_id = netdev->index;
128
 	ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest );
122
 	ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest );
129
 
123
 
124
+	/* Construct neighbour header */
125
+	memset ( &neigh, 0, sizeof ( neigh ) );
126
+	neigh.icmp.type = ICMPV6_NEIGHBOUR_SOLICITATION;
127
+	memcpy ( &neigh.target, net_dest, sizeof ( neigh.target ) );
128
+
130
 	/* Transmit neighbour discovery packet */
129
 	/* Transmit neighbour discovery packet */
131
-	return ndp_tx_neighbour ( netdev, &sin6_src, &sin6_dest, net_dest,
132
-				  ICMPV6_NEIGHBOUR_SOLICITATION, 0,
133
-				  NDP_OPT_LL_SOURCE );
130
+	if ( ( rc = ndp_tx_ll_addr ( netdev, &sin6_src, &sin6_dest, &neigh,
131
+				     sizeof ( neigh ),
132
+				     NDP_OPT_LL_SOURCE ) ) != 0 )
133
+		return rc;
134
+
135
+	return 0;
134
 }
136
 }
135
 
137
 
136
 /** NDP neighbour discovery protocol */
138
 /** NDP neighbour discovery protocol */
139
 	.tx_request = ndp_tx_request,
141
 	.tx_request = ndp_tx_request,
140
 };
142
 };
141
 
143
 
144
+/**
145
+ * Transmit NDP router solicitation
146
+ *
147
+ * @v netdev		Network device
148
+ * @ret rc		Return status code
149
+ */
150
+int ndp_tx_router_solicitation ( struct net_device *netdev ) {
151
+	struct ndp_router_solicitation_header rsol;
152
+	struct sockaddr_in6 sin6_dest;
153
+	int rc;
154
+
155
+	/* Construct multicast destination address */
156
+	memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
157
+	sin6_dest.sin6_family = AF_INET6;
158
+	sin6_dest.sin6_scope_id = netdev->index;
159
+	ipv6_all_routers ( &sin6_dest.sin6_addr );
160
+
161
+	/* Construct router solicitation */
162
+	memset ( &rsol, 0, sizeof ( rsol ) );
163
+	rsol.icmp.type = ICMPV6_ROUTER_SOLICITATION;
164
+
165
+	/* Transmit packet */
166
+	if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, &sin6_dest, &rsol,
167
+				     sizeof ( rsol ), NDP_OPT_LL_SOURCE ) ) !=0)
168
+		return rc;
169
+
170
+	return 0;
171
+}
172
+
142
 /**
173
 /**
143
  * Process NDP neighbour solicitation source link-layer address option
174
  * Process NDP neighbour solicitation source link-layer address option
144
  *
175
  *
185
 		return rc;
216
 		return rc;
186
 	}
217
 	}
187
 
218
 
219
+	/* Convert neighbour header to advertisement */
220
+	memset ( neigh, 0, offsetof ( typeof ( *neigh ), target ) );
221
+	neigh->icmp.type = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
222
+	neigh->flags = ( NDP_NEIGHBOUR_SOLICITED | NDP_NEIGHBOUR_OVERRIDE );
223
+
188
 	/* Send neighbour advertisement */
224
 	/* Send neighbour advertisement */
189
-	if ( ( rc = ndp_tx_neighbour ( netdev, NULL, sin6_src, &neigh->target,
190
-				       ICMPV6_NEIGHBOUR_ADVERTISEMENT,
191
-				       ( NDP_NEIGHBOUR_SOLICITED |
192
-					 NDP_NEIGHBOUR_OVERRIDE ),
193
-				       NDP_OPT_LL_TARGET ) ) != 0 ) {
225
+	if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, sin6_src, neigh,
226
+				     sizeof ( *neigh ),
227
+				     NDP_OPT_LL_TARGET ) ) != 0 )
194
 		return rc;
228
 		return rc;
195
-	}
196
 
229
 
197
 	return 0;
230
 	return 0;
198
 }
231
 }
512
 			offsetof ( typeof ( *radv ), option ) );
545
 			offsetof ( typeof ( *radv ), option ) );
513
 }
546
 }
514
 
547
 
515
-
516
 /** NDP ICMPv6 handlers */
548
 /** NDP ICMPv6 handlers */
517
 struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
549
 struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
518
 	{
550
 	{

Loading…
Cancel
Save