Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02945821 authored by Arik Nemtsov's avatar Arik Nemtsov Committed by John W. Linville
Browse files

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: default avatarGuy Eilam <guy@wizery.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 00f740e1
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -166,6 +166,7 @@ struct ieee80211_low_level_stats {
 *	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)
 * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
 */
enum ieee80211_bss_change {
	BSS_CHANGED_ASSOC		= 1<<0,
@@ -184,6 +185,7 @@ enum ieee80211_bss_change {
	BSS_CHANGED_QOS			= 1<<13,
	BSS_CHANGED_IDLE		= 1<<14,
	BSS_CHANGED_SSID		= 1<<15,
	BSS_CHANGED_AP_PROBE_RESP	= 1<<16,

	/* 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);
}

/**
 * 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
 * @hw: pointer obtained from ieee80211_alloc_hw().
+35 −3
Original line number Diff line number Diff line
@@ -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);
}

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
 */
@@ -501,6 +526,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
	int new_head_len, new_tail_len;
	int size;
	int err = -EINVAL;
	u32 changed = 0;

	old = rtnl_dereference(sdata->u.ap.beacon);

@@ -584,11 +610,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,

	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);
	changed |= BSS_CHANGED_BEACON_ENABLED |
		   BSS_CHANGED_BEACON |
						BSS_CHANGED_SSID);
		   BSS_CHANGED_SSID;

	ieee80211_bss_info_change_notify(sdata, changed);
	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -232,6 +232,7 @@ struct beacon_data {

struct ieee80211_if_ap {
	struct beacon_data __rcu *beacon;
	struct sk_buff __rcu *probe_resp;

	struct list_head vlans;

+5 −1
Original line number Diff line number Diff line
@@ -462,15 +462,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
		struct ieee80211_sub_if_data *vlan, *tmpsdata;
		struct beacon_data *old_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 */
		ieee80211_bss_info_change_notify(sdata,
						 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.probe_resp, NULL);
		synchronize_rcu();
		kfree(old_beacon);
		kfree(old_probe_resp);

		/* down all dependent devices, that is VLANs */
		list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
+31 −0
Original line number Diff line number Diff line
@@ -2415,6 +2415,37 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
}
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 ieee80211_vif *vif)
{
Loading