]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Use global netlink rtm event object
authorBen Greear <greearb@candelatech.com>
Thu, 20 Oct 2011 23:03:25 +0000 (02:03 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 22 Oct 2011 09:39:05 +0000 (12:39 +0300)
Netlink sockets can be shared among all driver instances, saving lots
of sockets, spurious log messages, memory, and CPU usage when using
multiple interfaces in a single process.

src/drivers/driver_nl80211.c

index 08e6025394f2812c2b39b636071f5811c4003c70..1289fcc748411468bddf6d9855b2b544934a3ab1 100644 (file)
@@ -119,8 +119,11 @@ static inline int __genl_ctrl_alloc_cache(struct nl_handle *h,
 struct nl80211_global {
        struct dl_list interfaces;
        int if_add_ifindex;
+       struct netlink_data *netlink;
 };
 
+static void nl80211_global_deinit(void *priv);
+
 struct i802_bss {
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *next;
@@ -138,7 +141,6 @@ struct wpa_driver_nl80211_data {
        u8 addr[ETH_ALEN];
        char phyname[32];
        void *ctx;
-       struct netlink_data *netlink;
        int ioctl_sock; /* socket for ioctl() use */
        int ifindex;
        int if_removed;
@@ -504,17 +506,32 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static struct wpa_driver_nl80211_data *
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+{
+       struct wpa_driver_nl80211_data *drv;
+       dl_list_for_each(drv, &global->interfaces,
+                        struct wpa_driver_nl80211_data, list) {
+               if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
+                   have_ifidx(drv, idx))
+                       return drv;
+       }
+       return NULL;
+}
+
+
 static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                                                 struct ifinfomsg *ifi,
                                                 u8 *buf, size_t len)
 {
-       struct wpa_driver_nl80211_data *drv = ctx;
+       struct nl80211_global *global = ctx;
+       struct wpa_driver_nl80211_data *drv;
        int attrlen, rta_len;
        struct rtattr *attr;
        u32 brid = 0;
 
-       if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
-           !have_ifidx(drv, ifi->ifi_index)) {
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       if (!drv) {
                wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
                           "ifindex %d", ifi->ifi_index);
                return;
@@ -556,7 +573,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        if (drv->operstate == 1 &&
            (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
            !(ifi->ifi_flags & IFF_RUNNING))
-               netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+               netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
                                       -1, IF_OPER_UP);
 
        attrlen = len;
@@ -590,11 +607,19 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                                                 struct ifinfomsg *ifi,
                                                 u8 *buf, size_t len)
 {
-       struct wpa_driver_nl80211_data *drv = ctx;
+       struct nl80211_global *global = ctx;
+       struct wpa_driver_nl80211_data *drv;
        int attrlen, rta_len;
        struct rtattr *attr;
        u32 brid = 0;
 
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       if (!drv) {
+               wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
+                          "foreign ifindex %d", ifi->ifi_index);
+               return;
+       }
+
        attrlen = len;
        attr = (struct rtattr *) buf;
 
@@ -2129,7 +2154,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                                      void *global_priv)
 {
        struct wpa_driver_nl80211_data *drv;
-       struct netlink_config *cfg;
        struct rfkill_config *rcfg;
        struct i802_bss *bss;
 
@@ -2159,18 +2183,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                goto failed;
        }
 
-       cfg = os_zalloc(sizeof(*cfg));
-       if (cfg == NULL)
-               goto failed;
-       cfg->ctx = drv;
-       cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
-       cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
-       drv->netlink = netlink_init(cfg);
-       if (drv->netlink == NULL) {
-               os_free(cfg);
-               goto failed;
-       }
-
        rcfg = os_zalloc(sizeof(*rcfg));
        if (rcfg == NULL)
                goto failed;
@@ -2199,7 +2211,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
 
 failed:
        rfkill_deinit(drv->rfkill);
-       netlink_deinit(drv->netlink);
        if (drv->ioctl_sock >= 0)
                close(drv->ioctl_sock);
 
@@ -2349,7 +2360,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
                }
        }
 
-       netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
                               1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
@@ -2454,8 +2465,8 @@ static void wpa_driver_nl80211_deinit(void *priv)
        if (drv->disable_11b_rates)
                nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
-       netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
-       netlink_deinit(drv->netlink);
+       netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+                              IF_OPER_UP);
        rfkill_deinit(drv->rfkill);
 
        eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
@@ -5758,7 +5769,7 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state)
        wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
                   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
        drv->operstate = state;
-       return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+       return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
                                      state ? IF_OPER_UP : IF_OPER_DORMANT);
 }
 
@@ -6453,7 +6464,6 @@ static void *i802_init(struct hostapd_data *hapd,
 failed:
        nl80211_remove_monitor_interface(drv);
        rfkill_deinit(drv->rfkill);
-       netlink_deinit(drv->netlink);
        if (drv->ioctl_sock >= 0)
                close(drv->ioctl_sock);
 
@@ -7168,12 +7178,32 @@ static int nl80211_set_param(void *priv, const char *param)
 static void * nl80211_global_init(void)
 {
        struct nl80211_global *global;
+       struct netlink_config *cfg;
+
        global = os_zalloc(sizeof(*global));
        if (global == NULL)
                return NULL;
        dl_list_init(&global->interfaces);
        global->if_add_ifindex = -1;
+
+       cfg = os_zalloc(sizeof(*cfg));
+       if (cfg == NULL)
+               goto err;
+
+       cfg->ctx = global;
+       cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+       cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+       global->netlink = netlink_init(cfg);
+       if (global->netlink == NULL) {
+               os_free(cfg);
+               goto err;
+       }
+
        return global;
+
+err:
+       nl80211_global_deinit(global);
+       return NULL;
 }
 
 
@@ -7187,6 +7217,10 @@ static void nl80211_global_deinit(void *priv)
                           "nl80211_global_deinit",
                           dl_list_len(&global->interfaces));
        }
+
+       if (global->netlink)
+               netlink_deinit(global->netlink);
+
        os_free(global);
 }