wl12xx cards require knowledge of the real SSID when operating as AP
with SSID hidden in beacon data. Allow passing the real SSID from
usermode apart from beacon data.
Signed-off-by: Arik Nemtsov <[email protected]>
---
include/net/cfg80211.h | 5 +++++
net/wireless/nl80211.c | 8 ++++++++
2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1322695..03b1b0c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -607,6 +607,9 @@ struct mpath_info {
* @ap_isolate: do not forward packets between connected stations
* @ht_opmode: HT Operation mode
* (u16 = opmode, -1 = do not change)
+ * @ssid_len: length of ssid string
+ * (>0 = ssid_len, -1 = do not change)
+ * @ssid: SSID string (for AP mode). NULL termination not required.
*/
struct bss_parameters {
int use_cts_prot;
@@ -616,6 +619,8 @@ struct bss_parameters {
u8 basic_rates_len;
int ap_isolate;
int ht_opmode;
+ int ssid_len;
+ u8 *ssid;
};
/*
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9b62710..ce5453d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2576,6 +2576,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
params.use_short_slot_time = -1;
params.ap_isolate = -1;
params.ht_opmode = -1;
+ params.ssid_len = -1;
if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
params.use_cts_prot =
@@ -2597,6 +2598,13 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE])
params.ht_opmode =
nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]);
+ if (info->attrs[NL80211_ATTR_SSID]) {
+ params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ params.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+ if (params.ssid_len == 0 ||
+ params.ssid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ }
if (!rdev->ops->change_bss)
return -EOPNOTSUPP;
--
1.7.1
On Thu, Jan 20, 2011 at 22:52, Johannes Berg <[email protected]> wrote:
>
> As I also just commented on the corresponding hostapd patch, I'm not
> sure this is sufficient. If this is necessary for probe response
> offloading, I'm tempted to say that we should be honest about it and let
> userspace determine the entire probe response (which will contain the
> correct SSID) since it can be different from the beacon which presumably
> you're now using to generate probe responses.
>
Well the SSID is still needed in its pure form (i.e. not bundled up
inside some skb). The FW needs it in order to decide which probe
requests it will respond to in hidden-SSID mode.
You're talking about adding another set_probe_resp() callback from
hostapd. That makes sense. I'll look into it.
In the meanwhile are there any comments for this portion?
Regards,
Arik
Detect whether our SSID is hidden by comparing beacon data with
the SSID in bss_conf.
If a hidden SSID is requested, generate a probe response tamplate
containing the real SSID.
Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 23 ++++------
drivers/net/wireless/wl12xx/main.c | 81 ++++++++++++++++++++++++++++++++----
2 files changed, 83 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index e28d9ca..7a6f39e 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -966,16 +966,6 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
wl1271_debug(DEBUG_CMD, "cmd start bss");
- /*
- * FIXME: 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");
- ret = -EINVAL;
- goto out;
- }
-
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
@@ -993,9 +983,16 @@ int wl1271_cmd_start_bss(struct wl1271 *wl)
cmd->dtim_interval = bss_conf->dtim_period;
cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
cmd->channel = wl->channel;
- cmd->ssid_len = wl->ssid_len;
- cmd->ssid_type = SSID_TYPE_PUBLIC;
- memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
+
+ /* We use a visible SSID if the beacon SSID matches bss_conf */
+ if (wl->ssid_len > 0 && wl->ssid_len == bss_conf->ssid_len &&
+ !memcmp(wl->ssid, bss_conf->ssid, wl->ssid_len))
+ cmd->ssid_type = SSID_TYPE_PUBLIC;
+ else
+ cmd->ssid_type = SSID_TYPE_HIDDEN;
+
+ cmd->ssid_len = bss_conf->ssid_len;
+ memcpy(cmd->ssid, bss_conf->ssid, bss_conf->ssid_len);
switch (wl->band) {
case IEEE80211_BAND_2GHZ:
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 9076555..b73d750 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2041,6 +2041,66 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
return -ENOENT;
}
+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;
+ u8 *ptr;
+
+ /* no need to change probe response if the SSID is set correctly */
+ if (wl->ssid_len > 0 && wl->ssid_len == bss_conf->ssid_len &&
+ !memcmp(wl->ssid, bss_conf->ssid, wl->ssid_len))
+ 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 = probe_rsp_data + ie_offset;
+
+ while (ptr < probe_rsp_data + probe_rsp_len) {
+ if (ptr[0] == WLAN_EID_SSID)
+ break;
+ ptr += (ptr[1] + 2);
+ }
+
+ if (ptr == probe_rsp_data + probe_rsp_len)
+ 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)
@@ -2126,20 +2186,25 @@ 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;
}
out:
+ if (ret != 0)
+ wl1271_error("beacon info change failed: %d", ret);
return ret;
}
--
1.7.1
On Fri, 2011-01-21 at 20:01 +0200, Arik Nemtsov wrote:
> On Thu, Jan 20, 2011 at 22:52, Johannes Berg <[email protected]> wrote:
> >
> > As I also just commented on the corresponding hostapd patch, I'm not
> > sure this is sufficient. If this is necessary for probe response
> > offloading, I'm tempted to say that we should be honest about it and let
> > userspace determine the entire probe response (which will contain the
> > correct SSID) since it can be different from the beacon which presumably
> > you're now using to generate probe responses.
> >
>
> Well the SSID is still needed in its pure form (i.e. not bundled up
> inside some skb).
Technically you can easily parse it out but I agree.
> You're talking about adding another set_probe_resp() callback from
> hostapd. That makes sense. I'll look into it.
>
> In the meanwhile are there any comments for this portion?
Not really, except that I think that by itself it's insufficient. I
might add that depending on how the probe response thing works out in
the supplicant, it might make sense to add a capability flag that makes
the driver request this behaviour, since it would also disable
multi-SSID operation on a single BSSID (if that gets ever implemented)
for example since only a single probe request can be transmitted.
Also, P2P GO might be quite tricky with this, but I'm not exactly sure.
johannes
On Sun, Jan 23, 2011 at 10:23:10AM +0100, Johannes Berg wrote:
> Not really, except that I think that by itself it's insufficient. I
> might add that depending on how the probe response thing works out in
> the supplicant, it might make sense to add a capability flag that makes
> the driver request this behaviour, since it would also disable
> multi-SSID operation on a single BSSID (if that gets ever implemented)
> for example since only a single probe request can be transmitted.
Yes, it would be useful to allow user space to figure out whether the
driver is generating Probe Response frames on it own (without having to
guess this based on never seeing Probe Request frames or something
similar).
> Also, P2P GO might be quite tricky with this, but I'm not exactly sure.
For the most basic functionality, it need a mechanism that allows the
Probe Response template to be updated during the lifetime of the BSS.
However, to fully comply with the P2P spec, whatever code is taking care
of processing Probe Request frames would need to be able to
conditionally include the P2P IE(s) from the template based on whether
the Probe Request frame included a P2P IE. In addition, it would need to
be able to check the Requested Device Type against the list of device
types (both local and remote) in the group to determine whether to reply
to the request.
--
Jouni Malinen PGP id EFC895FA
When operating as AP, save SSID data as part of the ieee80211_bss_conf
struct. Allow low level drivers to receive notifications about SSID
changes.
Signed-off-by: Arik Nemtsov <[email protected]>
---
include/net/mac80211.h | 6 ++++++
net/mac80211/cfg.c | 7 +++++++
net/mac80211/util.c | 7 ++++++-
3 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 62c0ce2..ff3bad1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -164,6 +164,7 @@ struct ieee80211_low_level_stats {
* @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note
* that it is only ever disabled for station mode.
* @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
+ * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -181,6 +182,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_ARP_FILTER = 1<<12,
BSS_CHANGED_QOS = 1<<13,
BSS_CHANGED_IDLE = 1<<14,
+ BSS_CHANGED_SSID = 1<<15,
/* when adding here, make sure to change ieee80211_reconfig */
};
@@ -243,6 +245,8 @@ enum ieee80211_bss_change {
* @idle: This interface is idle. There's also a global idle flag in the
* hardware config which may be more appropriate depending on what
* your driver/device needs to do.
+ * @ssid_len: Length of @ssid in octets (in AP mode)
+ * @ssid: SSID for this BSS (in AP mode)
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -269,6 +273,8 @@ struct ieee80211_bss_conf {
bool arp_filter_enabled;
bool qos;
bool idle;
+ u8 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
};
/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4bc8a92..a2a75e9 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1172,6 +1172,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
changed |= BSS_CHANGED_HT;
}
+ if (params->ssid_len > 0) {
+ memcpy(sdata->vif.bss_conf.ssid, params->ssid,
+ params->ssid_len);
+ sdata->vif.bss_conf.ssid_len = params->ssid_len;
+ changed |= BSS_CHANGED_SSID;
+ }
+
ieee80211_bss_info_change_notify(sdata, changed);
return 0;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index cf68700..a2d2f73 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1212,10 +1212,15 @@ int ieee80211_reconfig(struct ieee80211_local *local)
changed |= BSS_CHANGED_ASSOC;
ieee80211_bss_info_change_notify(sdata, changed);
break;
+ case NL80211_IFTYPE_AP:
+ changed |= BSS_CHANGED_SSID |
+ BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED;
+ ieee80211_bss_info_change_notify(sdata, changed);
+ break;
case NL80211_IFTYPE_ADHOC:
changed |= BSS_CHANGED_IBSS;
/* fall through */
- case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
changed |= BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED;
--
1.7.1
On Thu, 2011-01-20 at 22:28 +0200, Arik Nemtsov wrote:
> wl12xx cards require knowledge of the real SSID when operating as AP
> with SSID hidden in beacon data. Allow passing the real SSID from
> usermode apart from beacon data.
As I also just commented on the corresponding hostapd patch, I'm not
sure this is sufficient. If this is necessary for probe response
offloading, I'm tempted to say that we should be honest about it and let
userspace determine the entire probe response (which will contain the
correct SSID) since it can be different from the beacon which presumably
you're now using to generate probe responses.
johannes