mac80211: Save probe response data for bss
Allow setting a probe response template for an interface operating in AP mode. Low level drivers are notified about changes in the probe response template and are able to retrieve a copy of the current probe response. This data can, for example, be uploaded to hardware as a template. Signed-off-by: Guy Eilam <guy@wizery.com> Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
00f740e1a3
commit
0294582126
@ -166,6 +166,7 @@ struct ieee80211_low_level_stats {
|
|||||||
* that it is only ever disabled for station mode.
|
* that it is only ever disabled for station mode.
|
||||||
* @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
|
* @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
|
||||||
* @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
|
* @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
|
||||||
|
* @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
|
||||||
*/
|
*/
|
||||||
enum ieee80211_bss_change {
|
enum ieee80211_bss_change {
|
||||||
BSS_CHANGED_ASSOC = 1<<0,
|
BSS_CHANGED_ASSOC = 1<<0,
|
||||||
@ -184,6 +185,7 @@ enum ieee80211_bss_change {
|
|||||||
BSS_CHANGED_QOS = 1<<13,
|
BSS_CHANGED_QOS = 1<<13,
|
||||||
BSS_CHANGED_IDLE = 1<<14,
|
BSS_CHANGED_IDLE = 1<<14,
|
||||||
BSS_CHANGED_SSID = 1<<15,
|
BSS_CHANGED_SSID = 1<<15,
|
||||||
|
BSS_CHANGED_AP_PROBE_RESP = 1<<16,
|
||||||
|
|
||||||
/* when adding here, make sure to change ieee80211_reconfig */
|
/* when adding here, make sure to change ieee80211_reconfig */
|
||||||
};
|
};
|
||||||
@ -2674,6 +2676,19 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||||||
return ieee80211_beacon_get_tim(hw, vif, NULL, NULL);
|
return ieee80211_beacon_get_tim(hw, vif, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_proberesp_get - retrieve a Probe Response template
|
||||||
|
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||||
|
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||||
|
*
|
||||||
|
* Creates a Probe Response template which can, for example, be uploaded to
|
||||||
|
* hardware. The destination address should be set by the caller.
|
||||||
|
*
|
||||||
|
* Can only be called in AP mode.
|
||||||
|
*/
|
||||||
|
struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_pspoll_get - retrieve a PS Poll template
|
* ieee80211_pspoll_get - retrieve a PS Poll template
|
||||||
* @hw: pointer obtained from ieee80211_alloc_hw().
|
* @hw: pointer obtained from ieee80211_alloc_hw().
|
||||||
|
@ -491,6 +491,31 @@ static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
|
|||||||
(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
|
(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
|
||||||
|
u8 *resp, size_t resp_len)
|
||||||
|
{
|
||||||
|
struct sk_buff *new, *old;
|
||||||
|
|
||||||
|
if (!resp || !resp_len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
old = sdata->u.ap.probe_resp;
|
||||||
|
|
||||||
|
new = dev_alloc_skb(resp_len);
|
||||||
|
if (!new)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy(skb_put(new, resp_len), resp, resp_len);
|
||||||
|
|
||||||
|
rcu_assign_pointer(sdata->u.ap.probe_resp, new);
|
||||||
|
synchronize_rcu();
|
||||||
|
|
||||||
|
if (old)
|
||||||
|
dev_kfree_skb(old);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This handles both adding a beacon and setting new beacon info
|
* This handles both adding a beacon and setting new beacon info
|
||||||
*/
|
*/
|
||||||
@ -501,6 +526,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
|
|||||||
int new_head_len, new_tail_len;
|
int new_head_len, new_tail_len;
|
||||||
int size;
|
int size;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
u32 changed = 0;
|
||||||
|
|
||||||
old = rtnl_dereference(sdata->u.ap.beacon);
|
old = rtnl_dereference(sdata->u.ap.beacon);
|
||||||
|
|
||||||
@ -584,11 +610,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
|
|||||||
|
|
||||||
kfree(old);
|
kfree(old);
|
||||||
|
|
||||||
ieee80211_config_ap_ssid(sdata, params);
|
err = ieee80211_set_probe_resp(sdata, params->probe_resp,
|
||||||
|
params->probe_resp_len);
|
||||||
|
if (!err)
|
||||||
|
changed |= BSS_CHANGED_AP_PROBE_RESP;
|
||||||
|
|
||||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
|
ieee80211_config_ap_ssid(sdata, params);
|
||||||
BSS_CHANGED_BEACON |
|
changed |= BSS_CHANGED_BEACON_ENABLED |
|
||||||
BSS_CHANGED_SSID);
|
BSS_CHANGED_BEACON |
|
||||||
|
BSS_CHANGED_SSID;
|
||||||
|
|
||||||
|
ieee80211_bss_info_change_notify(sdata, changed);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +232,7 @@ struct beacon_data {
|
|||||||
|
|
||||||
struct ieee80211_if_ap {
|
struct ieee80211_if_ap {
|
||||||
struct beacon_data __rcu *beacon;
|
struct beacon_data __rcu *beacon;
|
||||||
|
struct sk_buff __rcu *probe_resp;
|
||||||
|
|
||||||
struct list_head vlans;
|
struct list_head vlans;
|
||||||
|
|
||||||
|
@ -462,15 +462,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||||||
struct ieee80211_sub_if_data *vlan, *tmpsdata;
|
struct ieee80211_sub_if_data *vlan, *tmpsdata;
|
||||||
struct beacon_data *old_beacon =
|
struct beacon_data *old_beacon =
|
||||||
rtnl_dereference(sdata->u.ap.beacon);
|
rtnl_dereference(sdata->u.ap.beacon);
|
||||||
|
struct sk_buff *old_probe_resp =
|
||||||
|
rtnl_dereference(sdata->u.ap.probe_resp);
|
||||||
|
|
||||||
/* sdata_running will return false, so this will disable */
|
/* sdata_running will return false, so this will disable */
|
||||||
ieee80211_bss_info_change_notify(sdata,
|
ieee80211_bss_info_change_notify(sdata,
|
||||||
BSS_CHANGED_BEACON_ENABLED);
|
BSS_CHANGED_BEACON_ENABLED);
|
||||||
|
|
||||||
/* remove beacon */
|
/* remove beacon and probe response */
|
||||||
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
|
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
|
||||||
|
RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
kfree(old_beacon);
|
kfree(old_beacon);
|
||||||
|
kfree(old_probe_resp);
|
||||||
|
|
||||||
/* down all dependent devices, that is VLANs */
|
/* down all dependent devices, that is VLANs */
|
||||||
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
|
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
|
||||||
|
@ -2415,6 +2415,37 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_beacon_get_tim);
|
EXPORT_SYMBOL(ieee80211_beacon_get_tim);
|
||||||
|
|
||||||
|
struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
|
{
|
||||||
|
struct ieee80211_if_ap *ap = NULL;
|
||||||
|
struct sk_buff *presp = NULL, *skb = NULL;
|
||||||
|
struct ieee80211_hdr *hdr;
|
||||||
|
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||||
|
|
||||||
|
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
ap = &sdata->u.ap;
|
||||||
|
presp = rcu_dereference(ap->probe_resp);
|
||||||
|
if (!presp)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
skb = skb_copy(presp, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
|
memset(hdr->addr1, 0, sizeof(hdr->addr1));
|
||||||
|
|
||||||
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_proberesp_get);
|
||||||
|
|
||||||
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
|
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif)
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
|
@ -1071,7 +1071,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||||||
changed |= BSS_CHANGED_IBSS;
|
changed |= BSS_CHANGED_IBSS;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
changed |= BSS_CHANGED_SSID;
|
changed |= BSS_CHANGED_SSID |
|
||||||
|
BSS_CHANGED_AP_PROBE_RESP;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
changed |= BSS_CHANGED_BEACON |
|
changed |= BSS_CHANGED_BEACON |
|
||||||
|
Loading…
x
Reference in New Issue
Block a user