nl80211: Use global netlink rtm event object

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.
This commit is contained in:
Ben Greear 2011-10-21 02:03:25 +03:00 committed by Jouni Malinen
parent 4b24282a17
commit 36d84860bb

View 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);
}