|
@@ -67,6 +67,24 @@ static uint32_t ipv6col ( struct in6_addr *in ) {
|
67
|
67
|
return crc32_le ( 0, in, sizeof ( *in ) );
|
68
|
68
|
}
|
69
|
69
|
|
|
70
|
+/**
|
|
71
|
+ * Dump IPv6 routing table entry
|
|
72
|
+ *
|
|
73
|
+ * @v miniroute Routing table entry
|
|
74
|
+ */
|
|
75
|
+static inline __attribute__ (( always_inline )) void
|
|
76
|
+ipv6_dump_miniroute ( struct ipv6_miniroute *miniroute ) {
|
|
77
|
+ struct net_device *netdev = miniroute->netdev;
|
|
78
|
+
|
|
79
|
+ DBGC ( netdev, "IPv6 %s has %s %s/%d", netdev->name,
|
|
80
|
+ ( ( miniroute->flags & IPV6_HAS_ADDRESS ) ?
|
|
81
|
+ "address" : "prefix" ),
|
|
82
|
+ inet6_ntoa ( &miniroute->address ), miniroute->prefix_len );
|
|
83
|
+ if ( miniroute->flags & IPV6_HAS_ROUTER )
|
|
84
|
+ DBGC ( netdev, " router %s", inet6_ntoa ( &miniroute->router ));
|
|
85
|
+ DBGC ( netdev, "\n" );
|
|
86
|
+}
|
|
87
|
+
|
70
|
88
|
/**
|
71
|
89
|
* Check if network device has a specific IPv6 address
|
72
|
90
|
*
|
|
@@ -79,6 +97,7 @@ int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ) {
|
79
|
97
|
|
80
|
98
|
list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
|
81
|
99
|
if ( ( miniroute->netdev == netdev ) &&
|
|
100
|
+ ( miniroute->flags & IPV6_HAS_ADDRESS ) &&
|
82
|
101
|
( memcmp ( &miniroute->address, addr,
|
83
|
102
|
sizeof ( miniroute->address ) ) == 0 ) ) {
|
84
|
103
|
/* Found matching address */
|
|
@@ -109,31 +128,45 @@ static int ipv6_is_on_link ( struct ipv6_miniroute *miniroute,
|
109
|
128
|
}
|
110
|
129
|
|
111
|
130
|
/**
|
112
|
|
- * Add IPv6 minirouting table entry
|
|
131
|
+ * Find IPv6 routing table entry for a given address
|
113
|
132
|
*
|
114
|
133
|
* @v netdev Network device
|
115
|
134
|
* @v address IPv6 address
|
|
135
|
+ * @ret miniroute Routing table entry, or NULL if not found
|
|
136
|
+ */
|
|
137
|
+static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
|
|
138
|
+ struct in6_addr *address ) {
|
|
139
|
+ struct ipv6_miniroute *miniroute;
|
|
140
|
+
|
|
141
|
+ list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
|
|
142
|
+ if ( ( miniroute->netdev == netdev ) &&
|
|
143
|
+ ipv6_is_on_link ( miniroute, address ) ) {
|
|
144
|
+ return miniroute;
|
|
145
|
+ }
|
|
146
|
+ }
|
|
147
|
+ return NULL;
|
|
148
|
+}
|
|
149
|
+
|
|
150
|
+/**
|
|
151
|
+ * Add IPv6 routing table entry
|
|
152
|
+ *
|
|
153
|
+ * @v netdev Network device
|
|
154
|
+ * @v address IPv6 address (or prefix)
|
116
|
155
|
* @v prefix_len Prefix length
|
117
|
|
- * @v router Router address (or NULL)
|
|
156
|
+ * @v flags Flags
|
118
|
157
|
* @ret miniroute Routing table entry, or NULL on failure
|
119
|
158
|
*/
|
120
|
|
-static struct ipv6_miniroute * __malloc
|
121
|
|
-add_ipv6_miniroute ( struct net_device *netdev, struct in6_addr *address,
|
122
|
|
- unsigned int prefix_len, struct in6_addr *router ) {
|
|
159
|
+static struct ipv6_miniroute * ipv6_add_miniroute ( struct net_device *netdev,
|
|
160
|
+ struct in6_addr *address,
|
|
161
|
+ unsigned int prefix_len,
|
|
162
|
+ unsigned int flags ) {
|
123
|
163
|
struct ipv6_miniroute *miniroute;
|
124
|
164
|
uint8_t *prefix_mask;
|
125
|
165
|
|
126
|
|
- DBGC ( netdev, "IPv6 add %s/%d ", inet6_ntoa ( address ), prefix_len );
|
127
|
|
- if ( router )
|
128
|
|
- DBGC ( netdev, "router %s ", inet6_ntoa ( router ) );
|
129
|
|
- DBGC ( netdev, "via %s\n", netdev->name );
|
130
|
|
-
|
131
|
|
- /* Allocate and populate miniroute structure */
|
|
166
|
+ /* Create routing table entry */
|
132
|
167
|
miniroute = zalloc ( sizeof ( *miniroute ) );
|
133
|
168
|
if ( ! miniroute )
|
134
|
169
|
return NULL;
|
135
|
|
-
|
136
|
|
- /* Record routing information */
|
137
|
170
|
miniroute->netdev = netdev_get ( netdev );
|
138
|
171
|
memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
|
139
|
172
|
miniroute->prefix_len = prefix_len;
|
|
@@ -144,41 +177,83 @@ add_ipv6_miniroute ( struct net_device *netdev, struct in6_addr *address,
|
144
|
177
|
}
|
145
|
178
|
if ( prefix_len )
|
146
|
179
|
*prefix_mask <<= ( 8 - prefix_len );
|
|
180
|
+ miniroute->flags = flags;
|
|
181
|
+ list_add ( &miniroute->list, &ipv6_miniroutes );
|
|
182
|
+ ipv6_dump_miniroute ( miniroute );
|
|
183
|
+
|
|
184
|
+ return miniroute;
|
|
185
|
+}
|
|
186
|
+
|
|
187
|
+/**
|
|
188
|
+ * Define IPv6 on-link prefix
|
|
189
|
+ *
|
|
190
|
+ * @v netdev Network device
|
|
191
|
+ * @v prefix IPv6 address prefix
|
|
192
|
+ * @v prefix_len Prefix length
|
|
193
|
+ * @v router Router address (or NULL)
|
|
194
|
+ * @ret rc Return status code
|
|
195
|
+ */
|
|
196
|
+int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix,
|
|
197
|
+ unsigned int prefix_len, struct in6_addr *router ) {
|
|
198
|
+ struct ipv6_miniroute *miniroute;
|
|
199
|
+ int changed;
|
|
200
|
+
|
|
201
|
+ /* Find or create routing table entry */
|
|
202
|
+ miniroute = ipv6_miniroute ( netdev, prefix );
|
|
203
|
+ if ( ! miniroute )
|
|
204
|
+ miniroute = ipv6_add_miniroute ( netdev, prefix, prefix_len, 0);
|
|
205
|
+ if ( ! miniroute )
|
|
206
|
+ return -ENOMEM;
|
|
207
|
+
|
|
208
|
+ /* Record router and add to start or end of list as appropriate */
|
|
209
|
+ list_del ( &miniroute->list );
|
147
|
210
|
if ( router ) {
|
148
|
|
- miniroute->has_router = 1;
|
|
211
|
+ changed = ( ( ! ( miniroute->flags & IPV6_HAS_ROUTER ) ) ||
|
|
212
|
+ ( memcmp ( &miniroute->router, router,
|
|
213
|
+ sizeof ( miniroute->router ) ) != 0 ) );
|
|
214
|
+ miniroute->flags |= IPV6_HAS_ROUTER;
|
149
|
215
|
memcpy ( &miniroute->router, router,
|
150
|
216
|
sizeof ( miniroute->router ) );
|
151
|
|
- }
|
152
|
|
-
|
153
|
|
- /* Add to end of list if we have a gateway, otherwise to start
|
154
|
|
- * of list.
|
155
|
|
- */
|
156
|
|
- if ( router ) {
|
157
|
217
|
list_add_tail ( &miniroute->list, &ipv6_miniroutes );
|
158
|
218
|
} else {
|
|
219
|
+ changed = ( miniroute->flags & IPV6_HAS_ROUTER );
|
|
220
|
+ miniroute->flags &= ~IPV6_HAS_ROUTER;
|
159
|
221
|
list_add ( &miniroute->list, &ipv6_miniroutes );
|
160
|
222
|
}
|
|
223
|
+ if ( changed )
|
|
224
|
+ ipv6_dump_miniroute ( miniroute );
|
161
|
225
|
|
162
|
|
- return miniroute;
|
|
226
|
+ return 0;
|
163
|
227
|
}
|
164
|
228
|
|
165
|
229
|
/**
|
166
|
|
- * Delete IPv6 minirouting table entry
|
|
230
|
+ * Add IPv6 on-link address
|
167
|
231
|
*
|
168
|
|
- * @v miniroute Routing table entry
|
|
232
|
+ * @v netdev Network device
|
|
233
|
+ * @v address IPv6 address
|
|
234
|
+ * @ret rc Return status code
|
|
235
|
+ *
|
|
236
|
+ * An on-link prefix for the address must already exist.
|
169
|
237
|
*/
|
170
|
|
-static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) {
|
171
|
|
- struct net_device *netdev = miniroute->netdev;
|
|
238
|
+int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) {
|
|
239
|
+ struct ipv6_miniroute *miniroute;
|
|
240
|
+ int changed;
|
|
241
|
+
|
|
242
|
+ /* Find routing table entry */
|
|
243
|
+ miniroute = ipv6_miniroute ( netdev, address );
|
|
244
|
+ if ( ! miniroute )
|
|
245
|
+ return -EADDRNOTAVAIL;
|
172
|
246
|
|
173
|
|
- DBGC ( netdev, "IPv6 del %s/%d ", inet6_ntoa ( &miniroute->address ),
|
174
|
|
- miniroute->prefix_len );
|
175
|
|
- if ( miniroute->has_router )
|
176
|
|
- DBGC ( netdev, "router %s ", inet6_ntoa ( &miniroute->router ));
|
177
|
|
- DBGC ( netdev, "via %s\n", netdev->name );
|
|
247
|
+ /* Record address */
|
|
248
|
+ changed = ( ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) ||
|
|
249
|
+ ( memcmp ( &miniroute->address, address,
|
|
250
|
+ sizeof ( miniroute->address ) ) != 0 ) );
|
|
251
|
+ memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
|
|
252
|
+ miniroute->flags |= IPV6_HAS_ADDRESS;
|
|
253
|
+ if ( changed )
|
|
254
|
+ ipv6_dump_miniroute ( miniroute );
|
178
|
255
|
|
179
|
|
- netdev_put ( miniroute->netdev );
|
180
|
|
- list_del ( &miniroute->list );
|
181
|
|
- free ( miniroute );
|
|
256
|
+ return 0;
|
182
|
257
|
}
|
183
|
258
|
|
184
|
259
|
/**
|
|
@@ -200,6 +275,10 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
200
|
275
|
if ( ! netdev_is_open ( miniroute->netdev ) )
|
201
|
276
|
continue;
|
202
|
277
|
|
|
278
|
+ /* Skip routing table entries with no usable source address */
|
|
279
|
+ if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) )
|
|
280
|
+ continue;
|
|
281
|
+
|
203
|
282
|
if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) ||
|
204
|
283
|
IN6_IS_ADDR_MULTICAST ( *dest ) ) {
|
205
|
284
|
|
|
@@ -221,7 +300,7 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
221
|
300
|
* address, and we have a default gateway,
|
222
|
301
|
* then use this route.
|
223
|
302
|
*/
|
224
|
|
- if ( miniroute->has_router ) {
|
|
303
|
+ if ( miniroute->flags & IPV6_HAS_ROUTER ) {
|
225
|
304
|
*dest = &miniroute->router;
|
226
|
305
|
return miniroute;
|
227
|
306
|
}
|
|
@@ -919,53 +998,6 @@ struct setting_type setting_type_ipv6 __setting_type = {
|
919
|
998
|
.format = format_ipv6_setting,
|
920
|
999
|
};
|
921
|
1000
|
|
922
|
|
-/**
|
923
|
|
- * Perform IPv6 stateless address autoconfiguration (SLAAC)
|
924
|
|
- *
|
925
|
|
- * @v netdev Network device
|
926
|
|
- * @v prefix Prefix
|
927
|
|
- * @v prefix_len Prefix length
|
928
|
|
- * @v router Router address (or NULL)
|
929
|
|
- * @ret rc Return status code
|
930
|
|
- */
|
931
|
|
-int ipv6_slaac ( struct net_device *netdev, struct in6_addr *prefix,
|
932
|
|
- unsigned int prefix_len, struct in6_addr *router ) {
|
933
|
|
- struct ipv6_miniroute *miniroute;
|
934
|
|
- struct ipv6_miniroute *tmp;
|
935
|
|
- struct in6_addr address;
|
936
|
|
- int check_prefix_len;
|
937
|
|
- int rc;
|
938
|
|
-
|
939
|
|
- /* Construct local address */
|
940
|
|
- memcpy ( &address, prefix, sizeof ( address ) );
|
941
|
|
- check_prefix_len = ipv6_eui64 ( &address, netdev );
|
942
|
|
- if ( check_prefix_len < 0 ) {
|
943
|
|
- rc = check_prefix_len;
|
944
|
|
- DBGC ( netdev, "IPv6 %s could not construct SLAAC address: "
|
945
|
|
- "%s\n", netdev->name, strerror ( rc ) );
|
946
|
|
- return rc;
|
947
|
|
- }
|
948
|
|
- if ( check_prefix_len != ( int ) prefix_len ) {
|
949
|
|
- DBGC ( netdev, "IPv6 %s incorrect SLAAC prefix length %d "
|
950
|
|
- "(expected %d)\n", netdev->name, prefix_len,
|
951
|
|
- check_prefix_len );
|
952
|
|
- return -EINVAL;
|
953
|
|
- }
|
954
|
|
-
|
955
|
|
- /* Delete any existing SLAAC miniroutes for this prefix */
|
956
|
|
- list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
957
|
|
- if ( ipv6_is_on_link ( miniroute, &address ) )
|
958
|
|
- del_ipv6_miniroute ( miniroute );
|
959
|
|
- }
|
960
|
|
-
|
961
|
|
- /* Add miniroute */
|
962
|
|
- miniroute = add_ipv6_miniroute ( netdev, &address, prefix_len, router );
|
963
|
|
- if ( ! miniroute )
|
964
|
|
- return -ENOMEM;
|
965
|
|
-
|
966
|
|
- return 0;
|
967
|
|
-}
|
968
|
|
-
|
969
|
1001
|
/**
|
970
|
1002
|
* Create IPv6 network device
|
971
|
1003
|
*
|
|
@@ -989,7 +1021,8 @@ static int ipv6_probe ( struct net_device *netdev ) {
|
989
|
1021
|
}
|
990
|
1022
|
|
991
|
1023
|
/* Create link-local address for this network device */
|
992
|
|
- miniroute = add_ipv6_miniroute ( netdev, &address, prefix_len, NULL );
|
|
1024
|
+ miniroute = ipv6_add_miniroute ( netdev, &address, prefix_len,
|
|
1025
|
+ IPV6_HAS_ADDRESS );
|
993
|
1026
|
if ( ! miniroute )
|
994
|
1027
|
return -ENOMEM;
|
995
|
1028
|
|
|
@@ -1007,8 +1040,11 @@ static void ipv6_remove ( struct net_device *netdev ) {
|
1007
|
1040
|
|
1008
|
1041
|
/* Delete all miniroutes for this network device */
|
1009
|
1042
|
list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
1010
|
|
- if ( miniroute->netdev == netdev )
|
1011
|
|
- del_ipv6_miniroute ( miniroute );
|
|
1043
|
+ if ( miniroute->netdev == netdev ) {
|
|
1044
|
+ netdev_put ( miniroute->netdev );
|
|
1045
|
+ list_del ( &miniroute->list );
|
|
1046
|
+ free ( miniroute );
|
|
1047
|
+ }
|
1012
|
1048
|
}
|
1013
|
1049
|
}
|
1014
|
1050
|
|