aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pingu_iface.c33
-rw-r--r--pingu_iface.h7
-rw-r--r--pingu_netlink.c57
3 files changed, 87 insertions, 10 deletions
diff --git a/pingu_iface.c b/pingu_iface.c
index b5d8355..4de0bc6 100644
--- a/pingu_iface.c
+++ b/pingu_iface.c
@@ -62,7 +62,7 @@ int pingu_iface_usable(struct pingu_iface *iface)
return iface->has_link && iface->has_binding;
}
-struct pingu_iface *pingu_iface_find(const char *name)
+struct pingu_iface *pingu_iface_get_by_name(const char *name)
{
struct pingu_iface *iface;
list_for_each_entry(iface, &iface_list, iface_list_entry) {
@@ -75,9 +75,19 @@ struct pingu_iface *pingu_iface_find(const char *name)
return NULL;
}
+struct pingu_iface *pingu_iface_get_by_index(int index)
+{
+ struct pingu_iface *iface;
+ list_for_each_entry(iface, &iface_list, iface_list_entry) {
+ if (iface->index == index)
+ return iface;
+ }
+ return NULL;
+}
+
struct pingu_iface *pingu_iface_find_or_create(struct ev_loop *loop, const char *name)
{
- struct pingu_iface *iface = pingu_iface_find(name);
+ struct pingu_iface *iface = pingu_iface_get_by_name(name);
if (iface != NULL)
return iface;
@@ -99,6 +109,25 @@ struct pingu_iface *pingu_iface_find_or_create(struct ev_loop *loop, const char
return iface;
}
+void pingu_iface_set_addr(struct pingu_iface *iface, int family,
+ void *data, int len)
+{
+ struct sockaddr_in *sin;
+ memset(&iface->primary_addr, 0, sizeof(iface->primary_addr));
+ if (len <= 0) {
+ log_debug("%s: address removed", iface->name);
+ return;
+ }
+ iface->primary_addr.sa_family = family;
+ switch (family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)&iface->primary_addr;
+ memcpy(&sin->sin_addr, data, len);
+ log_debug("%s: new address: %s", iface->name, inet_ntoa(sin->sin_addr));
+ break;
+ }
+}
+
int pingu_iface_init(struct ev_loop *loop, struct list_head *host_list)
{
struct pingu_host *host;
diff --git a/pingu_iface.h b/pingu_iface.h
index 518e441..84145a8 100644
--- a/pingu_iface.h
+++ b/pingu_iface.h
@@ -10,16 +10,21 @@ struct pingu_iface {
int has_binding;
int has_link;
int fd;
+ struct sockaddr primary_addr;
struct list_head iface_list_entry;
// struct list_head burst_list;
struct list_head ping_list;
struct ev_io socket_watcher;
};
-struct pingu_iface *pingu_iface_find(const char *name);
+struct pingu_iface *pingu_iface_get_by_name(const char *name);
+struct pingu_iface *pingu_iface_get_by_index(int index);
struct pingu_iface *pingu_iface_find_or_create(struct ev_loop *loop, const char *name);
int pingu_iface_bind_socket(struct pingu_iface *iface, int log_error);
int pingu_iface_usable(struct pingu_iface *iface);
int pingu_iface_init(struct ev_loop *loop, struct list_head *host_list);
+void pingu_iface_set_addr(struct pingu_iface *iface, int family,
+ void *data, int len);
+
#endif
diff --git a/pingu_netlink.c b/pingu_netlink.c
index 94422bd..98a7b6b 100644
--- a/pingu_netlink.c
+++ b/pingu_netlink.c
@@ -178,7 +178,7 @@ static void netlink_link_new(struct nlmsghdr *msg)
return;
ifname = RTA_DATA(rta[IFLA_IFNAME]);
- iface = pingu_iface_find(ifname);
+ iface = pingu_iface_get_by_name(ifname);
if (iface == NULL)
return;
@@ -207,7 +207,7 @@ static void netlink_link_del(struct nlmsghdr *msg)
return;
ifname = RTA_DATA(rta[IFLA_IFNAME]);
- iface = pingu_iface_find(ifname);
+ iface = pingu_iface_get_by_name(ifname);
if (iface == NULL)
return;
@@ -216,11 +216,54 @@ static void netlink_link_del(struct nlmsghdr *msg)
iface->has_link = 0;
}
+static void netlink_addr_new(struct nlmsghdr *msg)
+{
+ struct pingu_iface *iface;
+ struct ifaddrmsg *ifa = NLMSG_DATA(msg);
+ struct rtattr *rta[IFA_MAX+1];
+
+ if (ifa->ifa_flags & IFA_F_SECONDARY)
+ return;
+
+ netlink_parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(msg));
+ if (rta[IFA_LOCAL] == NULL)
+ return;
+
+ iface = pingu_iface_get_by_index(ifa->ifa_index);
+ if (iface == NULL || rta[IFA_LOCAL] == NULL)
+ return;
+
+ pingu_iface_set_addr(iface, ifa->ifa_family,
+ RTA_DATA(rta[IFA_LOCAL]),
+ RTA_PAYLOAD(rta[IFA_LOCAL]));
+}
+
+static void netlink_addr_del(struct nlmsghdr *nlmsg)
+{
+ struct pingu_iface *iface;
+ struct ifaddrmsg *ifa = NLMSG_DATA(nlmsg);
+ struct rtattr *rta[IFA_MAX+1];
+
+ if (ifa->ifa_flags & IFA_F_SECONDARY)
+ return;
+
+ netlink_parse_rtattr(rta, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(nlmsg));
+ if (rta[IFA_LOCAL] == NULL)
+ return;
+
+ iface = pingu_iface_get_by_index(ifa->ifa_index);
+ if (iface == NULL)
+ return;
+
+ pingu_iface_set_addr(iface, 0, NULL, 0);
+}
+
+
static const netlink_dispatch_f route_dispatch[RTM_MAX] = {
[RTM_NEWLINK] = netlink_link_new,
[RTM_DELLINK] = netlink_link_del,
-/* [RTM_NEWADDR] = netlink_addr_new,
- [RTM_DELADDR] = netlink_addr_del,
+ [RTM_NEWADDR] = netlink_addr_new,
+/* [RTM_DELADDR] = netlink_addr_del,
[RTM_NEWROUTE] = netlink_route_new,
[RTM_DELROUTE] = netlink_route_del,
*/
@@ -300,12 +343,12 @@ int kernel_init(struct ev_loop *loop)
netlink_enumerate(&talk_fd, PF_UNSPEC, RTM_GETLINK);
netlink_read_cb(loop, &talk_fd.io, EV_READ);
-/*
netlink_enumerate(&talk_fd, PF_UNSPEC, RTM_GETADDR);
- netlink_read_cb(&talk_fd.io, EV_READ);
+ netlink_read_cb(loop, &talk_fd.io, EV_READ);
+/*
netlink_enumerate(&talk_fd, PF_UNSPEC, RTM_GETROUTE);
- netlink_read_cb(&talk_fd.io, EV_READ);
+ netlink_read_cb(loop, &talk_fd.io, EV_READ);
*/
return TRUE;