struct ipv6_miniroute {
/* List of miniroutes */
struct list_head list;
+
/* Network device */
struct net_device *netdev;
+ /** Reference to network device */
+ struct reference netdev_ref;
+
/* Destination prefix */
struct in6_addr prefix;
/* Prefix length */
/** List of IPv6 miniroutes */
static LIST_HEAD ( miniroutes );
+static void ipv6_forget_netdev ( struct reference *ref );
+
+/**
+ * Add IPv6 minirouting table entry
+ *
+ * @v netdev Network device
+ * @v prefix Destination prefix
+ * @v address Address of the interface
+ * @v gateway Gateway address (or ::0 for no gateway)
+ * @ret miniroute Routing table entry, or NULL
+ */
+static struct ipv6_miniroute * add_ipv6_miniroute ( struct net_device *netdev,
+ struct in6_addr prefix,
+ int prefix_len,
+ struct in6_addr address,
+ struct in6_addr gateway ) {
+ struct ipv6_miniroute *miniroute;
+
+ miniroute = malloc ( sizeof ( *miniroute ) );
+ if ( miniroute ) {
+ /* Record routing information */
+ miniroute->netdev = netdev;
+ miniroute->prefix = prefix;
+ miniroute->prefix_len = prefix_len;
+ miniroute->address = address;
+ miniroute->gateway = gateway;
+
+ /* Add miniroute to list of miniroutes */
+ if ( !IP6_EQUAL ( gateway, ip6_none ) ) {
+ list_add_tail ( &miniroute->list, &miniroutes );
+ } else {
+ list_add ( &miniroute->list, &miniroutes );
+ }
+
+ /* Record reference to net_device */
+ miniroute->netdev_ref.forget = ipv6_forget_netdev;
+ ref_add ( &miniroute->netdev_ref, &netdev->references );
+ }
+
+ return miniroute;
+}
+
+/**
+ * Delete IPv6 minirouting table entry
+ *
+ * @v miniroute Routing table entry
+ */
+static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) {
+ ref_del ( &miniroute->netdev_ref );
+ list_del ( &miniroute->list );
+ free ( miniroute );
+}
+
+/**
+ * Forget reference to net_device
+ *
+ * @v ref Persistent reference
+ */
+static void ipv6_forget_netdev ( struct reference *ref ) {
+ struct ipv6_miniroute *miniroute
+ = container_of ( ref, struct ipv6_miniroute, netdev_ref );
+
+ del_ipv6_miniroute ( miniroute );
+}
+
/**
* Add IPv6 interface
*
struct in6_addr gateway ) {
struct ipv6_miniroute *miniroute;
- miniroute = malloc ( sizeof ( *miniroute ) );
- if ( !miniroute ) {
- DBG ( "Not enough memory\n" );
+ /* Clear any existing address for this net device */
+ del_ipv6_address ( netdev );
+
+ /* Add new miniroute */
+ miniroute = add_ipv6_miniroute ( netdev, prefix, prefix_len, address,
+ gateway );
+ if ( ! miniroute )
return -ENOMEM;
- }
- miniroute->netdev = netdev;
- miniroute->prefix = prefix;
- miniroute->prefix_len = prefix_len;
- miniroute->address = address;
- miniroute->gateway = gateway;
-
- /* Add miniroute to list of miniroutes */
- if ( !IP6_EQUAL ( gateway, ip6_none ) ) {
- list_add_tail ( &miniroute->list, &miniroutes );
- } else {
- list_add ( &miniroute->list, &miniroutes );
- }
+
return 0;
}
list_for_each_entry ( miniroute, &miniroutes, list ) {
if ( miniroute->netdev == netdev ) {
- list_del ( &miniroute->list );
+ del_ipv6_miniroute ( miniroute );
break;
}
}