Search Linux Wireless

Re: [PATCH] cfg80211: Store IEs from both Beacon and Probe Response frames

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2010-01-06 at 16:19 +0200, Jouni Malinen wrote:
> Store information elements from Beacon and Probe Response frames in
> separate buffers to allow both sets to be made available through
> nl80211. This allows user space applications to get access to IEs from
> Beacon frames even if we have received Probe Response frames from the
> BSS. Previously, the IEs from Probe Response frames would have
> overridden the IEs from Beacon frames.
> 
> This feature is of somewhat limited use since most protocols include
> the same (or extended) information in Probe Response frames. However,
> there are couple of exceptions where the IEs from Beacon frames could
> be of some use: TIM IE is only included in Beacon frames (and it would
> be needed to figure out the DTIM period used in the BSS) and at least
> some implementations of Wireless Provisioning Services seem to include
> the full IE only in Beacon frames).
> 
> The new BSS attribute for scan results is added to allow both the IE
> sets to be delivered. This is done in a way that maintains the
> previously used behavior for applications that are not aware of the
> new NL80211_BSS_BEACON_IES attribute.
> 
> Signed-off-by: Jouni Malinen <j@xxxxx>

Acked-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>

> 
> ---
>  include/linux/nl80211.h |   10 +++-
>  include/net/cfg80211.h  |   12 ++++
>  net/wireless/core.h     |    3 -
>  net/wireless/nl80211.c  |    4 +
>  net/wireless/scan.c     |  120
> ++++++++++++++++++++++++++++++++++++------------
>  5 files changed, 116 insertions(+), 33 deletions(-)
> 
> --- uml.orig/include/linux/nl80211.h	2010-01-06 14:50:20.000000000
> +0200
> +++ uml/include/linux/nl80211.h	2010-01-06 16:03:25.000000000 +0200
> @@ -1399,13 +1399,20 @@ enum nl80211_channel_type {
>   * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
>   * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
>   * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
> - *	raw information elements from the probe response/beacon (bin)
> + *	raw information elements from the probe response/beacon (bin);
> + *	if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here
> are
> + *	from a Probe Response frame; otherwise they are from a Beacon
> frame.
> + *	However, if the driver does not indicate the source of the IEs,
> these
> + *	IEs may be from either frame subtype.
>   * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
>   *	in mBm (100 * dBm) (s32)
>   * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe
> response/beacon
>   *	in unspecified units, scaled to 0..100 (u8)
>   * @NL80211_BSS_STATUS: status, if this BSS is "used"
>   * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
> + * @NL80211_BSS_BEACON_IES: binary attribute containing the raw
> information
> + *	elements from a Beacon frame (bin); not present if no Beacon frame
> has
> + *	yet been received
>   * @__NL80211_BSS_AFTER_LAST: internal
>   * @NL80211_BSS_MAX: highest BSS attribute
>   */
> @@ -1421,6 +1428,7 @@ enum nl80211_bss {
>  	NL80211_BSS_SIGNAL_UNSPEC,
>  	NL80211_BSS_STATUS,
>  	NL80211_BSS_SEEN_MS_AGO,
> +	NL80211_BSS_BEACON_IES,
>  
>  	/* keep last */
>  	__NL80211_BSS_AFTER_LAST,
> --- uml.orig/include/net/cfg80211.h	2010-01-06 14:47:50.000000000
> +0200
> +++ uml/include/net/cfg80211.h	2010-01-06 14:49:50.000000000 +0200
> @@ -626,8 +626,14 @@ enum cfg80211_signal_type {
>   * @beacon_interval: the beacon interval as from the frame
>   * @capability: the capability field in host byte order
>   * @information_elements: the information elements (Note that there
> - *	is no guarantee that these are well-formed!)
> + *	is no guarantee that these are well-formed!); this is a pointer to
> + *	either the beacon_ies or proberesp_ies depending on whether Probe
> + *	Response frame has been received
>   * @len_information_elements: total length of the information
> elements
> + * @beacon_ies: the information elements from the last Beacon frame
> + * @len_beacon_ies: total length of the beacon_ies
> + * @proberesp_ies: the information elements from the last Probe
> Response frame
> + * @len_proberesp_ies: total length of the proberesp_ies
>   * @signal: signal strength value (type depends on the wiphy's
> signal_type)
>   * @free_priv: function pointer to free private data
>   * @priv: private area for driver use, has at least wiphy->bss_priv_s
> ize bytes
> @@ -641,6 +647,10 @@ struct cfg80211_bss {
>  	u16 capability;
>  	u8 *information_elements;
>  	size_t len_information_elements;
> +	u8 *beacon_ies;
> +	size_t len_beacon_ies;
> +	u8 *proberesp_ies;
> +	size_t len_proberesp_ies;
>  
>  	s32 signal;
>  
> --- uml.orig/net/wireless/core.h	2010-01-06 14:55:19.000000000 +0200
> +++ uml/net/wireless/core.h	2010-01-06 14:55:37.000000000 +0200
> @@ -111,7 +111,8 @@ struct cfg80211_internal_bss {
>  	unsigned long ts;
>  	struct kref ref;
>  	atomic_t hold;
> -	bool ies_allocated;
> +	bool beacon_ies_allocated;
> +	bool proberesp_ies_allocated;
>  
>  	/* must be last because of priv member */
>  	struct cfg80211_bss pub;
> --- uml.orig/net/wireless/nl80211.c	2010-01-06 14:47:11.000000000
> +0200
> +++ uml/net/wireless/nl80211.c	2010-01-06 15:07:19.000000000 +0200
> @@ -3151,6 +3151,10 @@ static int nl80211_send_bss(struct sk_bu
>  		NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
>  			res->len_information_elements,
>  			res->information_elements);
> +	if (res->beacon_ies && res->len_beacon_ies &&
> +	    res->beacon_ies != res->information_elements)
> +		NLA_PUT(msg, NL80211_BSS_BEACON_IES,
> +			res->len_beacon_ies, res->beacon_ies);
>  	if (res->tsf)
>  		NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
>  	if (res->beacon_interval)
> --- uml.orig/net/wireless/scan.c	2010-01-06 14:46:47.000000000 +0200
> +++ uml/net/wireless/scan.c	2010-01-06 15:34:30.000000000 +0200
> @@ -100,8 +100,10 @@ static void bss_release(struct kref *ref
>  	if (bss->pub.free_priv)
>  		bss->pub.free_priv(&bss->pub);
>  
> -	if (bss->ies_allocated)
> -		kfree(bss->pub.information_elements);
> +	if (bss->beacon_ies_allocated)
> +		kfree(bss->pub.beacon_ies);
> +	if (bss->proberesp_ies_allocated)
> +		kfree(bss->pub.proberesp_ies);
>  
>  	BUG_ON(atomic_read(&bss->hold));
>  
> @@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_d
>  
>  static struct cfg80211_internal_bss *
>  cfg80211_bss_update(struct cfg80211_registered_device *dev,
> -		    struct cfg80211_internal_bss *res,
> -		    bool overwrite)
> +		    struct cfg80211_internal_bss *res)
>  {
>  	struct cfg80211_internal_bss *found = NULL;
>  	const u8 *meshid, *meshcfg;
> @@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_regi
>  		found->pub.capability = res->pub.capability;
>  		found->ts = res->ts;
>  
> -		/* overwrite IEs */
> -		if (overwrite) {
> +		/* Update IEs */
> +		if (res->pub.proberesp_ies) {
>  			size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
> -			size_t ielen = res->pub.len_information_elements;
> +			size_t ielen = res->pub.len_proberesp_ies;
>  
> -			if (!found->ies_allocated && ksize(found) >= used + ielen) {
> -				memcpy(found->pub.information_elements,
> -				       res->pub.information_elements, ielen);
> -				found->pub.len_information_elements = ielen;
> +			if (found->pub.proberesp_ies &&
> +			    !found->proberesp_ies_allocated &&
> +			    ksize(found) >= used + ielen) {
> +				memcpy(found->pub.proberesp_ies,
> +				       res->pub.proberesp_ies, ielen);
> +				found->pub.len_proberesp_ies = ielen;
>  			} else {
> -				u8 *ies = found->pub.information_elements;
> +				u8 *ies = found->pub.proberesp_ies;
>  
> -				if (found->ies_allocated)
> +				if (found->proberesp_ies_allocated)
>  					ies = krealloc(ies, ielen, GFP_ATOMIC);
>  				else
>  					ies = kmalloc(ielen, GFP_ATOMIC);
>  
>  				if (ies) {
> -					memcpy(ies, res->pub.information_elements, ielen);
> -					found->ies_allocated = true;
> -					found->pub.information_elements = ies;
> -					found->pub.len_information_elements = ielen;
> +					memcpy(ies, res->pub.proberesp_ies,
> +					       ielen);
> +					found->proberesp_ies_allocated = true;
> +					found->pub.proberesp_ies = ies;
> +					found->pub.len_proberesp_ies = ielen;
> +				}
> +			}
> +
> +			/* Override possible earlier Beacon frame IEs */
> +			found->pub.information_elements =
> +				found->pub.proberesp_ies;
> +			found->pub.len_information_elements =
> +				found->pub.len_proberesp_ies;
> +		}
> +		if (res->pub.beacon_ies) {
> +			size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
> +			size_t ielen = res->pub.len_beacon_ies;
> +
> +			if (found->pub.beacon_ies &&
> +			    !found->beacon_ies_allocated &&
> +			    ksize(found) >= used + ielen) {
> +				memcpy(found->pub.beacon_ies,
> +				       res->pub.beacon_ies, ielen);
> +				found->pub.len_beacon_ies = ielen;
> +			} else {
> +				u8 *ies = found->pub.beacon_ies;
> +
> +				if (found->beacon_ies_allocated)
> +					ies = krealloc(ies, ielen, GFP_ATOMIC);
> +				else
> +					ies = kmalloc(ielen, GFP_ATOMIC);
> +
> +				if (ies) {
> +					memcpy(ies, res->pub.beacon_ies,
> +					       ielen);
> +					found->beacon_ies_allocated = true;
> +					found->pub.beacon_ies = ies;
> +					found->pub.len_beacon_ies = ielen;
>  				}
>  			}
>  		}
> @@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy,
>  	res->pub.tsf = timestamp;
>  	res->pub.beacon_interval = beacon_interval;
>  	res->pub.capability = capability;
> -	/* point to after the private area */
> -	res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
> -	memcpy(res->pub.information_elements, ie, ielen);
> -	res->pub.len_information_elements = ielen;
> +	/*
> +	 * Since we do not know here whether the IEs are from a Beacon or
> Probe
> +	 * Response frame, we need to pick one of the options and only use
> it
> +	 * with the driver that does not provide the full Beacon/Probe
> Response
> +	 * frame. Use Beacon frame pointer to avoid indicating that this
> should
> +	 * override the information_elements pointer should we have received
> an
> +	 * earlier indication of Probe Response data.
> +	 *
> +	 * The initial buffer for the IEs is allocated with the BSS entry
> and
> +	 * is located after the private area.
> +	 */
> +	res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz;
> +	memcpy(res->pub.beacon_ies, ie, ielen);
> +	res->pub.len_beacon_ies = ielen;
> +	res->pub.information_elements = res->pub.beacon_ies;
> +	res->pub.len_information_elements = res->pub.len_beacon_ies;
>  
>  	kref_init(&res->ref);
>  
> -	res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0);
> +	res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
>  	if (!res)
>  		return NULL;
>  
> @@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *
>  	struct cfg80211_internal_bss *res;
>  	size_t ielen = len - offsetof(struct ieee80211_mgmt,
>  				      u.probe_resp.variable);
> -	bool overwrite;
>  	size_t privsz = wiphy->bss_priv_size;
>  
>  	if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
> @@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *
>  	res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
>  	res->pub.beacon_interval =
> le16_to_cpu(mgmt->u.probe_resp.beacon_int);
>  	res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
> -	/* point to after the private area */
> -	res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
> -	memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable,
> ielen);
> -	res->pub.len_information_elements = ielen;
> +	/*
> +	 * The initial buffer for the IEs is allocated with the BSS entry
> and
> +	 * is located after the private area.
> +	 */
> +	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
> +		res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz;
> +		memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable,
> +		       ielen);
> +		res->pub.len_proberesp_ies = ielen;
> +		res->pub.information_elements = res->pub.proberesp_ies;
> +		res->pub.len_information_elements = res->pub.len_proberesp_ies;
> +	} else {
> +		res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
> +		memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
> +		res->pub.len_beacon_ies = ielen;
> +		res->pub.information_elements = res->pub.beacon_ies;
> +		res->pub.len_information_elements = res->pub.len_beacon_ies;
> +	}
>  
>  	kref_init(&res->ref);
>  
> -	overwrite = ieee80211_is_probe_resp(mgmt->frame_control);
> -
> -	res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
> +	res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
>  	if (!res)
>  		return NULL;
>  
> 

Attachment: signature.asc
Description: This is a digitally signed message part


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux