wl12xx: AP mode - support hidden SSID
authorArik Nemtsov <arik@wizery.com>
Sat, 3 Sep 2011 17:22:03 +0000 (20:22 +0300)
committerLuciano Coelho <coelho@ti.com>
Fri, 23 Sep 2011 11:43:32 +0000 (14:43 +0300)
If a hidden SSID is requested, generate a probe response template
containing the real SSID.

Depends on the patch "mac80211: add ssid config to bss information
in AP-mode".

Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/main.c

index 084262f169b2e3469b3150f21657a08ce0f8a758..51be8f7fbb88af91331037ebca0d3ccd02fd1f65 100644 (file)
@@ -661,12 +661,9 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
 
        wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id);
 
-       /*
-        * We currently do not support hidden SSID. The real SSID
-        * should be fetched from mac80211 first.
-        */
-       if (wl->ssid_len == 0) {
-               wl1271_warning("Hidden SSID currently not supported for AP");
+       /* trying to use hidden SSID with an old hostapd version */
+       if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) {
+               wl1271_error("got a null SSID from beacon/bss");
                ret = -EINVAL;
                goto out;
        }
@@ -695,9 +692,18 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
        cmd->ap.dtim_interval = bss_conf->dtim_period;
        cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
        cmd->channel = wl->channel;
-       cmd->ap.ssid_len = wl->ssid_len;
-       cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
-       memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+
+       if (!bss_conf->hidden_ssid) {
+               /* take the SSID from the beacon for backward compatibility */
+               cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
+               cmd->ap.ssid_len = wl->ssid_len;
+               memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+       } else {
+               cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN;
+               cmd->ap.ssid_len = bss_conf->ssid_len;
+               memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
+       }
+
        cmd->ap.local_rates = cpu_to_le32(0xffffffff);
 
        switch (wl->band) {
index 62118b7988bd0acf9913c2620de46da3e226fe41..02b5c007d1bf7831a409f1b8ca9bace667a2d149 100644 (file)
@@ -3102,6 +3102,62 @@ static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
        skb_trim(skb, skb->len - len);
 }
 
+static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
+                                        u8 *probe_rsp_data,
+                                        size_t probe_rsp_len,
+                                        u32 rates)
+{
+       struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+       u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
+       int ssid_ie_offset, ie_offset, templ_len;
+       const u8 *ptr;
+
+       /* no need to change probe response if the SSID is set correctly */
+       if (wl->ssid_len > 0)
+               return wl1271_cmd_template_set(wl,
+                                              CMD_TEMPL_AP_PROBE_RESPONSE,
+                                              probe_rsp_data,
+                                              probe_rsp_len, 0,
+                                              rates);
+
+       if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
+               wl1271_error("probe_rsp template too big");
+               return -EINVAL;
+       }
+
+       /* start searching from IE offset */
+       ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+
+       ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
+                              probe_rsp_len - ie_offset);
+       if (!ptr) {
+               wl1271_error("No SSID in beacon!");
+               return -EINVAL;
+       }
+
+       ssid_ie_offset = ptr - probe_rsp_data;
+       ptr += (ptr[1] + 2);
+
+       memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
+
+       /* insert SSID from bss_conf */
+       probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
+       probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
+       memcpy(probe_rsp_templ + ssid_ie_offset + 2,
+              bss_conf->ssid, bss_conf->ssid_len);
+       templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
+
+       memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
+              ptr, probe_rsp_len - (ptr - probe_rsp_data));
+       templ_len += probe_rsp_len - (ptr - probe_rsp_data);
+
+       return wl1271_cmd_template_set(wl,
+                                      CMD_TEMPL_AP_PROBE_RESPONSE,
+                                      probe_rsp_templ,
+                                      templ_len, 0,
+                                      rates);
+}
+
 static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
                                       struct ieee80211_bss_conf *bss_conf,
                                       u32 changed)
@@ -3201,14 +3257,17 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
                hdr = (struct ieee80211_hdr *) beacon->data;
                hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                                 IEEE80211_STYPE_PROBE_RESP);
-
-               tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
-                                 CMD_TEMPL_PROBE_RESPONSE;
-               ret = wl1271_cmd_template_set(wl,
-                                             tmpl_id,
-                                             beacon->data,
-                                             beacon->len, 0,
-                                             wl1271_tx_min_rate_get(wl));
+               if (is_ap)
+                       ret = wl1271_ap_set_probe_resp_tmpl(wl,
+                                               beacon->data,
+                                               beacon->len,
+                                               wl1271_tx_min_rate_get(wl));
+               else
+                       ret = wl1271_cmd_template_set(wl,
+                                               CMD_TEMPL_PROBE_RESPONSE,
+                                               beacon->data,
+                                               beacon->len, 0,
+                                               wl1271_tx_min_rate_get(wl));
                dev_kfree_skb(beacon);
                if (ret < 0)
                        goto out;