diff --git a/Makefile.am b/Makefile.am index f82b6f40..31a1da71 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,7 @@ bin_PROGRAMS = src/iwd client/iwctl src_iwd_SOURCES = src/main.c linux/nl80211.h linux/kdbus.h \ src/kdbus.h src/kdbus.c \ + src/netdev.h src/netdev.c \ src/sha1.h src/sha1.c src_iwd_LDADD = ell/libell-internal.la diff --git a/src/main.c b/src/main.c index ef76a575..a74ea47c 100644 --- a/src/main.c +++ b/src/main.c @@ -77,8 +77,15 @@ int main(int argc, char *argv[]) goto destroy; } + if (!netdev_init()) { + exit_status = EXIT_FAILURE; + goto destroy; + } + l_main_run(); + netdev_exit(); + exit_status = EXIT_SUCCESS; destroy: diff --git a/src/netdev.c b/src/netdev.c new file mode 100644 index 00000000..57d472c5 --- /dev/null +++ b/src/netdev.c @@ -0,0 +1,174 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +struct netdev_data { + uint32_t index; + uint32_t flags; + char ifname[IF_NAMESIZE]; +}; + +static struct l_netlink *rtnl = NULL; +static struct l_hashmap *netdev_list = NULL; + +static void do_debug(const char *str, void *user_data) +{ + const char *prefix = user_data; + + l_info("%s%s", prefix, str); +} + +static void free_netdev_data(void *user_data) +{ + struct netdev_data *netdev = user_data; + + l_free(netdev); +} + +static void newlink_notify(const struct ifinfomsg *ifi, int bytes) +{ + struct netdev_data *netdev; + uint32_t index = ifi->ifi_index; + struct rtattr *rta; + + netdev = l_hashmap_lookup(netdev_list, L_UINT_TO_PTR(index)); + if (!netdev) { + netdev = l_new(struct netdev_data, 1); + + netdev->index = index; + + if (!l_hashmap_insert(netdev_list, + L_UINT_TO_PTR(index), netdev)) { + free_netdev_data(netdev); + return; + } + } + + netdev->flags = ifi->ifi_flags; + + for (rta = IFLA_RTA(ifi); RTA_OK(rta, bytes); + rta = RTA_NEXT(rta, bytes)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + if (RTA_PAYLOAD(rta) <= IF_NAMESIZE) + strcpy(netdev->ifname, RTA_DATA(rta)); + break; + } + } +} + +static void dellink_notify(const struct ifinfomsg *ifi, int bytes) +{ + struct netdev_data *netdev; + uint32_t index = ifi->ifi_index; + + netdev = l_hashmap_remove(netdev_list, L_UINT_TO_PTR(index)); + if (!netdev) + return; + + free_netdev_data(netdev); +} + +static void link_notify(uint16_t type, const void *data, uint32_t len, + void *user_data) +{ + const struct ifinfomsg *ifi = data; + int bytes; + + if (ifi->ifi_type != ARPHRD_ETHER) + return; + + bytes = len - NLMSG_ALIGN(sizeof(struct ifinfomsg)); + + switch (type) { + case RTM_NEWLINK: + newlink_notify(ifi, bytes); + break; + case RTM_DELLINK: + dellink_notify(ifi, bytes); + break; + } +} + +static void netdev_destroy(void) +{ + /* + * The netlink object keeps track of the registered notification + * callbacks and their multicast memberships. When destroying the + * netlink object, all resources will be freed. + */ + l_netlink_destroy(rtnl); + rtnl = NULL; + + l_hashmap_destroy(netdev_list, free_netdev_data); + netdev_list = NULL; +} + +bool netdev_init(void) +{ + if (rtnl) + return false; + + l_debug("Opening route netlink socket"); + + rtnl = l_netlink_new(NETLINK_ROUTE); + if (!rtnl) { + l_error("Failed to open route netlink socket"); + return false; + } + + l_netlink_set_debug(rtnl, do_debug, "[RTNL] ", NULL); + + netdev_list = l_hashmap_new(); + + if (!l_netlink_register(rtnl, RTNLGRP_LINK, link_notify, NULL, NULL)) { + l_error("Failed to register link notification"); + goto destroy; + } + + return true; + +destroy: + netdev_destroy(); + + return false; +} + +bool netdev_exit(void) +{ + if (!rtnl) + return false; + + l_debug("Closing route netlink socket"); + + netdev_destroy(); + + return true; +} diff --git a/src/netdev.h b/src/netdev.h new file mode 100644 index 00000000..20bc1e3d --- /dev/null +++ b/src/netdev.h @@ -0,0 +1,26 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +bool netdev_init(void); +bool netdev_exit(void);