diff options
author | Michael Brown <mcb30@etherboot.org> | 2007-01-04 03:28:30 +0000 |
---|---|---|
committer | Michael Brown <mcb30@etherboot.org> | 2007-01-04 03:28:30 +0000 |
commit | b29861a5aa8385cdaf4d41a92cc4786740b2d702 (patch) | |
tree | b2a8352ca3001aa55524617c5f903d121b30a9a9 /src/net/ipv6.c | |
parent | b22d4405c0c74aaac8a7f20c7bb13c4eb4f4af71 (diff) | |
download | ipxe-b29861a5aa8385cdaf4d41a92cc4786740b2d702.tar.gz |
IPv6 minirouting table entries hold persistent references to net devices.
Diffstat (limited to 'src/net/ipv6.c')
-rw-r--r-- | src/net/ipv6.c | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/src/net/ipv6.c b/src/net/ipv6.c index 8422da67f..1801891bd 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; } } |