Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: changing dev->needed_headroom/needed_tailroom?
From: Ben Hutchings @ 2013-08-02  8:55 UTC (permalink / raw)
  To: Johannes Berg; +Cc: netdev, linux-wireless
In-Reply-To: <1374850210.8248.59.camel@jlt4.sipsolutions.net>

On Fri, 2013-07-26 at 16:50 +0200, Johannes Berg wrote:
> Does it seem reasonable to change dev->needed_headroom and
> dev->needed_tailroom on the fly?
> 
> We currently set needed_headroom to the max of what we need, but we
> could do better like making it depend on the interface type (e.g. only
> asking for mesh space on mesh interfaces). This would be done only when
> the interface isn't connected, I can't promise it would be down but the
> carrier would be off.
[...]

I don't think this is safe when the interface is running (even if
carrier is off).  Some functions may read dev->needed_headroom twice and
rely on getting the same value each time.

Also, stacked devices would need to adjust their own needed_headroom
accordingly.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* Re: [PATCH 3.10 0/3] Enable 7000 device family on 3.10
From: Greg KH @ 2013-08-02  9:02 UTC (permalink / raw)
  To: Emmanuel Grumbach; +Cc: stable, linux-wireless
In-Reply-To: <1373888700-3040-1-git-send-email-emmanuel.grumbach@intel.com>

On Mon, Jul 15, 2013 at 02:44:57PM +0300, Emmanuel Grumbach wrote:
> This small patch series enables 7260 and 3160 devices on 3.10
> kernel. Three patches are already in linux.git (3.11-rc1).
> One patch is 3.10 specific and disables configuration that is not
> supported in 3.10.

I need the git commit id of these patches in Linus's tree before I can
apply them.  Please resend them with that information.

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH 3.11] nl80211: fix another nl80211_fam.attrbuf race
From: Ben Hutchings @ 2013-08-02  9:32 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Johannes Berg
In-Reply-To: <1375216722-31194-1-git-send-email-johannes@sipsolutions.net>

[-- Attachment #1: Type: text/plain, Size: 855 bytes --]

On Tue, 2013-07-30 at 22:38 +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> This is similar to the race Linus had reported, but in this case
> it's an older bug: nl80211_prepare_wdev_dump() uses the wiphy
> index in cb->args[0] as it is and thus parses the message over
> and over again instead of just once because 0 is the first valid
> wiphy index. Similar code in nl80211_testmode_dump() correctly
> offsets the wiphy_index by 1, do that here as well.
> 
> Cc: stable@vger.kernel.org
> Reported-by: Ben Hutchings <ben@decadent.org.uk>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
[...]

With this patch applied, I haven't seen another crash after another day
and a bit in the same wifi environment.

Ben.

-- 
Ben Hutchings
This sentence contradicts itself - no actually it doesn't.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* Re: [RFC 1/3] nl/cfg80211: add chan_time for scan request
From: Johannes Berg @ 2013-08-02 11:25 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, ath10k
In-Reply-To: <CA+BoTQm+rWRRpp6XQ_-YHMBfH0Q4ecZ3z-6TV3cvFZ=8uXWsQA@mail.gmail.com>

On Thu, 2013-08-01 at 11:14 +0200, Michal Kazior wrote:

> > This seems a bit iffy - you don't differentiate between active/passive
> > scans?
> 
> Is there a reason this should be differentiated?

Well they don't usually have the same timing, passive channel dwell time
usually needs to be longer than on active channels.

> > This also interferes a bit with some other scan optimisations that could
> > be done at a low firmware level, so I think we should be careful and
> > actually say that this is really more intended for measurement use cases
> > and not for normal scans?
> >
> > Or maybe we should have a separate measurement command with similar
> > semantics? This all doesn't seem very clear to me yet :)
> 
> Motivation behind this patchset is to simplify ACS implementation and
> depend on scan. This also allows easier fallback from survey-based ACS
> to BSS-based one.

Sure, I understand.

> Other use cases are a side-effect so perhaps clarifying the intent in
> the docs is enough.

I'm just saying that this is a fundamentally different usage than actual
scanning. Let's say for the sake of the argument I find a way to scan
channels quicker and implement that in my device (hw_scan). I don't
think this is too far-fetched, imagine I have an 80MHz capable device
and can send probe request 4x transmissions on all the subchannels, if
somehow I manage to separate the receive then I could scan 4x as
quickly. I don't think this particular thing is possible but I could
imagine scan optimisations like it.

Now this comes along - and suddenly the API requires that you stay on
each specified channel for the given period of time. Any such
"non-traditional" scan optimisations would have to be given up, so in a
sense this fundamentally alters the semantics of the scan primitive,
where before it was "give me the list of networks (with these SSIDs) on
these channels" it now becomes "go to each channel, stay there for this
amount of time and ..."

That's what I'm worried about - the implicit semantic change here.

johannes


^ permalink raw reply

* Re: [RFC 1/3] nl/cfg80211: add chan_time for scan request
From: Michal Kazior @ 2013-08-02 11:52 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, ath10k
In-Reply-To: <1375442751.18144.7.camel@jlt4.sipsolutions.net>

On 2 August 2013 13:25, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Thu, 2013-08-01 at 11:14 +0200, Michal Kazior wrote:
>
>> > This seems a bit iffy - you don't differentiate between active/passive
>> > scans?
>>
>> Is there a reason this should be differentiated?
>
> Well they don't usually have the same timing, passive channel dwell time
> usually needs to be longer than on active channels.
>
>> > This also interferes a bit with some other scan optimisations that could
>> > be done at a low firmware level, so I think we should be careful and
>> > actually say that this is really more intended for measurement use cases
>> > and not for normal scans?
>> >
>> > Or maybe we should have a separate measurement command with similar
>> > semantics? This all doesn't seem very clear to me yet :)
>>
>> Motivation behind this patchset is to simplify ACS implementation and
>> depend on scan. This also allows easier fallback from survey-based ACS
>> to BSS-based one.
>
> Sure, I understand.
>
>> Other use cases are a side-effect so perhaps clarifying the intent in
>> the docs is enough.
>
> I'm just saying that this is a fundamentally different usage than actual
> scanning. Let's say for the sake of the argument I find a way to scan
> channels quicker and implement that in my device (hw_scan). I don't
> think this is too far-fetched, imagine I have an 80MHz capable device
> and can send probe request 4x transmissions on all the subchannels, if
> somehow I manage to separate the receive then I could scan 4x as
> quickly. I don't think this particular thing is possible but I could
> imagine scan optimisations like it.
>
> Now this comes along - and suddenly the API requires that you stay on
> each specified channel for the given period of time. Any such
> "non-traditional" scan optimisations would have to be given up, so in a
> sense this fundamentally alters the semantics of the scan primitive,
> where before it was "give me the list of networks (with these SSIDs) on
> these channels" it now becomes "go to each channel, stay there for this
> amount of time and ..."
>
> That's what I'm worried about - the implicit semantic change here.

I think I understand your point now.

I'm thinking of using series of passive scans for ACS now, so perhaps
the whole chan_time stuff is unnecessary. What are your thoughts about
it?


Pozdrawiam / Best regards,
Michał Kazior.

^ permalink raw reply

* Re: [RFC 1/3] nl/cfg80211: add chan_time for scan request
From: Sunil Dutt @ 2013-08-02 12:56 UTC (permalink / raw)
  To: linux-wireless, ath10k
In-Reply-To: <CACA4iOrZSARKFVFx1E2QPyH=xZzQp+VoyPu_tuFWgBR3tQwOmw@mail.gmail.com>

Hi Johannes and Michal ,
In this context I would also like to mention that there are also some
use cases ( Ex WiFi Positioning) ,  where good performance shall
result from using signals from as many Access Points as possible, a
fixed dwell / chan time in the host driver shall result in the poor
discovery efficiency of the Access Points,negatively impacting WiFi
positioning performance.

I would say such applications shall benefit by configuring a chan (dwell)_time.
Also,an attribute corresponding to the mode of the scan ( active /
passive ) , along with chan_time would benefit such applications with
more configurable options. Isn't it ?
Please correct me .

Regards,
Sunil

On Fri, Aug 2, 2013 at 6:00 PM, Sunil Dutt <usdutt@gmail.com> wrote:
> Hi Johannes and Michal ,
> In this context I would also like to mention that there are also some use
> cases ( Ex WiFi Positioning) ,  where good performance shall result from
> using signals from as many Access Points as possible, a fixed dwell / chan
> time in the host driver shall result in the poor discovery efficiency of the
> Access Points,negatively impacting WiFi positioning performance.
>
> I would say such applications shall benefit by configuring a chan
> (dwell)_time.
> Also,an attribute corresponding to the mode of the scan ( active / passive )
> , along with chan_time would benefit such applications with more
> configurable options. Isn't it ?
> Please correct me .
>
> Regards,
> Sunil
>
>
>
>
> On Fri, Aug 2, 2013 at 4:55 PM, Johannes Berg <johannes@sipsolutions.net>
> wrote:
>>
>> On Thu, 2013-08-01 at 11:14 +0200, Michal Kazior wrote:
>>
>> > > This seems a bit iffy - you don't differentiate between active/passive
>> > > scans?
>> >
>> > Is there a reason this should be differentiated?
>>
>> Well they don't usually have the same timing, passive channel dwell time
>> usually needs to be longer than on active channels.
>>
>> > > This also interferes a bit with some other scan optimisations that
>> > > could
>> > > be done at a low firmware level, so I think we should be careful and
>> > > actually say that this is really more intended for measurement use
>> > > cases
>> > > and not for normal scans?
>> > >
>> > > Or maybe we should have a separate measurement command with similar
>> > > semantics? This all doesn't seem very clear to me yet :)
>> >
>> > Motivation behind this patchset is to simplify ACS implementation and
>> > depend on scan. This also allows easier fallback from survey-based ACS
>> > to BSS-based one.
>>
>> Sure, I understand.
>>
>> > Other use cases are a side-effect so perhaps clarifying the intent in
>> > the docs is enough.
>>
>> I'm just saying that this is a fundamentally different usage than actual
>> scanning. Let's say for the sake of the argument I find a way to scan
>> channels quicker and implement that in my device (hw_scan). I don't
>> think this is too far-fetched, imagine I have an 80MHz capable device
>> and can send probe request 4x transmissions on all the subchannels, if
>> somehow I manage to separate the receive then I could scan 4x as
>> quickly. I don't think this particular thing is possible but I could
>> imagine scan optimisations like it.
>>
>> Now this comes along - and suddenly the API requires that you stay on
>> each specified channel for the given period of time. Any such
>> "non-traditional" scan optimisations would have to be given up, so in a
>> sense this fundamentally alters the semantics of the scan primitive,
>> where before it was "give me the list of networks (with these SSIDs) on
>> these channels" it now becomes "go to each channel, stay there for this
>> amount of time and ..."
>>
>> That's what I'm worried about - the implicit semantic change here.
>>
>> johannes
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-wireless"
>> in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>

^ permalink raw reply

* Re: [RFC 1/3] nl/cfg80211: add chan_time for scan request
From: Johannes Berg @ 2013-08-02 13:01 UTC (permalink / raw)
  To: Michal Kazior; +Cc: linux-wireless, ath10k
In-Reply-To: <CA+BoTQ=XNeYL1KLGQ4gRCZ03a9XsAWde4O7_T-dqKndLLKeX_g@mail.gmail.com>


> > That's what I'm worried about - the implicit semantic change here.
> 
> I think I understand your point now.
> 
> I'm thinking of using series of passive scans for ACS now, so perhaps
> the whole chan_time stuff is unnecessary. What are your thoughts about
> it?

Well, still then you're relying on the fact that passive channels scans
will stick to each channel for ~110ms or so. This is true today, but
it's not really specified.

I don't think that using the scan command would be a big deal, but maybe
this 'measurement' behaviour should be explicitly enabled? Maybe other
devices even have to do something special to collect the data.

johannes


^ permalink raw reply

* Re: changing dev->needed_headroom/needed_tailroom?
From: Eric Dumazet @ 2013-08-02 13:11 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: Johannes Berg, netdev, linux-wireless
In-Reply-To: <1375433758.24371.20.camel@deadeye.wl.decadent.org.uk>

On Fri, 2013-08-02 at 10:55 +0200, Ben Hutchings wrote:

> I don't think this is safe when the interface is running (even if
> carrier is off).  Some functions may read dev->needed_headroom twice and
> rely on getting the same value each time.

It should be no problem. Remaining unsafe places should be fixed.

We already had this discussion in the past, and some patches were
issued. Check commit ae641949df01b85117845bec45328eab6d6fada1
("net: Remove all uses of LL_ALLOCATED_SPACE")





^ permalink raw reply

* [PATCH 2/7] mac80211: fix ieee80211_sta_process_chanswitch for 5/10 MHz channels
From: Simon Wunderlich @ 2013-08-02 15:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-1-git-send-email-siwu@hrz.tu-chemnitz.de>

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/mac80211/mlme.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 211246b..45a87ee 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1102,6 +1102,15 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	case -1:
 		cfg80211_chandef_create(&new_chandef, new_chan,
 					NL80211_CHAN_NO_HT);
+		/* keep width for 5/10 MHz channels */
+		switch (sdata->vif.bss_conf.chandef.width) {
+		case NL80211_CHAN_WIDTH_5:
+		case NL80211_CHAN_WIDTH_10:
+			new_chandef.width = sdata->vif.bss_conf.chandef.width;
+			break;
+		default:
+			break;
+		}
 		break;
 	}
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 0/7] add IBSS channel switch announcement support
From: Simon Wunderlich @ 2013-08-02 15:37 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich

This patchset adds channel switch support for IBSS mode. This is required for
later DFS support in IBSS. It builds on top of the previously submitted AP DFS
patchset.

The rough design is:
 * Userspace may request to change channel using the already introduced
   NL80211_CMD_CHANNEL_SWITCH command. Unlike AP mode, it does not contain
   IEs or offset for CSA elements, because this is to be generated by the kernel.
 * Also other stations may request a channel change by sending (E)CSA within
   beacons or action frames. This is parsed and further handled as if it would
   have come from userspace.
 * When performing a channel switch, an action frame is sent, because beaconing
   is distributed among IBSS peers and might be lost early. Furthermore,
   channel switch announcement IEs are added to the beacon/probe response.
 * When a channel switch could was not understood, it disconnects from the
   IBSS and tries to re-connect.

Discussion points:
 * When disconnecting from the IBSS because a channel switch announcement was
   bogus or not understood, we might reconnect to the same BSS again - on the
   old channel, because the other stas are still there, and stay there.
   Although it is "accepted behaviour" in IEEE 802.11 that not all station
   could make it, we should consider ignoring beacons/presp if they include CSAs
   when scanning for networks to prevent this problem.

As always, any comments are appreciated.

Cheers,
        Simon

Simon Wunderlich (7):
  cfg80211: export cfg80211_chandef_dfs_required
  mac80211: fix ieee80211_sta_process_chanswitch for 5/10 MHz channels
  mac80211: split off channel switch parsing function
  mac80211: move ibss presp generation in own function
  mac80211: add support for CSA in IBSS mode
  mac80211: send a CSA action frame when changing channel
  nl80211: enable IBSS support for channel switch announcements

 include/net/cfg80211.h     |    9 +
 net/mac80211/cfg.c         |   84 ++++--
 net/mac80211/ibss.c        |  715 +++++++++++++++++++++++++++++++++++---------
 net/mac80211/ieee80211_i.h |   24 ++
 net/mac80211/iface.c       |    4 +
 net/mac80211/mlme.c        |  143 +++++----
 net/mac80211/rx.c          |   36 ++-
 net/mac80211/tx.c          |   34 ++-
 net/wireless/chan.c        |    1 +
 net/wireless/core.h        |    8 -
 net/wireless/nl80211.c     |   49 ++-
 11 files changed, 853 insertions(+), 254 deletions(-)

-- 
1.7.10.4


^ permalink raw reply

* [PATCH 4/7] mac80211: move ibss presp generation in own function
From: Simon Wunderlich @ 2013-08-02 15:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-1-git-send-email-siwu@hrz.tu-chemnitz.de>

Channel Switch will later require to generate beacons without setting
them immediately. Therefore split the presp generation in an own
function. Splitting the original very long function might be a good idea
anyway.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/mac80211/ibss.c |  185 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 109 insertions(+), 76 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index e08387c..29f1a7b 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -34,13 +34,12 @@
 
 #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
 
-
-static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
-				      const u8 *bssid, const int beacon_int,
-				      struct ieee80211_channel *chan,
-				      const u32 basic_rates,
-				      const u16 capability, u64 tsf,
-				      bool creator)
+static struct beacon_data *
+ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
+			   const int beacon_int, const u32 basic_rates,
+			   const u16 capability, u64 tsf,
+			   struct cfg80211_chan_def *chandef,
+			   bool *have_higher_than_11mbit)
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
@@ -48,70 +47,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos;
 	struct ieee80211_supported_band *sband;
-	struct cfg80211_bss *bss;
-	u32 bss_change, rate_flags, rates = 0, rates_added = 0;
-	struct cfg80211_chan_def chandef;
-	enum nl80211_bss_scan_width scan_width;
-	bool have_higher_than_11mbit = false;
+	u32 rate_flags, rates = 0, rates_added = 0;
 	struct beacon_data *presp;
 	int frame_len;
 	int shift;
 
-	sdata_assert_lock(sdata);
-
-	/* Reset own TSF to allow time synchronization work. */
-	drv_reset_tsf(local, sdata);
-
-	if (!ether_addr_equal(ifibss->bssid, bssid))
-		sta_info_flush(sdata);
-
-	/* if merging, indicate to driver that we leave the old IBSS */
-	if (sdata->vif.bss_conf.ibss_joined) {
-		sdata->vif.bss_conf.ibss_joined = false;
-		sdata->vif.bss_conf.ibss_creator = false;
-		sdata->vif.bss_conf.enable_beacon = false;
-		netif_carrier_off(sdata->dev);
-		ieee80211_bss_info_change_notify(sdata,
-						 BSS_CHANGED_IBSS |
-						 BSS_CHANGED_BEACON_ENABLED);
-	}
-
-	presp = rcu_dereference_protected(ifibss->presp,
-					  lockdep_is_held(&sdata->wdev.mtx));
-	rcu_assign_pointer(ifibss->presp, NULL);
-	if (presp)
-		kfree_rcu(presp, rcu_head);
-
-	sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
-	chandef = ifibss->chandef;
-	if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
-		if (chandef.width == NL80211_CHAN_WIDTH_5 ||
-		    chandef.width == NL80211_CHAN_WIDTH_10 ||
-		    chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
-		    chandef.width == NL80211_CHAN_WIDTH_20) {
-			sdata_info(sdata,
-				   "Failed to join IBSS, beacons forbidden\n");
-			return;
-		}
-		chandef.width = NL80211_CHAN_WIDTH_20;
-		chandef.center_freq1 = chan->center_freq;
-	}
-
-	ieee80211_vif_release_channel(sdata);
-	if (ieee80211_vif_use_channel(sdata, &chandef,
-				      ifibss->fixed_channel ?
-					IEEE80211_CHANCTX_SHARED :
-					IEEE80211_CHANCTX_EXCLUSIVE)) {
-		sdata_info(sdata, "Failed to join IBSS, no channel context\n");
-		return;
-	}
-
-	memcpy(ifibss->bssid, bssid, ETH_ALEN);
-
-	sband = local->hw.wiphy->bands[chan->band];
-	shift = ieee80211_vif_get_shift(&sdata->vif);
-
 	/* Build IBSS probe response */
 	frame_len = sizeof(struct ieee80211_hdr_3addr) +
 		    12 /* struct ieee80211_mgmt.u.beacon */ +
@@ -125,7 +65,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 		    ifibss->ie_len;
 	presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL);
 	if (!presp)
-		return;
+		return NULL;
 
 	presp->head = (void *)(presp + 1);
 
@@ -146,12 +86,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	memcpy(pos, ifibss->ssid, ifibss->ssid_len);
 	pos += ifibss->ssid_len;
 
-	rate_flags = ieee80211_chandef_rate_flags(&chandef);
+	sband = local->hw.wiphy->bands[chandef->chan->band];
+	rate_flags = ieee80211_chandef_rate_flags(chandef);
+	shift = ieee80211_chandef_get_shift(chandef);
+	rates_n = 0;
+	if (have_higher_than_11mbit)
+		*have_higher_than_11mbit = false;
+
 	for (i = 0; i < sband->n_bitrates; i++) {
 		if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
 			continue;
-		if (sband->bitrates[i].bitrate > 110)
-			have_higher_than_11mbit = true;
+		if (sband->bitrates[i].bitrate > 110 &&
+		    have_higher_than_11mbit)
+			*have_higher_than_11mbit = true;
 
 		rates |= BIT(i);
 		rates_n++;
@@ -178,7 +125,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	if (sband->band == IEEE80211_BAND_2GHZ) {
 		*pos++ = WLAN_EID_DS_PARAMS;
 		*pos++ = 1;
-		*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
+		*pos++ = ieee80211_frequency_to_channel(
+				chandef->chan->center_freq);
 	}
 
 	*pos++ = WLAN_EID_IBSS_PARAMS;
@@ -210,9 +158,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	}
 
 	/* add HT capability and information IEs */
-	if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
-	    chandef.width != NL80211_CHAN_WIDTH_5 &&
-	    chandef.width != NL80211_CHAN_WIDTH_10 &&
+	if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT &&
+	    chandef->width != NL80211_CHAN_WIDTH_5 &&
+	    chandef->width != NL80211_CHAN_WIDTH_10 &&
 	    sband->ht_cap.ht_supported) {
 		struct ieee80211_sta_ht_cap ht_cap;
 
@@ -226,7 +174,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 		 * keep them at 0
 		 */
 		pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
-						 &chandef, 0);
+						 chandef, 0);
 	}
 
 	if (local->hw.queues >= IEEE80211_NUM_ACS) {
@@ -243,9 +191,94 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
 	presp->head_len = pos - presp->head;
 	if (WARN_ON(presp->head_len > frame_len))
+		goto error;
+
+	return presp;
+error:
+	kfree(presp);
+	return NULL;
+}
+
+static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+				      const u8 *bssid, const int beacon_int,
+				      struct ieee80211_channel *chan,
+				      const u32 basic_rates,
+				      const u16 capability, u64 tsf,
+				      bool creator)
+{
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_mgmt *mgmt;
+	struct cfg80211_bss *bss;
+	u32 bss_change;
+	struct cfg80211_chan_def chandef;
+	struct beacon_data *presp;
+	enum nl80211_bss_scan_width scan_width;
+	bool have_higher_than_11mbit;
+
+	sdata_assert_lock(sdata);
+
+	/* Reset own TSF to allow time synchronization work. */
+	drv_reset_tsf(local, sdata);
+
+	if (!ether_addr_equal(ifibss->bssid, bssid))
+		sta_info_flush(sdata);
+
+	/* if merging, indicate to driver that we leave the old IBSS */
+	if (sdata->vif.bss_conf.ibss_joined) {
+		sdata->vif.bss_conf.ibss_joined = false;
+		sdata->vif.bss_conf.ibss_creator = false;
+		sdata->vif.bss_conf.enable_beacon = false;
+		netif_carrier_off(sdata->dev);
+		ieee80211_bss_info_change_notify(sdata,
+						 BSS_CHANGED_IBSS |
+						 BSS_CHANGED_BEACON_ENABLED);
+	}
+
+	presp = rcu_dereference_protected(ifibss->presp,
+					  lockdep_is_held(&sdata->wdev.mtx));
+	rcu_assign_pointer(ifibss->presp, NULL);
+	if (presp)
+		kfree_rcu(presp, rcu_head);
+
+	sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+	chandef = ifibss->chandef;
+	if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+		if (chandef.width == NL80211_CHAN_WIDTH_5 ||
+		    chandef.width == NL80211_CHAN_WIDTH_10 ||
+		    chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+		    chandef.width == NL80211_CHAN_WIDTH_20) {
+			sdata_info(sdata,
+				   "Failed to join IBSS, beacons forbidden\n");
+			return;
+		}
+		chandef.width = NL80211_CHAN_WIDTH_20;
+		chandef.center_freq1 = chan->center_freq;
+	}
+
+	ieee80211_vif_release_channel(sdata);
+	if (ieee80211_vif_use_channel(sdata, &chandef,
+				      ifibss->fixed_channel ?
+					IEEE80211_CHANCTX_SHARED :
+					IEEE80211_CHANCTX_EXCLUSIVE)) {
+		sdata_info(sdata, "Failed to join IBSS, no channel context\n");
+		return;
+	}
+
+	memcpy(ifibss->bssid, bssid, ETH_ALEN);
+
+	sband = local->hw.wiphy->bands[chan->band];
+
+	presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
+					   capability, tsf, &chandef,
+					   &have_higher_than_11mbit);
+	if (!presp)
 		return;
 
 	rcu_assign_pointer(ifibss->presp, presp);
+	mgmt = (void *)presp->head;
 
 	sdata->vif.bss_conf.enable_beacon = true;
 	sdata->vif.bss_conf.beacon_int = beacon_int;
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 3/7] mac80211: split off channel switch parsing function
From: Simon Wunderlich @ 2013-08-02 15:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-1-git-send-email-siwu@hrz.tu-chemnitz.de>

The channel switch parsing function can be re-used for the IBSS code,
put the common part into an extra function.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/mac80211/ieee80211_i.h |   22 +++++++
 net/mac80211/mlme.c        |  136 ++++++++++++++++++++++++--------------------
 2 files changed, 97 insertions(+), 61 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e94c840..1275bde 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1333,6 +1333,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 				   struct sk_buff *skb);
+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
+			      struct cfg80211_csa_settings *csa_settings);
+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
 
 /* mesh code */
 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
@@ -1560,6 +1563,25 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
 u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 			       struct ieee802_11_elems *elems,
 			       u64 filter, u32 crc);
+
+/**
+ * ieee80211_parse_ch_switch_ie - parses channel switch IEs
+ * @sdata: the sdata of the interface which has received the frame
+ * @elems: parsed 802.11 elements received with the frame
+ * @beacon: indicates if the frame was a beacon or probe response
+ * @current_band: indicates the current band
+ * @sta_flags: contains information about own capabilities and restrictions
+ * @count: to be filled with the counter until the switch (on success only)
+ * @mode: to be filled with CSA mode (on success only)
+ * @new_chandef: to be filled with destination chandef (on success only)
+ * Return: 0 on success, <0 on error and >0 if there is nothing to parse.
+ */
+int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
+				 struct ieee802_11_elems *elems, bool beacon,
+				 enum ieee80211_band current_band,
+				 u32 sta_flags, u8 *count, u8 *mode,
+				 struct cfg80211_chan_def *new_chandef);
+
 static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
 					  bool action,
 					  struct ieee802_11_elems *elems)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 45a87ee..60554c8 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -981,54 +981,35 @@ static void ieee80211_chswitch_timer(unsigned long data)
 	ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
 }
 
-static void
-ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
-				 u64 timestamp, struct ieee802_11_elems *elems,
-				 bool beacon)
+int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
+				 struct ieee802_11_elems *elems, bool beacon,
+				 enum ieee80211_band current_band,
+				 u32 sta_flags, u8 *count, u8 *mode,
+				 struct cfg80211_chan_def *new_chandef)
 {
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct cfg80211_bss *cbss = ifmgd->associated;
-	struct ieee80211_bss *bss;
-	struct ieee80211_chanctx *chanctx;
 	enum ieee80211_band new_band;
 	int new_freq;
 	u8 new_chan_no;
-	u8 count;
-	u8 mode;
 	struct ieee80211_channel *new_chan;
-	struct cfg80211_chan_def new_chandef = {};
 	struct cfg80211_chan_def new_vht_chandef = {};
 	const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
 	const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
 	const struct ieee80211_ht_operation *ht_oper;
 	int secondary_channel_offset = -1;
 
-	sdata_assert_lock(sdata);
-
-	if (!cbss)
-		return;
-
-	if (local->scanning)
-		return;
-
-	/* disregard subsequent announcements if we are already processing */
-	if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
-		return;
-
 	sec_chan_offs = elems->sec_chan_offs;
 	wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
 	ht_oper = elems->ht_operation;
 
-	if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
-			    IEEE80211_STA_DISABLE_40MHZ)) {
+	if (sta_flags & (IEEE80211_STA_DISABLE_HT |
+			 IEEE80211_STA_DISABLE_40MHZ)) {
 		sec_chan_offs = NULL;
 		wide_bw_chansw_ie = NULL;
 		/* only used for bandwidth here */
 		ht_oper = NULL;
 	}
 
-	if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
+	if (sta_flags & IEEE80211_STA_DISABLE_VHT)
 		wide_bw_chansw_ie = NULL;
 
 	if (elems->ext_chansw_ie) {
@@ -1038,33 +1019,28 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 			sdata_info(sdata,
 				   "cannot understand ECSA IE operating class %d, disconnecting\n",
 				   elems->ext_chansw_ie->new_operating_class);
-			ieee80211_queue_work(&local->hw,
-					     &ifmgd->csa_connection_drop_work);
+			return -EINVAL;
 		}
 		new_chan_no = elems->ext_chansw_ie->new_ch_num;
-		count = elems->ext_chansw_ie->count;
-		mode = elems->ext_chansw_ie->mode;
+		*count = elems->ext_chansw_ie->count;
+		*mode = elems->ext_chansw_ie->mode;
 	} else if (elems->ch_switch_ie) {
-		new_band = cbss->channel->band;
+		new_band = current_band;
 		new_chan_no = elems->ch_switch_ie->new_ch_num;
-		count = elems->ch_switch_ie->count;
-		mode = elems->ch_switch_ie->mode;
+		*count = elems->ch_switch_ie->count;
+		*mode = elems->ch_switch_ie->mode;
 	} else {
 		/* nothing here we understand */
-		return;
+		return 1;
 	}
 
-	bss = (void *)cbss->priv;
-
 	new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
 	new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
 	if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
 		sdata_info(sdata,
-			   "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
-			   ifmgd->associated->bssid, new_freq);
-		ieee80211_queue_work(&local->hw,
-				     &ifmgd->csa_connection_drop_work);
-		return;
+			   "network switches to unsupported channel (%d MHz), disconnecting\n",
+			   new_freq);
+		return -EINVAL;
 	}
 
 	if (!beacon && sec_chan_offs) {
@@ -1072,7 +1048,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	} else if (beacon && ht_oper) {
 		secondary_channel_offset =
 			ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
-	} else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+	} else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) {
 		/*
 		 * If it's not a beacon, HT is enabled and the IE not present,
 		 * it's 20 MHz, 802.11-2012 8.5.2.6:
@@ -1088,25 +1064,25 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	default:
 		/* secondary_channel_offset was present but is invalid */
 	case IEEE80211_HT_PARAM_CHA_SEC_NONE:
-		cfg80211_chandef_create(&new_chandef, new_chan,
+		cfg80211_chandef_create(new_chandef, new_chan,
 					NL80211_CHAN_HT20);
 		break;
 	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-		cfg80211_chandef_create(&new_chandef, new_chan,
+		cfg80211_chandef_create(new_chandef, new_chan,
 					NL80211_CHAN_HT40PLUS);
 		break;
 	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-		cfg80211_chandef_create(&new_chandef, new_chan,
+		cfg80211_chandef_create(new_chandef, new_chan,
 					NL80211_CHAN_HT40MINUS);
 		break;
 	case -1:
-		cfg80211_chandef_create(&new_chandef, new_chan,
+		cfg80211_chandef_create(new_chandef, new_chan,
 					NL80211_CHAN_NO_HT);
 		/* keep width for 5/10 MHz channels */
 		switch (sdata->vif.bss_conf.chandef.width) {
 		case NL80211_CHAN_WIDTH_5:
 		case NL80211_CHAN_WIDTH_10:
-			new_chandef.width = sdata->vif.bss_conf.chandef.width;
+			new_chandef->width = sdata->vif.bss_conf.chandef.width;
 			break;
 		default:
 			break;
@@ -1142,13 +1118,13 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 			new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
 			break;
 		}
-		if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
+		if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
 		    new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
 			chandef_downgrade(&new_vht_chandef);
-		if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
+		if (sta_flags & IEEE80211_STA_DISABLE_160MHZ &&
 		    new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
 			chandef_downgrade(&new_vht_chandef);
-		if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
+		if (sta_flags & IEEE80211_STA_DISABLE_40MHZ &&
 		    new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
 			chandef_downgrade(&new_vht_chandef);
 	}
@@ -1156,23 +1132,61 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	/* if VHT data is there validate & use it */
 	if (new_vht_chandef.chan) {
 		if (!cfg80211_chandef_compatible(&new_vht_chandef,
-						 &new_chandef)) {
+						 new_chandef)) {
 			sdata_info(sdata,
-				   "AP %pM CSA has inconsistent channel data, disconnecting\n",
-				   ifmgd->associated->bssid);
-			ieee80211_queue_work(&local->hw,
-					     &ifmgd->csa_connection_drop_work);
-			return;
+				   "network CSA has inconsistent channel data, disconnecting\n");
+			return -EINVAL;
 		}
-		new_chandef = new_vht_chandef;
+		*new_chandef = new_vht_chandef;
 	}
 
+	return 0;
+}
+
+static void
+ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+				 u64 timestamp, struct ieee802_11_elems *elems,
+				 bool beacon)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	struct cfg80211_bss *cbss = ifmgd->associated;
+	struct ieee80211_chanctx *chanctx;
+	enum ieee80211_band current_band;
+	u8 count;
+	u8 mode;
+	struct cfg80211_chan_def new_chandef = {};
+	int res;
+
+	sdata_assert_lock(sdata);
+
+	if (!cbss)
+		return;
+
+	if (local->scanning)
+		return;
+
+	/* disregard subsequent announcements if we are already processing */
+	if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
+		return;
+
+	current_band = cbss->channel->band;
+	res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
+					   ifmgd->flags, &count, &mode,
+					   &new_chandef);
+	if (res	< 0)
+		ieee80211_queue_work(&local->hw,
+				     &ifmgd->csa_connection_drop_work);
+	if (res)
+		return;
+
 	if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef,
 				     IEEE80211_CHAN_DISABLED)) {
 		sdata_info(sdata,
-			   "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
-			   ifmgd->associated->bssid, new_freq,
-			   new_chandef.width, new_chandef.center_freq1,
+			   "network switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+			   new_chandef.chan->center_freq,
+			   new_chandef.width,
+			   new_chandef.center_freq1,
 			   new_chandef.center_freq2);
 		ieee80211_queue_work(&local->hw,
 				     &ifmgd->csa_connection_drop_work);
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 6/7] mac80211: send a CSA action frame when changing channel
From: Simon Wunderlich @ 2013-08-02 15:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-1-git-send-email-siwu@hrz.tu-chemnitz.de>

IBSS members may not immediately be able to send out their beacon when
performing CSA, therefore also send a CSA action frame.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/mac80211/ibss.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 4a10e00..2bd86a2 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -405,6 +405,61 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 				  tsf, false);
 }
 
+static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+				     struct cfg80211_csa_settings *csa_settings)
+{
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+	struct ieee80211_local *local = sdata->local;
+	int freq;
+	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
+		      sizeof(mgmt->u.action.u.chan_switch);
+	u8 *pos;
+
+	skb = dev_alloc_skb(local->tx_headroom + hdr_len +
+			    5 +	/* channel switch announcement element */
+			    3);	/* secondary channel offset element */
+	if (!skb)
+		return -1;
+
+	skb_reserve(skb, local->tx_headroom);
+	mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
+	memset(mgmt, 0, hdr_len);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
+
+	eth_broadcast_addr(mgmt->da);
+	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+	memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
+	mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+	mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
+	pos = skb_put(skb, 5);
+	*pos++ = WLAN_EID_CHANNEL_SWITCH;			/* EID */
+	*pos++ = 3;						/* IE length */
+	*pos++ = csa_settings->block_tx ? 1 : 0;		/* CSA mode */
+	freq = csa_settings->chandef.chan->center_freq;
+	*pos++ = ieee80211_frequency_to_channel(freq);		/* channel */
+	*pos++ = csa_settings->count;				/* count */
+
+	if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
+		enum nl80211_channel_type ch_type;
+
+		skb_put(skb, 3);
+		*pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;	/* EID */
+		*pos++ = 1;					/* IE length */
+		ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
+		if (ch_type == NL80211_CHAN_HT40PLUS)
+			*pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+		else
+			*pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+	}
+
+	ieee80211_tx_skb(sdata, skb);
+	return 0;
+}
+
+
 /* must hold sdata lock */
 int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
 			      struct cfg80211_csa_settings *csa_settings)
@@ -458,6 +513,12 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
 	if (old_presp)
 		kfree_rcu(old_presp, rcu_head);
 
+	/* it might not send the beacon for a while. send an action frame
+	 * immediately to announce the channel switch.
+	 */
+	if (csa_settings)
+		ieee80211_send_action_csa(sdata, csa_settings);
+
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
  out:
 	return ret;
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 7/7] nl80211: enable IBSS support for channel switch announcements
From: Simon Wunderlich @ 2013-08-02 15:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-1-git-send-email-siwu@hrz.tu-chemnitz.de>

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/wireless/nl80211.c |   49 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 34 insertions(+), 15 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f7cb121..6d3d788 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5632,15 +5632,26 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 	static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
 	u8 radar_detect_width = 0;
 	int err;
+	bool need_new_beacon = false;
 
 	if (!rdev->ops->channel_switch ||
 	    !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
 		return -EOPNOTSUPP;
 
-	/* may add IBSS support later */
-	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+	switch (dev->ieee80211_ptr->iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		need_new_beacon = true;
+
+		/* useless if AP is not running */
+		if (!wdev->beacon_interval)
+			return -EINVAL;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		break;
+	default:
 		return -EOPNOTSUPP;
+	}
 
 	memset(&params, 0, sizeof(params));
 
@@ -5649,15 +5660,16 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 
 	/* only important for AP, IBSS and mesh create IEs internally */
-	if (!info->attrs[NL80211_ATTR_CSA_IES])
-		return -EINVAL;
-
-	/* useless if AP is not running */
-	if (!wdev->beacon_interval)
+	if (need_new_beacon &&
+	    (!info->attrs[NL80211_ATTR_CSA_IES] ||
+	     !info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON]))
 		return -EINVAL;
 
 	params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
 
+	if (!need_new_beacon)
+		goto skip_beacons;
+
 	err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
 	if (err)
 		return err;
@@ -5697,6 +5709,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 			return -EINVAL;
 	}
 
+skip_beacons:
 	err = nl80211_parse_chandef(rdev, info, &params.chandef);
 	if (err)
 		return err;
@@ -5704,12 +5717,17 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
 		return -EINVAL;
 
-	err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
-	if (err < 0) {
-		return err;
-	} else if (err) {
-		radar_detect_width = BIT(params.chandef.width);
-		params.radar_required = true;
+	/* DFS channels are only supported for AP/P2P GO ... for now. */
+	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
+	    dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+		err = cfg80211_chandef_dfs_required(wdev->wiphy,
+						    &params.chandef);
+		if (err < 0) {
+			return err;
+		} else if (err) {
+			radar_detect_width = BIT(params.chandef.width);
+			params.radar_required = true;
+		}
 	}
 
 	err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
@@ -10725,7 +10743,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
 	wdev_lock(wdev);
 
 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-		    wdev->iftype != NL80211_IFTYPE_P2P_GO))
+		    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+		    wdev->iftype != NL80211_IFTYPE_ADHOC))
 		goto out;
 
 	wdev->channel = chandef->chan;
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 1/7] cfg80211: export cfg80211_chandef_dfs_required
From: Simon Wunderlich @ 2013-08-02 15:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-1-git-send-email-siwu@hrz.tu-chemnitz.de>

It will be used later by the IBSS CSA implementation of mac80211.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 include/net/cfg80211.h |    9 +++++++++
 net/wireless/chan.c    |    1 +
 net/wireless/core.h    |    8 --------
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6da5a6b..14c914f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -437,6 +437,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
 			     u32 prohibited_flags);
 
 /**
+ * cfg80211_chandef_dfs_required - checks if radar detection is required
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
+ */
+int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
+				  const struct cfg80211_chan_def *c);
+
+/**
  * ieee80211_chandef_rate_flags - returns rate flags for a channel
  *
  * In some channel types, not all rates may be used - for example CCK
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 50f6195..16f3c3a 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -328,6 +328,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 	return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
 					       width);
 }
+EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
 static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
 					u32 center_freq, u32 bandwidth,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 9ad43c6..8ed2094 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -382,14 +382,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 				 enum cfg80211_chan_mode chanmode,
 				 u8 radar_detect);
 
-/**
- * cfg80211_chandef_dfs_required - checks if radar detection is required
- * @wiphy: the wiphy to validate against
- * @chandef: the channel definition to check
- * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
- */
-int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
-				  const struct cfg80211_chan_def *c);
 
 void cfg80211_set_dfs_state(struct wiphy *wiphy,
 			    const struct cfg80211_chan_def *chandef,
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 5/7] mac80211: add support for CSA in IBSS mode
From: Simon Wunderlich @ 2013-08-02 15:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Mathias Kretschmer, Simon Wunderlich
In-Reply-To: <1375457886-7275-1-git-send-email-siwu@hrz.tu-chemnitz.de>

Ths function adds the channel switch announcement implementation for the
IBSS code. It is triggered by userspace (mac80211/cfg) or by external
channel switch announcement, which have to be adopted. Both CSAs in
beacons and action frames are supported. As for AP mode, the channel
switch is applied after some time. However in IBSS mode, the channel
switch IEs are generated in the kernel.

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
---
 net/mac80211/cfg.c         |   84 +++++---
 net/mac80211/ibss.c        |  475 ++++++++++++++++++++++++++++++++++++++------
 net/mac80211/ieee80211_i.h |    2 +
 net/mac80211/iface.c       |    4 +
 net/mac80211/rx.c          |   36 +++-
 net/mac80211/tx.c          |   34 +++-
 6 files changed, 537 insertions(+), 98 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 44449ce..e603450 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2852,30 +2852,35 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 	if (!ieee80211_sdata_running(sdata))
 		return;
 
-	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
-		return;
-
 	sdata->radar_required = sdata->csa_radar_required;
 	err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
 					   &changed);
 	if (WARN_ON(err < 0))
 		return;
 
-	err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
-	if (err < 0)
+	ieee80211_bss_info_change_notify(sdata, changed);
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP) {
+		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
+		if (err < 0)
+			return;
+		changed |= err;
+		kfree(sdata->u.ap.next_beacon);
+		sdata->u.ap.next_beacon = NULL;
+
+		ieee80211_bss_info_change_notify(sdata, err);
+	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		ieee80211_ibss_finish_csa(sdata);
+	} else {
+		WARN_ON(1);
 		return;
-
-	changed |= err;
-	kfree(sdata->u.ap.next_beacon);
-	sdata->u.ap.next_beacon = NULL;
+	}
 	sdata->vif.csa_active = false;
 
 	ieee80211_wake_queues_by_reason(&sdata->local->hw,
 					IEEE80211_MAX_QUEUE_MAP,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
 
-	ieee80211_bss_info_change_notify(sdata, changed);
-
 	cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
 }
 
@@ -2923,20 +2928,56 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	if (sdata->vif.csa_active)
 		return -EBUSY;
 
-	/* only handle AP for now. */
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_AP:
+		sdata->csa_counter_offset_beacon =
+			params->counter_offset_beacon;
+		sdata->csa_counter_offset_presp = params->counter_offset_presp;
+		sdata->u.ap.next_beacon =
+			cfg80211_beacon_dup(&params->beacon_after);
+		if (!sdata->u.ap.next_beacon)
+			return -ENOMEM;
+
+		err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
+		if (err < 0) {
+			kfree(sdata->u.ap.next_beacon);
+			return err;
+		}
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		if (!sdata->vif.bss_conf.ibss_joined)
+			return -EINVAL;
+
+		if (params->chandef.width != sdata->u.ibss.chandef.width)
+			return -EINVAL;
+
+		switch (params->chandef.width) {
+		case NL80211_CHAN_WIDTH_40:
+			if (cfg80211_get_chandef_type(&params->chandef) !=
+			    cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
+				return -EINVAL;
+		case NL80211_CHAN_WIDTH_5:
+		case NL80211_CHAN_WIDTH_10:
+		case NL80211_CHAN_WIDTH_20_NOHT:
+		case NL80211_CHAN_WIDTH_20:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* changes into another band are not supported */
+		if (sdata->u.ibss.chandef.chan->band !=
+		    params->chandef.chan->band)
+			return -EINVAL;
+
+		err = ieee80211_ibss_csa_beacon(sdata, params);
+		if (err < 0)
+			return err;
 		break;
 	default:
 		return -EOPNOTSUPP;
 	}
 
-	sdata->u.ap.next_beacon = cfg80211_beacon_dup(&params->beacon_after);
-	if (!sdata->u.ap.next_beacon)
-		return -ENOMEM;
-
-	sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
-	sdata->csa_counter_offset_presp = params->counter_offset_presp;
 	sdata->csa_radar_required = params->radar_required;
 
 	if (params->block_tx)
@@ -2944,10 +2985,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				IEEE80211_MAX_QUEUE_MAP,
 				IEEE80211_QUEUE_STOP_REASON_CSA);
 
-	err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
-	if (err < 0)
-		return err;
-
 	local->csa_chandef = params->chandef;
 	sdata->vif.csa_active = true;
 
@@ -3001,7 +3038,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			need_offchan = true;
 		if (!ieee80211_is_action(mgmt->frame_control) ||
 		    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
-		    mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED)
+		    mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||
+		    mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
 			break;
 		rcu_read_lock();
 		sta = sta_info_get(sdata, mgmt->da);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 29f1a7b..4a10e00 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -34,12 +34,15 @@
 
 #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
 
+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata);
+
 static struct beacon_data *
 ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
 			   const int beacon_int, const u32 basic_rates,
 			   const u16 capability, u64 tsf,
 			   struct cfg80211_chan_def *chandef,
-			   bool *have_higher_than_11mbit)
+			   bool *have_higher_than_11mbit,
+			   struct cfg80211_csa_settings *csa_settings)
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
 	struct ieee80211_local *local = sdata->local;
@@ -59,6 +62,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
 		    2 + 8 /* max Supported Rates */ +
 		    3 /* max DS params */ +
 		    4 /* IBSS params */ +
+		    5 /* Channel Switch Announcement */ +
 		    2 + (IEEE80211_MAX_SUPP_RATES - 8) +
 		    2 + sizeof(struct ieee80211_ht_cap) +
 		    2 + sizeof(struct ieee80211_ht_operation) +
@@ -135,6 +139,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
 	*pos++ = 0;
 	*pos++ = 0;
 
+	if (csa_settings) {
+		*pos++ = WLAN_EID_CHANNEL_SWITCH;
+		*pos++ = 3;
+		*pos++ = csa_settings->block_tx ? 1 : 0;
+		*pos++ = ieee80211_frequency_to_channel(
+				csa_settings->chandef.chan->center_freq);
+		sdata->csa_counter_offset_beacon = (pos - presp->head);
+		*pos++ = csa_settings->count;
+	}
+
 	/* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */
 	if (rates_n > 8) {
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
@@ -273,7 +287,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
 	presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
 					   capability, tsf, &chandef,
-					   &have_higher_than_11mbit);
+					   &have_higher_than_11mbit, NULL);
 	if (!presp)
 		return;
 
@@ -391,6 +405,110 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 				  tsf, false);
 }
 
+/* must hold sdata lock */
+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
+			      struct cfg80211_csa_settings *csa_settings)
+{
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+	struct beacon_data *presp, *old_presp;
+	struct cfg80211_bss *cbss;
+	const struct cfg80211_bss_ies *ies;
+	u16 capability;
+	u64 tsf;
+	int ret = 0;
+
+	sdata_assert_lock(sdata);
+
+	capability = WLAN_CAPABILITY_IBSS;
+
+	if (ifibss->privacy)
+		capability |= WLAN_CAPABILITY_PRIVACY;
+
+	cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
+				ifibss->bssid, ifibss->ssid,
+				ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+				WLAN_CAPABILITY_PRIVACY,
+				capability);
+
+	if (WARN_ON(!cbss)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	rcu_read_lock();
+	ies = rcu_dereference(cbss->ies);
+	tsf = ies->tsf;
+	rcu_read_unlock();
+	cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+
+	old_presp = rcu_dereference_protected(ifibss->presp,
+					  lockdep_is_held(&sdata->wdev.mtx));
+
+	presp = ieee80211_ibss_build_presp(sdata,
+					   sdata->vif.bss_conf.beacon_int,
+					   sdata->vif.bss_conf.basic_rates,
+					   capability, tsf, &ifibss->chandef,
+					   NULL, csa_settings);
+	if (!presp) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	rcu_assign_pointer(ifibss->presp, presp);
+	if (old_presp)
+		kfree_rcu(old_presp, rcu_head);
+
+	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ out:
+	return ret;
+}
+
+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+	struct cfg80211_bss *cbss;
+	int err;
+	u16 capability;
+
+	sdata_lock(sdata);
+	/* update cfg80211 bss information with the new channel */
+	if (!is_zero_ether_addr(ifibss->bssid)) {
+		capability = WLAN_CAPABILITY_IBSS;
+
+		if (ifibss->privacy)
+			capability |= WLAN_CAPABILITY_PRIVACY;
+
+		cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
+					ifibss->chandef.chan,
+					ifibss->bssid, ifibss->ssid,
+					ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+					WLAN_CAPABILITY_PRIVACY,
+					capability);
+		/* XXX: should not really modify cfg80211 data */
+		if (cbss) {
+			cbss->channel = sdata->local->csa_chandef.chan;
+			cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+		}
+	}
+
+	ifibss->chandef = sdata->local->csa_chandef;
+
+	/* generate the beacon */
+	err = ieee80211_ibss_csa_beacon(sdata, NULL);
+	sdata_unlock(sdata);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+	cancel_work_sync(&ifibss->csa_connection_drop_work);
+}
+
 static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
 	__acquires(RCU)
 {
@@ -474,6 +592,265 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
 	return ieee80211_ibss_finish_sta(sta);
 }
 
+static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+	struct ieee80211_local *local = sdata->local;
+	struct cfg80211_bss *cbss;
+	struct beacon_data *presp;
+	struct sta_info *sta;
+	int active_ibss;
+	u16 capability;
+
+	active_ibss = ieee80211_sta_active_ibss(sdata);
+
+	if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
+		capability = WLAN_CAPABILITY_IBSS;
+
+		if (ifibss->privacy)
+			capability |= WLAN_CAPABILITY_PRIVACY;
+
+		cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
+					ifibss->bssid, ifibss->ssid,
+					ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+					WLAN_CAPABILITY_PRIVACY,
+					capability);
+
+		if (cbss) {
+			cfg80211_unlink_bss(local->hw.wiphy, cbss);
+			cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+		}
+	}
+
+	ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
+
+	sta_info_flush(sdata);
+
+	spin_lock_bh(&ifibss->incomplete_lock);
+	while (!list_empty(&ifibss->incomplete_stations)) {
+		sta = list_first_entry(&ifibss->incomplete_stations,
+				       struct sta_info, list);
+		list_del(&sta->list);
+		spin_unlock_bh(&ifibss->incomplete_lock);
+
+		sta_info_free(local, sta);
+		spin_lock_bh(&ifibss->incomplete_lock);
+	}
+	spin_unlock_bh(&ifibss->incomplete_lock);
+
+	netif_carrier_off(sdata->dev);
+
+	sdata->vif.bss_conf.ibss_joined = false;
+	sdata->vif.bss_conf.ibss_creator = false;
+	sdata->vif.bss_conf.enable_beacon = false;
+	sdata->vif.bss_conf.ssid_len = 0;
+
+	/* remove beacon */
+	presp = rcu_dereference_protected(ifibss->presp,
+					  lockdep_is_held(&sdata->wdev.mtx));
+	RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
+	if (presp)
+		kfree_rcu(presp, rcu_head);
+
+	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
+	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
+						BSS_CHANGED_IBSS);
+}
+
+static void ieee80211_csa_connection_drop_work(struct work_struct *work)
+{
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data,
+			     u.ibss.csa_connection_drop_work);
+
+	ieee80211_ibss_disconnect(sdata);
+	synchronize_rcu();
+	skb_queue_purge(&sdata->skb_queue);
+
+	/* trigger a scan to find another IBSS network to join */
+	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+}
+
+static bool
+ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+				  struct ieee802_11_elems *elems,
+				  bool beacon)
+{
+	struct cfg80211_csa_settings params;
+	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_chanctx *chanctx;
+	enum nl80211_channel_type ch_type;
+	int err, num_chanctx;
+	u32 sta_flags;
+	u8 mode;
+
+	if (sdata->vif.csa_active)
+		return true;
+
+	if (!sdata->vif.bss_conf.ibss_joined)
+		return false;
+
+	sta_flags = IEEE80211_STA_DISABLE_VHT;
+	switch (ifibss->chandef.width) {
+	case NL80211_CHAN_WIDTH_5:
+	case NL80211_CHAN_WIDTH_10:
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		sta_flags |= IEEE80211_STA_DISABLE_HT;
+		/* fall through */
+	case NL80211_CHAN_WIDTH_20:
+		sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+		break;
+	default:
+		break;
+	}
+
+	memset(&params, 0, sizeof(params));
+	err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
+					   ifibss->chandef.chan->band,
+					   sta_flags, &params.count,
+					   &mode, &params.chandef);
+
+	/* can't switch to destination channel, fail */
+	if (err < 0)
+		goto disconnect;
+
+	/* did not contain a CSA */
+	if (err)
+		return false;
+
+	if (ifibss->chandef.chan->band != params.chandef.chan->band)
+		goto disconnect;
+
+	switch (ifibss->chandef.width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+	case NL80211_CHAN_WIDTH_20:
+	case NL80211_CHAN_WIDTH_40:
+		/* keep our current HT mode (HT20/HT40+/HT40-), even if
+		 * another mode  has been announced. The mode is not adopted
+		 * within the beacon while doing CSA and we should therefore
+		 * keep the mode which we announce.
+		 */
+		ch_type = cfg80211_get_chandef_type(&ifibss->chandef);
+		cfg80211_chandef_create(&params.chandef, params.chandef.chan,
+					ch_type);
+		break;
+	case NL80211_CHAN_WIDTH_5:
+	case NL80211_CHAN_WIDTH_10:
+		if (WARN_ON(params.chandef.width != ifibss->chandef.width))
+			sdata_info(sdata,
+				   "received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+				   params.chandef.chan->center_freq,
+				   params.chandef.width,
+				   params.chandef.center_freq1,
+				   params.chandef.center_freq2);
+			goto disconnect;
+		break;
+	default:
+		/* should not happen, sta_flags should prevent VHT modes. */
+		WARN_ON(1);
+		goto disconnect;
+	}
+
+	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
+				     IEEE80211_CHAN_DISABLED)) {
+		sdata_info(sdata,
+			   "network switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+			   params.chandef.chan->center_freq,
+			   params.chandef.width,
+			   params.chandef.center_freq1,
+			   params.chandef.center_freq2);
+		goto disconnect;
+	}
+
+	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
+					    &params.chandef);
+	if (err < 0)
+		goto disconnect;
+	if (err) {
+		params.radar_required = true;
+
+		/* TODO: IBSS-DFS not (yet) supported, disconnect. */
+		goto disconnect;
+	}
+
+	rcu_read_lock();
+	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+	if (!chanctx_conf) {
+		rcu_read_unlock();
+		goto disconnect;
+	}
+
+	/* don't handle for multi-VIF cases */
+	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+	if (chanctx->refcount > 1) {
+		rcu_read_unlock();
+		goto disconnect;
+	}
+	num_chanctx = 0;
+	list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
+		num_chanctx++;
+
+	if (num_chanctx > 1) {
+		rcu_read_unlock();
+		goto disconnect;
+	}
+	rcu_read_unlock();
+
+	/* all checks done, now perform the channel switch. */
+	ibss_dbg(sdata,
+		 "received channel switch announcement to go to channel %d MHz\n",
+		 params.chandef.chan->center_freq);
+
+	params.block_tx = !!mode;
+
+	ieee80211_ibss_csa_beacon(sdata, &params);
+	sdata->csa_radar_required = params.radar_required;
+
+	if (params.block_tx)
+		ieee80211_stop_queues_by_reason(&sdata->local->hw,
+				IEEE80211_MAX_QUEUE_MAP,
+				IEEE80211_QUEUE_STOP_REASON_CSA);
+
+	sdata->local->csa_chandef = params.chandef;
+	sdata->vif.csa_active = true;
+
+	ieee80211_bss_info_change_notify(sdata, err);
+	drv_channel_switch_beacon(sdata, &params.chandef);
+
+	return true;
+disconnect:
+	ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");
+	ieee80211_queue_work(&sdata->local->hw,
+			     &ifibss->csa_connection_drop_work);
+
+	return true;
+}
+
+static void
+ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
+				struct ieee80211_mgmt *mgmt, size_t len,
+				struct ieee80211_rx_status *rx_status,
+				struct ieee802_11_elems *elems)
+{
+	int required_len;
+
+	if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+		return;
+
+	/* CSA is the only action we handle for now */
+	if (mgmt->u.action.u.measurement.action_code !=
+	    WLAN_ACTION_SPCT_CHL_SWITCH)
+		return;
+
+	required_len = IEEE80211_MIN_ACTION_SIZE +
+		       sizeof(mgmt->u.action.u.chan_switch);
+	if (len < required_len)
+		return;
+
+	ieee80211_ibss_process_chanswitch(sdata, elems, false);
+}
+
 static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
 					  struct ieee80211_mgmt *mgmt,
 					  size_t len)
@@ -636,10 +1013,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
 	/* check if we need to merge IBSS */
 
-	/* we use a fixed BSSID */
-	if (sdata->u.ibss.fixed_bssid)
-		goto put_bss;
-
 	/* not an IBSS */
 	if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
 		goto put_bss;
@@ -655,10 +1028,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 				sdata->u.ibss.ssid_len))
 		goto put_bss;
 
+	/* process channel switch */
+	if (ieee80211_ibss_process_chanswitch(sdata, elems, true))
+		goto put_bss;
+
 	/* same BSSID */
 	if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))
 		goto put_bss;
 
+	/* we use a fixed BSSID */
+	if (sdata->u.ibss.fixed_bssid)
+		goto put_bss;
+
 	if (ieee80211_have_rx_timestamp(rx_status)) {
 		/* time when timestamp field was received */
 		rx_timestamp =
@@ -1040,6 +1421,8 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_rx_status *rx_status;
 	struct ieee80211_mgmt *mgmt;
 	u16 fc;
+	struct ieee802_11_elems elems;
+	int ies_len;
 
 	rx_status = IEEE80211_SKB_RXCB(skb);
 	mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1065,6 +1448,27 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 	case IEEE80211_STYPE_DEAUTH:
 		ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len);
 		break;
+	case IEEE80211_STYPE_ACTION:
+		switch (mgmt->u.action.category) {
+		case WLAN_CATEGORY_SPECTRUM_MGMT:
+			ies_len = skb->len -
+				  offsetof(struct ieee80211_mgmt,
+					   u.action.u.chan_switch.variable);
+
+			if (ies_len < 0)
+				break;
+
+			ieee802_11_parse_elems(
+				mgmt->u.action.u.chan_switch.variable,
+				ies_len, true, &elems);
+
+			if (elems.parse_error)
+				break;
+
+			ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
+							rx_status, &elems);
+			break;
+		}
 	}
 
  mgmt_out:
@@ -1131,6 +1535,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
 		    (unsigned long) sdata);
 	INIT_LIST_HEAD(&ifibss->incomplete_stations);
 	spin_lock_init(&ifibss->incomplete_lock);
+	INIT_WORK(&ifibss->csa_connection_drop_work,
+		  ieee80211_csa_connection_drop_work);
 }
 
 /* scan finished notification */
@@ -1229,72 +1635,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-	struct ieee80211_local *local = sdata->local;
-	struct cfg80211_bss *cbss;
-	u16 capability;
-	int active_ibss;
-	struct sta_info *sta;
-	struct beacon_data *presp;
 
-	active_ibss = ieee80211_sta_active_ibss(sdata);
+	ieee80211_ibss_disconnect(sdata);
 
-	if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
-		capability = WLAN_CAPABILITY_IBSS;
-
-		if (ifibss->privacy)
-			capability |= WLAN_CAPABILITY_PRIVACY;
-
-		cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
-					ifibss->bssid, ifibss->ssid,
-					ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
-					WLAN_CAPABILITY_PRIVACY,
-					capability);
-
-		if (cbss) {
-			cfg80211_unlink_bss(local->hw.wiphy, cbss);
-			cfg80211_put_bss(local->hw.wiphy, cbss);
-		}
-	}
-
-	ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
-	memset(ifibss->bssid, 0, ETH_ALEN);
 	ifibss->ssid_len = 0;
-
-	sta_info_flush(sdata);
-
-	spin_lock_bh(&ifibss->incomplete_lock);
-	while (!list_empty(&ifibss->incomplete_stations)) {
-		sta = list_first_entry(&ifibss->incomplete_stations,
-				       struct sta_info, list);
-		list_del(&sta->list);
-		spin_unlock_bh(&ifibss->incomplete_lock);
-
-		sta_info_free(local, sta);
-		spin_lock_bh(&ifibss->incomplete_lock);
-	}
-	spin_unlock_bh(&ifibss->incomplete_lock);
-
-	netif_carrier_off(sdata->dev);
-
+	memset(ifibss->bssid, 0, ETH_ALEN);
 	/* remove beacon */
 	kfree(sdata->u.ibss.ie);
-	presp = rcu_dereference_protected(ifibss->presp,
-					  lockdep_is_held(&sdata->wdev.mtx));
-	RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
 
 	/* on the next join, re-program HT parameters */
 	memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
 	memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
 
-	sdata->vif.bss_conf.ibss_joined = false;
-	sdata->vif.bss_conf.ibss_creator = false;
-	sdata->vif.bss_conf.enable_beacon = false;
-	sdata->vif.bss_conf.ssid_len = 0;
-	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
-	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
-						BSS_CHANGED_IBSS);
 	synchronize_rcu();
-	kfree(presp);
 
 	skb_queue_purge(&sdata->skb_queue);
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1275bde..dbbd124 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -490,6 +490,7 @@ struct ieee80211_if_managed {
 
 struct ieee80211_if_ibss {
 	struct timer_list timer;
+	struct work_struct csa_connection_drop_work;
 
 	unsigned long last_scan_completed;
 
@@ -1336,6 +1337,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
 			      struct cfg80211_csa_settings *csa_settings);
 int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
 
 /* mesh code */
 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 7ca534b..a8bce73 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -763,6 +763,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 	if (sdata->vif.type == NL80211_IFTYPE_STATION)
 		ieee80211_mgd_stop(sdata);
 
+	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+		ieee80211_ibss_stop(sdata);
+
+
 	/*
 	 * Remove all stations associated with this interface.
 	 *
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 0ac7512..59595d6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2396,7 +2396,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 		return RX_DROP_UNUSABLE;
 
 	if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
-	    mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED)
+	    mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
+	    mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
 		return RX_DROP_UNUSABLE;
 
 	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
@@ -2560,31 +2561,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
 		goto queue;
 	case WLAN_CATEGORY_SPECTRUM_MGMT:
-		if (status->band != IEEE80211_BAND_5GHZ)
-			break;
-
-		if (sdata->vif.type != NL80211_IFTYPE_STATION)
-			break;
-
 		/* verify action_code is present */
 		if (len < IEEE80211_MIN_ACTION_SIZE + 1)
 			break;
 
 		switch (mgmt->u.action.u.measurement.action_code) {
 		case WLAN_ACTION_SPCT_MSR_REQ:
+			if (status->band != IEEE80211_BAND_5GHZ)
+				break;
+
 			if (len < (IEEE80211_MIN_ACTION_SIZE +
 				   sizeof(mgmt->u.action.u.measurement)))
 				break;
+
+			if (sdata->vif.type != NL80211_IFTYPE_STATION)
+				break;
+
 			ieee80211_process_measurement_req(sdata, mgmt, len);
 			goto handled;
-		case WLAN_ACTION_SPCT_CHL_SWITCH:
-			if (sdata->vif.type != NL80211_IFTYPE_STATION)
+		case WLAN_ACTION_SPCT_CHL_SWITCH: {
+			u8 *bssid;
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.chan_switch)))
 				break;
 
-			if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid))
+			if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+			    sdata->vif.type != NL80211_IFTYPE_ADHOC)
+				break;
+
+			if (sdata->vif.type == NL80211_IFTYPE_STATION)
+				bssid = sdata->u.mgd.bssid;
+			else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+				bssid = sdata->u.ibss.bssid;
+			else
+				break;
+
+			if (!ether_addr_equal(mgmt->bssid, bssid))
 				break;
 
 			goto queue;
+			}
 		}
 		break;
 	case WLAN_CATEGORY_SA_QUERY:
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0e42322..ab5e151 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2353,15 +2353,28 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
 	struct probe_resp *resp;
 	int counter_offset_beacon = sdata->csa_counter_offset_beacon;
 	int counter_offset_presp = sdata->csa_counter_offset_presp;
+	u8 *beacon_data;
+	size_t beacon_data_len;
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP) {
+		beacon_data = beacon->tail;
+		beacon_data_len = beacon->tail_len;
+	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+		beacon_data = beacon->head;
+		beacon_data_len = beacon->head_len;
+	} else {
+		return;
+	}
+	if (WARN_ON(counter_offset_beacon >= beacon_data_len))
+		return;
 
 	/* warn if the driver did not check for/react to csa completeness */
-	if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
+	if (WARN_ON(beacon_data[counter_offset_beacon] == 0))
 		return;
 
-	((u8 *)beacon->tail)[counter_offset_beacon]--;
+	beacon_data[counter_offset_beacon]--;
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP &&
-	    counter_offset_presp) {
+	if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
 		rcu_read_lock();
 		resp = rcu_dereference(sdata->u.ap.probe_resp);
 
@@ -2396,6 +2409,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
 			goto out;
 		beacon_data = beacon->tail;
 		beacon_data_len = beacon->tail_len;
+	} else if (vif->type == NL80211_IFTYPE_ADHOC) {
+		struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+		beacon = rcu_dereference(ifibss->presp);
+		if (!beacon)
+			goto out;
+
+		beacon_data = beacon->head;
+		beacon_data_len = beacon->head_len;
 	} else {
 		WARN_ON(1);
 		goto out;
@@ -2480,6 +2502,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 		if (!presp)
 			goto out;
 
+		if (sdata->vif.csa_active)
+			ieee80211_update_csa(sdata, presp);
+
+
 		skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
 		if (!skb)
 			goto out;
-- 
1.7.10.4


^ permalink raw reply related

* Slow firmware timeouts again (Re: [3.11 regression?] iwlwifi firmware takes two minutes to load)
From: Andy Lutomirski @ 2013-08-02 16:04 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Linux Wireless List, Intel Linux Wireless, linux-hotplug,
	linux-kernel, systemd-devel

[cc: linux-kernel, linux-hotplug, and systemd-devel.  This is 3.11-rc3+]

On Fri, Aug 2, 2013 at 12:38 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Thu, 2013-08-01 at 21:38 -0700, Andy Lutomirski wrote:
>> At boot, I get:
>> [   12.537108] iwlwifi 0000:03:00.0: irq 51 for MSI/MSI-X
>> ...
>> [  132.676781] iwlwifi 0000:03:00.0: loaded firmware version 9.221.4.1
>> build 25532 op_mode iwldvm
>>
>> This sounds familiar, but wasn't it fixed awhile ago?
>
> It wasn't exactly fixed and it's really more of a userspace problem - we
> probably request firmware version 8, and then it takes 30 seconds to
> time out for each of 8,7,6,5, after which the next request for 4 is
> successful.

Why's it requesting those firmwares?  They don't seem to exist on
intellinuxwireless.org.

I have:

CONFIG_FW_LOADER=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
CONFIG_EXTRA_FIRMWARE=""
CONFIG_FW_LOADER_USER_HELPER=y


>
> I don't know why your userspace isn't behaving differently though.
>
> johannes
>



-- 
Andy Lutomirski
AMA Capital Management, LLC

^ permalink raw reply

* Re: Slow firmware timeouts again (Re: [3.11 regression?] iwlwifi firmware takes two minutes to load)
From: Johannes Berg @ 2013-08-02 16:21 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Linux Wireless List, Intel Linux Wireless, linux-hotplug,
	linux-kernel, systemd-devel
In-Reply-To: <CALCETrU+C+sO8tJ0X5G4RDVLV=kHQQHurOnEQCoqbAouh60dng@mail.gmail.com>

On Fri, 2013-08-02 at 09:04 -0700, Andy Lutomirski wrote:

> > It wasn't exactly fixed and it's really more of a userspace problem - we
> > probably request firmware version 8, and then it takes 30 seconds to
> > time out for each of 8,7,6,5, after which the next request for 4 is
> > successful.
> 
> Why's it requesting those firmwares?  They don't seem to exist on
> intellinuxwireless.org.

Well for one you've never even mentioned what device you have, and then
also it's not requesting 8/7 only 6,5,4 -- I guess the timeout was
increased to 60 seconds (or I'm remembering wrong and it always was? I
thought it was 30s)

johannes


^ permalink raw reply

* Re: Slow firmware timeouts again (Re: [3.11 regression?] iwlwifi firmware takes two minutes to load)
From: Andy Lutomirski @ 2013-08-02 16:24 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Linux Wireless List, Intel Linux Wireless, linux-hotplug,
	linux-kernel, systemd-devel
In-Reply-To: <1375460484.18144.11.camel@jlt4.sipsolutions.net>

On Fri, Aug 2, 2013 at 9:21 AM, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2013-08-02 at 09:04 -0700, Andy Lutomirski wrote:
>
>> > It wasn't exactly fixed and it's really more of a userspace problem - we
>> > probably request firmware version 8, and then it takes 30 seconds to
>> > time out for each of 8,7,6,5, after which the next request for 4 is
>> > successful.
>>
>> Why's it requesting those firmwares?  They don't seem to exist on
>> intellinuxwireless.org.
>
> Well for one you've never even mentioned what device you have, and then
> also it's not requesting 8/7 only 6,5,4 -- I guess the timeout was
> increased to 60 seconds (or I'm remembering wrong and it always was? I
> thought it was 30s)

I have an "Ultimate-N 6300 (rev 35)".  It's requesting at least
versions 6 and 5 (I saw them in udevadm monitor).  It looks like the
g2a and g2b variants have -5 and -6 versions, but 6000-4 appears to be
the only relevant version for my hardware.

^ permalink raw reply

* Re: Slow firmware timeouts again (Re: [3.11 regression?] iwlwifi firmware takes two minutes to load)
From: Zbigniew Jędrzejewski-Szmek @ 2013-08-02 16:28 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Johannes Berg, Linux Wireless List, Intel Linux Wireless,
	linux-hotplug, linux-kernel, systemd-devel
In-Reply-To: <CALCETrU+C+sO8tJ0X5G4RDVLV=kHQQHurOnEQCoqbAouh60dng@mail.gmail.com>

On Fri, Aug 02, 2013 at 09:04:44AM -0700, Andy Lutomirski wrote:
> CONFIG_FW_LOADER_USER_HELPER=y
Do you need this? Unsetting this should help.

"""This option enables / disables the invocation of user-helper
(e.g. udev) for loading firmware files as a fallback after the
direct file loading in kernel fails. The user-mode helper is
no longer required unless you have a special firmware file that
resides in a non-standard path."""

Zbyszek
-- 
they are not broken. they are refucktored
                           -- alxchk

^ permalink raw reply

* Re: pull-request: mac80211 2013-07-31
From: John W. Linville @ 2013-08-02 18:59 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1375298735.8289.25.camel@jlt4.sipsolutions.net>

On Wed, Jul 31, 2013 at 09:25:35PM +0200, Johannes Berg wrote:
> John,
> 
> Another pull request for mac80211 - this time with a bunch of important
> fixes.
> 
> I have a fix from Chris for an infinite loop along with fixes from
> myself to prevent it entering the loop to start with (continue using
> disabled channels, many thanks to Chris for his debug/test help) and a
> workaround for broken APs that advertise a bad HT primary channel in
> their beacons. Additionally, a fix for another attrbuf race in mac80211
> and a fix to clean up properly while P2P GO interfaces go down.
> 
> Let me know if there's any problem.
> 
> johannes
> 
> The following changes since commit 23df0b731954502a9391e739b92927cee4360343:
> 
>   regulatory: use correct regulatory initiator on wiphy register (2013-07-25 09:52:46 +0200)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git for-john
> 
> for you to fetch changes up to ddfe49b42d8ad4bfdf92d63d4a74f162660d878d:
> 
>   mac80211: continue using disabled channels while connected (2013-07-31 21:18:17 +0200)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: pull-request: iwlwifi-next 2013-07-26
From: John W. Linville @ 2013-08-02 19:38 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1374827327-3464-1-git-send-email-johannes@sipsolutions.net>

On Fri, Jul 26, 2013 at 10:28:17AM +0200, Johannes Berg wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
> 
> John,
> 
> First -next pull request for iwlwifi. I'm trying something new, writing
> the pull request directly into the cover letter of git send-email so I
> can send the patches out at the same time as the pull request and don't
> forget the patches - let me know if there's a problem with that.
> 
> There are a lot of various changes, I can't really list them all in a
> meaningful way. One thing to note is maybe that we're removing the P2P
> support from the older driver - it has never been really functional and
> should be converted to P2P-Device, but we don't have time or testing
> support to do that, and as it is it's not really functional.
> 
> 
> johannes
> 
> 
> The following changes since commit ad81f0545ef01ea651886dddac4bef6cec930092:
> 
>   Linux 3.11-rc1 (2013-07-14 15:18:27 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git for-john
> 
> for you to fetch changes up to 5e216eb4ed04b9b1725ce3e7779a4fb680e63446:
> 
>   iwlwifi: mvm: add high temperature SKU thermal throttling parameters (2013-07-26 10:21:14 +0200)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: Pull request: ath 20130730
From: John W. Linville @ 2013-08-02 19:40 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, ath10k
In-Reply-To: <87txjct6pf.fsf@kamboji.qca.qualcomm.com>

On Tue, Jul 30, 2013 at 06:20:44PM +0300, Kalle Valo wrote:
> Hi John,
> 
> here's a new pull request containing just ath10k patches from Michal.
> 
> A major new feature is that we can now restart the firmware when it
> crashes. For this Michal needed quite a few preparation patches. It's
> now possible to to crash the firmware from debugfs, which makes it
> easier to test the restart feature.
> 
> Michal also sent fixes and cleanup to various parts in the driver. Most
> visible to users are RTS and fragmentation related fixes.
> 
> Please pull and do let me know if there are any problems.
> 
> Kalle
> 
> The following changes since commit 2cdf359a521bb72286b6714478dfdbcd2691f3fe:
> 
>   mwifiex: code rearrangement in sdio.c (2013-07-26 16:57:45 -0400)
> 
> are available in the git repository at:
> 
>   git://github.com/kvalo/ath6kl.git tags/for-linville-20130730
> 
> for you to fetch changes up to 424121c365aed6ec93bbc8b515548df79c5af61c:
> 
>   ath10k: fix rts/fragmentation threshold setup (2013-07-30 18:01:21 +0300)

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* [PATCH] cw1200:  Fix spurious BUG_ON() trigger when starting AP mode.
From: Solomon Peachy @ 2013-08-02 23:57 UTC (permalink / raw)
  To: linux-wireless; +Cc: Solomon Peachy

There's an underlying race condition with the unjoin_work() call that is
sometimes triggered depending on scheduling order and the phase of the
moon.  This doesn't fix the race condition, but it does remove the
ill-advised BUG_ON() call in an easily-recoverable situation.

Signed-off-by: Solomon Peachy <pizza@shaftnet.org>
---
This should go into 3.11-rc!
 drivers/net/wireless/cw1200/sta.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c
index 7365674..010b252 100644
--- a/drivers/net/wireless/cw1200/sta.c
+++ b/drivers/net/wireless/cw1200/sta.c
@@ -1406,11 +1406,8 @@ static void cw1200_do_unjoin(struct cw1200_common *priv)
 	if (!priv->join_status)
 		goto done;
 
-	if (priv->join_status > CW1200_JOIN_STATUS_IBSS) {
-		wiphy_err(priv->hw->wiphy, "Unexpected: join status: %d\n",
-			  priv->join_status);
-		BUG_ON(1);
-	}
+	if (priv->join_status == CW1200_JOIN_STATUS_AP)
+		goto done;
 
 	cancel_work_sync(&priv->update_filtering_work);
 	cancel_work_sync(&priv->set_beacon_wakeup_period_work);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH] mac80211: allow lowest basic rate for unicast management for mesh
From: Chun-Yeow Yeoh @ 2013-08-03 10:35 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh

Allow lowest basic rate to be used for unicast management frame in
mesh. Otherwise, the lowest supported rate is used for unicast
management frame, such as 1Mbps for 2.4GHz and 6Mbps for 5GHz. Rename
the rc_send_low_broadcast to re_send_low_basicrate since now it is
also applied to unicast management frame in mesh.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
 net/mac80211/rate.c |   23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index ba63ac8..4aa7bb6 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -210,7 +210,7 @@ static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc)
 		!ieee80211_is_data(fc);
 }
 
-static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
+static void rc_send_low_basicrate(s8 *idx, u32 basic_rates,
 				  struct ieee80211_supported_band *sband)
 {
 	u8 i;
@@ -263,28 +263,37 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
 }
 
 
-bool rate_control_send_low(struct ieee80211_sta *sta,
+bool rate_control_send_low(struct ieee80211_sta *pubsta,
 			   void *priv_sta,
 			   struct ieee80211_tx_rate_control *txrc)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
 	struct ieee80211_supported_band *sband = txrc->sband;
+	struct sta_info *sta;
 	int mcast_rate;
+	bool use_basicrate = false;
 
-	if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
-		__rate_control_send_low(txrc->hw, sband, sta, info);
+	if (!pubsta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
+		__rate_control_send_low(txrc->hw, sband, pubsta, info);
 
-		if (!sta && txrc->bss) {
+		if (!pubsta && txrc->bss) {
 			mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
 			if (mcast_rate > 0) {
 				info->control.rates[0].idx = mcast_rate - 1;
 				return true;
 			}
+			use_basicrate = true;
+		} else {
+			sta = container_of(pubsta, struct sta_info, sta);
+			if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+				use_basicrate = true;
+		}
 
-			rc_send_low_broadcast(&info->control.rates[0].idx,
+		if (use_basicrate)
+			rc_send_low_basicrate(&info->control.rates[0].idx,
 					      txrc->bss_conf->basic_rates,
 					      sband);
-		}
+
 		return true;
 	}
 	return false;
-- 
1.7.9.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox