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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2016-12-03 22:37:41 +02:00
parent da2c284169
commit a1fce3911f
3 changed files with 65 additions and 42 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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",