From a1fce3911f4b04e67b4ecd9f91af8e5e0b8b72c1 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 3 Dec 2016 22:37:41 +0200 Subject: [PATCH] nl80211: Optimize memory use in nl80211_get_assoc_freq() Do not use the generic bss_info_handler() design to fetch all scan results into temporary memory buffer. Instead, use a separate BSS info handler that fetches the requested information without fully parsing the BSS entries and without allocating any memory for collecting all the results. This is also simplifying bss_info_handler() and nl80211_parse_bss_info() design by getting rid of the special case that was used only for nl80211_get_assoc_freq() and not normal scan result fetching. Signed-off-by: Jouni Malinen --- src/drivers/driver_nl80211.c | 58 +++++++++++++++++++++++++++++-- src/drivers/driver_nl80211.h | 9 ----- src/drivers/driver_nl80211_scan.c | 40 +++++---------------- 3 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 4f7069bf2..6bd984d56 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1181,16 +1181,70 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, } +struct nl80211_get_assoc_freq_arg { + struct wpa_driver_nl80211_data *drv; + unsigned int assoc_freq; + unsigned int ibss_freq; + u8 assoc_bssid[ETH_ALEN]; +}; + +static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *bss[NL80211_BSS_MAX + 1]; + static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { + [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, + [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + }; + struct nl80211_get_assoc_freq_arg *ctx = arg; + enum nl80211_bss_status status; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[NL80211_ATTR_BSS] || + nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], + bss_policy) || + !bss[NL80211_BSS_STATUS]) + return NL_SKIP; + + status = nla_get_u32(bss[NL80211_BSS_STATUS]); + if (status == NL80211_BSS_STATUS_ASSOCIATED && + bss[NL80211_BSS_FREQUENCY]) { + ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); + wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz", + ctx->assoc_freq); + } + if (status == NL80211_BSS_STATUS_IBSS_JOINED && + bss[NL80211_BSS_FREQUENCY]) { + ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); + wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz", + ctx->ibss_freq); + } + if (status == NL80211_BSS_STATUS_ASSOCIATED && + bss[NL80211_BSS_BSSID]) { + os_memcpy(ctx->assoc_bssid, + nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); + wpa_printf(MSG_DEBUG, "nl80211: Associated with " + MACSTR, MAC2STR(ctx->assoc_bssid)); + } + + return NL_SKIP; +} + + unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv) { struct nl_msg *msg; int ret; - struct nl80211_bss_info_arg arg; + struct nl80211_get_assoc_freq_arg arg; msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); os_memset(&arg, 0, sizeof(arg)); arg.drv = drv; - ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); + ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler, + &arg); if (ret == 0) { unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ? arg.ibss_freq : arg.assoc_freq; diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 8d12978bd..3e33158ae 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -282,15 +282,6 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, /* driver_nl80211_scan.c */ -struct nl80211_bss_info_arg { - struct wpa_driver_nl80211_data *drv; - struct wpa_scan_results *res; - unsigned int assoc_freq; - unsigned int ibss_freq; - u8 assoc_bssid[ETH_ALEN]; -}; - -int bss_info_handler(struct nl_msg *msg, void *arg); void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); int wpa_driver_nl80211_scan(struct i802_bss *bss, struct wpa_driver_scan_params *params); diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 385ba6b2a..43ed2b74c 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -628,7 +628,7 @@ static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv, static struct wpa_scan_res * nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, - struct nl_msg *msg, struct nl80211_bss_info_arg *_arg) + struct nl_msg *msg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); @@ -658,33 +658,6 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) return NULL; - if (bss[NL80211_BSS_STATUS] && _arg) { - enum nl80211_bss_status status; - status = nla_get_u32(bss[NL80211_BSS_STATUS]); - if (status == NL80211_BSS_STATUS_ASSOCIATED && - bss[NL80211_BSS_FREQUENCY]) { - _arg->assoc_freq = - nla_get_u32(bss[NL80211_BSS_FREQUENCY]); - wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz", - _arg->assoc_freq); - } - if (status == NL80211_BSS_STATUS_IBSS_JOINED && - bss[NL80211_BSS_FREQUENCY]) { - _arg->ibss_freq = - nla_get_u32(bss[NL80211_BSS_FREQUENCY]); - wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz", - _arg->ibss_freq); - } - if (status == NL80211_BSS_STATUS_ASSOCIATED && - bss[NL80211_BSS_BSSID]) { - os_memcpy(_arg->assoc_bssid, - nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); - wpa_printf(MSG_DEBUG, "nl80211: Associated with " - MACSTR, MAC2STR(_arg->assoc_bssid)); - } - } - if (_arg && !_arg->res) - return NULL; if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); @@ -761,14 +734,19 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, } -int bss_info_handler(struct nl_msg *msg, void *arg) +struct nl80211_bss_info_arg { + struct wpa_driver_nl80211_data *drv; + struct wpa_scan_results *res; +}; + +static int bss_info_handler(struct nl_msg *msg, void *arg) { struct nl80211_bss_info_arg *_arg = arg; struct wpa_scan_results *res = _arg->res; struct wpa_scan_res **tmp; struct wpa_scan_res *r; - r = nl80211_parse_bss_info(_arg->drv, msg, _arg); + r = nl80211_parse_bss_info(_arg->drv, msg); if (!r) return NL_SKIP; @@ -920,7 +898,7 @@ static int nl80211_dump_scan_handler(struct nl_msg *msg, void *arg) struct nl80211_dump_scan_ctx *ctx = arg; struct wpa_scan_res *r; - r = nl80211_parse_bss_info(ctx->drv, msg, NULL); + r = nl80211_parse_bss_info(ctx->drv, msg); if (!r) return NL_SKIP; wpa_printf(MSG_DEBUG, "nl80211: %d " MACSTR " %d%s",