]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Update drv->ssid on connect/associate event based on BSS data
authorNingyuan Wang <nywang@google.com>
Mon, 24 Oct 2016 17:59:52 +0000 (10:59 -0700)
committerJouni Malinen <j@w1.fi>
Mon, 5 Dec 2016 10:08:46 +0000 (12:08 +0200)
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 <nywang@google.com>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_event.c

index b23c440fdfdcce429c4123fa45fd4ced3a8d2d35..d5716dbcc6f6f18686f90b0d0f0f1e3c84ed3cad 100644 (file)
@@ -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;
index 3e33158ae92931e11374bdd9cc24d966f0296b2a..94b8bdf19327474195824c3fb5f5267f99e48c4b 100644 (file)
@@ -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,
index 994bc4c103b55aadb70e58709777cc5b81a2f66a..66cfb72009fd8fa1a68a70b37de3a5bf23f7e549 100644 (file)
@@ -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");