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,6 +46,9 @@ struct icmpv6_handler {
46 46
 /** ICMPv6 echo reply */
47 47
 #define ICMPV6_ECHO_REPLY 129
48 48
 
49
+/** ICMPv6 router solicitation */
50
+#define ICMPV6_ROUTER_SOLICITATION 133
51
+
49 52
 /** ICMPv6 router advertisement */
50 53
 #define ICMPV6_ROUTER_ADVERTISEMENT 134
51 54
 

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

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

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

@@ -124,12 +124,24 @@ struct ndp_router_advertisement_header {
124 124
 /** NDP other configuration */
125 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 137
 /** An NDP header */
128 138
 union ndp_header {
129 139
 	/** ICMPv6 header */
130 140
 	struct icmp_header icmp;
131 141
 	/** Neighbour solicitation or advertisement header */
132 142
 	struct ndp_neighbour_header neigh;
143
+	/** Router solicitation header */
144
+	struct ndp_router_solicitation_header rsol;
133 145
 	/** Router advertisement header */
134 146
 	struct ndp_router_advertisement_header radv;
135 147
 } __attribute__ (( packed ));
@@ -154,4 +166,6 @@ static inline int ndp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
154 166
 			      &ndp_discovery, net_source, ll_source );
155 167
 }
156 168
 
169
+extern int ndp_tx_router_solicitation ( struct net_device *netdev );
170
+
157 171
 #endif /* _IPXE_NDP_H */

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

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

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

@@ -37,60 +37,52 @@ FILE_LICENCE ( GPL2_OR_LATER );
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 42
  * @v netdev		Network device
43 43
  * @v sin6_src		Source socket address
44 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 47
  * @v option_type	NDP option type
49 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 55
 	struct sockaddr_tcpip *st_src =
59 56
 		( ( struct sockaddr_tcpip * ) sin6_src );
60 57
 	struct sockaddr_tcpip *st_dest =
61 58
 		( ( struct sockaddr_tcpip * ) sin6_dest );
62 59
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
63 60
 	struct io_buffer *iobuf;
64
-	struct ndp_neighbour_header *neigh;
65 61
 	struct ndp_ll_addr_option *ll_addr_opt;
62
+	union ndp_header *ndp;
66 63
 	size_t option_len;
67
-	size_t len;
68 64
 	int rc;
69 65
 
70 66
 	/* Allocate and populate buffer */
71 67
 	option_len = ( ( sizeof ( *ll_addr_opt ) +
72 68
 			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
73 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 71
 	if ( ! iobuf )
77 72
 		return -ENOMEM;
78 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 76
 	ll_addr_opt->header.type = option_type;
86 77
 	ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
87 78
 	memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
88 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 83
 	/* Transmit packet */
92 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 86
 		DBGC ( netdev, "NDP could not transmit packet: %s\n",
95 87
 		       strerror ( rc ) );
96 88
 		return rc;
@@ -113,6 +105,8 @@ static int ndp_tx_request ( struct net_device *netdev,
113 105
 			    const void *net_dest, const void *net_source ) {
114 106
 	struct sockaddr_in6 sin6_src;
115 107
 	struct sockaddr_in6 sin6_dest;
108
+	struct ndp_neighbour_header neigh;
109
+	int rc;
116 110
 
117 111
 	/* Construct source address */
118 112
 	memset ( &sin6_src, 0, sizeof ( sin6_src ) );
@@ -127,10 +121,18 @@ static int ndp_tx_request ( struct net_device *netdev,
127 121
 	sin6_dest.sin6_scope_id = netdev->index;
128 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 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 138
 /** NDP neighbour discovery protocol */
@@ -139,6 +141,35 @@ struct neighbour_discovery ndp_discovery = {
139 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 174
  * Process NDP neighbour solicitation source link-layer address option
144 175
  *
@@ -185,14 +216,16 @@ ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
185 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 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 228
 		return rc;
195
-	}
196 229
 
197 230
 	return 0;
198 231
 }
@@ -512,7 +545,6 @@ ndp_rx_router_advertisement ( struct io_buffer *iobuf,
512 545
 			offsetof ( typeof ( *radv ), option ) );
513 546
 }
514 547
 
515
-
516 548
 /** NDP ICMPv6 handlers */
517 549
 struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
518 550
 	{

Loading…
Cancel
Save