|
@@ -164,107 +164,85 @@ static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
|
164
|
164
|
* @v netdev Network device
|
165
|
165
|
* @v address IPv6 address (or prefix)
|
166
|
166
|
* @v prefix_len Prefix length
|
167
|
|
- * @v flags Flags
|
168
|
|
- * @ret miniroute Routing table entry, or NULL on failure
|
|
167
|
+ * @v router Router address (if any)
|
|
168
|
+ * @ret rc Return status code
|
169
|
169
|
*/
|
170
|
|
-static struct ipv6_miniroute * ipv6_add_miniroute ( struct net_device *netdev,
|
171
|
|
- struct in6_addr *address,
|
172
|
|
- unsigned int prefix_len,
|
173
|
|
- unsigned int flags ) {
|
|
170
|
+static int ipv6_add_miniroute ( struct net_device *netdev,
|
|
171
|
+ struct in6_addr *address,
|
|
172
|
+ unsigned int prefix_len,
|
|
173
|
+ struct in6_addr *router ) {
|
174
|
174
|
struct ipv6_miniroute *miniroute;
|
175
|
175
|
uint8_t *prefix_mask;
|
|
176
|
+ unsigned int remaining;
|
|
177
|
+ unsigned int i;
|
176
|
178
|
|
177
|
|
- /* Create routing table entry */
|
178
|
|
- miniroute = zalloc ( sizeof ( *miniroute ) );
|
179
|
|
- if ( ! miniroute )
|
180
|
|
- return NULL;
|
181
|
|
- miniroute->netdev = netdev_get ( netdev );
|
182
|
|
- memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
|
183
|
|
- miniroute->prefix_len = prefix_len;
|
184
|
|
- assert ( prefix_len <= ( 8 * sizeof ( miniroute->prefix_mask ) ) );
|
185
|
|
- for ( prefix_mask = miniroute->prefix_mask.s6_addr ; prefix_len >= 8 ;
|
186
|
|
- prefix_mask++, prefix_len -= 8 ) {
|
187
|
|
- *prefix_mask = 0xff;
|
188
|
|
- }
|
189
|
|
- if ( prefix_len )
|
190
|
|
- *prefix_mask <<= ( 8 - prefix_len );
|
191
|
|
- miniroute->flags = flags;
|
192
|
|
- list_add ( &miniroute->list, &ipv6_miniroutes );
|
193
|
|
- ipv6_dump_miniroute ( miniroute );
|
194
|
|
-
|
195
|
|
- return miniroute;
|
196
|
|
-}
|
|
179
|
+ /* Find or create routing table entry */
|
|
180
|
+ miniroute = ipv6_miniroute ( netdev, address );
|
|
181
|
+ if ( ! miniroute ) {
|
|
182
|
+
|
|
183
|
+ /* Create new routing table entry */
|
|
184
|
+ miniroute = zalloc ( sizeof ( *miniroute ) );
|
|
185
|
+ if ( ! miniroute )
|
|
186
|
+ return -ENOMEM;
|
|
187
|
+ miniroute->netdev = netdev_get ( netdev );
|
|
188
|
+ memcpy ( &miniroute->address, address,
|
|
189
|
+ sizeof ( miniroute->address ) );
|
|
190
|
+
|
|
191
|
+ /* Default to prefix length of 64 if none specified */
|
|
192
|
+ if ( ! prefix_len )
|
|
193
|
+ prefix_len = IPV6_DEFAULT_PREFIX_LEN;
|
|
194
|
+ miniroute->prefix_len = prefix_len;
|
|
195
|
+ assert ( prefix_len <= IPV6_MAX_PREFIX_LEN );
|
|
196
|
+
|
|
197
|
+ /* Construct prefix mask */
|
|
198
|
+ remaining = prefix_len;
|
|
199
|
+ for ( prefix_mask = miniroute->prefix_mask.s6_addr ;
|
|
200
|
+ remaining >= 8 ; prefix_mask++, remaining -= 8 ) {
|
|
201
|
+ *prefix_mask = 0xff;
|
|
202
|
+ }
|
|
203
|
+ if ( remaining )
|
|
204
|
+ *prefix_mask <<= ( 8 - remaining );
|
197
|
205
|
|
198
|
|
-/**
|
199
|
|
- * Define IPv6 on-link prefix
|
200
|
|
- *
|
201
|
|
- * @v netdev Network device
|
202
|
|
- * @v prefix IPv6 address prefix
|
203
|
|
- * @v prefix_len Prefix length
|
204
|
|
- * @v router Router address (or NULL)
|
205
|
|
- * @ret rc Return status code
|
206
|
|
- */
|
207
|
|
-int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix,
|
208
|
|
- unsigned int prefix_len, struct in6_addr *router ) {
|
209
|
|
- struct ipv6_miniroute *miniroute;
|
210
|
|
- int changed;
|
|
206
|
+ /* Add to list of routes */
|
|
207
|
+ list_add ( &miniroute->list, &ipv6_miniroutes );
|
|
208
|
+ }
|
211
|
209
|
|
212
|
|
- /* Find or create routing table entry */
|
213
|
|
- miniroute = ipv6_miniroute ( netdev, prefix );
|
214
|
|
- if ( ! miniroute )
|
215
|
|
- miniroute = ipv6_add_miniroute ( netdev, prefix, prefix_len, 0);
|
216
|
|
- if ( ! miniroute )
|
217
|
|
- return -ENOMEM;
|
|
210
|
+ /* Set or update address, if applicable */
|
|
211
|
+ for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
|
|
212
|
+ sizeof ( address->s6_addr32[0] ) ) ; i++ ) {
|
|
213
|
+ if ( ( address->s6_addr32[i] &
|
|
214
|
+ ~miniroute->prefix_mask.s6_addr32[i] ) != 0 ) {
|
|
215
|
+ memcpy ( &miniroute->address, address,
|
|
216
|
+ sizeof ( miniroute->address ) );
|
|
217
|
+ miniroute->flags |= IPV6_HAS_ADDRESS;
|
|
218
|
+ }
|
|
219
|
+ }
|
|
220
|
+ if ( miniroute->prefix_len == IPV6_MAX_PREFIX_LEN )
|
|
221
|
+ miniroute->flags |= IPV6_HAS_ADDRESS;
|
218
|
222
|
|
219
|
|
- /* Record router and add to start or end of list as appropriate */
|
220
|
|
- list_del ( &miniroute->list );
|
|
223
|
+ /* Set or update router, if applicable */
|
221
|
224
|
if ( router ) {
|
222
|
|
- changed = ( ( ! ( miniroute->flags & IPV6_HAS_ROUTER ) ) ||
|
223
|
|
- ( memcmp ( &miniroute->router, router,
|
224
|
|
- sizeof ( miniroute->router ) ) != 0 ) );
|
225
|
|
- miniroute->flags |= IPV6_HAS_ROUTER;
|
226
|
225
|
memcpy ( &miniroute->router, router,
|
227
|
226
|
sizeof ( miniroute->router ) );
|
|
227
|
+ miniroute->flags |= IPV6_HAS_ROUTER;
|
|
228
|
+ list_del ( &miniroute->list );
|
228
|
229
|
list_add_tail ( &miniroute->list, &ipv6_miniroutes );
|
229
|
|
- } else {
|
230
|
|
- changed = ( miniroute->flags & IPV6_HAS_ROUTER );
|
231
|
|
- miniroute->flags &= ~IPV6_HAS_ROUTER;
|
232
|
|
- list_add ( &miniroute->list, &ipv6_miniroutes );
|
233
|
230
|
}
|
234
|
|
- if ( changed )
|
235
|
|
- ipv6_dump_miniroute ( miniroute );
|
236
|
231
|
|
|
232
|
+ ipv6_dump_miniroute ( miniroute );
|
237
|
233
|
return 0;
|
238
|
234
|
}
|
239
|
235
|
|
240
|
236
|
/**
|
241
|
|
- * Add IPv6 on-link address
|
|
237
|
+ * Delete IPv6 minirouting table entry
|
242
|
238
|
*
|
243
|
|
- * @v netdev Network device
|
244
|
|
- * @v address IPv6 address
|
245
|
|
- * @ret rc Return status code
|
246
|
|
- *
|
247
|
|
- * An on-link prefix for the address must already exist.
|
|
239
|
+ * @v miniroute Routing table entry
|
248
|
240
|
*/
|
249
|
|
-int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) {
|
250
|
|
- struct ipv6_miniroute *miniroute;
|
251
|
|
- int changed;
|
252
|
|
-
|
253
|
|
- /* Find routing table entry */
|
254
|
|
- miniroute = ipv6_miniroute ( netdev, address );
|
255
|
|
- if ( ! miniroute )
|
256
|
|
- return -EADDRNOTAVAIL;
|
|
241
|
+static void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute ) {
|
257
|
242
|
|
258
|
|
- /* Record address */
|
259
|
|
- changed = ( ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) ||
|
260
|
|
- ( memcmp ( &miniroute->address, address,
|
261
|
|
- sizeof ( miniroute->address ) ) != 0 ) );
|
262
|
|
- memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
|
263
|
|
- miniroute->flags |= IPV6_HAS_ADDRESS;
|
264
|
|
- if ( changed )
|
265
|
|
- ipv6_dump_miniroute ( miniroute );
|
266
|
|
-
|
267
|
|
- return 0;
|
|
243
|
+ netdev_put ( miniroute->netdev );
|
|
244
|
+ list_del ( &miniroute->list );
|
|
245
|
+ free ( miniroute );
|
268
|
246
|
}
|
269
|
247
|
|
270
|
248
|
/**
|
|
@@ -1198,65 +1176,98 @@ static int ipv6_register_settings ( struct net_device *netdev ) {
|
1198
|
1176
|
return rc;
|
1199
|
1177
|
}
|
1200
|
1178
|
|
|
1179
|
+/** IPv6 network device driver */
|
|
1180
|
+struct net_driver ipv6_driver __net_driver = {
|
|
1181
|
+ .name = "IPv6",
|
|
1182
|
+ .probe = ipv6_register_settings,
|
|
1183
|
+};
|
|
1184
|
+
|
1201
|
1185
|
/**
|
1202
|
|
- * Create IPv6 network device
|
|
1186
|
+ * Create IPv6 routing table based on configured settings
|
1203
|
1187
|
*
|
1204
|
1188
|
* @v netdev Network device
|
|
1189
|
+ * @v settings Settings block
|
1205
|
1190
|
* @ret rc Return status code
|
1206
|
1191
|
*/
|
1207
|
|
-static int ipv6_probe ( struct net_device *netdev ) {
|
1208
|
|
- struct ipv6_miniroute *miniroute;
|
1209
|
|
- struct in6_addr address;
|
1210
|
|
- int prefix_len;
|
|
1192
|
+static int ipv6_create_routes ( struct net_device *netdev,
|
|
1193
|
+ struct settings *settings ) {
|
|
1194
|
+ struct settings *child;
|
|
1195
|
+ struct settings *origin;
|
|
1196
|
+ struct in6_addr ip6_buf;
|
|
1197
|
+ struct in6_addr gateway6_buf;
|
|
1198
|
+ struct in6_addr *ip6 = &ip6_buf;
|
|
1199
|
+ struct in6_addr *gateway6 = &gateway6_buf;
|
|
1200
|
+ uint8_t len6;
|
|
1201
|
+ size_t len;
|
1211
|
1202
|
int rc;
|
1212
|
1203
|
|
1213
|
|
- /* Construct link-local address from EUI-64 as per RFC 2464 */
|
1214
|
|
- memset ( &address, 0, sizeof ( address ) );
|
1215
|
|
- prefix_len = ipv6_link_local ( &address, netdev );
|
1216
|
|
- if ( prefix_len < 0 ) {
|
1217
|
|
- rc = prefix_len;
|
1218
|
|
- DBGC ( netdev, "IPv6 %s could not construct link-local "
|
1219
|
|
- "address: %s\n", netdev->name, strerror ( rc ) );
|
|
1204
|
+ /* First, create routing table for any child settings. We do
|
|
1205
|
+ * this depth-first and in reverse order so that the end
|
|
1206
|
+ * result reflects the relative priorities of the settings
|
|
1207
|
+ * blocks.
|
|
1208
|
+ */
|
|
1209
|
+ list_for_each_entry_reverse ( child, &settings->children, siblings )
|
|
1210
|
+ ipv6_create_routes ( netdev, child );
|
|
1211
|
+
|
|
1212
|
+ /* Fetch IPv6 address, if any */
|
|
1213
|
+ len = fetch_setting ( settings, &ip6_setting, &origin, NULL,
|
|
1214
|
+ ip6, sizeof ( *ip6 ) );
|
|
1215
|
+ if ( ( len != sizeof ( *ip6 ) ) || ( origin != settings ) )
|
|
1216
|
+ return 0;
|
|
1217
|
+
|
|
1218
|
+ /* Fetch prefix length, if defined */
|
|
1219
|
+ len = fetch_setting ( settings, &len6_setting, &origin, NULL,
|
|
1220
|
+ &len6, sizeof ( len6 ) );
|
|
1221
|
+ if ( ( len != sizeof ( len6 ) ) || ( origin != settings ) )
|
|
1222
|
+ len6 = 0;
|
|
1223
|
+ if ( len6 > IPV6_MAX_PREFIX_LEN )
|
|
1224
|
+ len6 = IPV6_MAX_PREFIX_LEN;
|
|
1225
|
+
|
|
1226
|
+ /* Fetch gateway, if defined */
|
|
1227
|
+ len = fetch_setting ( settings, &gateway6_setting, &origin, NULL,
|
|
1228
|
+ gateway6, sizeof ( *gateway6 ) );
|
|
1229
|
+ if ( ( len != sizeof ( *gateway6 ) ) || ( origin != settings ) )
|
|
1230
|
+ gateway6 = NULL;
|
|
1231
|
+
|
|
1232
|
+ /* Create or update route */
|
|
1233
|
+ if ( ( rc = ipv6_add_miniroute ( netdev, ip6, len6, gateway6 ) ) != 0){
|
|
1234
|
+ DBGC ( netdev, "IPv6 %s could not add route: %s\n",
|
|
1235
|
+ netdev->name, strerror ( rc ) );
|
1220
|
1236
|
return rc;
|
1221
|
1237
|
}
|
1222
|
1238
|
|
1223
|
|
- /* Create link-local address for this network device */
|
1224
|
|
- miniroute = ipv6_add_miniroute ( netdev, &address, prefix_len,
|
1225
|
|
- IPV6_HAS_ADDRESS );
|
1226
|
|
- if ( ! miniroute )
|
1227
|
|
- return -ENOMEM;
|
1228
|
|
-
|
1229
|
|
- /* Register link-local address settings */
|
1230
|
|
- if ( ( rc = ipv6_register_settings ( netdev ) ) != 0 )
|
1231
|
|
- return rc;
|
1232
|
|
-
|
1233
|
1239
|
return 0;
|
1234
|
1240
|
}
|
1235
|
1241
|
|
1236
|
1242
|
/**
|
1237
|
|
- * Destroy IPv6 network device
|
|
1243
|
+ * Create IPv6 routing table based on configured settings
|
1238
|
1244
|
*
|
1239
|
|
- * @v netdev Network device
|
|
1245
|
+ * @ret rc Return status code
|
1240
|
1246
|
*/
|
1241
|
|
-static void ipv6_remove ( struct net_device *netdev ) {
|
|
1247
|
+static int ipv6_create_all_routes ( void ) {
|
1242
|
1248
|
struct ipv6_miniroute *miniroute;
|
1243
|
1249
|
struct ipv6_miniroute *tmp;
|
|
1250
|
+ struct net_device *netdev;
|
|
1251
|
+ struct settings *settings;
|
|
1252
|
+ int rc;
|
1244
|
1253
|
|
1245
|
|
- /* Delete all miniroutes for this network device */
|
1246
|
|
- list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
|
1247
|
|
- if ( miniroute->netdev == netdev ) {
|
1248
|
|
- netdev_put ( miniroute->netdev );
|
1249
|
|
- list_del ( &miniroute->list );
|
1250
|
|
- free ( miniroute );
|
1251
|
|
- }
|
|
1254
|
+ /* Delete all existing routes */
|
|
1255
|
+ list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list )
|
|
1256
|
+ ipv6_del_miniroute ( miniroute );
|
|
1257
|
+
|
|
1258
|
+ /* Create routes for each configured network device */
|
|
1259
|
+ for_each_netdev ( netdev ) {
|
|
1260
|
+ settings = netdev_settings ( netdev );
|
|
1261
|
+ if ( ( rc = ipv6_create_routes ( netdev, settings ) ) != 0 )
|
|
1262
|
+ return rc;
|
1252
|
1263
|
}
|
|
1264
|
+
|
|
1265
|
+ return 0;
|
1253
|
1266
|
}
|
1254
|
1267
|
|
1255
|
|
-/** IPv6 network device driver */
|
1256
|
|
-struct net_driver ipv6_driver __net_driver = {
|
1257
|
|
- .name = "IPv6",
|
1258
|
|
- .probe = ipv6_probe,
|
1259
|
|
- .remove = ipv6_remove,
|
|
1268
|
+/** IPv6 settings applicator */
|
|
1269
|
+struct settings_applicator ipv6_settings_applicator __settings_applicator = {
|
|
1270
|
+ .apply = ipv6_create_all_routes,
|
1260
|
1271
|
};
|
1261
|
1272
|
|
1262
|
1273
|
/* Drag in objects via ipv6_protocol */
|