Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH mac80211-next] brcm80211: fix null pointer access
From: Antonio Quartulli @ 2013-06-19 11:35 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Do not unconditionally access the chan variable in
brcmf_cfg80211_mgmt_tx() as it may be NULL.
Use freq instead.

Introduced by c2ff8cad64233b539c71a27e2a6e324001143ef0
("brcm80211: make mgmt_tx in brcmfmac accept a NULL channel")

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 8bd256b..d316d62 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -3985,8 +3985,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 		       le16_to_cpu(action_frame->len));
 
 		brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
-			  *cookie, le16_to_cpu(action_frame->len),
-			  chan->center_freq);
+			  *cookie, le16_to_cpu(action_frame->len), freq);
 
 		ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
 						  af_params);
-- 
1.8.1.5


^ permalink raw reply related

* Re: brcm80211: make mgmt_tx in brcmfmac accept a NULL channel
From: Antonio Quartulli @ 2013-06-19 11:27 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: linux-wireless@vger.kernel.org, brcm80211-dev-list@broadcom.com
In-Reply-To: <20130619111620.GA969@elgon.mountain>

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

Hello Dan,

On Wed, Jun 19, 2013 at 04:16:27AM -0700, Dan Carpenter wrote:
> Hello Antonio Quartulli,
> 
> This is a semi-automatic email about new static checker warnings.
> 
> The patch c2ff8cad6423: "brcm80211: make mgmt_tx in brcmfmac accept a
> NULL channel" from Jun 11, 2013, leads to the following Smatch
> complaint:
> 
> drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c:4052 brcmf_cfg80211_mgmt_tx()
> 	 error: we previously assumed 'chan' could be null (see line 4041)
> 
> drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
>   4040			 */
>   4041			if (chan)
>                             ^^^^
> New check reflects that "chan" can now be NULL.
> 
>   4042				freq = chan->center_freq;
>   4043			else
>   4044				brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
>   4045						      &freq);
>   4046			chan_nr = ieee80211_frequency_to_channel(freq);
>   4047			af_params->channel = cpu_to_le32(chan_nr);
>   4048	
>   4049			memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
>   4050			       le16_to_cpu(action_frame->len));
>   4051	
>   4052			brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
>   4053				  *cookie, le16_to_cpu(action_frame->len),
>   4054				  chan->center_freq);
>                                   ^^^^^^
> This needs to be updated as well.
> 

Thank you very much for spotting this. I'm going to send a patch fixing it.
(however the line numbers were shifted..)

Regards,

-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* re: brcm80211: make mgmt_tx in brcmfmac accept a NULL channel
From: Dan Carpenter @ 2013-06-19 11:16 UTC (permalink / raw)
  To: antonio; +Cc: linux-wireless, brcm80211-dev-list

Hello Antonio Quartulli,

This is a semi-automatic email about new static checker warnings.

The patch c2ff8cad6423: "brcm80211: make mgmt_tx in brcmfmac accept a
NULL channel" from Jun 11, 2013, leads to the following Smatch
complaint:

drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c:4052 brcmf_cfg80211_mgmt_tx()
	 error: we previously assumed 'chan' could be null (see line 4041)

drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
  4040			 */
  4041			if (chan)
                            ^^^^
New check reflects that "chan" can now be NULL.

  4042				freq = chan->center_freq;
  4043			else
  4044				brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
  4045						      &freq);
  4046			chan_nr = ieee80211_frequency_to_channel(freq);
  4047			af_params->channel = cpu_to_le32(chan_nr);
  4048	
  4049			memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
  4050			       le16_to_cpu(action_frame->len));
  4051	
  4052			brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
  4053				  *cookie, le16_to_cpu(action_frame->len),
  4054				  chan->center_freq);
                                  ^^^^^^
This needs to be updated as well.

regards,
dan carpenter

^ permalink raw reply

* Re: [PATCH 2/6] mac80211:  Fix bss ref leak.
From: Johannes Berg @ 2013-06-19 10:51 UTC (permalink / raw)
  To: greearb; +Cc: linux-wireless
In-Reply-To: <1371638988.8349.11.camel@jlt4.sipsolutions.net>

On Wed, 2013-06-19 at 12:49 +0200, Johannes Berg wrote:
> I think we should do this differently and have mac80211 pass the BSS
> entry back to cfg80211_connect_result. That way, we can also hold it to
> make sure it doesn't expire while we're trying to connect, which is
> another corner case here ...

Oh, actually, mac80211 doesn't have this issue but all the other drivers
do.

johannes


^ permalink raw reply

* Re: [PATCH 2/6] mac80211:  Fix bss ref leak.
From: Johannes Berg @ 2013-06-19 10:49 UTC (permalink / raw)
  To: greearb; +Cc: linux-wireless
In-Reply-To: <1371593017-10985-2-git-send-email-greearb@candelatech.com>

I think we should do this differently and have mac80211 pass the BSS
entry back to cfg80211_connect_result. That way, we can also hold it to
make sure it doesn't expire while we're trying to connect, which is
another corner case here ...

I'll take a look at this, but that'll be in mac80211-next.

johannes


^ permalink raw reply

* Re: [PATCH 1/6] wireless:  Add memory usage debugging.
From: Johannes Berg @ 2013-06-19  9:49 UTC (permalink / raw)
  To: greearb; +Cc: linux-wireless
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

On Tue, 2013-06-18 at 15:03 -0700, greearb@candelatech.com wrote:
> From: Ben Greear <greearb@candelatech.com>
> 
> The bss objects are reference counted, and the ies
> are also tricky to keep track of.  Add option to
> track allocation and freeing of the ies and bss objects,
> and add debugfs files to show the current objects.

I'm not really sure this is worth it -- you found the bug with
kmemleak() after all. Having very specific things for all of this
doesn't really seem worth it.

Either way though, I can't apply the patches since they won't apply. I
realize that you're working on 3.9, but you're going to have to send me
patches I can apply to one of my trees (and right now, not really
mac80211 but mac80211-next)

johannes


^ permalink raw reply

* mac80211: impact of netif_carrier_off during roaming
From: Mark Fitzjohn @ 2013-06-19  9:28 UTC (permalink / raw)
  To: linux-wireless

Hi

I've noticed that during roaming triggered by detection of a significantly
better AP in wpa_supplicant that mac80211 calls netif_carrier_off and then
netif_carrier_on when associated with the new AP.

Does this have any detrimental impact on applications using the wifi
connection or is the assumption that as long as the roam happens in a
reasonable time then applications should tolerate it?

Just wondering if signalling the netif_carrier_off only when the current AP
is lost and there is no immediate alternative AP for the network available
was considered?

Thanks
Mark



^ permalink raw reply

* [PATCH] nl80211: use small state buffer for wiphy_dump
From: Johannes Berg @ 2013-06-19  9:00 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Avoid parsing the original dump message again and again by
allocating a small state struct that is used by the functions
involved in the dump, storing this struct in cb->args[0].
This reduces the memory allocation size as well.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/wireless/nl80211.c | 210 +++++++++++++++++++++++++++----------------------
 1 file changed, 116 insertions(+), 94 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f8ffb9a..7dc3343 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1111,10 +1111,16 @@ nl80211_send_mgmt_stypes(struct sk_buff *msg,
 	return 0;
 }
 
+struct nl80211_dump_wiphy_state {
+	s64 filter_wiphy;
+	long start;
+	long split_start, band_start, chan_start;
+	bool split;
+};
+
 static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 			      struct sk_buff *msg, u32 portid, u32 seq,
-			      int flags, bool split, long *split_start,
-			      long *band_start, long *chan_start)
+			      int flags, struct nl80211_dump_wiphy_state *state)
 {
 	void *hdr;
 	struct nlattr *nl_bands, *nl_band;
@@ -1125,19 +1131,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 	int i;
 	const struct ieee80211_txrx_stypes *mgmt_stypes =
 				dev->wiphy.mgmt_stypes;
-	long start = 0, start_chan = 0, start_band = 0;
 	u32 features;
 
 	hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
 	if (!hdr)
 		return -ENOBUFS;
 
-	/* allow always using the variables */
-	if (!split) {
-		split_start = &start;
-		band_start = &start_band;
-		chan_start = &start_chan;
-	}
+	if (WARN_ON(!state))
+		return -EINVAL;
 
 	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
 	    nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
@@ -1146,7 +1147,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 			cfg80211_rdev_list_generation))
 		goto nla_put_failure;
 
-	switch (*split_start) {
+	switch (state->split_start) {
 	case 0:
 		if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
 			       dev->wiphy.retry_short) ||
@@ -1192,8 +1193,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 		    nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
 			goto nla_put_failure;
 
-		(*split_start)++;
-		if (split)
+		state->split_start++;
+		if (state->split)
 			break;
 	case 1:
 		if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
@@ -1237,22 +1238,23 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 			}
 		}
 
-		(*split_start)++;
-		if (split)
+		state->split_start++;
+		if (state->split)
 			break;
 	case 2:
 		if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
 					dev->wiphy.interface_modes))
 				goto nla_put_failure;
-		(*split_start)++;
-		if (split)
+		state->split_start++;
+		if (state->split)
 			break;
 	case 3:
 		nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
 		if (!nl_bands)
 			goto nla_put_failure;
 
-		for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) {
+		for (band = state->band_start;
+		     band < IEEE80211_NUM_BANDS; band++) {
 			struct ieee80211_supported_band *sband;
 
 			sband = dev->wiphy.bands[band];
@@ -1264,12 +1266,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 			if (!nl_band)
 				goto nla_put_failure;
 
-			switch (*chan_start) {
+			switch (state->chan_start) {
 			case 0:
 				if (nl80211_send_band_rateinfo(msg, sband))
 					goto nla_put_failure;
-				(*chan_start)++;
-				if (split)
+				state->chan_start++;
+				if (state->split)
 					break;
 			default:
 				/* add frequencies */
@@ -1278,7 +1280,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 				if (!nl_freqs)
 					goto nla_put_failure;
 
-				for (i = *chan_start - 1;
+				for (i = state->chan_start - 1;
 				     i < sband->n_channels;
 				     i++) {
 					nl_freq = nla_nest_start(msg, i);
@@ -1287,26 +1289,27 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 
 					chan = &sband->channels[i];
 
-					if (nl80211_msg_put_channel(msg, chan,
-								    split))
+					if (nl80211_msg_put_channel(
+							msg, chan,
+							state->split))
 						goto nla_put_failure;
 
 					nla_nest_end(msg, nl_freq);
-					if (split)
+					if (state->split)
 						break;
 				}
 				if (i < sband->n_channels)
-					*chan_start = i + 2;
+					state->chan_start = i + 2;
 				else
-					*chan_start = 0;
+					state->chan_start = 0;
 				nla_nest_end(msg, nl_freqs);
 			}
 
 			nla_nest_end(msg, nl_band);
 
-			if (split) {
+			if (state->split) {
 				/* start again here */
-				if (*chan_start)
+				if (state->chan_start)
 					band--;
 				break;
 			}
@@ -1314,14 +1317,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 		nla_nest_end(msg, nl_bands);
 
 		if (band < IEEE80211_NUM_BANDS)
-			*band_start = band + 1;
+			state->band_start = band + 1;
 		else
-			*band_start = 0;
+			state->band_start = 0;
 
 		/* if bands & channels are done, continue outside */
-		if (*band_start == 0 && *chan_start == 0)
-			(*split_start)++;
-		if (split)
+		if (state->band_start == 0 && state->chan_start == 0)
+			state->split_start++;
+		if (state->split)
 			break;
 	case 4:
 		nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
@@ -1387,7 +1390,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 		}
 		CMD(start_p2p_device, START_P2P_DEVICE);
 		CMD(set_mcast_rate, SET_MCAST_RATE);
-		if (split) {
+		if (state->split) {
 			CMD(crit_proto_start, CRIT_PROTOCOL_START);
 			CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
 		}
@@ -1411,8 +1414,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 		}
 
 		nla_nest_end(msg, nl_cmds);
-		(*split_start)++;
-		if (split)
+		state->split_start++;
+		if (state->split)
 			break;
 	case 5:
 		if (dev->ops->remain_on_channel &&
@@ -1428,29 +1431,30 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 
 		if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
 			goto nla_put_failure;
-		(*split_start)++;
-		if (split)
+		state->split_start++;
+		if (state->split)
 			break;
 	case 6:
 #ifdef CONFIG_PM
-		if (nl80211_send_wowlan(msg, dev, split))
+		if (nl80211_send_wowlan(msg, dev, state->split))
 			goto nla_put_failure;
-		(*split_start)++;
-		if (split)
+		state->split_start++;
+		if (state->split)
 			break;
 #else
-		(*split_start)++;
+		state->split_start++;
 #endif
 	case 7:
 		if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
 					dev->wiphy.software_iftypes))
 			goto nla_put_failure;
 
-		if (nl80211_put_iface_combinations(&dev->wiphy, msg, split))
+		if (nl80211_put_iface_combinations(&dev->wiphy, msg,
+						   state->split))
 			goto nla_put_failure;
 
-		(*split_start)++;
-		if (split)
+		state->split_start++;
+		if (state->split)
 			break;
 	case 8:
 		if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
@@ -1464,7 +1468,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 		 * dump is split, otherwise it makes it too big. Therefore
 		 * only advertise it in that case.
 		 */
-		if (split)
+		if (state->split)
 			features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
 		if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
 			goto nla_put_failure;
@@ -1491,7 +1495,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 		 * case we'll continue with more data in the next round,
 		 * but break unconditionally so unsplit data stops here.
 		 */
-		(*split_start)++;
+		state->split_start++;
 		break;
 	case 9:
 		if (dev->wiphy.extended_capabilities &&
@@ -1510,7 +1514,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 			goto nla_put_failure;
 
 		/* done */
-		*split_start = 0;
+		state->split_start = 0;
 		break;
 	}
 	return genlmsg_end(msg, hdr);
@@ -1520,66 +1524,76 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
 	return -EMSGSIZE;
 }
 
+static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
+				    struct netlink_callback *cb,
+				    struct nl80211_dump_wiphy_state *state)
+{
+	struct nlattr **tb = nl80211_fam.attrbuf;
+	int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+			      tb, nl80211_fam.maxattr, nl80211_policy);
+	/* ignore parse errors for backward compatibility */
+	if (ret)
+		return 0;
+
+	state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
+	if (tb[NL80211_ATTR_WIPHY])
+		state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+	if (tb[NL80211_ATTR_WDEV])
+		state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
+	if (tb[NL80211_ATTR_IFINDEX]) {
+		struct net_device *netdev;
+		struct cfg80211_registered_device *rdev;
+		int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+		netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
+		if (!netdev)
+			return -ENODEV;
+		if (netdev->ieee80211_ptr) {
+			rdev = wiphy_to_dev(
+				netdev->ieee80211_ptr->wiphy);
+			state->filter_wiphy = rdev->wiphy_idx;
+		}
+		dev_put(netdev);
+	}
+
+	return 0;
+}
+
 static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int idx = 0, ret;
-	int start = cb->args[0];
+	struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
 	struct cfg80211_registered_device *dev;
-	s64 filter_wiphy = -1;
-	bool split = false;
-	struct nlattr **tb;
-	int res;
-
-	/* will be zeroed in nlmsg_parse() */
-	tb = kmalloc(sizeof(*tb) * (NL80211_ATTR_MAX + 1), GFP_KERNEL);
-	if (!tb)
-		return -ENOMEM;
 
 	rtnl_lock();
-	res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
-			  tb, NL80211_ATTR_MAX, nl80211_policy);
-	if (res == 0) {
-		split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
-		if (tb[NL80211_ATTR_WIPHY])
-			filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
-		if (tb[NL80211_ATTR_WDEV])
-			filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
-		if (tb[NL80211_ATTR_IFINDEX]) {
-			struct net_device *netdev;
-			int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-
-			netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
-			if (!netdev) {
-				rtnl_unlock();
-				kfree(tb);
-				return -ENODEV;
-			}
-			if (netdev->ieee80211_ptr) {
-				dev = wiphy_to_dev(
-					netdev->ieee80211_ptr->wiphy);
-				filter_wiphy = dev->wiphy_idx;
-			}
-			dev_put(netdev);
+	if (!state) {
+		state = kzalloc(sizeof(*state), GFP_KERNEL);
+		if (!state)
+			return -ENOMEM;
+		state->filter_wiphy = -1;
+		ret = nl80211_dump_wiphy_parse(skb, cb, state);
+		if (ret) {
+			kfree(state);
+			rtnl_unlock();
+			return ret;
 		}
+		cb->args[0] = (long)state;
 	}
-	kfree(tb);
 
 	list_for_each_entry(dev, &cfg80211_rdev_list, list) {
 		if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
 			continue;
-		if (++idx <= start)
+		if (++idx <= state->start)
 			continue;
-		if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy)
+		if (state->filter_wiphy != -1 &&
+		    state->filter_wiphy != dev->wiphy_idx)
 			continue;
 		/* attempt to fit multiple wiphy data chunks into the skb */
 		do {
 			ret = nl80211_send_wiphy(dev, skb,
 						 NETLINK_CB(cb->skb).portid,
 						 cb->nlh->nlmsg_seq,
-						 NLM_F_MULTI,
-						 split, &cb->args[1],
-						 &cb->args[2],
-						 &cb->args[3]);
+						 NLM_F_MULTI, state);
 			if (ret < 0) {
 				/*
 				 * If sending the wiphy data didn't fit (ENOBUFS
@@ -1604,27 +1618,34 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 				idx--;
 				break;
 			}
-		} while (cb->args[1] > 0);
+		} while (state->split_start > 0);
 		break;
 	}
 	rtnl_unlock();
 
-	cb->args[0] = idx;
+	state->start = idx;
 
 	return skb->len;
 }
 
+static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
+{
+	kfree((void *)cb->args[0]);
+	return 0;
+}
+
 static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
 	struct sk_buff *msg;
 	struct cfg80211_registered_device *dev = info->user_ptr[0];
+	struct nl80211_dump_wiphy_state state = {};
 
 	msg = nlmsg_new(4096, GFP_KERNEL);
 	if (!msg)
 		return -ENOMEM;
 
 	if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0,
-			       false, NULL, NULL, NULL) < 0) {
+			       &state) < 0) {
 		nlmsg_free(msg);
 		return -ENOBUFS;
 	}
@@ -8418,6 +8439,7 @@ static struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_GET_WIPHY,
 		.doit = nl80211_get_wiphy,
 		.dumpit = nl80211_dump_wiphy,
+		.done = nl80211_dump_wiphy_done,
 		.policy = nl80211_policy,
 		/* can be retrieved by unprivileged users */
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
@@ -9038,13 +9060,13 @@ static struct genl_multicast_group nl80211_regulatory_mcgrp = {
 void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
 {
 	struct sk_buff *msg;
+	struct nl80211_dump_wiphy_state state = {};
 
 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 	if (!msg)
 		return;
 
-	if (nl80211_send_wiphy(rdev, msg, 0, 0, 0,
-			       false, NULL, NULL, NULL) < 0) {
+	if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, &state) < 0) {
 		nlmsg_free(msg);
 		return;
 	}
-- 
1.8.0


^ permalink raw reply related

* Re: [PATCH] nl80211: fix attrbuf access race by allocating a separate one
From: David Miller @ 2013-06-19  8:39 UTC (permalink / raw)
  To: johannes; +Cc: torvalds, linville, linux-wireless, netdev
In-Reply-To: <1371630238.8349.6.camel@jlt4.sipsolutions.net>

From: Johannes Berg <johannes@sipsolutions.net>
Date: Wed, 19 Jun 2013 10:23:58 +0200

> From: Johannes Berg <johannes.berg@intel.com>
> 
> Since my commit 3713b4e364, nl80211_dump_wiphy() uses the global
> nl80211_fam.attrbuf for parsing the incoming data. This wouldn't
> be a problem if it only did so on the first dump iteration which
> is locked against other commands in generic netlink, but due to
> space constraints in cb->args (the needed state doesn't fit) I
> decided to always parse the original message. That's racy though
> since nl80211_fam.attrbuf could be used by some other parsing in
> generic netlink concurrently.
> 
> For now, fix this by allocating a separate parse buffer (it's a
> bit too big for the stack, currently 1448 bytes on 64-bit). For
> -next, I'll change the code to parse into the global buffer in
> the first round only and then allocate a smaller buffer to keep
> the state in cb->args.
> 
> Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* [PATCH] nl80211: fix attrbuf access race by allocating a separate one
From: Johannes Berg @ 2013-06-19  8:23 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: David Miller, John Linville, Linux Wireless List,
	Network Development
In-Reply-To: <1371628488.8349.3.camel@jlt4.sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

Since my commit 3713b4e364, nl80211_dump_wiphy() uses the global
nl80211_fam.attrbuf for parsing the incoming data. This wouldn't
be a problem if it only did so on the first dump iteration which
is locked against other commands in generic netlink, but due to
space constraints in cb->args (the needed state doesn't fit) I
decided to always parse the original message. That's racy though
since nl80211_fam.attrbuf could be used by some other parsing in
generic netlink concurrently.

For now, fix this by allocating a separate parse buffer (it's a
bit too big for the stack, currently 1448 bytes on 64-bit). For
-next, I'll change the code to parse into the global buffer in
the first round only and then allocate a smaller buffer to keep
the state in cb->args.

Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
Let me know if you want to apply this directly, otherwise I'll send it
on its way to John.

 net/wireless/nl80211.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d5aed3b..b14b7e3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1564,12 +1564,17 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 	struct cfg80211_registered_device *dev;
 	s64 filter_wiphy = -1;
 	bool split = false;
-	struct nlattr **tb = nl80211_fam.attrbuf;
+	struct nlattr **tb;
 	int res;
 
+	/* will be zeroed in nlmsg_parse() */
+	tb = kmalloc(sizeof(*tb) * (NL80211_ATTR_MAX + 1), GFP_KERNEL);
+	if (!tb)
+		return -ENOMEM;
+
 	mutex_lock(&cfg80211_mutex);
 	res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
-			  tb, nl80211_fam.maxattr, nl80211_policy);
+			  tb, NL80211_ATTR_MAX, nl80211_policy);
 	if (res == 0) {
 		split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
 		if (tb[NL80211_ATTR_WIPHY])
@@ -1583,6 +1588,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 			netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
 			if (!netdev) {
 				mutex_unlock(&cfg80211_mutex);
+				kfree(tb);
 				return -ENODEV;
 			}
 			if (netdev->ieee80211_ptr) {
@@ -1593,6 +1599,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 			dev_put(netdev);
 		}
 	}
+	kfree(tb);
 
 	list_for_each_entry(dev, &cfg80211_rdev_list, list) {
 		if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
-- 
1.8.0




^ permalink raw reply related

* Re: nl80211 NULL pointer dereference
From: Johannes Berg @ 2013-06-19  7:54 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: David Miller, John Linville, Linux Wireless List,
	Network Development
In-Reply-To: <CA+55aFz=eG5-zh1toHxrx=4Qm4DvwyiBCU3u-6tc0-utfZ6xiA@mail.gmail.com>

On Tue, 2013-06-18 at 16:24 -1000, Linus Torvalds wrote:

> So it would seem that it's that
> 
>     info->attrs[NL80211_ATTR_REG_RULES]
> 
> thing that is NULL.
> 
> And yes, the code checks that for being non-NULL in at the top of the
> function, but maybe there is a race with something else setting it to
> NULL? There is a kzalloc(GFP_KERNEL) in between, so it doesn't even
> have to be a very small race...

Yes. I looked at it, and reproduced it (after making the window larger
by putting some sleeps in there and WARN_ON()). It's really just a
stupid mistake I made: in nl80211_dump_wiphy() I parse attributes into
the global nl80211_fam.attrbuf, without making sure that it has proper
locking. Normally we do something like that only on the first iteration
of a dump which is OK because it's locked, but here I did it always,
which is clearly a bug.

I'll have a patch in a minute.

johannes




^ permalink raw reply

* Re: nl80211 NULL pointer dereference
From: David Miller @ 2013-06-19  7:47 UTC (permalink / raw)
  To: torvalds; +Cc: johannes, linville, linux-wireless, netdev
In-Reply-To: <CA+55aFz=eG5-zh1toHxrx=4Qm4DvwyiBCU3u-6tc0-utfZ6xiA@mail.gmail.com>

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue, 18 Jun 2013 16:24:57 -1000

> And yes, the code checks that for being non-NULL in at the top of the
> function, but maybe there is a race with something else setting it to
> NULL? There is a kzalloc(GFP_KERNEL) in between, so it doesn't even
> have to be a very small race...

The nl80211 code uses a flag for each netlink command to determine
whether the RTNL mutex should be held across the operation.

This is handled in the pre_doit and post_doit methods implemented
in nl80211.c.

And this operation, in fact, just so happens to be one that doesn't
have the "take the RTNL mutex" flag set.

But for internal consistency of the netlink message itself, the RTNL
mutex should not matter.  It's in a private SKB buffer which is in use
only by the ->doit() method.


^ permalink raw reply

* Re: [PATCH] brcmfmac: Turn off ARP offloading when configured for AP.
From: Arend van Spriel @ 2013-06-19  7:27 UTC (permalink / raw)
  To: Greg KH; +Cc: stable, linux-wireless, Hante Meuleman, John W. Linville
In-Reply-To: <1370508957-12709-1-git-send-email-arend@broadcom.com>

On 06/06/2013 10:55 AM, Arend van Spriel wrote:
> From: Hante Meuleman <meuleman@broadcom.com>

Hi Greg,

I noticed your review announcement for v3.9.7 and did not see the change 
below. I sent it to stable because the original upstream commit did not 
apply. Did I miss some step in the process?

Regards,
Arend

> [backport of upstream commit b3657453f16a7b84eab9b93bb9a9a2901ffc70af]
>
> ARP offloading should only be used in STA or P2P client mode. It
> is currently configured once at init. When being configured for AP
> ARP offloading should be turned off and when AP mode is left it can
> be turned back on.
>
> Reviewed-by: Arend Van Spriel <arend@broadcom.com>
> Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> Signed-off-by: John W. Linville <linville@tuxdriver.com>
> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> ---
>   .../net/wireless/brcm80211/brcmfmac/dhd_common.c   |   18 ---------
>   .../net/wireless/brcm80211/brcmfmac/fwil_types.h   |    6 +++
>   .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c  |   40 +++++++++++++++++++-
>   3 files changed, 45 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
> index 4544342..9480e19 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
> @@ -26,7 +26,6 @@
>   #include "fwil.h"
>
>   #define PKTFILTER_BUF_SIZE		128
> -#define BRCMF_ARPOL_MODE		0xb	/* agent|snoop|peer_autoreply */
>   #define BRCMF_DEFAULT_BCN_TIMEOUT	3
>   #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME	40
>   #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME	40
> @@ -337,23 +336,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
>   		goto done;
>   	}
>
> -	/* Try to set and enable ARP offload feature, this may fail */
> -	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE);
> -	if (err) {
> -		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
> -			  BRCMF_ARPOL_MODE, err);
> -		err = 0;
> -	} else {
> -		err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1);
> -		if (err) {
> -			brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n",
> -				  err);
> -			err = 0;
> -		} else
> -			brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n",
> -				  BRCMF_ARPOL_MODE);
> -	}
> -
>   	/* Setup packet filter */
>   	brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
>   	brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
> index 0f2c83b..665ef69 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
> @@ -23,6 +23,12 @@
>
>   #define BRCMF_FIL_ACTION_FRAME_SIZE	1800
>
> +/* ARP Offload feature flags for arp_ol iovar */
> +#define BRCMF_ARP_OL_AGENT		0x00000001
> +#define BRCMF_ARP_OL_SNOOP		0x00000002
> +#define BRCMF_ARP_OL_HOST_AUTO_REPLY	0x00000004
> +#define BRCMF_ARP_OL_PEER_AUTO_REPLY	0x00000008
> +
>
>   enum brcmf_fil_p2p_if_types {
>   	BRCMF_FIL_P2P_IF_CLIENT,
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
> index 78da3ef..d5c4e24 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
> @@ -505,6 +505,38 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
>   	return err;
>   }
>
> +static s32
> +brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
> +{
> +	s32 err;
> +	u32 mode;
> +
> +	if (enable)
> +		mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
> +	else
> +		mode = 0;
> +
> +	/* Try to set and enable ARP offload feature, this may fail, then it  */
> +	/* is simply not supported and err 0 will be returned                 */
> +	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
> +	if (err) {
> +		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
> +			  mode, err);
> +		err = 0;
> +	} else {
> +		err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
> +		if (err) {
> +			brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
> +				  enable, err);
> +			err = 0;
> +		} else
> +			brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
> +				  enable, mode);
> +	}
> +
> +	return err;
> +}
> +
>   static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
>   						     const char *name,
>   						     enum nl80211_iftype type,
> @@ -3709,6 +3741,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
>   	}
>
>   	brcmf_set_mpc(ndev, 0);
> +	brcmf_configure_arp_offload(ifp, false);
>
>   	/* find the RSN_IE */
>   	rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
> @@ -3815,8 +3848,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
>   	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
>
>   exit:
> -	if (err)
> +	if (err) {
>   		brcmf_set_mpc(ndev, 1);
> +		brcmf_configure_arp_offload(ifp, true);
> +	}
>   	return err;
>   }
>
> @@ -3857,6 +3892,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
>   			brcmf_err("bss_enable config failed %d\n", err);
>   	}
>   	brcmf_set_mpc(ndev, 1);
> +	brcmf_configure_arp_offload(ifp, true);
>   	set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
>   	clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
>
> @@ -4995,6 +5031,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
>   	if (err)
>   		goto default_conf_out;
>
> +	brcmf_configure_arp_offload(ifp, true);
> +
>   	cfg->dongle_up = true;
>   default_conf_out:
>
>



^ permalink raw reply

* Re: [PATCH 6/6] wireless: Add comments about bss refcounting.
From: Julian Calaby @ 2013-06-19  2:51 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-wireless
In-Reply-To: <1371593017-10985-6-git-send-email-greearb@candelatech.com>

Hi Ben,

On Wed, Jun 19, 2013 at 8:03 AM,  <greearb@candelatech.com> wrote:
> From: Ben Greear <greearb@candelatech.com>
>
> Should help the next person that tries to understand
> the bss refcounting logic.
>
> Signed-off-by: Ben Greear <greearb@candelatech.com>
> ---
>  net/wireless/scan.c |    4 ++++
>  net/wireless/sme.c  |    3 +++
>  2 files changed, 7 insertions(+), 0 deletions(-)
>
> diff --git a/net/wireless/scan.c b/net/wireless/scan.c
> index 542ff6d..834d2f9 100644
> --- a/net/wireless/scan.c
> +++ b/net/wireless/scan.c
> @@ -622,6 +622,7 @@ static int cmp_bss(struct cfg80211_bss *a,
>         }
>  }
>
> +/** Returned bss is reference counted and must be cleaned up appropriately. */

/** is for kernel doc, I'm not sure that is valid kernel doc.

Thanks,

--
Julian Calaby

Email: julian.calaby@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/

^ permalink raw reply

* Re: nl80211 NULL pointer dereference
From: Linus Torvalds @ 2013-06-19  2:24 UTC (permalink / raw)
  To: David Miller
  Cc: Johannes Berg, John Linville, Linux Wireless List,
	Network Development
In-Reply-To: <20130618.190632.33329016434510583.davem@davemloft.net>

On Tue, Jun 18, 2013 at 4:06 PM, David Miller <davem@davemloft.net> wrote:
>
> nl80211_set_reg() is really careful about validating which netlink
> attributes the user has specified, and either not dereferencing or
> signalling an error when NULL is seen.
>
> Hmmm...

The code disassembles to

   0: 41 0f b6 46 04       movzbl 0x4(%r14),%eax
   5: 0f b6 fb             movzbl %bl,%edi
   8: 41 88 45 14           mov    %al,0x14(%r13)
   c: 41 0f b6 46 05       movzbl 0x5(%r14),%eax
  11: 41 88 45 15           mov    %al,0x15(%r13)
  15: e8 8c c5 fe ff       callq  0xfffffffffffec5a6
  1a: 84 c0                 test   %al,%al
  1c: 75 68                 jne    0x86
  1e: 49 8b 47 20           mov    0x20(%r15),%rax
  22: 4c 8b a0 10 01 00 00 mov    0x110(%rax),%r12
  29:* 45 0f b7 34 24       movzwl (%r12),%r14d <-- trapping instruction
  2e: 41 83 ee 04           sub    $0x4,%r14d
  32: 41 83 fe 03           cmp    $0x3,%r14d
  36: 7e 0e                 jle    0x46
  38: 41 0f b7 44 24 04     movzwl 0x4(%r12),%eax

(I deleted the two first bytes. they were part of an incomplete
preceding instruction). The "call/test/jne" seems to be this paert:

        /*
         * Disable DFS master mode if the DFS region was
         * not supported or known on this kernel.
         */
        if (reg_supported_dfs_region(dfs_region))
                rd->dfs_region = dfs_region;

and then the two moves into %rax an %r12 seem to be setting up for

        nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],

and then the movzwl (that traps) and the subsequent subtract seems to
be the inlined nla_len(nla), which is the "len" to the
nla_for_each_nested() -> nla_for_each_attr() macro expansion.

So it would seem that it's that

    info->attrs[NL80211_ATTR_REG_RULES]

thing that is NULL.

And yes, the code checks that for being non-NULL in at the top of the
function, but maybe there is a race with something else setting it to
NULL? There is a kzalloc(GFP_KERNEL) in between, so it doesn't even
have to be a very small race...

Hmm? I really don't know this code at all, so I'm just looking at the
source and lining up the oops...

                    Linus

^ permalink raw reply

* Re: nl80211 NULL pointer dereference
From: David Miller @ 2013-06-19  2:06 UTC (permalink / raw)
  To: torvalds; +Cc: johannes, linville, linux-wireless, netdev
In-Reply-To: <CA+55aFxOde8n0M2=77-TQ2Ea9iz8s-e8zGFwjj6RVyMFXBgxEA@mail.gmail.com>

From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Tue, 18 Jun 2013 15:46:13 -1000

> Hmm. Maybe this is old, but I don't think I've seen it before (who
> knows, maybe it has killed the machine before, I had a hard hang the
> other day).
> 
> It's a NULL pointer dereference in nl80211_set_reg() on my Pixel. The
> machine kind of stayed up afterwards, although with no working
> wireless, and it would not shut down cleanly presumably due to locks
> held etc.
> 
> Any ideas? I'm including the few wireless-related messages that
> happened justr before the oops. Being a pixel, this is with the ath9k
> driver.

nl80211_set_reg() is really careful about validating which netlink
attributes the user has specified, and either not dereferencing or
signalling an error when NULL is seen.

Hmmm...

^ permalink raw reply

* nl80211 NULL pointer dereference
From: Linus Torvalds @ 2013-06-19  1:46 UTC (permalink / raw)
  To: Johannes Berg, John W. Linville, David S. Miller
  Cc: Linux Wireless List, Network Development

Hmm. Maybe this is old, but I don't think I've seen it before (who
knows, maybe it has killed the machine before, I had a hard hang the
other day).

It's a NULL pointer dereference in nl80211_set_reg() on my Pixel. The
machine kind of stayed up afterwards, although with no working
wireless, and it would not shut down cleanly presumably due to locks
held etc.

Any ideas? I'm including the few wireless-related messages that
happened justr before the oops. Being a pixel, this is with the ath9k
driver.

                     Linus

---
  wlp1s0: authenticate with 00:c0:23:ba:27:40
  wlp1s0: send auth to 00:c0:23:ba:27:40 (try 1/3)
  wlp1s0: authenticated
  ath9k 0000:01:00.0 wlp1s0: disabling HT as WMM/QoS is not supported by the AP
  ath9k 0000:01:00.0 wlp1s0: disabling VHT as WMM/QoS is not supported by the AP
  wlp1s0: associate with 00:c0:23:ba:27:40 (try 1/3)
  wlp1s0: RX AssocResp from 00:c0:23:ba:27:40 (capab=0x501 status=0 aid=4)
  wlp1s0: associated
  cfg80211: Calling CRDA for country: US

  BUG: unable to handle kernel NULL pointer dereference at           (null)
  IP: [<ffffffffa02a77d3>] nl80211_set_reg+0x113/0x2c0 [cfg80211]
  PGD 1459c3067 PUD 10f6fa067 PMD 0
  Oops: 0000 [#1] SMP
  Modules linked in: ftdi_sio tpm_tis tpm tpm_bios usb_storage fuse
ebtable_nat nf_conntrack_netbios_ns nf_conntrack_broadcast
ipt_MASQUERADE ip6table_nat nf_nat_ipv6 ip6table_mangle ip6t_REJECT
nf_conntra
   media chromeos_laptop snd_timer snd microcode lpc_ich rfkill
soundcore mfd_core i2c_i801 uinput binfmt_misc dm_crypt i915
i2c_algo_bit drm_kms_helper drm crc32_pclmul crc32c_intel
ghash_clmulni_intel i2
  CPU: 1 PID: 4859 Comm: crda Not tainted 3.10.0-rc6 #2
  Hardware name: GOOGLE Link, BIOS          12/10/2012
  RIP: 0010:[<ffffffffa02a77d3>]  [<ffffffffa02a77d3>]
nl80211_set_reg+0x113/0x2c0 [cfg80211]
  RSP: 0018:ffff8801277779f0  EFLAGS: 00010202
  RAX: ffff8801456b0000 RBX: 0000000000000000 RCX: 0000000000000000
  RDX: 00000000000000c0 RSI: 0000000000000000 RDI: 0000000000000000
  RBP: ffff880127777a58 R08: 0000000000015d40 R09: ffff880141c8ecc0
  R10: ffffffffa02a779a R11: 0000000000000004 R12: 0000000000000000
  R13: ffff880141c8ecc0 R14: ffff88013af8d414 R15: ffff880127777a80
  FS:  00007f2c82fb5740(0000) GS:ffff88014f280000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 0000000000000000 CR3: 00000001459b2000 CR4: 00000000001407e0
  DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
  DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
  Call Trace:
   [<ffffffff81531b44>] genl_family_rcv_msg+0x1f4/0x2e0
   [<ffffffff81531cc1>] genl_rcv_msg+0x91/0xd0
   [<ffffffff81531339>] netlink_rcv_skb+0xa9/0xc0
   [<ffffffff81531758>] genl_rcv+0x28/0x40
   [<ffffffff81530d62>] netlink_unicast+0x142/0x1f0
   [<ffffffff815310ad>] netlink_sendmsg+0x29d/0x370
   [<ffffffff814f22e9>] sock_sendmsg+0x99/0xd0
   [<ffffffff814f270e>] ___sys_sendmsg+0x39e/0x3b0
   [<ffffffff814f34f2>] __sys_sendmsg+0x42/0x80
   [<ffffffff814f3542>] SyS_sendmsg+0x12/0x20
   [<ffffffff81615e42>] system_call_fastpath+0x16/0x1b
  Code: 60 10 41 0f b6 46 04 0f b6 fb 41 88 45 14 41 0f b6 46 05 41 88
45 15 e8 8c c5 fe ff 84 c0 75 68 49 8b 47 20 4c 8b a0 10 01 00 00 <45>
0f b7 34 24 41 83 ee 04 41 83 fe 03 7e 0e 41 0f b7 44 24 04
  RIP  [<ffffffffa02a77d3>] nl80211_set_reg+0x113/0x2c0 [cfg80211]
   RSP <ffff8801277779f0>
  CR2: 0000000000000000

^ permalink raw reply

* Association status 5 from Netgear
From: Ben Greear @ 2013-06-19  0:28 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org

I'm seeing association status code 5 coming from an over-loaded
netgear.

I'm guessing that the AP is buggy and is trying to use a reason-code for
a status-code?

A reason-code of 5 would make sense here:
"Disassociated because AP is unable to handle all currently associated STAs"

(per 802.11-2012, pages 442, 445)

# grep sta325 /tmp/iwlog.txt
sta325 (phy #3): scan started
sta325: new station c4:3d:c7:af:3c:7c
sta325 (phy #3): scan finished: 5745, ""
sta325 (phy #3): auth c4:3d:c7:af:3c:7c -> 00:1d:ea:be:ef:7c status: 0: Successful
sta325: del station c4:3d:c7:af:3c:7c
sta325 (phy #3): assoc c4:3d:c7:af:3c:7c -> 00:1d:ea:be:ef:7c status: 5: <unknown>
sta325 (phy #3): failed to connect to c4:3d:c7:af:3c:7c, status: 5: <unknown>

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* [PATCH 1/3] mwifiex: code rearrangement for better readability
From: Bing Zhao @ 2013-06-18 23:36 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Amitkumar Karwar, Avinash Patil,
	Yogesh Ashok Powar, Nishant Sarmukadam, Frank Huang, Bing Zhao

From: Amitkumar Karwar <akarwar@marvell.com>

Use negative check (if(!bss_desc)) and return failure
instead of failing a NULL check later in
mwifiex_check_network_compatibility() routine.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
---
 drivers/net/wireless/mwifiex/sta_ioctl.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 23aa910..15b5457 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -255,25 +255,24 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 	}
 
 	if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+		u8 config_bands;
+
 		/* Infra mode */
 		ret = mwifiex_deauthenticate(priv, NULL);
 		if (ret)
 			goto done;
 
-		if (bss_desc) {
-			u8 config_bands = 0;
+		if (!bss_desc)
+			return -1;
 
-			if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band)
-			    == HostCmd_SCAN_RADIO_TYPE_BG)
-				config_bands = BAND_B | BAND_G | BAND_GN |
-					       BAND_GAC;
-			else
-				config_bands = BAND_A | BAND_AN | BAND_AAC;
+		if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
+						HostCmd_SCAN_RADIO_TYPE_BG)
+			config_bands = BAND_B | BAND_G | BAND_GN | BAND_GAC;
+		else
+			config_bands = BAND_A | BAND_AN | BAND_AAC;
 
-			if (!((config_bands | adapter->fw_bands) &
-			      ~adapter->fw_bands))
-				adapter->config_bands = config_bands;
-		}
+		if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
+			adapter->config_bands = config_bands;
 
 		ret = mwifiex_check_network_compatibility(priv, bss_desc);
 		if (ret)
-- 
1.8.2.3


^ permalink raw reply related

* [PATCH 3/3] mwifiex: channel switch handling for station
From: Bing Zhao @ 2013-06-18 23:36 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Amitkumar Karwar, Avinash Patil,
	Yogesh Ashok Powar, Nishant Sarmukadam, Frank Huang, Bing Zhao,
	Paul Stewart
In-Reply-To: <1371598618-26593-1-git-send-email-bzhao@marvell.com>

From: Amitkumar Karwar <akarwar@marvell.com>

After receiving channel switch announcement from AP, scan and
association on that channel is blocked for DFS_CHAN_MOVE_TIME
(10 seconds). Hence station will be able to connect to the AP,
once it is moved to new channel.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Paul Stewart <pstew@chromium.org>
---
 drivers/net/wireless/mwifiex/fw.h        |  2 ++
 drivers/net/wireless/mwifiex/init.c      |  3 +++
 drivers/net/wireless/mwifiex/main.h      | 20 ++++++++++++++++++++
 drivers/net/wireless/mwifiex/scan.c      | 18 ++++++++++++++++++
 drivers/net/wireless/mwifiex/sta_event.c |  3 +++
 drivers/net/wireless/mwifiex/sta_ioctl.c |  8 ++++++++
 6 files changed, 54 insertions(+)

diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index b6fbbf6..1b45aa5 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -245,6 +245,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HT_BW_20    0
 #define HT_BW_40    1
 
+#define DFS_CHAN_MOVE_TIME      10000
+
 #define HostCmd_CMD_GET_HW_SPEC                       0x0003
 #define HostCmd_CMD_802_11_SCAN                       0x0006
 #define HostCmd_CMD_802_11_GET_LOG                    0x000b
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 2fe31dc..caaf4bd 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -133,6 +133,9 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
 
 	priv->scan_block = false;
 
+	priv->csa_chan = 0;
+	priv->csa_expire_time = 0;
+
 	return mwifiex_add_bss_prio_tbl(priv);
 }
 
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 95a6f52..3da73d3 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -513,6 +513,8 @@ struct mwifiex_private {
 	u32 mgmt_frame_mask;
 	struct mwifiex_roc_cfg roc_cfg;
 	bool scan_aborting;
+	u8 csa_chan;
+	unsigned long csa_expire_time;
 };
 
 enum mwifiex_ba_status {
@@ -1021,6 +1023,24 @@ static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb)
 	return (*(u32 *)skb->data == PKT_TYPE_MGMT);
 }
 
+/* This function retrieves channel closed for operation by Channel
+ * Switch Announcement.
+ */
+static inline u8
+mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv)
+{
+	if (!priv->csa_chan)
+		return 0;
+
+	/* Clear csa channel, if DFS channel move time has passed */
+	if (jiffies > priv->csa_expire_time) {
+		priv->csa_chan = 0;
+		priv->csa_expire_time = 0;
+	}
+
+	return priv->csa_chan;
+}
+
 int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
 			     u32 func_init_shutdown);
 int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 284d68b..c447d9b 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -575,6 +575,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
 		return -1;
 	}
 
+	/* Check csa channel expiry before preparing scan list */
+	mwifiex_11h_get_csa_closed_channel(priv);
+
 	chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
 
 	/* Set the temp channel struct pointer to the start of the desired
@@ -604,6 +607,11 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
 		while (tlv_idx < max_chan_per_scan &&
 		       tmp_chan_list->chan_number && !done_early) {
 
+			if (tmp_chan_list->chan_number == priv->csa_chan) {
+				tmp_chan_list++;
+				continue;
+			}
+
 			dev_dbg(priv->adapter->dev,
 				"info: Scan: Chan(%3d), Radio(%d),"
 				" Mode(%d, %d), Dur(%d)\n",
@@ -1594,6 +1602,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 		goto check_next_scan;
 	}
 
+	/* Check csa channel expiry before parsing scan response */
+	mwifiex_11h_get_csa_closed_channel(priv);
+
 	bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
 	dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
 		bytes_left);
@@ -1746,6 +1757,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
 			struct ieee80211_channel *chan;
 			u8 band;
 
+			/* Skip entry if on csa closed channel */
+			if (channel == priv->csa_chan) {
+				dev_dbg(adapter->dev,
+					"Dropping entry on csa closed channel\n");
+				continue;
+			}
+
 			band = BAND_G;
 			if (chan_band_tlv) {
 				chan_band =
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 0f7b4cf..8155471 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -429,6 +429,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
 	case EVENT_CHANNEL_SWITCH_ANN:
 		dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+		priv->csa_expire_time =
+				jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME);
+		priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel;
 		ret = mwifiex_send_cmd_async(priv,
 			HostCmd_CMD_802_11_DEAUTHENTICATE,
 			HostCmd_ACT_GEN_SET, 0,
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 498add7..206c3e0 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -281,6 +281,14 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 		if (ret)
 			goto done;
 
+		if (mwifiex_11h_get_csa_closed_channel(priv) ==
+							(u8)bss_desc->channel) {
+			dev_err(adapter->dev,
+				"Attempt to reconnect on csa closed chan(%d)\n",
+				bss_desc->channel);
+			goto done;
+		}
+
 		dev_dbg(adapter->dev, "info: SSID found in scan list ... "
 				      "associating...\n");
 
-- 
1.8.2.3


^ permalink raw reply related

* [PATCH 2/3] mwifiex: add basic 11h support for station
From: Bing Zhao @ 2013-06-18 23:36 UTC (permalink / raw)
  To: linux-wireless
  Cc: John W. Linville, Amitkumar Karwar, Avinash Patil,
	Yogesh Ashok Powar, Nishant Sarmukadam, Frank Huang, Bing Zhao,
	Paul Stewart
In-Reply-To: <1371598618-26593-1-git-send-email-bzhao@marvell.com>

From: Amitkumar Karwar <akarwar@marvell.com>

This patch adds code to parse requested AP's 11h capabilities
and add 11h information in association request.

Also, deauth is sent to the AP after receiving channel switch
announcement event from firmware. This happens when AP advertises
WLAN_EID_CHANNEL_SWITCH IE in it's beacon.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: Paul Stewart <pstew@chromium.org>
---
 drivers/net/wireless/mwifiex/11h.c       | 101 +++++++++++++++++++++++++++++++
 drivers/net/wireless/mwifiex/Makefile    |   1 +
 drivers/net/wireless/mwifiex/fw.h        |  14 +++++
 drivers/net/wireless/mwifiex/join.c      |   2 +
 drivers/net/wireless/mwifiex/main.h      |   7 +++
 drivers/net/wireless/mwifiex/scan.c      |  19 ++++++
 drivers/net/wireless/mwifiex/sta_event.c |   7 +++
 drivers/net/wireless/mwifiex/sta_ioctl.c |   3 +
 8 files changed, 154 insertions(+)
 create mode 100644 drivers/net/wireless/mwifiex/11h.c

diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
new file mode 100644
index 0000000..8d68307
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -0,0 +1,101 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11h
+ *
+ * Copyright (C) 2013, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+#include "fw.h"
+
+
+/* This function appends 11h info to a buffer while joining an
+ * infrastructure BSS
+ */
+static void
+mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
+			       struct mwifiex_bssdescriptor *bss_desc)
+{
+	struct mwifiex_ie_types_header *ie_header;
+	struct mwifiex_ie_types_pwr_capability *cap;
+	struct mwifiex_ie_types_local_pwr_constraint *constraint;
+	struct ieee80211_supported_band *sband;
+	u8 radio_type;
+	int i;
+
+	if (!buffer || !(*buffer))
+		return;
+
+	radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+	sband = priv->wdev->wiphy->bands[radio_type];
+
+	cap = (struct mwifiex_ie_types_pwr_capability *)*buffer;
+	cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
+	cap->header.len = cpu_to_le16(2);
+	cap->min_pwr = 0;
+	cap->max_pwr = 0;
+	*buffer += sizeof(*cap);
+
+	constraint = (struct mwifiex_ie_types_local_pwr_constraint *)*buffer;
+	constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT);
+	constraint->header.len = cpu_to_le16(2);
+	constraint->chan = bss_desc->channel;
+	constraint->constraint = bss_desc->local_constraint;
+	*buffer += sizeof(*constraint);
+
+	ie_header = (struct mwifiex_ie_types_header *)*buffer;
+	ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+	ie_header->len  = cpu_to_le16(2 * sband->n_channels + 2);
+	*buffer += sizeof(*ie_header);
+	*(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS;
+	*(*buffer)++ = 2 * sband->n_channels;
+	for (i = 0; i < sband->n_channels; i++) {
+		*(*buffer)++ = ieee80211_frequency_to_channel(
+					sband->channels[i].center_freq);
+		*(*buffer)++ = 1; /* one channel in the subband */
+	}
+}
+
+/* Enable or disable the 11h extensions in the firmware */
+static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
+{
+	u32 enable = flag;
+
+	return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+				     HostCmd_ACT_GEN_SET, DOT11H_I, &enable);
+}
+
+/* This functions processes TLV buffer for a pending BSS Join command.
+ *
+ * Activate 11h functionality in the firmware if the spectrum management
+ * capability bit is found in the network we are joining. Also, necessary
+ * TLVs are set based on requested network's 11h capability.
+ */
+void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
+			      struct mwifiex_bssdescriptor *bss_desc)
+{
+	if (bss_desc->sensed_11h) {
+		/* Activate 11h functions in firmware, turns on capability
+		 * bit
+		 */
+		mwifiex_11h_activate(priv, true);
+		bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+		mwifiex_11h_process_infra_join(priv, buffer, bss_desc);
+	} else {
+		/* Deactivate 11h functions in the firmware */
+		mwifiex_11h_activate(priv, false);
+		bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
+	}
+}
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index ecf2846..a42a506 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -40,6 +40,7 @@ mwifiex-y += sta_rx.o
 mwifiex-y += uap_txrx.o
 mwifiex-y += cfg80211.o
 mwifiex-y += ethtool.o
+mwifiex-y += 11h.o
 mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_MWIFIEX) += mwifiex.o
 
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index d6ada73..b6fbbf6 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -438,6 +438,7 @@ enum P2P_MODES {
 #define EVENT_BW_CHANGE                 0x00000048
 #define EVENT_UAP_MIC_COUNTERMEASURES   0x0000004c
 #define EVENT_HOSTWAKE_STAIE		0x0000004d
+#define EVENT_CHANNEL_SWITCH_ANN        0x00000050
 #define EVENT_REMAIN_ON_CHAN_EXPIRED    0x0000005f
 
 #define EVENT_ID_MASK                   0xffff
@@ -975,6 +976,7 @@ enum SNMP_MIB_INDEX {
 	LONG_RETRY_LIM_I = 7,
 	FRAG_THRESH_I = 8,
 	DOT11D_I = 9,
+	DOT11H_I = 10,
 };
 
 #define MAX_SNMP_BUF_SIZE   128
@@ -1206,6 +1208,18 @@ struct host_cmd_ds_sta_deauth {
 	__le16 reason;
 } __packed;
 
+struct mwifiex_ie_types_pwr_capability {
+	struct mwifiex_ie_types_header header;
+	s8 min_pwr;
+	s8 max_pwr;
+};
+
+struct mwifiex_ie_types_local_pwr_constraint {
+	struct mwifiex_ie_types_header header;
+	u8 chan;
+	u8 constraint;
+};
+
 struct mwifiex_ie_types_wmm_param_set {
 	struct mwifiex_ie_types_header header;
 	u8 wmm_ie[1];
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 122175a..1c8a771 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -534,6 +534,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
 
 	mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
 
+	mwifiex_11h_process_join(priv, &pos, bss_desc);
+
 	cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
 
 	/* Set the Capability info at last */
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 0832c24..95a6f52 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -309,6 +309,9 @@ struct mwifiex_bssdescriptor {
 	u16 wapi_offset;
 	u8 *beacon_buf;
 	u32 beacon_buf_size;
+	u8 sensed_11h;
+	u8 local_constraint;
+	u8 chan_sw_ie_present;
 };
 
 struct mwifiex_current_bss_params {
@@ -1119,6 +1122,10 @@ u8 *mwifiex_11d_code_2_region(u8 code);
 void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
 			      struct mwifiex_sta_node *node);
 
+void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
+			      struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
+
 extern const struct ethtool_ops mwifiex_ethtool_ops;
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 801b6b7..284d68b 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -391,6 +391,12 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
 		return 0;
 	}
 
+	if (bss_desc->chan_sw_ie_present) {
+		dev_err(adapter->dev,
+			"Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
+		return -1;
+	}
+
 	if (mwifiex_is_bss_wapi(priv, bss_desc)) {
 		dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
 		return 0;
@@ -1169,6 +1175,19 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
 			bss_entry->erp_flags = *(current_ptr + 2);
 			break;
 
+		case WLAN_EID_PWR_CONSTRAINT:
+			bss_entry->local_constraint = *(current_ptr + 2);
+			bss_entry->sensed_11h = true;
+			break;
+
+		case WLAN_EID_CHANNEL_SWITCH:
+			bss_entry->chan_sw_ie_present = true;
+		case WLAN_EID_PWR_CAPABILITY:
+		case WLAN_EID_TPC_REPORT:
+		case WLAN_EID_QUIET:
+			bss_entry->sensed_11h = true;
+		    break;
+
 		case WLAN_EID_EXT_SUPP_RATES:
 			/*
 			 * Only process extended supported rate
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 41aafc7..0f7b4cf 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -427,6 +427,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
 		break;
 
+	case EVENT_CHANNEL_SWITCH_ANN:
+		dev_dbg(adapter->dev, "event: Channel Switch Announcement\n");
+		ret = mwifiex_send_cmd_async(priv,
+			HostCmd_CMD_802_11_DEAUTHENTICATE,
+			HostCmd_ACT_GEN_SET, 0,
+			priv->curr_bss_params.bss_descriptor.mac_address);
+
 	default:
 		dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
 			eventcause);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 15b5457..498add7 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -178,6 +178,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
 	 */
 	bss_desc->disable_11ac = true;
 
+	if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
+		bss_desc->sensed_11h = true;
+
 	return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
 }
 
-- 
1.8.2.3


^ permalink raw reply related

* [PATCH 5/6] wireless:  Fix bss ref count leak in __cfg80211_mlme_assoc
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

The rdev_assoc path holds it's own reference, so the
mlme_assoc must release the reference it took earlier
before returning.

This actually appears to be the leak I have been seeing
in my tests.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/mlme.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index d975510..1c60268 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -432,8 +432,8 @@ out:
 	if (err) {
 		if (was_connected)
 			SET_SME_STATE(wdev, CFG80211_SME_CONNECTED);
-		cfg80211_put_bss(&rdev->wiphy, req.bss);
 	}
+	cfg80211_put_bss(&rdev->wiphy, req.bss);
 
 	return err;
 }
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 4/6] wireless:  Check for dangling wdev->current_bss pointer.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

If it *is* still set when the netdev is being deleted,
then we are about to leak a pointer.  Warn and clean up
in that case.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/core.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index eb3e1de..9e05da9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1063,6 +1063,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		 * freed.
 		 */
 		cfg80211_process_wdev_events(wdev);
+
+		if (WARN_ON(wdev->current_bss)) {
+			cfg80211_unhold_bss(wdev->current_bss);
+			cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
+			SET_BSS(wdev, NULL);
+		}
 		break;
 	case NETDEV_PRE_UP:
 		if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 3/6] wireless:  Make sure __cfg80211_connect_result always puts bss.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

Otherwise, we can leak a bss reference.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/sme.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 6066720..ea2ce33 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -420,6 +420,7 @@ void cfg80211_sme_failed_assoc(struct wireless_dev *wdev)
 	schedule_work(&rdev->conn_work);
 }
 
+/** This method must consume bss one way or another */
 void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 			       const u8 *req_ie, size_t req_ie_len,
 			       const u8 *resp_ie, size_t resp_ie_len,
@@ -435,11 +436,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 	ASSERT_WDEV_LOCK(wdev);
 
 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
-		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
+		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
+		if (bss)
+			cfg80211_put_bss(wdev->wiphy, bss);
 		return;
+	}
 
-	if (wdev->sme_state != CFG80211_SME_CONNECTING)
+	if (wdev->sme_state != CFG80211_SME_CONNECTING) {
+		if (bss)
+			cfg80211_put_bss(wdev->wiphy, bss);
 		return;
+	}
 
 	nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
 				    bssid, req_ie, req_ie_len,
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 6/6] wireless:  Add comments about bss refcounting.
From: greearb @ 2013-06-18 22:03 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <1371593017-10985-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>

Should help the next person that tries to understand
the bss refcounting logic.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 net/wireless/scan.c |    4 ++++
 net/wireless/sme.c  |    3 +++
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 542ff6d..834d2f9 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -622,6 +622,7 @@ static int cmp_bss(struct cfg80211_bss *a,
 	}
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
 				      struct ieee80211_channel *channel,
 				      const u8 *bssid,
@@ -777,6 +778,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
 	return true;
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 static struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *dev,
 		    struct cfg80211_internal_bss *tmp)
@@ -962,6 +964,7 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
 	return channel;
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss*
 cfg80211_inform_bss(struct wiphy *wiphy,
 		    struct ieee80211_channel *channel,
@@ -1019,6 +1022,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_inform_bss);
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss *
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
 			  struct ieee80211_channel *channel,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ea2ce33..d26cd68 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -263,6 +263,7 @@ void cfg80211_conn_work(struct work_struct *work)
 	rtnl_unlock();
 }
 
+/** Returned bss is reference counted and must be cleaned up appropriately. */
 static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -579,6 +580,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 }
 EXPORT_SYMBOL(cfg80211_connect_result);
 
+/** Consumes bss object one way or another */
 void __cfg80211_roamed(struct wireless_dev *wdev,
 		       struct cfg80211_bss *bss,
 		       const u8 *req_ie, size_t req_ie_len,
@@ -662,6 +664,7 @@ void cfg80211_roamed(struct net_device *dev,
 }
 EXPORT_SYMBOL(cfg80211_roamed);
 
+/** Consumes bss object one way or another */
 void cfg80211_roamed_bss(struct net_device *dev,
 			 struct cfg80211_bss *bss, const u8 *req_ie,
 			 size_t req_ie_len, const u8 *resp_ie,
-- 
1.7.3.4


^ 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