diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 08e602539..1289fcc74 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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); }