summaryrefslogtreecommitdiffstats
path: root/src/net/ipv4.c
diff options
context:
space:
mode:
authorMichael Brown2007-01-04 04:10:21 +0100
committerMichael Brown2007-01-04 04:10:21 +0100
commit35b5e5d3f59ace41c048f7914479e583386c9467 (patch)
treef2dd246d01e23ba64ffb19f43bcf65a7e85c7280 /src/net/ipv4.c
parentUse hotplug support to notify persistent reference holders when a (diff)
downloadipxe-35b5e5d3f59ace41c048f7914479e583386c9467.tar.gz
ipxe-35b5e5d3f59ace41c048f7914479e583386c9467.tar.xz
ipxe-35b5e5d3f59ace41c048f7914479e583386c9467.zip
Minirouting table entries hold a persistent reference to a net_device.
Diffstat (limited to 'src/net/ipv4.c')
-rw-r--r--src/net/ipv4.c107
1 files changed, 91 insertions, 16 deletions
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index a37c27a8..228a5a53 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -34,8 +34,12 @@ struct net_protocol ipv4_protocol;
struct ipv4_miniroute {
/** List of miniroutes */
struct list_head list;
+
/** Network device */
struct net_device *netdev;
+ /** Reference to network device */
+ struct reference netdev_ref;
+
/** IPv4 address */
struct in_addr address;
/** Subnet mask */
@@ -50,6 +54,86 @@ static LIST_HEAD ( miniroutes );
/** List of fragment reassembly buffers */
static LIST_HEAD ( frag_buffers );
+static void ipv4_forget_netdev ( struct reference *ref );
+
+/**
+ * Add IPv4 minirouting table entry
+ *
+ * @v netdev Network device
+ * @v address IPv4 address
+ * @v netmask Subnet mask
+ * @v gateway Gateway address (or @c INADDR_NONE for no gateway)
+ * @ret miniroute Routing table entry, or NULL
+ */
+static struct ipv4_miniroute * add_ipv4_miniroute ( struct net_device *netdev,
+ struct in_addr address,
+ struct in_addr netmask,
+ struct in_addr gateway ) {
+ struct ipv4_miniroute *miniroute;
+
+ /* Allocate and populate miniroute structure */
+ miniroute = malloc ( sizeof ( *miniroute ) );
+ if ( miniroute ) {
+
+ DBG ( "IPv4 add %s", inet_ntoa ( address ) );
+ DBG ( "/%s ", inet_ntoa ( netmask ) );
+ if ( gateway.s_addr != INADDR_NONE )
+ DBG ( "gw %s ", inet_ntoa ( gateway ) );
+ DBG ( "via %s\n", netdev_name ( netdev ) );
+
+ /* Record routing information */
+ miniroute->netdev = netdev;
+ miniroute->address = address;
+ miniroute->netmask = netmask;
+ miniroute->gateway = gateway;
+
+ /* Add to end of list if we have a gateway, otherwise
+ * to start of list.
+ */
+ if ( gateway.s_addr != INADDR_NONE ) {
+ list_add_tail ( &miniroute->list, &miniroutes );
+ } else {
+ list_add ( &miniroute->list, &miniroutes );
+ }
+
+ /* Record reference to net_device */
+ miniroute->netdev_ref.forget = ipv4_forget_netdev;
+ ref_add ( &miniroute->netdev_ref, &netdev->references );
+ }
+
+ return miniroute;
+}
+
+/**
+ * Delete IPv4 minirouting table entry
+ *
+ * @v miniroute Routing table entry
+ */
+static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
+
+ DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
+ DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
+ if ( miniroute->gateway.s_addr != INADDR_NONE )
+ DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
+ DBG ( "via %s\n", netdev_name ( miniroute->netdev ) );
+
+ ref_del ( &miniroute->netdev_ref );
+ list_del ( &miniroute->list );
+ free ( miniroute );
+}
+
+/**
+ * Forget reference to net_device
+ *
+ * @v ref Persistent reference
+ */
+static void ipv4_forget_netdev ( struct reference *ref ) {
+ struct ipv4_miniroute *miniroute
+ = container_of ( ref, struct ipv4_miniroute, netdev_ref );
+
+ del_ipv4_miniroute ( miniroute );
+}
+
/**
* Add IPv4 interface
*
@@ -64,23 +148,14 @@ int add_ipv4_address ( struct net_device *netdev, struct in_addr address,
struct in_addr netmask, struct in_addr gateway ) {
struct ipv4_miniroute *miniroute;
- /* Allocate and populate miniroute structure */
- miniroute = malloc ( sizeof ( *miniroute ) );
+ /* Clear any existing address for this net device */
+ del_ipv4_address ( netdev );
+
+ /* Add new miniroute */
+ miniroute = add_ipv4_miniroute ( netdev, address, netmask, gateway );
if ( ! miniroute )
return -ENOMEM;
- miniroute->netdev = netdev;
- miniroute->address = address;
- miniroute->netmask = netmask;
- miniroute->gateway = gateway;
-
- /* Add to end of list if we have a gateway, otherwise to start
- * of list.
- */
- if ( gateway.s_addr != INADDR_NONE ) {
- list_add_tail ( &miniroute->list, &miniroutes );
- } else {
- list_add ( &miniroute->list, &miniroutes );
- }
+
return 0;
}
@@ -94,7 +169,7 @@ void del_ipv4_address ( struct net_device *netdev ) {
list_for_each_entry ( miniroute, &miniroutes, list ) {
if ( miniroute->netdev == netdev ) {
- list_del ( &miniroute->list );
+ del_ipv4_miniroute ( miniroute );
break;
}
}