summaryrefslogtreecommitdiffstats
path: root/src/net/ipv6.c
diff options
context:
space:
mode:
authorMichael Brown2007-01-04 04:28:30 +0100
committerMichael Brown2007-01-04 04:28:30 +0100
commitb29861a5aa8385cdaf4d41a92cc4786740b2d702 (patch)
treeb2a8352ca3001aa55524617c5f903d121b30a9a9 /src/net/ipv6.c
parentAn AoE session holds a persistent reference to a net device. (diff)
downloadipxe-b29861a5aa8385cdaf4d41a92cc4786740b2d702.tar.gz
ipxe-b29861a5aa8385cdaf4d41a92cc4786740b2d702.tar.xz
ipxe-b29861a5aa8385cdaf4d41a92cc4786740b2d702.zip
IPv6 minirouting table entries hold persistent references to net devices.
Diffstat (limited to 'src/net/ipv6.c')
-rw-r--r--src/net/ipv6.c95
1 files changed, 78 insertions, 17 deletions
diff --git a/src/net/ipv6.c b/src/net/ipv6.c
index 8422da67..1801891b 100644
--- a/src/net/ipv6.c
+++ b/src/net/ipv6.c
@@ -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;
}
}