From ed0a4ddc22526361a138c6b145561fcaac24e2a5 Mon Sep 17 00:00:00 2001 From: Ningyuan Wang Date: Mon, 24 Oct 2016 10:59:52 -0700 Subject: [PATCH] nl80211: Update drv->ssid on connect/associate event based on BSS data On a connect nl80211 event, wpa_supplicant uses wpa_driver_nl80211_get_ssid() to fetch the current associated SSID to compare to existing configurations. However, wpa_driver_nl80211_get_ssid() uses drv->ssid, which is a cached value. It is set when we explicitly initial a connect request using wpa_supplicant. If the association was initiated outside of wpa_supplicant, we need another way to populate drv->ssid. This commit sets drv->ssid based on cfg80211 BSS information on connect/associate nl80211 events. Signed-off-by: Ningyuan Wang --- src/drivers/driver_nl80211.c | 38 ++++++++++++++++++++++++++++++ src/drivers/driver_nl80211.h | 1 + src/drivers/driver_nl80211_event.c | 28 +++++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b23c440fd..d5716dbcc 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1186,6 +1186,8 @@ struct nl80211_get_assoc_freq_arg { unsigned int assoc_freq; unsigned int ibss_freq; u8 assoc_bssid[ETH_ALEN]; + u8 assoc_ssid[SSID_MAX_LEN]; + u8 assoc_ssid_len; }; static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) @@ -1196,6 +1198,7 @@ static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, }; struct nl80211_get_assoc_freq_arg *ctx = arg; @@ -1230,10 +1233,45 @@ static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) MACSTR, MAC2STR(ctx->assoc_bssid)); } + if (status == NL80211_BSS_STATUS_ASSOCIATED && + bss[NL80211_BSS_INFORMATION_ELEMENTS]) { + const u8 *ie, *ssid; + size_t ie_len; + + ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + ssid = get_ie(ie, ie_len, WLAN_EID_SSID); + if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) { + ctx->assoc_ssid_len = ssid[1]; + os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]); + } + } + return NL_SKIP; } +int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid) +{ + struct nl_msg *msg; + int ret; + 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, nl80211_get_assoc_freq_handler, + &arg); + if (ret == 0) { + os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len); + return arg.assoc_ssid_len; + } + wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)", + ret, strerror(-ret)); + return ret; +} + + unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv) { struct nl_msg *msg; diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 3e33158ae..94b8bdf19 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -228,6 +228,7 @@ int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, void *arg, int use_existing); void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx); unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv); +int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid); enum chan_width convert2width(int width); void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv); struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv, diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 994bc4c10..66cfb7200 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -206,6 +206,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, const struct ieee80211_mgmt *mgmt; union wpa_event_data event; u16 status; + int ssid_len; if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && drv->force_connect_cmd) { @@ -257,6 +258,16 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, event.assoc_info.freq = drv->assoc_freq; + /* When this association was initiated outside of wpa_supplicant, + * drv->ssid needs to be set here to satisfy later checking. */ + ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid); + if (ssid_len > 0) { + drv->ssid_len = ssid_len; + wpa_printf(MSG_DEBUG, + "nl80211: Set drv->ssid based on scan res info to '%s'", + wpa_ssid_txt(drv->ssid, drv->ssid_len)); + } + nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params); wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); @@ -275,8 +286,9 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, struct nlattr *subnet_status) { union wpa_event_data event; - const u8 *ssid; + const u8 *ssid = NULL; u16 status_code; + int ssid_len; if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { /* @@ -347,6 +359,10 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, if (ssid && ssid[1] > 0 && ssid[1] <= 32) { drv->ssid_len = ssid[1]; os_memcpy(drv->ssid, ssid + 2, ssid[1]); + wpa_printf(MSG_DEBUG, + "nl80211: Set drv->ssid based on req_ie to '%s'", + wpa_ssid_txt(drv->ssid, + drv->ssid_len)); } } } @@ -357,6 +373,16 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, event.assoc_info.freq = nl80211_get_assoc_freq(drv); + if ((!ssid || ssid[1] == 0 || ssid[1] > 32) && + (ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) { + /* When this connection was initiated outside of wpa_supplicant, + * drv->ssid needs to be set here to satisfy later checking. */ + drv->ssid_len = ssid_len; + wpa_printf(MSG_DEBUG, + "nl80211: Set drv->ssid based on scan res info to '%s'", + wpa_ssid_txt(drv->ssid, drv->ssid_len)); + } + if (authorized && nla_get_u8(authorized)) { event.assoc_info.authorized = 1; wpa_printf(MSG_DEBUG, "nl80211: connection authorized");