IPv6 minirouting table entries hold persistent references to net devices.
authorMichael Brown <mcb30@etherboot.org>
Thu, 4 Jan 2007 03:28:30 +0000 (03:28 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 4 Jan 2007 03:28:30 +0000 (03:28 +0000)
src/include/gpxe/ip6.h
src/net/ipv6.c

index 0589f8e..0ba1712 100644 (file)
@@ -69,5 +69,10 @@ extern struct net_protocol ipv6_protocol;
 extern struct tcpip_net_protocol ipv6_tcpip_protocol;
 extern char * inet6_ntoa ( struct in6_addr in6 );
 
+extern int add_ipv6_address ( struct net_device *netdev,
+                             struct in6_addr prefix, int prefix_len,
+                             struct in6_addr address,
+                             struct in6_addr gateway );
+extern void del_ipv6_address ( struct net_device *netdev );
 
 #endif /* _GPXE_IP6_H */
index 8422da6..1801891 100644 (file)
@@ -30,8 +30,12 @@ static struct in6_addr ip6_none = {
 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 */
@@ -45,6 +49,71 @@ struct ipv6_miniroute {
 /** 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
  *
@@ -58,23 +127,15 @@ int add_ipv6_address ( struct net_device *netdev, struct in6_addr prefix,
                       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;
 }
 
@@ -88,7 +149,7 @@ void del_ipv6_address ( struct net_device *netdev ) {
 
        list_for_each_entry ( miniroute, &miniroutes, list ) {
                if ( miniroute->netdev == netdev ) {
-                       list_del ( &miniroute->list );
+                       del_ipv6_miniroute ( miniroute );
                        break;
                }
        }