summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2012-01-23 01:26:40 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2012-01-23 01:26:40 +0100
commit732a0a257d180a95a02587203555b8552b6128ac (patch)
tree298d92b6fd7c7c59f4c58f60692ecdf592cd9ba3
parent5c78e0e386d4c770b646cab4a8adc3c87987f50f (diff)
Fixes problems with creating/removing/renaming ifaces on BSD.
-rw-r--r--nest/iface.c20
-rw-r--r--nest/iface.h1
-rw-r--r--sysdep/bsd/krt-sock.c34
-rw-r--r--sysdep/linux/netlink/netlink.c27
4 files changed, 54 insertions, 28 deletions
diff --git a/nest/iface.c b/nest/iface.c
index 2b14d3f0..d871ff33 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -253,6 +253,24 @@ if_change_flags(struct iface *i, unsigned flags)
}
/**
+ * if_delete - remove interface
+ * @old: interface
+ *
+ * This function is called by the low-level platform dependent code
+ * whenever it notices an interface disappears. It is just a shorthand
+ * for if_update().
+ */
+
+void
+if_delete(struct iface *old)
+{
+ struct iface f = {};
+ strncpy(f.name, old->name, sizeof(f.name)-1);
+ f.flags = IF_SHUTDOWN;
+ if_update(&f);
+}
+
+/**
* if_update - update interface status
* @new: new interface status
*
@@ -400,7 +418,7 @@ if_find_by_index(unsigned idx)
struct iface *i;
WALK_LIST(i, iface_list)
- if (i->index == idx)
+ if (i->index == idx && !(i->flags & IF_SHUTDOWN))
return i;
return NULL;
}
diff --git a/nest/iface.h b/nest/iface.h
index d6d58ff9..2416f82f 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -88,6 +88,7 @@ void ifa_dump(struct ifa *);
void if_show(void);
void if_show_summary(void);
struct iface *if_update(struct iface *);
+void if_delete(struct iface *old);
struct ifa *ifa_update(struct ifa *);
void ifa_delete(struct ifa *);
void if_start_update(void);
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index 4a91e85a..f831327b 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -416,8 +416,9 @@ krt_read_ifinfo(struct ks_msg *msg)
void *body = (void *)(ifm + 1);
struct sockaddr_dl *dl = NULL;
unsigned int i;
- struct iface *iface = NULL, f;
+ struct iface *iface = NULL, f = {};
int fl = ifm->ifm_flags;
+ int nlen = 0;
for (i = 1; i<=RTA_IFP; i <<= 1)
{
@@ -432,31 +433,42 @@ krt_read_ifinfo(struct ks_msg *msg)
}
}
- if(dl && (dl->sdl_family != AF_LINK))
+ if (dl && (dl->sdl_family != AF_LINK))
{
log("Ignoring strange IFINFO");
return;
}
- iface = if_find_by_index(ifm->ifm_index);
+ if (dl)
+ nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen);
+
+ /* Note that asynchronous IFINFO messages do not contain iface
+ name, so we have to found an existing iface by iface index */
- if(!iface)
+ iface = if_find_by_index(ifm->ifm_index);
+ if (!iface)
{
/* New interface */
- if(!dl) return; /* No interface name, ignoring */
+ if (!dl)
+ return; /* No interface name, ignoring */
- bzero(&f, sizeof(f));
- f.index = ifm->ifm_index;
- memcpy(f.name, dl->sdl_data, MIN(sizeof(f.name)-1, dl->sdl_nlen));
- DBG("New interface '%s' found", f.name);
+ memcpy(f.name, dl->sdl_data, nlen);
+ DBG("New interface '%s' found\n", f.name);
+ }
+ else if (dl && memcmp(iface->name, dl->sdl_data, nlen))
+ {
+ /* Interface renamed */
+ if_delete(iface);
+ memcpy(f.name, dl->sdl_data, nlen);
}
else
{
- memcpy(&f, iface, sizeof(struct iface));
+ /* Old interface */
+ memcpy(f.name, iface->name, sizeof(f.name));
}
+ f.index = ifm->ifm_index;
f.mtu = ifm->ifm_data.ifi_mtu;
- f.flags = 0;
if (fl & IFF_UP)
f.flags |= IF_ADMIN_UP;
diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c
index cf808231..17c369ea 100644
--- a/sysdep/linux/netlink/netlink.c
+++ b/sysdep/linux/netlink/netlink.c
@@ -386,7 +386,7 @@ nl_parse_link(struct nlmsghdr *h, int scan)
struct ifinfomsg *i;
struct rtattr *a[IFLA_WIRELESS+1];
int new = h->nlmsg_type == RTM_NEWLINK;
- struct iface f;
+ struct iface f = {};
struct iface *ifi;
char *name;
u32 mtu;
@@ -408,26 +408,21 @@ nl_parse_link(struct nlmsghdr *h, int scan)
if (!new)
{
DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
- if (ifi && !scan)
- {
- memcpy(&f, ifi, sizeof(struct iface));
- f.flags |= IF_SHUTDOWN;
- if_update(&f);
- }
+ if (!ifi)
+ return;
+
+ if_delete(ifi);
}
else
{
DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
- if (ifi)
- memcpy(&f, ifi, sizeof(f));
- else
- {
- bzero(&f, sizeof(f));
- f.index = i->ifi_index;
- }
- strncpy(f.name, RTA_DATA(a[IFLA_IFNAME]), sizeof(f.name)-1);
+ if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1))
+ if_delete(ifi);
+
+ strncpy(f.name, name, sizeof(f.name)-1);
+ f.index = i->ifi_index;
f.mtu = mtu;
- f.flags = 0;
+
fl = i->ifi_flags;
if (fl & IFF_UP)
f.flags |= IF_ADMIN_UP;