Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 08/18] atm: use wrapper functions of net_ratelimit() to simplify code
From: Kefeng Wang @ 2013-10-15 11:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

net_ratelimited_function() is called to simplify code.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 drivers/atm/solos-pci.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 32784d1..a4d20e9 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -807,8 +807,8 @@ void solos_bh(unsigned long card_arg)
 
 				skb = alloc_skb(size + 1, GFP_ATOMIC);
 				if (!skb) {
-					if (net_ratelimit())
-						dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
+					net_ratelimited_function(dev_warn, &card->dev->dev,
+						"Failed to allocate sk_buff for RX\n");
 					continue;
 				}
 
@@ -829,8 +829,8 @@ void solos_bh(unsigned long card_arg)
 				vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi),
 					       le16_to_cpu(header->vci));
 				if (!vcc) {
-					if (net_ratelimit())
-						dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n",
+					net_ratelimited_function(dev_warn, &card->dev->dev,
+						"Received packet for unknown VPI.VCI %d.%d on port %d\n",
 							 le16_to_cpu(header->vpi), le16_to_cpu(header->vci),
 							 port);
 					dev_kfree_skb_any(skb);
@@ -856,9 +856,8 @@ void solos_bh(unsigned long card_arg)
 					break;
 				spin_lock(&card->cli_queue_lock);
 				if (skb_queue_len(&card->cli_queue[port]) > 10) {
-					if (net_ratelimit())
-						dev_warn(&card->dev->dev, "Dropping console response on port %d\n",
-							 port);
+					net_ratelimited_function(dev_warn, &card->dev->dev,
+						"Dropping console response on port %d\n", port);
 					dev_kfree_skb_any(skb);
 				} else
 					skb_queue_tail(&card->cli_queue[port], skb);
@@ -878,8 +877,7 @@ void solos_bh(unsigned long card_arg)
 					  card->config_regs + RX_DMA_ADDR(port));
 				card->rx_skb[port] = skb;
 			} else {
-				if (net_ratelimit())
-					dev_warn(&card->dev->dev, "Failed to allocate RX skb");
+				net_ratelimited_function(dev_warn, &card->dev->dev, "Failed to allocate RX skb");
 
 				/* We'll have to try again later */
 				tasklet_schedule(&card->tlet);
@@ -927,8 +925,8 @@ static int popen(struct atm_vcc *vcc)
 
 	skb = alloc_skb(sizeof(*header), GFP_KERNEL);
 	if (!skb) {
-		if (net_ratelimit())
-			dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
+		net_ratelimited_function(dev_warn, &card->dev->dev,
+			"Failed to allocate sk_buff in popen()\n");
 		return -ENOMEM;
 	}
 	header = (void *)skb_put(skb, sizeof(*header));
-- 
1.8.2.1



^ permalink raw reply related

* [PATCH 12/18] net: irda: use wrapper functions of net_ratelimit() to simplify code
From: Kefeng Wang @ 2013-10-15 11:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

net_ratelimited_function() is called to simplify code.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 drivers/net/irda/stir4200.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 876e709..d499b2b 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -783,8 +783,7 @@ static int stir_transmit_thread(void *arg)
 				break;
 
 			if (unlikely(receive_start(stir))) {
-				if (net_ratelimit())
-					dev_info(&dev->dev,
+				net_ratelimited_function(dev_info, &dev->dev,
 						 "%s: receive usb submit failed\n",
 						 stir->netdev->name);
 				stir->receiving = 0;
-- 
1.8.2.1



^ permalink raw reply related

* [PATCH 11/18] net: hamradio: use wrapper functions of net_ratelimit() to simplify code
From: Kefeng Wang @ 2013-10-15 11:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

net_XXX_ratelimited() is called to simplify code.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 drivers/net/hamradio/6pack.c    | 3 +--
 drivers/net/hamradio/bpqether.c | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 1450e33..9e97eba 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -237,8 +237,7 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
 out_drop:
 	sp->dev->stats.tx_dropped++;
 	netif_start_queue(sp->dev);
-	if (net_ratelimit())
-		printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
+	net_dbg_ratelimited("%s: %s - dropped.\n", sp->dev->name, msg);
 }
 
 /* Encapsulate an IP datagram and kick it into a TTY queue. */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index f91bf0d..1522b4a 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -269,8 +269,7 @@ static netdev_tx_t bpq_xmit(struct sk_buff *skb, struct net_device *dev)
 	 * space for the BPQ headers.
 	 */
 	if (skb_cow(skb, AX25_BPQ_HEADER_LEN)) {
-		if (net_ratelimit())
-			pr_err("bpqether: out of memory\n");
+		net_err_ratelimited("pqether: out of memory\n");
 		kfree_skb(skb);
 
 		return NETDEV_TX_OK;
-- 
1.8.2.1



^ permalink raw reply related

* [PATCH 01/18] netfilter: cleanup: delete Macro PRINTR
From: Kefeng Wang @ 2013-10-15 11:44 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

Macro PRINTR is only used once in nfnetlink_log.c, so it can be
replaced by helper function net_err_ratelimited().

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 net/netfilter/nfnetlink_log.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index d92cc31..8713111 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -47,9 +47,6 @@
 #define NFULNL_QTHRESH_DEFAULT 	100	/* 100 packets */
 #define NFULNL_COPY_RANGE_MAX	0xFFFF	/* max packet size is limited by 16-bit struct nfattr nfa_len field */
 
-#define PRINTR(x, args...)	do { if (net_ratelimit()) \
-				     printk(x, ## args); } while (0);
-
 struct nfulnl_instance {
 	struct hlist_node hlist;	/* global list of instances */
 	spinlock_t lock;
@@ -587,7 +584,7 @@ __build_packet_message(struct nfnl_log_net *log,
 	return 0;
 
 nla_put_failure:
-	PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n");
+	net_err_ratelimited("nfnetlink_log: error creating log nlmsg\n");
 	return -1;
 }
 
-- 
1.8.2.1



^ permalink raw reply related

* [PATCH 02/18] net: use wrapper functions of net_ratelimit() to simplify code
From: Kefeng Wang @ 2013-10-15 11:44 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

Wrapper functions net_ratelimited_function() and net_XXX_ratelimited()
are called to simplify code.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 net/bridge/br_fdb.c                   |  6 ++----
 net/bridge/br_multicast.c             | 13 ++++---------
 net/bridge/br_stp_bpdu.c              | 11 ++++-------
 net/mac80211/rx.c                     |  6 ++----
 net/netfilter/ipset/ip_set_hash_gen.h |  3 +--
 5 files changed, 13 insertions(+), 26 deletions(-)

diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index ffd5874..e47dfe5 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -465,10 +465,8 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
 	if (likely(fdb)) {
 		/* attempt to update an entry for a local interface */
 		if (unlikely(fdb->is_local)) {
-			if (net_ratelimit())
-				br_warn(br, "received packet on %s with "
-					"own address as source address\n",
-					source->dev->name);
+			net_ratelimited_function(br_warn, br, "received packet on %s "
+				"with own address as source address\n", source->dev->name);
 		} else {
 			/* fastpath: update of existing entry */
 			fdb->dst = source;
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index d1c5786..c00d8a2 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -530,11 +530,8 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
 	max = mdb->max;
 
 	if (unlikely(count > br->hash_elasticity && count)) {
-		if (net_ratelimit())
-			br_info(br, "Multicast hash table "
-				"chain limit reached: %s\n",
-				port ? port->dev->name : br->dev->name);
-
+		net_ratelimited_function(br_info, br, "Multicast hash table "
+			"chain limit reached: %s\n", port ? port->dev->name : br->dev->name);
 		elasticity = br->hash_elasticity;
 	}
 
@@ -554,10 +551,8 @@ disable:
 
 	if (max > mdb->max || elasticity) {
 		if (mdb->old) {
-			if (net_ratelimit())
-				br_info(br, "Multicast hash table "
-					"on fire: %s\n",
-					port ? port->dev->name : br->dev->name);
+			net_ratelimited_function(br_info, br, "Multicast hash table "
+				"on fire: %s\n", port ? port->dev->name : br->dev->name);
 			err = -EEXIST;
 			goto err;
 		}
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 8660ea3..482ef11 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -220,13 +220,10 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
 		bpdu.forward_delay = br_get_ticks(buf+30);
 
 		if (bpdu.message_age > bpdu.max_age) {
-			if (net_ratelimit())
-				br_notice(p->br,
-					  "port %u config from %pM"
-					  " (message_age %ul > max_age %ul)\n",
-					  p->port_no,
-					  eth_hdr(skb)->h_source,
-					  bpdu.message_age, bpdu.max_age);
+			net_ratelimited_function(br_notice, p->br,
+				"port %u config from %pM (message_age %ul > max_age %ul)\n",
+				p->port_no, eth_hdr(skb)->h_source,
+				bpdu.message_age, bpdu.max_age);
 			goto out;
 		}
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 54395d7..35b8b1d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3156,10 +3156,8 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
 	if (!consume) {
 		skb = skb_copy(skb, GFP_ATOMIC);
 		if (!skb) {
-			if (net_ratelimit())
-				wiphy_debug(local->hw.wiphy,
-					"failed to copy skb for %s\n",
-					sdata->name);
+			net_ratelimited_function(wiphy_debug, local->hw.wiphy,
+				"failed to copy skb for %s\n", sdata->name);
 			return true;
 		}
 
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 707bc52..6179436 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -607,8 +607,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 		mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
 
 	if (h->elements >= h->maxelem) {
-		if (net_ratelimit())
-			pr_warning("Set %s is full, maxelem %u reached\n",
+		net_warn_ratelimited("Set %s is full, maxelem %u reached\n",
 				   set->name, h->maxelem);
 		return -IPSET_ERR_HASH_FULL;
 	}
-- 
1.8.2.1



^ permalink raw reply related

* [PATCH 05/18] rt18192u: use wrapper functions of net_ratelimit() to simplify code
From: Kefeng Wang @ 2013-10-15 11:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

net_XXX_ratelimited() is called to simplify code.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 .../rtl8192u/ieee80211/ieee80211_crypt_ccmp.c      | 17 ++++-------------
 .../rtl8192u/ieee80211/ieee80211_crypt_tkip.c      | 22 +++++-----------------
 drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c  |  7 ++-----
 drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c  |  4 +---
 4 files changed, 12 insertions(+), 38 deletions(-)

diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
index f2b1677..534f0a4 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c
@@ -284,10 +284,8 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 	pos = skb->data + hdr_len;
 	keyidx = pos[3];
 	if (!(keyidx & (1 << 5))) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "CCMP: received packet without ExtIV"
+		net_dbg_ratelimited("CCMP: received packet without ExtIV"
 			       " flag from %pM\n", hdr->addr2);
-		}
 		key->dot11RSNAStatsCCMPFormatErrors++;
 		return -2;
 	}
@@ -298,11 +296,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		return -6;
 	}
 	if (!key->key_set) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "CCMP: received packet from %pM"
+		net_dbg_ratelimited("CCMP: received packet from %pM"
 			       " with keyid=%d that does not have a configured"
 			       " key\n", hdr->addr2, keyidx);
-		}
 		return -3;
 	}
 
@@ -315,11 +311,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 	pos += 8;
 
 	if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "CCMP: replay detected: STA=%pM"
+		net_dbg_ratelimited("CCMP: replay detected: STA=%pM"
 			       " previous PN %pm received PN %pm\n",
 			       hdr->addr2, key->rx_pn, pn);
-		}
 		key->dot11RSNAStatsCCMPReplays++;
 		return -4;
 	}
@@ -353,10 +347,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		}
 
 		if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "CCMP: decrypt failed: STA="
-				"%pM\n", hdr->addr2);
-			}
+			net_dbg_ratelimited("CCMP: decrypt failed: STA=%pM\n", hdr->addr2);
 			key->dot11RSNAStatsCCMPDecryptErrors++;
 			return -5;
 		}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
index 93121b4..7bb5a96 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
@@ -406,10 +406,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 	pos = skb->data + hdr_len;
 	keyidx = pos[3];
 	if (!(keyidx & (1 << 5))) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP: received packet without ExtIV"
+		net_dbg_ratelimited("TKIP: received packet without ExtIV"
 			       " flag from %pM\n", hdr->addr2);
-		}
 		return -2;
 	}
 	keyidx >>= 6;
@@ -419,11 +417,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		return -6;
 	}
 	if (!tkey->key_set) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP: received packet from %pM"
+		net_dbg_ratelimited("TKIP: received packet from %pM"
 			       " with keyid=%d that does not have a configured"
 			       " key\n", hdr->addr2, keyidx);
-		}
 		return -3;
 	}
 	iv16 = (pos[0] << 8) | pos[2];
@@ -434,12 +430,10 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 	{
 		if (iv32 < tkey->rx_iv32 ||
 		(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
+			net_dbg_ratelimited("TKIP: replay detected: STA=%pM"
 				" previous TSC %08x%04x received TSC "
 				"%08x%04x\n", hdr->addr2,
 				tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
-			}
 			tkey->dot11RSNAStatsTKIPReplays++;
 			return -4;
 		}
@@ -456,11 +450,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		sg_init_one(&sg, pos, plen+4);
 
 		if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG ": TKIP: failed to decrypt "
-						"received packet from %pM\n",
+			net_dbg_ratelimited("TKIP: failed to decrypt received packet from %pM\n",
 						hdr->addr2);
-			}
 			return -7;
 		}
 
@@ -476,10 +467,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 				* it needs to be recalculated for the next packet. */
 				tkey->rx_phase1_done = 0;
 			}
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "TKIP: ICV error detected: STA="
-				"%pM\n", hdr->addr2);
-			}
+			net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n", hdr->addr2);
 			tkey->dot11RSNAStatsTKIPICVErrors++;
 			return -5;
 		}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index 59900bf..5e6c1eb 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -355,11 +355,9 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
 #ifdef CONFIG_IEEE80211_CRYPT_TKIP
 	if (ieee->tkip_countermeasures &&
 	    strcmp(crypt->ops->name, "TKIP") == 0) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+		net_dbg_ratelimited("%s: TKIP countermeasures: dropped "
 			       "received packet from %pM\n",
 			       ieee->dev->name, hdr->addr2);
-		}
 		return -1;
 	}
 #endif
@@ -946,8 +944,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 
 	if(HTCCheck(ieee, skb->data))
 	{
-		if(net_ratelimit())
-		printk("find HTCControl\n");
+		net_info_ratelimited("find HTCControl\n");
 		hdrlen += 4;
 		rx_stats->bContainHTC = 1;
 	}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index a7bcc64f..55c24d7 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -197,11 +197,9 @@ int ieee80211_encrypt_fragment(
 	if (ieee->tkip_countermeasures &&
 	    crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) {
 		header = (struct ieee80211_hdr *) frag->data;
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+		net_dbg_ratelimited("%s: TKIP countermeasures: dropped "
 			       "TX packet to %pM\n",
 			       ieee->dev->name, header->addr1);
-		}
 		return -1;
 	}
 #endif
-- 
1.8.2.1



^ permalink raw reply related

* [PATCH 04/18] rt18192e: use wrapper functions of net_ratelimit() to simplify code
From: Kefeng Wang @ 2013-10-15 11:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

Wrapper functions net_ratelimited_function() and net_XXX_ratelimited()
are called to simplify code.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 drivers/staging/rtl8192e/rtllib_crypt_ccmp.c | 13 +++----------
 drivers/staging/rtl8192e/rtllib_crypt_tkip.c | 21 +++++----------------
 drivers/staging/rtl8192e/rtllib_rx.c         |  6 ++----
 3 files changed, 10 insertions(+), 30 deletions(-)

diff --git a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
index e51cb49..0d089c1 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
@@ -275,10 +275,8 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 	pos = skb->data + hdr_len;
 	keyidx = pos[3];
 	if (!(keyidx & (1 << 5))) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "CCMP: received packet without ExtIV"
+		net_dbg_ratelimited("CCMP: received packet without ExtIV"
 			       " flag from %pM\n", hdr->addr2);
-		}
 		key->dot11RSNAStatsCCMPFormatErrors++;
 		return -2;
 	}
@@ -289,11 +287,9 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		return -6;
 	}
 	if (!key->key_set) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "CCMP: received packet from %pM"
+		net_dbg_ratelimited("CCMP: received packet from %pM"
 			       " with keyid=%d that does not have a configured"
 			       " key\n", hdr->addr2, keyidx);
-		}
 		return -3;
 	}
 
@@ -338,10 +334,7 @@ static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		}
 
 		if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "CCMP: decrypt failed: STA="
-				" %pM\n", hdr->addr2);
-			}
+			net_dbg_ratelimited("CCMP: decrypt failed: STA= %pM\n", hdr->addr2);
 			key->dot11RSNAStatsCCMPDecryptErrors++;
 			return -5;
 		}
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
index 5cfd73b..c1f7683 100644
--- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
+++ b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
@@ -396,10 +396,8 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 	pos = skb->data + hdr_len;
 	keyidx = pos[3];
 	if (!(keyidx & (1 << 5))) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP: received packet without ExtIV"
+		net_dbg_ratelimited("TKIP: received packet without ExtIV"
 			       " flag from %pM\n", hdr->addr2);
-		}
 		return -2;
 	}
 	keyidx >>= 6;
@@ -409,11 +407,9 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		return -6;
 	}
 	if (!tkey->key_set) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP: received packet from %pM"
+		net_dbg_ratelimited("TKIP: received packet from %pM"
 			       " with keyid=%d that does not have a configured"
 			       " key\n", hdr->addr2, keyidx);
-		}
 		return -3;
 	}
 	iv16 = (pos[0] << 8) | pos[2];
@@ -424,12 +420,10 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 		if ((iv32 < tkey->rx_iv32 ||
 		    (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) &&
 		    tkey->initialized) {
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "TKIP: replay detected: STA="
+			net_dbg_ratelimited("TKIP: replay detected: STA="
 				       " %pM previous TSC %08x%04x received "
 				      "TSC %08x%04x\n",hdr->addr2,
 				      tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
-			}
 			tkey->dot11RSNAStatsTKIPReplays++;
 			return -4;
 		}
@@ -448,11 +442,9 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 
 		crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
 		if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG ": TKIP: failed to decrypt "
+			net_dbg_ratelimited(": TKIP: failed to decrypt "
 				       "received packet from %pM\n",
 				       hdr->addr2);
-			}
 			return -7;
 		}
 
@@ -469,10 +461,7 @@ static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
 				 * next packet. */
 				tkey->rx_phase1_done = 0;
 			}
-			if (net_ratelimit()) {
-				printk(KERN_DEBUG "TKIP: ICV error detected: STA="
-				" %pM\n", hdr->addr2);
-			}
+			net_dbg_ratelimited("TKIP: ICV error detected: STA= %pM\n", hdr->addr2);
 			tkey->dot11RSNAStatsTKIPICVErrors++;
 			return -5;
 		}
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 8aeaed5..4335611 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -870,8 +870,7 @@ static size_t rtllib_rx_get_hdrlen(struct rtllib_device *ieee,
 
 	hdrlen = rtllib_get_hdrlen(fc);
 	if (HTCCheck(ieee, skb->data)) {
-		if (net_ratelimit())
-			printk(KERN_INFO "%s: find HTCControl!\n", __func__);
+		net_info_ratelimited("%s: find HTCControl!\n", __func__);
 		hdrlen += 4;
 		rx_stats->bContainHTC = 1;
 	}
@@ -1439,8 +1438,7 @@ static int rtllib_rx_Monitor(struct rtllib_device *ieee, struct sk_buff *skb,
 	}
 
 	if (HTCCheck(ieee, skb->data)) {
-		if (net_ratelimit())
-			printk(KERN_INFO "%s: Find HTCControl!\n", __func__);
+		net_info_ratelimited("%s: Find HTCControl!\n", __func__);
 		hdrlen += 4;
 	}
 
-- 
1.8.2.1



^ permalink raw reply related

* [PATCH 06/18] net: wireless: use wrapper functions of net_ratelimit() to simplify code
From: Kefeng Wang @ 2013-10-15 11:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: Greg Kroah-Hartman, David S. Miller, Pablo Neira Ayuso,
	Stephen Hemminger, Johannes Berg, John W. Linville,
	Stanislaw Gruszka, Johannes Berg, Francois Romieu, Ben Hutchings,
	Chas Williams, Marc Kleine-Budde, Samuel Ortiz, Paul Mackerras,
	Oliver Neukum, Konrad Rzeszutek Wilk, Boris Ostrovsky,
	David Vrabel, Rusty Russell, Michael S. Tsirkin, netfilter,
	netdev, linux-wireless, guohanjun
In-Reply-To: <1381837514-50660-1-git-send-email-wangkefeng.wang@huawei.com>

Wrapper functions net_ratelimited_function() and net_XXX_ratelimited()
are called to simplify code.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 drivers/net/wireless/adm8211.c                |  5 ++-
 drivers/net/wireless/ath/carl9170/cmd.c       | 15 +++------
 drivers/net/wireless/ath/carl9170/phy.c       |  7 ++---
 drivers/net/wireless/ath/carl9170/rx.c        | 45 ++++++++-------------------
 drivers/net/wireless/ath/carl9170/usb.c       | 12 +++----
 drivers/net/wireless/hostap/hostap_80211_rx.c |  8 ++---
 drivers/net/wireless/hostap/hostap_80211_tx.c | 13 +++-----
 drivers/net/wireless/hostap/hostap_ap.c       |  6 ++--
 drivers/net/wireless/hostap/hostap_hw.c       | 17 +++-------
 drivers/net/wireless/iwlegacy/3945-mac.c      |  4 +--
 drivers/net/wireless/iwlegacy/4965-mac.c      |  6 ++--
 drivers/net/wireless/iwlwifi/pcie/rx.c        |  7 ++---
 drivers/net/wireless/libertas_tf/cmd.c        |  6 ++--
 drivers/net/wireless/mwl8k.c                  |  5 ++-
 drivers/net/wireless/orinoco/hermes.c         |  6 ++--
 drivers/net/wireless/orinoco/main.c           | 16 +++-------
 drivers/net/wireless/orinoco/orinoco_usb.c    |  3 +-
 drivers/net/wireless/p54/p54pci.c             |  6 ++--
 18 files changed, 61 insertions(+), 126 deletions(-)

diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index f9a24e5..2fafb8a 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -374,9 +374,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
 
 		pktlen = status & RDES0_STATUS_FL;
 		if (pktlen > RX_PKT_SIZE) {
-			if (net_ratelimit())
-				wiphy_debug(dev->wiphy, "frame too long (%d)\n",
-					    pktlen);
+			net_ratelimited_function(wiphy_debug, dev->wiphy,
+				"frame too long (%d)\n", pktlen);
 			pktlen = RX_PKT_SIZE;
 		}
 
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
index 39a6387..3f13398 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.c
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -50,12 +50,9 @@ int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
 
 	err = carl9170_exec_cmd(ar, CARL9170_CMD_WREG, sizeof(buf),
 				(u8 *) buf, 0, NULL);
-	if (err) {
-		if (net_ratelimit()) {
-			wiphy_err(ar->hw->wiphy, "writing reg %#x "
-				"(val %#x) failed (%d)\n", reg, val, err);
-		}
-	}
+	if (err)
+		net_ratelimited_function(wiphy_err, ar->hw->wiphy,
+			"writing reg %#x (val %#x) failed (%d)\n", reg, val, err);
 	return err;
 }
 
@@ -77,10 +74,8 @@ int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
 				4 * nregs, (u8 *)offs,
 				4 * nregs, (u8 *)res);
 	if (err) {
-		if (net_ratelimit()) {
-			wiphy_err(ar->hw->wiphy, "reading regs failed (%d)\n",
-				  err);
-		}
+		net_ratelimited_function(wiphy_err, ar->hw->wiphy,
+			"reading regs failed (%d)\n", err);
 		return err;
 	}
 
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index ab4ee7d..cae9125 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1715,11 +1715,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
 		err = carl9170_write_reg(ar, AR9170_PHY_REG_HEAVY_CLIP_ENABLE,
 					 0x200 | ar->heavy_clip);
 		if (err) {
-			if (net_ratelimit()) {
-				wiphy_err(ar->hw->wiphy, "failed to set "
-				       "heavy clip\n");
-			}
-
+			net_ratelimited_function(wiphy_err,
+				ar->hw->wiphy, "failed to set heavy clip\n");
 			return err;
 		}
 	}
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index e935f61..0ad905e 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -343,9 +343,8 @@ static int carl9170_rx_mac_status(struct ar9170 *ar,
 	if (unlikely(error)) {
 		/* TODO: update netdevice's RX dropped/errors statistics */
 
-		if (net_ratelimit())
-			wiphy_dbg(ar->hw->wiphy, "received frame with "
-			       "suspicious error code (%#x).\n", error);
+		net_ratelimited_function(wiphy_dbg, ar->hw->wiphy,
+			"received frame with suspicious error code (%#x).\n", error);
 
 		return -EINVAL;
 	}
@@ -374,11 +373,8 @@ static int carl9170_rx_mac_status(struct ar9170 *ar,
 			status->rate_idx = 3;
 			break;
 		default:
-			if (net_ratelimit()) {
-				wiphy_err(ar->hw->wiphy, "invalid plcp cck "
-				       "rate (%x).\n", head->plcp[0]);
-			}
-
+			net_ratelimited_function(wiphy_err, ar->hw->wiphy,
+				"invalid plcp cck rate (%x).\n", head->plcp[0]);
 			return -EINVAL;
 		}
 		break;
@@ -411,11 +407,8 @@ static int carl9170_rx_mac_status(struct ar9170 *ar,
 			status->rate_idx = 7;
 			break;
 		default:
-			if (net_ratelimit()) {
-				wiphy_err(ar->hw->wiphy, "invalid plcp ofdm "
-					"rate (%x).\n", head->plcp[0]);
-			}
-
+			net_ratelimited_function(wiphy_err, ar->hw->wiphy,
+				"invalid plcp ofdm rate (%x).\n", head->plcp[0]);
 			return -EINVAL;
 		}
 		if (status->band == IEEE80211_BAND_2GHZ)
@@ -742,11 +735,8 @@ static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len)
 
 			ar->rx_has_plcp = true;
 		} else {
-			if (net_ratelimit()) {
-				wiphy_err(ar->hw->wiphy, "plcp info "
-					"is clipped.\n");
-			}
-
+			net_ratelimited_function(wiphy_err, ar->hw->wiphy,
+				"plcp info is clipped.\n");
 			goto drop;
 		}
 		break;
@@ -763,11 +753,8 @@ static void carl9170_rx_untie_data(struct ar9170 *ar, u8 *buf, int len)
 			mpdu_len -= sizeof(struct ar9170_rx_phystatus);
 			phy = (void *)(buf + mpdu_len);
 		} else {
-			if (net_ratelimit()) {
-				wiphy_err(ar->hw->wiphy, "frame tail "
-					"is clipped.\n");
-			}
-
+			net_ratelimited_function(wiphy_err, ar->hw->wiphy,
+				"frame tail is clipped.\n");
 			goto drop;
 		}
 
@@ -900,11 +887,8 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
 			if (!ar->rx_failover_missing) {
 
 				/* this is not "short read". */
-				if (net_ratelimit()) {
-					wiphy_err(ar->hw->wiphy,
+				net_ratelimited_function(wiphy_err, ar->hw->wiphy,
 						"missing tag!\n");
-				}
-
 				__carl9170_rx(ar, tbuf, tlen);
 				return;
 			}
@@ -973,11 +957,8 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
 	}
 
 	if (tlen) {
-		if (net_ratelimit()) {
-			wiphy_err(ar->hw->wiphy, "%d bytes of unprocessed "
-				"data left in rx stream!\n", tlen);
-		}
-
+		net_ratelimited_function(wiphy_err, ar->hw->wiphy,
+			"%d bytes of unprocessed data left in rx stream!\n", tlen);
 		goto err_telluser;
 	}
 
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index 307bc0d..0369f0f 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -144,10 +144,8 @@ static void carl9170_usb_submit_data_urb(struct ar9170 *ar)
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (unlikely(err)) {
-		if (net_ratelimit()) {
-			dev_err(&ar->udev->dev, "tx submit failed (%d)\n",
-				urb->status);
-		}
+		net_ratelimited_function(dev_err, &ar->udev->dev,
+			"tx submit failed (%d)\n", urb->status);
 
 		usb_unanchor_urb(urb);
 		usb_anchor_urb(urb, &ar->tx_err);
@@ -194,10 +192,8 @@ static void carl9170_usb_tx_data_complete(struct urb *urb)
 
 	/* a random transmission error has occurred? */
 	default:
-		if (net_ratelimit()) {
-			dev_err(&ar->udev->dev, "tx failed (%d)\n",
-				urb->status);
-		}
+		net_ratelimited_function(dev_err, &ar->udev->dev,
+			"tx failed (%d)\n", urb->status);
 
 		usb_anchor_urb(urb, &ar->tx_err);
 		break;
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index d39e3e2..a547d79 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -661,11 +661,9 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
 
 	if (local->tkip_countermeasures &&
 	    strcmp(crypt->ops->name, "TKIP") == 0) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
+		net_dbg_ratelimited("%s: TKIP countermeasures: dropped "
 			       "received packet from %pM\n",
 			       local->dev->name, hdr->addr2);
-		}
 		return -1;
 	}
 
@@ -995,11 +993,9 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
 
 	if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) &&
 	    !hostap_is_eapol_frame(local, skb)) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: dropped unencrypted RX data "
+		net_dbg_ratelimited("%s: dropped unencrypted RX data "
 			       "frame from %pM (drop_unencrypted=1)\n",
 			       dev->name, hdr->addr2);
-		}
 		goto rx_dropped;
 	}
 
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 344a981..7c8f798 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -330,11 +330,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
 	if (local->tkip_countermeasures &&
 	    strcmp(crypt->ops->name, "TKIP") == 0) {
 		hdr = (struct ieee80211_hdr *) skb->data;
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-			       "TX packet to %pM\n",
-			       local->dev->name, hdr->addr1);
-		}
+		net_dbg_ratelimited("%s: TKIP countermeasures: dropped "
+			"TX packet to %pM\n", local->dev->name, hdr->addr1);
 		kfree_skb(skb);
 		return NULL;
 	}
@@ -502,10 +499,8 @@ netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
 	} else if (local->drop_unencrypted &&
 		   ieee80211_is_data(hdr->frame_control) &&
 		   meta->ethertype != ETH_P_PAE) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: dropped unencrypted TX data "
-			       "frame (drop_unencrypted=1)\n", dev->name);
-		}
+		net_dbg_ratelimited("%s: dropped unencrypted TX data "
+			"frame (drop_unencrypted=1)\n", dev->name);
 		iface->stats.tx_dropped++;
 		ret = NETDEV_TX_OK;
 		goto fail;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index d6033a8..9320dc7 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -2781,10 +2781,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
 		 * for a unicast frame. In this case, the packet is send to all
 		 * ports of the bridge. Since this is a valid scenario, do not
 		 * print out any errors here. */
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "AP: drop packet to non-associated "
-			       "STA %pM\n", hdr->addr1);
-		}
+		net_dbg_ratelimited("AP: drop packet to non-associatedSTA %pM\n",
+			hdr->addr1);
 #endif
 		local->ap->tx_drop_nonassoc++;
 		ret = AP_TX_DROP;
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index c275dc1..34b7246 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -1820,10 +1820,8 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)
 
 	if ((local->func->card_present && !local->func->card_present(local)) ||
 	    !local->hw_ready || local->hw_downloading || local->pri_only) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -"
-			       " skipping\n", dev->name);
-		}
+		net_dbg_ratelimited("%s: prism2_tx_80211: hw not ready skipping\n",
+			dev->name);
 		goto fail;
 	}
 
@@ -2620,10 +2618,8 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
 	/* Detect early interrupt before driver is fully configured */
 	spin_lock(&local->irq_init_lock);
 	if (!dev->base_addr) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
-			       dev->name);
-		}
+		net_dbg_ratelimited("%s: Interrupt, but dev not configured\n",
+			dev->name);
 		spin_unlock(&local->irq_init_lock);
 		return IRQ_HANDLED;
 	}
@@ -2632,10 +2628,7 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
 	prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
 
 	if (local->func->card_present && !local->func->card_present(local)) {
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n",
-			       dev->name);
-		}
+		net_dbg_ratelimited("%s: Interrupt, but dev not OK\n", dev->name);
 		return IRQ_HANDLED;
 	}
 
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 9581d07..920c0b8 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -1027,8 +1027,8 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
 		/* Alloc a new receive buffer */
 		page = alloc_pages(gfp_mask, il->hw_params.rx_page_order);
 		if (!page) {
-			if (net_ratelimit())
-				D_INFO("Failed to allocate SKB buffer.\n");
+			net_ratelimited_function(D_INFO,
+				"Failed to allocate SKB buffer.\n");
 			if (rxq->free_count <= RX_LOW_WATERMARK &&
 			    net_ratelimit())
 				IL_ERR("Failed to allocate SKB buffer with %0x."
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 5ab50a5..4f8de71 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -340,9 +340,9 @@ il4965_rx_allocate(struct il_priv *il, gfp_t priority)
 		/* Alloc a new receive buffer */
 		page = alloc_pages(gfp_mask, il->hw_params.rx_page_order);
 		if (!page) {
-			if (net_ratelimit())
-				D_INFO("alloc_pages failed, " "order: %d\n",
-				       il->hw_params.rx_page_order);
+			net_ratelimited_function(D_INFO,
+				"alloc_pages failed, order: %d\n",
+				il->hw_params.rx_page_order);
 
 			if (rxq->free_count <= RX_LOW_WATERMARK &&
 			    net_ratelimit())
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 3f237b4..022f612 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -293,10 +293,9 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
 		/* Alloc a new receive buffer */
 		page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
 		if (!page) {
-			if (net_ratelimit())
-				IWL_DEBUG_INFO(trans, "alloc_pages failed, "
-					   "order: %d\n",
-					   trans_pcie->rx_page_order);
+			net_ratelimited_function(IWL_DEBUG_INFO, trans,
+				"alloc_pages failed, order: %d\n",
+				trans_pcie->rx_page_order);
 
 			if ((rxq->free_count <= RX_LOW_WATERMARK) &&
 			    net_ratelimit())
diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c
index 909ac36..806f750 100644
--- a/drivers/net/wireless/libertas_tf/cmd.c
+++ b/drivers/net/wireless/libertas_tf/cmd.c
@@ -737,10 +737,8 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
 	respcmd = le16_to_cpu(resp->command);
 	result = le16_to_cpu(resp->result);
 
-	if (net_ratelimit())
-		pr_info("libertastf: cmd response 0x%04x, seq %d, size %d\n",
-			respcmd, le16_to_cpu(resp->seqnum),
-			le16_to_cpu(resp->size));
+	net_info_ratelimited("libertastf: cmd response 0x%04x, seq %d, size %d\n",
+		respcmd, le16_to_cpu(resp->seqnum), le16_to_cpu(resp->size));
 
 	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
 		spin_unlock_irqrestore(&priv->driver_lock, flags);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index a3707fd..fe19424 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -5060,9 +5060,8 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
 	 * interface is active.
 	 */
 	if (!list_empty(&priv->vif_list)) {
-		if (net_ratelimit())
-			wiphy_info(hw->wiphy,
-				   "not enabling sniffer mode because STA interface is active\n");
+		net_ratelimited_function(wiphy_info, hw->wiphy,
+			"not enabling sniffer mode because STA interface is active\n");
 		return 0;
 	}
 
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index 75c15bc..e4ff42f 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -261,14 +261,12 @@ static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
 	err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
 	if (err) {
 		if (!hermes_present(hw)) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "hermes @ %p: "
+			net_warn_ratelimited("hermes @ %p: "
 				       "Card removed while issuing command "
 				       "0x%04x.\n", hw->iobase, cmd);
 			err = -ENODEV;
 		} else
-			if (net_ratelimit())
-				printk(KERN_ERR "hermes @ %p: "
+			net_err_ratelimited("hermes @ %p: "
 				       "Error %d issuing command 0x%04x.\n",
 				       hw->iobase, err, cmd);
 		goto out;
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 38ec8d1..22f3a6a 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -394,9 +394,7 @@ int orinoco_process_xmit_skb(struct sk_buff *skb,
 		int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
 
 		if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
-			if (net_ratelimit())
-				printk(KERN_ERR
-				       "%s: Not enough headroom for 802.2 headers %d\n",
+			net_err_ratelimited("%s: Not enough headroom for 802.2 headers %d\n",
 				       dev->name, skb_headroom(skb));
 			return -ENOMEM;
 		}
@@ -495,8 +493,7 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 		err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
 					  txfid, 0);
 		if (err) {
-			if (net_ratelimit())
-				printk(KERN_ERR "%s: Error %d writing Tx "
+			net_err_ratelimited("%s: Error %d writing Tx "
 				       "descriptor to BAP\n", dev->name, err);
 			goto busy;
 		}
@@ -509,8 +506,7 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 		err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
 					  txfid, 0);
 		if (err) {
-			if (net_ratelimit())
-				printk(KERN_ERR "%s: Error %d writing Tx "
+			net_err_ratelimited("%s: Error %d writing Tx "
 				       "descriptor to BAP\n", dev->name, err);
 			goto busy;
 		}
@@ -554,8 +550,7 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 				txfid, NULL);
 	if (err) {
 		netif_start_queue(dev);
-		if (net_ratelimit())
-			printk(KERN_ERR "%s: Error %d transmitting packet\n",
+		net_err_ratelimited("%s: Error %d transmitting packet\n",
 				dev->name, err);
 		goto busy;
 	}
@@ -1622,8 +1617,7 @@ EXPORT_SYMBOL(__orinoco_ev_info);
 
 static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw)
 {
-	if (net_ratelimit())
-		printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
+	net_dbg_ratelimited("%s: Information frame lost.\n", dev->name);
 }
 
 /********************************************************************/
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index bdfe637..65a43d6 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1286,8 +1286,7 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	if (err) {
 		netif_start_queue(dev);
-		if (net_ratelimit())
-			printk(KERN_ERR "%s: Error %d transmitting packet\n",
+		net_err_ratelimited("%s: Error %d transmitting packet\n",
 				dev->name, err);
 		goto busy;
 	}
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 57e3af8..1609084 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -212,10 +212,8 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
 		}
 
 		if (unlikely(len > priv->common.rx_mtu)) {
-			if (net_ratelimit())
-				dev_err(&priv->pdev->dev, "rx'd frame size "
-					"exceeds length threshold.\n");
-
+			net_ratelimited_function(dev_err, &priv->pdev->dev,
+				"rx'd frame size exceeds length threshold.\n");
 			len = priv->common.rx_mtu;
 		}
 		dma_addr = le32_to_cpu(desc->host_addr);
-- 
1.8.2.1



^ permalink raw reply related

* RE: [Ilw] drivers/net/wireless/iwlwifi/dvm/tx.c:456 iwlagn_tx_skb+0x6c5/0x883()
From: Grumbach, Emmanuel @ 2013-10-15 10:52 UTC (permalink / raw)
  To: Sander Eikelenboom, John W. Linville, Berg, Johannes,
	ilw@linux.intel.com
  Cc: ilw@linux.intel.com, netdev@vger.kernel.org,
	linux-wireless@vger.kernel.org
In-Reply-To: <9010061839.20131015123940@eikelenboom.it>

> 
> Hi,
> 
> I'm having a:
> 
> 02:00.0 Network controller: Intel Corporation Centrino Advanced-N 6235 (rev
> 24)
> 
> And i'm running into this warning on boot with a 3.11.2 and 3.12-rc5 kernel.
> 
> [   23.904950] ------------[ cut here ]------------
> [   23.904957] WARNING: CPU: 0 PID: 2531 at
> drivers/net/wireless/iwlwifi/dvm/tx.c:456 iwlagn_tx_skb+0x6c5/0x883()

Can you reproduce easily?
If yes, please reproduce with debug parameters:
modprobe iwlwifi debug=0xC0800000

Also, please enable MAC80211_HT_DEBUG

Thanks


^ permalink raw reply

* drivers/net/wireless/iwlwifi/dvm/tx.c:456 iwlagn_tx_skb+0x6c5/0x883()
From: Sander Eikelenboom @ 2013-10-15 10:39 UTC (permalink / raw)
  To: John W. Linville, johannes.berg, ilw; +Cc: ilw, linux-wireless, netdev

Hi,

I'm having a:

02:00.0 Network controller: Intel Corporation Centrino Advanced-N 6235 (rev 24)

And i'm running into this warning on boot with a 3.11.2 and 3.12-rc5 kernel.

[   23.904950] ------------[ cut here ]------------
[   23.904957] WARNING: CPU: 0 PID: 2531 at drivers/net/wireless/iwlwifi/dvm/tx.c:456 iwlagn_tx_skb+0x6c5/0x883()
[   23.904959] Modules linked in:
[   23.904962] CPU: 0 PID: 2531 Comm: hostapd Not tainted 3.12.0-rc5+ #1
[   23.904963] Hardware name:                  /D53427RKE, BIOS RKPPT10H.86A.0017.2013.0425.1251 04/25/2013
[   23.904966]  0000000000000000 0000000000000009 ffffffff8189aa62 0000000000000000
[   23.904968]  ffffffff8105a4f2 ffff880058339a48 ffffffff815f8a04 0000000000000000
[   23.904970]  ffff8800560097b0 0000000000000208 0000000000000000 ffff8800561a9e5e
[   23.904971] Call Trace:
[   23.904977]  [<ffffffff8189aa62>] ? dump_stack+0x41/0x51
[   23.904981]  [<ffffffff8105a4f2>] ? warn_slowpath_common+0x78/0x90
[   23.904984]  [<ffffffff815f8a04>] ? iwlagn_tx_skb+0x6c5/0x883
[   23.904986]  [<ffffffff815f8a04>] ? iwlagn_tx_skb+0x6c5/0x883
[   23.904989]  [<ffffffff818a0040>] ? put_cred+0x15/0x15
[   23.904991]  [<ffffffff815f6db4>] ? iwlagn_mac_tx+0x19/0x2f
[   23.904995]  [<ffffffff8186cc45>] ? __ieee80211_tx+0x226/0x29b
[   23.904998]  [<ffffffff8186e6bd>] ? ieee80211_tx+0xa6/0xb5
[   23.905001]  [<ffffffff8186e98b>] ? ieee80211_monitor_start_xmit+0x1e9/0x204
[   23.905005]  [<ffffffff8171ce5f>] ? dev_hard_start_xmit+0x271/0x3ec
[   23.905008]  [<ffffffff817351ac>] ? sch_direct_xmit+0x66/0x164
[   23.905010]  [<ffffffff8171d1bf>] ? dev_queue_xmit+0x1e5/0x3c8
[   23.905013]  [<ffffffff817fac5a>] ? packet_sendmsg+0xac5/0xb3d
[   23.905017]  [<ffffffff81709a09>] ? sock_sendmsg+0x37/0x52
[   23.905020]  [<ffffffff810f9e0c>] ? __do_fault+0x338/0x36b
[   23.905023]  [<ffffffff81713820>] ? verify_iovec+0x44/0x94
[   23.905025]  [<ffffffff81709e63>] ? ___sys_sendmsg+0x1f1/0x283
[   23.905029]  [<ffffffff81140a73>] ? __inode_wait_for_writeback+0x67/0xae
[   23.905031]  [<ffffffff8111735e>] ? __cache_free.isra.46+0x178/0x187
[   23.905033]  [<ffffffff811173b1>] ? kmem_cache_free+0x44/0x84
[   23.905036]  [<ffffffff81132c22>] ? dentry_kill+0x13d/0x149
[   23.905038]  [<ffffffff81132f6f>] ? dput+0xe5/0xef
[   23.905041]  [<ffffffff81136e04>] ? fget_light+0x2e/0x7c
[   23.905043]  [<ffffffff8170ae62>] ? __sys_sendmsg+0x39/0x57
[   23.905046]  [<ffffffff818a7e39>] ? system_call_fastpath+0x16/0x1b
[   23.905047] ---[ end trace 1b3eb79359c1d1e6 ]---

--
Sander


^ permalink raw reply

* Re: [PATCH 3.12] mwifiex: fix SDIO interrupt lost issue
From: Daniel Mack @ 2013-10-15 10:38 UTC (permalink / raw)
  To: Bing Zhao, linux-wireless
  Cc: John W. Linville, Sven Neumann, Andreas Fenkart, Dylan Reid,
	Paul Stewart, Amitkumar Karwar
In-Reply-To: <1380304538-2816-1-git-send-email-bzhao@marvell.com>

On 27.09.2013 19:55, Bing Zhao wrote:
> From: Amitkumar Karwar <akarwar@marvell.com>
> 
> 601216e "mwifiex: process RX packets in SDIO IRQ thread directly"
> introduced a command timeout issue which can be reproduced easily on
> an AM33xx platform using a test application written by Daniel Mack:
> 
> https://gist.github.com/zonque/6579314
> 
> mwifiex_main_process() is called from both the SDIO handler and
> the workqueue. In case an interrupt occurs right after the
> int_status check, but before updating the mwifiex_processing flag,
> this interrupt gets lost, resulting in a command timeout and
> consequently a card reset.
> 
> Let main_proc_lock protect both int_status and mwifiex_processing
> flag. This fixes the interrupt lost issue.

John, could you take this patch trough your tree?


Thanks,
Daniel


> 
> Cc: <stable@vger.kernel.org> # 3.7+
> Reported-by: Sven Neumann <s.neumann@raumfeld.com>
> Reported-by: Andreas Fenkart <andreas.fenkart@streamunlimited.com>
> Tested-by: Daniel Mack <zonque@gmail.com>
> Reviewed-by: Dylan Reid <dgreid@chromium.org>
> 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/main.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
> index fd77833..c2b91f5 100644
> --- a/drivers/net/wireless/mwifiex/main.c
> +++ b/drivers/net/wireless/mwifiex/main.c
> @@ -358,10 +358,12 @@ process_start:
>  		}
>  	} while (true);
>  
> -	if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter))
> +	spin_lock_irqsave(&adapter->main_proc_lock, flags);
> +	if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) {
> +		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
>  		goto process_start;
> +	}
>  
> -	spin_lock_irqsave(&adapter->main_proc_lock, flags);
>  	adapter->mwifiex_processing = false;
>  	spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
>  
> 


^ permalink raw reply

* [PATCH] mac80211: fixes for mesh powersave logic
From: Marco Porsch @ 2013-10-15 10:29 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, devel, Marco Porsch

This patch fixes errors in the mesh powersave logic which
cause that remote peers do not get peer power mode change
notifications and mesh peer service periods (MPSPs) got
stuck.

When closing a peer link, set the (now invalid) peer-specific
power mode to 'unknown'.

Avoid overhead when local power mode is unchanged.

Reliably clear MPSP flags on peering status update.

Avoid MPSP flags getting stuck by not requesting a further
MPSP ownership if we already are an MPSP owner.

Signed-off-by: Marco Porsch <marco@cozybit.com>
---
 net/mac80211/cfg.c        |  4 ++--
 net/mac80211/mesh_plink.c |  3 ++-
 net/mac80211/mesh_ps.c    | 33 ++++++++++++++++++---------------
 3 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b0a651c..f1e1944 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1342,8 +1342,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
 				sta->plink_state = params->plink_state;
 
 				ieee80211_mps_sta_status_update(sta);
-				changed |=
-				      ieee80211_mps_local_status_update(sdata);
+				changed |= ieee80211_mps_set_sta_local_pm(sta,
+						NL80211_MESH_POWER_UNKNOWN);
 				break;
 			default:
 				/*  nothing  */
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 6b65d50..4301aa5 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -222,7 +222,8 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta)
 	mesh_path_flush_by_nexthop(sta);
 
 	ieee80211_mps_sta_status_update(sta);
-	changed |= ieee80211_mps_local_status_update(sdata);
+	changed |= ieee80211_mps_set_sta_local_pm(sta,
+			NL80211_MESH_POWER_UNKNOWN);
 
 	return changed;
 }
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c
index 22290a9..0f79b78 100644
--- a/net/mac80211/mesh_ps.c
+++ b/net/mac80211/mesh_ps.c
@@ -152,6 +152,9 @@ u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta,
 {
 	struct ieee80211_sub_if_data *sdata = sta->sdata;
 
+	if (sta->local_pm == pm)
+		return 0;
+
 	mps_dbg(sdata, "local STA operates in mode %d with %pM\n",
 		pm, sta->sta.addr);
 
@@ -245,6 +248,14 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
 
 	do_buffer = (pm != NL80211_MESH_POWER_ACTIVE);
 
+	/* clear the MPSP flags for non-peers or active STA */
+	if (sta->plink_state != NL80211_PLINK_ESTAB) {
+		clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
+		clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT);
+	} else if (!do_buffer) {
+		clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
+	}
+
 	/* Don't let the same PS state be set twice */
 	if (test_sta_flag(sta, WLAN_STA_PS_STA) == do_buffer)
 		return;
@@ -257,14 +268,6 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
 	} else {
 		ieee80211_sta_ps_deliver_wakeup(sta);
 	}
-
-	/* clear the MPSP flags for non-peers or active STA */
-	if (sta->plink_state != NL80211_PLINK_ESTAB) {
-		clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
-		clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT);
-	} else if (!do_buffer) {
-		clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
-	}
 }
 
 static void mps_set_sta_peer_pm(struct sta_info *sta,
@@ -444,8 +447,7 @@ static void mpsp_qos_null_append(struct sta_info *sta,
  */
 static void mps_frame_deliver(struct sta_info *sta, int n_frames)
 {
-	struct ieee80211_sub_if_data *sdata = sta->sdata;
-	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_local *local = sta->sdata->local;
 	int ac;
 	struct sk_buff_head frames;
 	struct sk_buff *skb;
@@ -558,10 +560,10 @@ void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta,
 }
 
 /**
- * ieee80211_mps_frame_release - release buffered frames in response to beacon
+ * ieee80211_mps_frame_release - release frames buffered due to mesh power save
  *
  * @sta: mesh STA
- * @elems: beacon IEs
+ * @elems: IEs of beacon or probe response
  *
  * For peers if we have individually-addressed frames buffered or the peer
  * indicates buffered frames, send a corresponding MPSP trigger frame. Since
@@ -588,9 +590,10 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
 	    (!elems->awake_window || !le16_to_cpu(*elems->awake_window)))
 		return;
 
-	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-		buffer_local += skb_queue_len(&sta->ps_tx_buf[ac]) +
-				skb_queue_len(&sta->tx_filtered[ac]);
+	if (!test_sta_flag(sta, WLAN_STA_MPSP_OWNER))
+		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+			buffer_local += skb_queue_len(&sta->ps_tx_buf[ac]) +
+					skb_queue_len(&sta->tx_filtered[ac]);
 
 	if (!has_buffered && !buffer_local)
 		return;
-- 
1.8.1.2


^ permalink raw reply related

* Re: [PATCH] cfg80211: fix channel to frequency mapping in 5.9GHz range
From: Dennis H Jensen @ 2013-10-15  9:40 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1381763193.13092.19.camel@jlt4.sipsolutions.net>

On Mon, 2013-10-14 at 17:06 +0200, Johannes Berg wrote:
> On Mon, 2013-10-14 at 16:58 +0200, Dennis H Jensen wrote:
> 
> > > > The commit 59eb21a6504731fc16db4cf9463065dd61093e08 moved those channels
> > > > to 4.9 GHz but left a hole in the 5.9 Ghz range.
> > > 
> > > But there was no +/- 15 before, so what gives?
> > 
> > Well no :) but there also wasn't a special case for that particular
> > channel set (182 - 196).
> 
> Yes, but then before 5910 would have been channel 182. Now you're making
> it channel 197. That doesn't really make sense at all.

OK, fair enough, but the fact is that there is a hole in the frequencies
that were added in 802.11p.

> > In case that doesn't do it. What is needed to get channel 182 to be 5910
> > MHz as Annex E defines for the US and Europe? Channel to frequency
> > mapping based on operating class?
> 
> Annex E is the 802.11 spec, to get something into that ...

You misunderstood me; the European operating class 14, for example,
states that channel 182 is to be 5910.

Best regards,
Dennis



^ permalink raw reply

* [PATCH 2/2] ath10k: return better errno for unsupported pdev params
From: Bartosz Markowski @ 2013-10-15  7:55 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Bartosz Markowski
In-Reply-To: <1381823732-10128-1-git-send-email-bartosz.markowski@tieto.com>

Return -EOPNOTSUPP if given parameter is not supported by firmware.

Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>
---
 drivers/net/wireless/ath/ath10k/wmi.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index ea2669b..b28bd2d3 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2119,7 +2119,7 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
 
 	if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
 		ath10k_warn("pdev param %d not supported by firmware\n", id);
-		return -EINVAL;
+		return -EOPNOTSUPP;
 	}
 
 	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
-- 
1.7.10


^ permalink raw reply related

* [PATCH 1/2] ath10k: rename WMI_CMD_UNDEFINED
From: Bartosz Markowski @ 2013-10-15  7:55 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Bartosz Markowski

Rename WMI_CMD_UNDEFINED to WMI_CMD_UNSUPPORTED. This is more
accurate here. Also return -EOPNOTSUPP instead of -EINVAL in
wmi_cmd_send().

Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>
---
 drivers/net/wireless/ath/ath10k/wmi.c |   46 ++++++++++++++++-----------------
 drivers/net/wireless/ath/ath10k/wmi.h |    2 +-
 2 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index f9766fa..ea2669b 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -149,7 +149,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
 	.start_scan_cmdid = WMI_10X_START_SCAN_CMDID,
 	.stop_scan_cmdid = WMI_10X_STOP_SCAN_CMDID,
 	.scan_chan_list_cmdid = WMI_10X_SCAN_CHAN_LIST_CMDID,
-	.scan_sch_prio_tbl_cmdid = WMI_CMD_UNDEFINED,
+	.scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
 	.pdev_set_regdomain_cmdid = WMI_10X_PDEV_SET_REGDOMAIN_CMDID,
 	.pdev_set_channel_cmdid = WMI_10X_PDEV_SET_CHANNEL_CMDID,
 	.pdev_set_param_cmdid = WMI_10X_PDEV_SET_PARAM_CMDID,
@@ -182,11 +182,11 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
 	.peer_mcast_group_cmdid = WMI_10X_PEER_MCAST_GROUP_CMDID,
 	.bcn_tx_cmdid = WMI_10X_BCN_TX_CMDID,
 	.pdev_send_bcn_cmdid = WMI_10X_PDEV_SEND_BCN_CMDID,
-	.bcn_tmpl_cmdid = WMI_CMD_UNDEFINED,
+	.bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
 	.bcn_filter_rx_cmdid = WMI_10X_BCN_FILTER_RX_CMDID,
 	.prb_req_filter_rx_cmdid = WMI_10X_PRB_REQ_FILTER_RX_CMDID,
 	.mgmt_tx_cmdid = WMI_10X_MGMT_TX_CMDID,
-	.prb_tmpl_cmdid = WMI_CMD_UNDEFINED,
+	.prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
 	.addba_clear_resp_cmdid = WMI_10X_ADDBA_CLEAR_RESP_CMDID,
 	.addba_send_cmdid = WMI_10X_ADDBA_SEND_CMDID,
 	.addba_status_cmdid = WMI_10X_ADDBA_STATUS_CMDID,
@@ -211,9 +211,9 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
 	.p2p_dev_set_discoverability = WMI_10X_P2P_DEV_SET_DISCOVERABILITY,
 	.p2p_go_set_beacon_ie = WMI_10X_P2P_GO_SET_BEACON_IE,
 	.p2p_go_set_probe_resp_ie = WMI_10X_P2P_GO_SET_PROBE_RESP_IE,
-	.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNDEFINED,
-	.ap_ps_peer_param_cmdid = WMI_CMD_UNDEFINED,
-	.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNDEFINED,
+	.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
+	.ap_ps_peer_param_cmdid = WMI_CMD_UNSUPPORTED,
+	.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
 	.peer_rate_retry_sched_cmdid = WMI_10X_PEER_RATE_RETRY_SCHED_CMDID,
 	.wlan_profile_trigger_cmdid = WMI_10X_WLAN_PROFILE_TRIGGER_CMDID,
 	.wlan_profile_set_hist_intvl_cmdid =
@@ -242,25 +242,25 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
 	.vdev_spectral_scan_enable_cmdid =
 				WMI_10X_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
 	.request_stats_cmdid = WMI_10X_REQUEST_STATS_CMDID,
-	.set_arp_ns_offload_cmdid = WMI_CMD_UNDEFINED,
-	.network_list_offload_config_cmdid = WMI_CMD_UNDEFINED,
-	.gtk_offload_cmdid = WMI_CMD_UNDEFINED,
-	.csa_offload_enable_cmdid = WMI_CMD_UNDEFINED,
-	.csa_offload_chanswitch_cmdid = WMI_CMD_UNDEFINED,
-	.chatter_set_mode_cmdid = WMI_CMD_UNDEFINED,
-	.peer_tid_addba_cmdid = WMI_CMD_UNDEFINED,
-	.peer_tid_delba_cmdid = WMI_CMD_UNDEFINED,
-	.sta_dtim_ps_method_cmdid = WMI_CMD_UNDEFINED,
-	.sta_uapsd_auto_trig_cmdid = WMI_CMD_UNDEFINED,
-	.sta_keepalive_cmd = WMI_CMD_UNDEFINED,
+	.set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
+	.network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
+	.gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
+	.csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
+	.csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
+	.chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
+	.peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
+	.peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
+	.sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
+	.sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
+	.sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
 	.echo_cmdid = WMI_10X_ECHO_CMDID,
 	.pdev_utf_cmdid = WMI_10X_PDEV_UTF_CMDID,
 	.dbglog_cfg_cmdid = WMI_10X_DBGLOG_CFG_CMDID,
 	.pdev_qvit_cmdid = WMI_10X_PDEV_QVIT_CMDID,
-	.pdev_ftm_intg_cmdid = WMI_CMD_UNDEFINED,
-	.vdev_set_keepalive_cmdid = WMI_CMD_UNDEFINED,
-	.vdev_get_keepalive_cmdid = WMI_CMD_UNDEFINED,
-	.force_fw_hang_cmdid = WMI_CMD_UNDEFINED,
+	.pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
+	.vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+	.vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+	.force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
 	.gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID,
 	.gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID,
 };
@@ -611,9 +611,9 @@ static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar)
 static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
 			       u32 cmd_id)
 {
-	int ret = -EINVAL;
+	int ret = -EOPNOTSUPP;
 
-	if (cmd_id == WMI_CMD_UNDEFINED) {
+	if (cmd_id == WMI_CMD_UNSUPPORTED) {
 		ath10k_warn("wmi command %d is not supported by firmware\n",
 			    cmd_id);
 		return ret;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 7692c14..78c991a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -359,7 +359,7 @@ enum wmi_cmd_group {
 #define WMI_CMD_GRP(grp_id) (((grp_id) << 12) | 0x1)
 #define WMI_EVT_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1)
 
-#define WMI_CMD_UNDEFINED 0
+#define WMI_CMD_UNSUPPORTED 0
 
 /* Command IDs and command events for MAIN FW. */
 enum wmi_cmd_id {
-- 
1.7.10


^ permalink raw reply related

* Lower throughput in Ad-hoc than in Infrastructure mode?
From: Floris Van den Abeele @ 2013-10-15  7:28 UTC (permalink / raw)
  To: linux-wireless

While running throughput experiments using iperf I noticed that UDP
throughput in ad-hoc mode was considerably lower than in Infrastructure
mode. The setups I'm comparing is a 802.11a ad-hoc network consisting of
two clients vs a 802.11a infrastructure network consisting of an access
point and a client (11a because the tests were run in the 5GHz band).

For ad-hoc mode I'm consistenly seeing a lower throughput than for
infrastructure mode: i.e. 22.4 Mbits/sec vs 28.2 Mbits/sec. Note that
while sniffing the medium radiotap headers report a PHY data rate of
54Mbit/s in both cases. There is no other traffic on the Wi-Fi channel
in question (44). Considering the medium access for both setups is
similair I would expect to find similair throughputs. Is this a known
issue with the linux wireless/mac80211/ath9k driver stack or is this
behaviour conform the 802.11 standard (based on my knowledge I would say
no to the latter)? My test specs are below.

For testing I'm using Sparklan WPEA-111N NIC's (AR9280). The nodes are
running OpenWrt attitude adjusment on r32482 (from 2012-06-21) with the
REGD patch enabled. I believe that this build of OpenWRT uses the
compat-wireless-2012-06-14.tar.bz2 drivers.

Kind regards,
Floris

-- 
Floris Van den Abeele
Department of Information Technology
Internet Based Communication Networks and Services (IBCN)
Ghent University - iMinds
Gaston Crommenlaan 8 (Bus 201), B-9050 Gent, Belgium
M: +32 (0)494 24 92 76
E: floris.vandenabeele@intec.UGent.be
W : www.ibcn.intec.UGent.be


^ permalink raw reply

* [PATCH v2] ath10k: do not warn about unsupported vdev param
From: Bartosz Markowski @ 2013-10-15  7:26 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Bartosz Markowski

10.X firmware does not support WMI_VDEV_PARAM_TX_ENCAP_TYPE.
It's a known limitation and we should not warn about this.

Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>
---
 drivers/net/wireless/ath/ath10k/mac.c |    3 ++-
 drivers/net/wireless/ath/ath10k/wmi.c |    2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 049eca2..97d7111 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2085,7 +2085,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 	vdev_param = ar->wmi.vdev_param->tx_encap_type;
 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
 					ATH10K_HW_TXRX_NATIVE_WIFI);
-	if (ret)
+	/* 10.X firmware does not support this VDEV parameter. Do not warn */
+	if (ret && ret != -EOPNOTSUPP)
 		ath10k_warn("Failed to set TX encap: %d\n", ret);
 
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index f9766fa..fa07388 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2763,7 +2763,7 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
 		ath10k_dbg(ATH10K_DBG_WMI,
 			   "vdev param %d not supported by firmware\n",
 			    param_id);
-		return -EINVAL;
+		return -EOPNOTSUPP;
 	}
 
 	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
-- 
1.7.10


^ permalink raw reply related

* [PATCH v5 5/5] mac80211: process mesh channel switching using beacon
From: Chun-Yeow Yeoh @ 2013-10-15  2:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1381802911-3921-1-git-send-email-yeohchunyeow@cozybit.com>

Trigger the mesh channel switching procedure if the mesh STA
happens to miss the CSA action frame but able to receive the
beacon containing the CSA and MCSP elements from its peer
mesh STAs.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: fix return value (Johannes Berg)

 net/mac80211/mesh.c      |  132 +++++++++++++++++++++++++++++++++++++++++++---
 net/mac80211/spectmgmt.c |    6 +++
 2 files changed, 130 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 50b1863..35c4147 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -850,6 +850,124 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 	ieee80211_configure_filter(local);
 }
 
+static bool
+ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
+				 struct ieee802_11_elems *elems, bool beacon)
+{
+	struct cfg80211_csa_settings params;
+	struct ieee80211_csa_ie csa_ie;
+	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_chanctx *chanctx;
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
+	int err, num_chanctx;
+	u32 sta_flags;
+
+	if (sdata->vif.csa_active)
+		return true;
+
+	if (!ifmsh->mesh_id)
+		return false;
+
+	sta_flags = IEEE80211_STA_DISABLE_VHT;
+	switch (sdata->vif.bss_conf.chandef.width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		sta_flags |= IEEE80211_STA_DISABLE_HT;
+	case NL80211_CHAN_WIDTH_20:
+		sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+		break;
+	default:
+		break;
+	}
+
+	memset(&params, 0, sizeof(params));
+	memset(&csa_ie, 0, sizeof(csa_ie));
+	err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band,
+					   sta_flags, sdata->vif.addr,
+					   &csa_ie);
+	if (err < 0)
+		return false;
+	if (err)
+		return false;
+
+	params.chandef = csa_ie.chandef;
+	params.count = csa_ie.count;
+
+	if (sdata->vif.bss_conf.chandef.chan->band !=
+	    params.chandef.chan->band)
+		return false;
+
+	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
+				     IEEE80211_CHAN_DISABLED)) {
+		sdata_info(sdata,
+			   "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
+			   sdata->vif.addr,
+			   params.chandef.chan->center_freq,
+			   params.chandef.width,
+			   params.chandef.center_freq1,
+			   params.chandef.center_freq2);
+		return false;
+	}
+
+	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
+					    &params.chandef);
+	if (err < 0)
+		return false;
+	if (err) {
+		params.radar_required = true;
+		/* TODO: DFS not (yet) supported */
+		return false;
+	}
+
+	rcu_read_lock();
+	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+	if (!chanctx_conf)
+		goto failed_chswitch;
+
+	/* don't handle for multi-VIF cases */
+	chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+	if (chanctx->refcount > 1)
+		goto failed_chswitch;
+
+	num_chanctx = 0;
+	list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
+		num_chanctx++;
+
+	if (num_chanctx > 1)
+		goto failed_chswitch;
+
+	rcu_read_unlock();
+
+	mcsa_dbg(sdata,
+		 "received channel switch announcement to go to channel %d MHz\n",
+		 params.chandef.chan->center_freq);
+
+	params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
+	if (beacon)
+		ifmsh->chsw_ttl = csa_ie.ttl - 1;
+
+	if (ifmsh->chsw_ttl > 0)
+		ieee80211_mesh_csa_beacon(sdata, &params, false);
+
+	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;
+failed_chswitch:
+	rcu_read_unlock();
+	return false;
+}
+
 static void
 ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
 			    struct ieee80211_mgmt *mgmt, size_t len)
@@ -956,6 +1074,9 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 	if (ifmsh->sync_ops)
 		ifmsh->sync_ops->rx_bcn_presp(sdata,
 			stype, mgmt, &elems, rx_status);
+
+	if (!ifmsh->chsw_init)
+		ieee80211_mesh_process_chnswitch(sdata, &elems, true);
 }
 
 int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
@@ -1051,7 +1172,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct ieee802_11_elems elems;
 	u16 pre_value;
-	bool block_tx, fwd_csa = true;
+	bool fwd_csa = true;
 	size_t baselen;
 	u8 *pos, ttl;
 
@@ -1080,13 +1201,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
 			mcsa_dbg(sdata, "Failed to forward the CSA frame");
 	}
 
-	/* block the Tx only after forwarding the CSA frame if required */
-	block_tx = elems.mesh_chansw_params_ie->mesh_flags &
-		   WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
-	if (block_tx)
-		ieee80211_stop_queues_by_reason(&sdata->local->hw,
-				IEEE80211_MAX_QUEUE_MAP,
-				IEEE80211_QUEUE_STOP_REASON_CSA);
+	if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false))
+		mcsa_dbg(sdata, "Failed to process CSA action frame");
 }
 
 static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index a298e12..a40da20 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -74,6 +74,12 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
 		return 1;
 	}
 
+	/* Mesh Channel Switch Parameters Element */
+	if (elems->mesh_chansw_params_ie) {
+		csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl;
+		csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags;
+	}
+
 	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) {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v5 1/5] mac80211: process the CSA frame for mesh accordingly
From: Chun-Yeow Yeoh @ 2013-10-15  2:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1381802911-3921-1-git-send-email-yeohchunyeow@cozybit.com>

Process the CSA frame according to the procedures define in IEEE Std
802.11-2012 section 10.9.8.4.3 as follow:
* The mesh channel switch parameters element (MCSP) must be availabe.
* If the MCSP's TTL is 1, drop the frame but still process the CSA.
* If the MCSP's precedence value is less than or equal to the current
  precedence value, drop the frame and do not process the CSA.
* The CSA frame is forwarded after TTL is decremented by 1 and the
  initiator field is set to 0. Transmit restrict field and others
  are maintained as is.
* No beacon or probe response frame are handled here.

Also, introduce the debug message used for mesh CSA purpose.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: fix return value, typo and others (Johannes Berg)

 include/linux/ieee80211.h  |   20 +++++++++++
 net/mac80211/Kconfig       |   11 ++++++
 net/mac80211/debug.h       |   10 ++++++
 net/mac80211/ieee80211_i.h |    4 +++
 net/mac80211/mesh.c        |   83 ++++++++++++++++++++++++++++++++++++++++++--
 net/mac80211/util.c        |    9 +++++
 6 files changed, 134 insertions(+), 3 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 23a8877..f117427 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -696,6 +696,18 @@ struct ieee80211_sec_chan_offs_ie {
 } __packed;
 
 /**
+ * struct ieee80211_mesh_chansw_params_ie - mesh channel switch parameters IE
+ *
+ * This structure represents the "Mesh Channel Switch Paramters element"
+ */
+struct ieee80211_mesh_chansw_params_ie {
+	u8 mesh_ttl;
+	u8 mesh_flags;
+	__le16 mesh_reason;
+	__le16 mesh_pre_value;
+} __packed;
+
+/**
  * struct ieee80211_wide_bw_chansw_ie - wide bandwidth channel switch IE
  */
 struct ieee80211_wide_bw_chansw_ie {
@@ -750,6 +762,14 @@ enum mesh_config_capab_flags {
 };
 
 /**
+ * mesh channel switch parameters element's flag indicator
+ *
+ */
+#define WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT BIT(0)
+#define WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR BIT(1)
+#define WLAN_EID_CHAN_SWITCH_PARAM_REASON BIT(2)
+
+/**
  * struct ieee80211_rann_ie
  *
  * This structure refers to "Root Announcement information element"
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 62535fe..bf1871e 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -258,6 +258,17 @@ config MAC80211_MESH_SYNC_DEBUG
 
 	  Do not select this option.
 
+config MAC80211_MESH_CSA_DEBUG
+	bool "Verbose mesh channel switch debugging"
+	depends on MAC80211_DEBUG_MENU
+	depends on MAC80211_MESH
+	---help---
+	  Selecting this option causes mac80211 to print out very verbose mesh
+	  channel switch debugging messages (when mac80211 is taking part in a
+	  mesh network).
+
+	  Do not select this option.
+
 config MAC80211_MESH_PS_DEBUG
 	bool "Verbose mesh powersave debugging"
 	depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 4ccc5ed..493d680 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -44,6 +44,12 @@
 #define MAC80211_MESH_SYNC_DEBUG 0
 #endif
 
+#ifdef CONFIG_MAC80211_MESH_CSA_DEBUG
+#define MAC80211_MESH_CSA_DEBUG 1
+#else
+#define MAC80211_MESH_CSA_DEBUG 0
+#endif
+
 #ifdef CONFIG_MAC80211_MESH_PS_DEBUG
 #define MAC80211_MESH_PS_DEBUG 1
 #else
@@ -157,6 +163,10 @@ do {									\
 	_sdata_dbg(MAC80211_MESH_SYNC_DEBUG,				\
 		   sdata, fmt, ##__VA_ARGS__)
 
+#define mcsa_dbg(sdata, fmt, ...)					\
+	_sdata_dbg(MAC80211_MESH_CSA_DEBUG,				\
+		   sdata, fmt, ##__VA_ARGS__)
+
 #define mps_dbg(sdata, fmt, ...)					\
 	_sdata_dbg(MAC80211_MESH_PS_DEBUG,				\
 		   sdata, fmt, ##__VA_ARGS__)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3a87c89..7f13b65 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -598,6 +598,9 @@ struct ieee80211_if_mesh {
 	int ps_peers_light_sleep;
 	int ps_peers_deep_sleep;
 	struct ps_data ps;
+	/* Channel Switching Support */
+	bool chsw_init;
+	u16 pre_value;
 };
 
 #ifdef CONFIG_MAC80211_MESH
@@ -1239,6 +1242,7 @@ struct ieee802_11_elems {
 	const struct ieee80211_timeout_interval_ie *timeout_int;
 	const u8 *opmode_notif;
 	const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
+	const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
 
 	/* length of them, respectively */
 	u8 ssid_len;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 707ac61..0a3ccaa 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -920,6 +920,82 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 			stype, mgmt, &elems, rx_status);
 }
 
+static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
+			       struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct ieee80211_mgmt *mgmt_fwd;
+	struct sk_buff *skb;
+	struct ieee80211_local *local = sdata->local;
+	u8 *pos = mgmt->u.action.u.chan_switch.variable;
+	size_t offset_ttl;
+
+	skb = dev_alloc_skb(local->tx_headroom + len);
+	if (!skb)
+		return -ENOMEM;
+	skb_reserve(skb, local->tx_headroom);
+	mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
+
+	/* offset_ttl is based on whether the secondary channel
+	 * offset is available or not. Substract 1 from the mesh TTL
+	 * and disable the initiator flag before forwarding.
+	 */
+	offset_ttl = (len < 42) ? 7 : 10;
+	*(pos + offset_ttl) -= 1;
+	*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+
+	memcpy(mgmt_fwd, mgmt, len);
+	eth_broadcast_addr(mgmt_fwd->da);
+	memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
+	memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
+
+	ieee80211_tx_skb(sdata, skb);
+	return 0;
+}
+
+static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
+			      struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee802_11_elems elems;
+	u16 pre_value;
+	bool block_tx, fwd_csa = true;
+	size_t baselen;
+	u8 *pos, ttl;
+
+	if (mgmt->u.action.u.measurement.action_code !=
+	    WLAN_ACTION_SPCT_CHL_SWITCH)
+		return;
+
+	pos = mgmt->u.action.u.chan_switch.variable;
+	baselen = offsetof(struct ieee80211_mgmt,
+			   u.action.u.chan_switch.variable);
+	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
+
+	ttl = elems.mesh_chansw_params_ie->mesh_ttl;
+	if (!--ttl)
+		fwd_csa = false;
+
+	pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
+	if (ifmsh->pre_value >= pre_value)
+		return;
+
+	ifmsh->pre_value = pre_value;
+
+	/* forward or re-broadcast the CSA frame */
+	if (fwd_csa) {
+		if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
+			mcsa_dbg(sdata, "Failed to forward the CSA frame");
+	}
+
+	/* block the Tx only after forwarding the CSA frame if required */
+	block_tx = elems.mesh_chansw_params_ie->mesh_flags &
+		   WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
+	if (block_tx)
+		ieee80211_stop_queues_by_reason(&sdata->local->hw,
+				IEEE80211_MAX_QUEUE_MAP,
+				IEEE80211_QUEUE_STOP_REASON_CSA);
+}
+
 static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
 					  struct ieee80211_mgmt *mgmt,
 					  size_t len,
@@ -939,6 +1015,9 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
 		if (mesh_action_is_path_sel(mgmt))
 			mesh_rx_path_sel_frame(sdata, mgmt, len);
 		break;
+	case WLAN_CATEGORY_SPECTRUM_MGMT:
+		mesh_rx_csa_frame(sdata, mgmt, len);
+		break;
 	}
 }
 
@@ -1056,13 +1135,11 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
 		    (unsigned long) sdata);
 
 	ifmsh->accepting_plinks = true;
-	ifmsh->preq_id = 0;
-	ifmsh->sn = 0;
-	ifmsh->num_gates = 0;
 	atomic_set(&ifmsh->mpaths, 0);
 	mesh_rmc_init(sdata);
 	ifmsh->last_preq = jiffies;
 	ifmsh->next_perr = jiffies;
+	ifmsh->chsw_init = false;
 	/* Allocate all mesh structures when creating the first mesh interface. */
 	if (!mesh_allocated)
 		ieee80211s_init();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3c8283b..133667c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -743,6 +743,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 		case WLAN_EID_TIMEOUT_INTERVAL:
 		case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
 		case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
+		case WLAN_EID_CHAN_SWITCH_PARAM:
 		/*
 		 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
 		 * that if the content gets bigger it might be needed more than once
@@ -908,6 +909,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 			}
 			elems->sec_chan_offs = (void *)pos;
 			break;
+		case WLAN_EID_CHAN_SWITCH_PARAM:
+			if (elen !=
+			    sizeof(*elems->mesh_chansw_params_ie)) {
+				elem_parse_failed = true;
+				break;
+			}
+			elems->mesh_chansw_params_ie = (void *)pos;
+			break;
 		case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
 			if (!action ||
 			    elen != sizeof(*elems->wide_bw_chansw_ie)) {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v5 4/5] {nl,cfg,mac}80211: implement mesh channel switch userspace API
From: Chun-Yeow Yeoh @ 2013-10-15  2:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1381802911-3921-1-git-send-email-yeohchunyeow@cozybit.com>

Implement the required procedures for mesh channel switching as defined
in the IEEE Std 802.11-2012 section 10.9.8.4.3 and also handle the CSA
and MCSP elements as followed:
 * Add the function for updating the beacon and probe response frames
   with CSA and MCSP elements during the period of switching to the new
   channel. Both CSA and MCSP elements must be included in beacon and
   probe response frames until the intended channel switch time.
 * The ifmsh->csa_settings is set to NULL and the CSA and MCSP elements
   will then be removed from the beacon or probe response frames once the
   new channel is switched to.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: fix typo mistake, commit message and return value (Johannes Berg)
v3: use RCU to protect csa_settings for beaconing (Johannes Berg)
v4: fix broken kfree with kree_rcu (Johannes Berg)
v5: introduce wrapper struct for rcu purpose and fix sparse warning 
    on symbol 'ifmsh' warning(Johannes Berg)

 net/mac80211/cfg.c         |    7 +++-
 net/mac80211/ieee80211_i.h |   11 ++++++
 net/mac80211/mesh.c        |   93 ++++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/rx.c          |    5 ++-
 net/mac80211/tx.c          |   16 ++++++++
 net/wireless/nl80211.c     |    3 +-
 6 files changed, 132 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 438c689..a0b41d7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2887,6 +2887,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
 	case NL80211_IFTYPE_ADHOC:
 		ieee80211_ibss_finish_csa(sdata);
 		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		err = ieee80211_mesh_finish_csa(sdata);
+		if (err < 0)
+			return;
+		break;
 	default:
 		WARN_ON(1);
 		return;
@@ -3005,7 +3010,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		    params->chandef.chan->band)
 			return -EINVAL;
 
-		err = ieee80211_send_action_csa(sdata, params);
+		err = ieee80211_mesh_csa_beacon(sdata, params, true);
 		if (err < 0)
 			return err;
 		break;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3a6d2e7..2c0b477 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -538,6 +538,11 @@ struct ieee80211_mesh_sync_ops {
 	/* add other framework functions here */
 };
 
+struct mesh_csa_settings {
+	struct rcu_head rcu_head;
+	struct cfg80211_csa_settings settings;
+};
+
 struct ieee80211_if_mesh {
 	struct timer_list housekeeping_timer;
 	struct timer_list mesh_path_timer;
@@ -599,7 +604,9 @@ struct ieee80211_if_mesh {
 	int ps_peers_deep_sleep;
 	struct ps_data ps;
 	/* Channel Switching Support */
+	struct mesh_csa_settings __rcu *csa;
 	bool chsw_init;
+	u8 chsw_ttl;
 	u16 pre_value;
 };
 
@@ -1351,6 +1358,10 @@ void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
 void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 				   struct sk_buff *skb);
+int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
+			      struct cfg80211_csa_settings *csa_settings,
+			      bool csa_action);
+int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
 
 /* scan/BSS handling */
 void ieee80211_scan_work(struct work_struct *work);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0a3ccaa..50b1863 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -12,6 +12,7 @@
 #include <asm/unaligned.h>
 #include "ieee80211_i.h"
 #include "mesh.h"
+#include "driver-ops.h"
 
 static int mesh_allocated;
 static struct kmem_cache *rm_cache;
@@ -610,6 +611,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct mesh_csa_settings *csa;
 	enum ieee80211_band band;
 	u8 *pos;
 	struct ieee80211_sub_if_data *sdata;
@@ -624,6 +626,10 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 
 	head_len = hdr_len +
 		   2 + /* NULL SSID */
+		   /* Channel Switch Announcement */
+		   2 + sizeof(struct ieee80211_channel_sw_ie) +
+		   /* Mesh Channel Swith Parameters */
+		   2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
 		   2 + 8 + /* supported rates */
 		   2 + 3; /* DS params */
 	tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
@@ -665,6 +671,38 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 	*pos++ = WLAN_EID_SSID;
 	*pos++ = 0x0;
 
+	rcu_read_lock();
+	csa = rcu_dereference(ifmsh->csa);
+	if (csa) {
+		__le16 pre_value;
+
+		pos = skb_put(skb, 13);
+		memset(pos, 0, 13);
+		*pos++ = WLAN_EID_CHANNEL_SWITCH;
+		*pos++ = 3;
+		*pos++ = 0x0;
+		*pos++ = ieee80211_frequency_to_channel(
+				csa->settings.chandef.chan->center_freq);
+		sdata->csa_counter_offset_beacon = hdr_len + 6;
+		*pos++ = csa->settings.count;
+		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
+		*pos++ = 6;
+		if (ifmsh->chsw_init) {
+			*pos++ = ifmsh->mshcfg.dot11MeshTTL;
+			*pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+		} else {
+			*pos++ = ifmsh->chsw_ttl;
+		}
+		*pos++ |= csa->settings.block_tx ?
+			  WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
+		put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
+		pos += 2;
+		pre_value = cpu_to_le16(ifmsh->pre_value);
+		memcpy(pos, &pre_value, 2);
+		pos += 2;
+	}
+	rcu_read_unlock();
+
 	if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
 	    mesh_add_ds_params_ie(sdata, skb))
 		goto out_free;
@@ -920,6 +958,60 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 			stype, mgmt, &elems, rx_status);
 }
 
+int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct mesh_csa_settings *tmp_csa_settings;
+	int ret = 0;
+
+	/* Remove the CSA and MCSP elements from the beacon */
+	tmp_csa_settings = rcu_dereference(ifmsh->csa);
+	rcu_assign_pointer(ifmsh->csa, NULL);
+	kfree_rcu(tmp_csa_settings, rcu_head);
+	ret = ieee80211_mesh_rebuild_beacon(sdata);
+	if (ret)
+		return -EINVAL;
+
+	/* Reset the TTL value and Initiator flag */
+	ifmsh->chsw_init = false;
+	ifmsh->chsw_ttl = 0;
+
+	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+
+	mcsa_dbg(sdata, "complete switching to center freq %d MHz",
+		 sdata->vif.bss_conf.chandef.chan->center_freq);
+	return 0;
+}
+
+int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
+			      struct cfg80211_csa_settings *csa_settings,
+			      bool csa_action)
+{
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct mesh_csa_settings *tmp_csa_settings;
+	int ret = 0;
+
+	if (csa_action)
+		ieee80211_send_action_csa(sdata, csa_settings);
+
+	tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
+				   GFP_ATOMIC);
+	if (!tmp_csa_settings)
+		return -ENOMEM;
+
+	memcpy(&tmp_csa_settings->settings, csa_settings,
+	       sizeof(struct cfg80211_csa_settings));
+
+	rcu_assign_pointer(ifmsh->csa, tmp_csa_settings);
+
+	ret = ieee80211_mesh_rebuild_beacon(sdata);
+	if (ret)
+		return -EINVAL;
+
+	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+	return 0;
+}
+
 static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
 			       struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -942,6 +1034,7 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
 	offset_ttl = (len < 42) ? 7 : 10;
 	*(pos + offset_ttl) -= 1;
 	*(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+	sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
 
 	memcpy(mgmt_fwd, mgmt, len);
 	eth_broadcast_addr(mgmt_fwd->da);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8e908e1..0ba1fad 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2592,13 +2592,16 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 				break;
 
 			if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-			    sdata->vif.type != NL80211_IFTYPE_ADHOC)
+			    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+			    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
 				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 if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+				bssid = mgmt->sa;
 			else
 				break;
 
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4fcbf63..80b9a57 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2369,6 +2369,10 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
 		beacon_data = beacon->head;
 		beacon_data_len = beacon->head_len;
 		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		beacon_data = beacon->head;
+		beacon_data_len = beacon->head_len;
+		break;
 	default:
 		return;
 	}
@@ -2425,6 +2429,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
 
 		beacon_data = beacon->head;
 		beacon_data_len = beacon->head_len;
+	} else if (vif->type == NL80211_IFTYPE_MESH_POINT) {
+		struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+		beacon = rcu_dereference(ifmsh->beacon);
+		if (!beacon)
+			goto out;
+
+		beacon_data = beacon->head;
+		beacon_data_len = beacon->head_len;
 	} else {
 		WARN_ON(1);
 		goto out;
@@ -2530,6 +2543,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 		if (!bcn)
 			goto out;
 
+		if (sdata->vif.csa_active)
+			ieee80211_update_csa(sdata, bcn);
+
 		if (ifmsh->sync_ops)
 			ifmsh->sync_ops->adjust_tbtt(
 						sdata);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7bb5aca..be844d4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10760,7 +10760,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
 
 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
 		    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
-		    wdev->iftype != NL80211_IFTYPE_ADHOC))
+		    wdev->iftype != NL80211_IFTYPE_ADHOC &&
+		    wdev->iftype != NL80211_IFTYPE_MESH_POINT))
 		goto out;
 
 	wdev->channel = chandef->chan;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v5 3/5] mac80211: refactor the parsing of chan switch ie
From: Chun-Yeow Yeoh @ 2013-10-15  2:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1381802911-3921-1-git-send-email-yeohchunyeow@cozybit.com>

Refactor the channel switch IE parsing to reduce the number
of function parameters.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v3: refactor ieee80211_parse_ch_switch_ie to have less function
    parameters (Johannes Berg)

 net/mac80211/ibss.c        |   13 +++++++------
 net/mac80211/ieee80211_i.h |   17 ++++++++++++-----
 net/mac80211/mlme.c        |   32 +++++++++++++++-----------------
 net/mac80211/spectmgmt.c   |   27 ++++++++++++++-------------
 4 files changed, 48 insertions(+), 41 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 017e206..d6b80ef 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -730,13 +730,13 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 				  bool beacon)
 {
 	struct cfg80211_csa_settings params;
+	struct ieee80211_csa_ie csa_ie;
 	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;
@@ -759,12 +759,10 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 
 	memset(&params, 0, sizeof(params));
+	memset(&csa_ie, 0, sizeof(csa_ie));
 	err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
 					   ifibss->chandef.chan->band,
-					   sta_flags, ifibss->bssid,
-					   &params.count, &mode,
-					   &params.chandef);
-
+					   sta_flags, ifibss->bssid, &csa_ie);
 	/* can't switch to destination channel, fail */
 	if (err < 0)
 		goto disconnect;
@@ -773,6 +771,9 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	if (err)
 		return false;
 
+	params.count = csa_ie.count;
+	params.chandef = csa_ie.chandef;
+
 	if (ifibss->chandef.chan->band != params.chandef.chan->band)
 		goto disconnect;
 
@@ -859,7 +860,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		 "received channel switch announcement to go to channel %d MHz\n",
 		 params.chandef.chan->center_freq);
 
-	params.block_tx = !!mode;
+	params.block_tx = !!csa_ie.mode;
 
 	ieee80211_ibss_csa_beacon(sdata, &params);
 	sdata->csa_radar_required = params.radar_required;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 829ff7e..3a6d2e7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1206,6 +1206,14 @@ struct ieee80211_ra_tid {
 	u16 tid;
 };
 
+/* this struct holds the value parsing from channel switch IE  */
+struct ieee80211_csa_ie {
+	struct cfg80211_chan_def chandef;
+	u8 mode;
+	u8 count;
+	u8 ttl;
+};
+
 /* Parsed Information Elements */
 struct ieee802_11_elems {
 	const u8 *ie_start;
@@ -1501,17 +1509,16 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
  *	%IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,
  *	%IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,
  *	%IEEE80211_STA_DISABLE_160MHZ.
- * @count: to be filled with the counter until the switch (on success only)
  * @bssid: the currently connected bssid (for reporting)
- * @mode: to be filled with CSA mode (on success only)
- * @new_chandef: to be filled with destination chandef (on success only)
+ * @csa_ie: parsed 802.11 csa elements on count, mode, chandef and mesh ttl.
+	All of them will be filled with if 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 *bssid, u8 *count, u8 *mode,
-				 struct cfg80211_chan_def *new_chandef);
+				 u32 sta_flags, u8 *bssid,
+				 struct ieee80211_csa_ie *csa_ie);
 
 /* Suspend/resume and hw reconfiguration */
 int ieee80211_reconfig(struct ieee80211_local *local);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9fce0f4..16e4238 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -941,9 +941,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	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 = {};
+	struct ieee80211_csa_ie csa_ie;
 	int res;
 
 	sdata_assert_lock(sdata);
@@ -959,24 +957,24 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		return;
 
 	current_band = cbss->channel->band;
+	memset(&csa_ie, 0, sizeof(csa_ie));
 	res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
 					   ifmgd->flags,
-					   ifmgd->associated->bssid, &count,
-					   &mode, &new_chandef);
+					   ifmgd->associated->bssid, &csa_ie);
 	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,
+	if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.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_chandef.chan->center_freq,
-			   new_chandef.width, new_chandef.center_freq1,
-			   new_chandef.center_freq2);
+			   csa_ie.chandef.chan->center_freq,
+			   csa_ie.chandef.width, csa_ie.chandef.center_freq1,
+			   csa_ie.chandef.center_freq2);
 		ieee80211_queue_work(&local->hw,
 				     &ifmgd->csa_connection_drop_work);
 		return;
@@ -1009,9 +1007,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 	mutex_unlock(&local->chanctx_mtx);
 
-	local->csa_chandef = new_chandef;
+	local->csa_chandef = csa_ie.chandef;
 
-	if (mode)
+	if (csa_ie.mode)
 		ieee80211_stop_queues_by_reason(&local->hw,
 				IEEE80211_MAX_QUEUE_MAP,
 				IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1020,9 +1018,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		/* use driver's channel switch callback */
 		struct ieee80211_channel_switch ch_switch = {
 			.timestamp = timestamp,
-			.block_tx = mode,
-			.chandef = new_chandef,
-			.count = count,
+			.block_tx = csa_ie.mode,
+			.chandef = csa_ie.chandef,
+			.count = csa_ie.count,
 		};
 
 		drv_channel_switch(local, &ch_switch);
@@ -1030,11 +1028,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 	}
 
 	/* channel switch handled in software */
-	if (count <= 1)
+	if (csa_ie.count <= 1)
 		ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work);
 	else
 		mod_timer(&ifmgd->chswitch_timer,
-			  TU_TO_EXP_TIME(count * cbss->beacon_interval));
+			  TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval));
 }
 
 static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
@@ -3965,7 +3963,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 	}
 
 	/* prepare assoc data */
-	
+
 	ifmgd->beacon_crc_valid = false;
 
 	/*
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 921597e..a298e12 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -24,8 +24,8 @@
 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 *bssid, u8 *count, u8 *mode,
-				 struct cfg80211_chan_def *new_chandef)
+				 u32 sta_flags, u8 *bssid,
+				 struct ieee80211_csa_ie *csa_ie)
 {
 	enum ieee80211_band new_band;
 	int new_freq;
@@ -62,13 +62,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
 			return -EINVAL;
 		}
 		new_chan_no = elems->ext_chansw_ie->new_ch_num;
-		*count = elems->ext_chansw_ie->count;
-		*mode = elems->ext_chansw_ie->mode;
+		csa_ie->count = elems->ext_chansw_ie->count;
+		csa_ie->mode = elems->ext_chansw_ie->mode;
 	} else if (elems->ch_switch_ie) {
 		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;
+		csa_ie->count = elems->ch_switch_ie->count;
+		csa_ie->mode = elems->ch_switch_ie->mode;
 	} else {
 		/* nothing here we understand */
 		return 1;
@@ -103,25 +103,26 @@ int ieee80211_parse_ch_switch_ie(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(&csa_ie->chandef, new_chan,
 					NL80211_CHAN_HT20);
 		break;
 	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-		cfg80211_chandef_create(new_chandef, new_chan,
+		cfg80211_chandef_create(&csa_ie->chandef, new_chan,
 					NL80211_CHAN_HT40PLUS);
 		break;
 	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-		cfg80211_chandef_create(new_chandef, new_chan,
+		cfg80211_chandef_create(&csa_ie->chandef, new_chan,
 					NL80211_CHAN_HT40MINUS);
 		break;
 	case -1:
-		cfg80211_chandef_create(new_chandef, new_chan,
+		cfg80211_chandef_create(&csa_ie->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;
+			csa_ie->chandef.width =
+				sdata->vif.bss_conf.chandef.width;
 			break;
 		default:
 			break;
@@ -171,13 +172,13 @@ int ieee80211_parse_ch_switch_ie(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)) {
+						 &csa_ie->chandef)) {
 			sdata_info(sdata,
 				   "BSS %pM: CSA has inconsistent channel data, disconnecting\n",
 				   bssid);
 			return -EINVAL;
 		}
-		*new_chandef = new_vht_chandef;
+		csa_ie->chandef = new_vht_chandef;
 	}
 
 	return 0;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v5 2/5] {nl,cfg,mac}80211: enable the triggering of CSA frame in mesh
From: Chun-Yeow Yeoh @ 2013-10-15  2:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh
In-Reply-To: <1381802911-3921-1-git-send-email-yeohchunyeow@cozybit.com>

Allow the triggering of CSA frame using mesh interface. The
rules are more or less same with IBSS, such as not allowed to
change between the band and channel width has to be same from
the previous mode. Also, move the ieee80211_send_action_csa
to a common space so that it can be re-used by mesh interface.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
---
v2: fix return value and others (Johannes Berg)

 net/mac80211/cfg.c         |   19 ++++++++++
 net/mac80211/ibss.c        |   54 ---------------------------
 net/mac80211/ieee80211_i.h |    2 +
 net/mac80211/util.c        |   87 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.c     |    1 +
 5 files changed, 109 insertions(+), 54 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b455e72..438c689 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2907,6 +2907,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_chanctx_conf *chanctx_conf;
 	struct ieee80211_chanctx *chanctx;
+	struct ieee80211_if_mesh *ifmsh;
 	int err, num_chanctx;
 
 	if (!list_empty(&local->roc_list) || local->scanning)
@@ -2990,6 +2991,24 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 		if (err < 0)
 			return err;
 		break;
+	case NL80211_IFTYPE_MESH_POINT:
+		ifmsh = &sdata->u.mesh;
+
+		if (!ifmsh->mesh_id)
+			return -EINVAL;
+
+		if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
+			return -EINVAL;
+
+		/* changes into another band are not supported */
+		if (sdata->vif.bss_conf.chandef.chan->band !=
+		    params->chandef.chan->band)
+			return -EINVAL;
+
+		err = ieee80211_send_action_csa(sdata, params);
+		if (err < 0)
+			return err;
+		break;
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 5ea9b3a..017e206 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -428,60 +428,6 @@ 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;
-}
-
 int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
 			      struct cfg80211_csa_settings *csa_settings)
 {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7f13b65..829ff7e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1714,6 +1714,8 @@ void ieee80211_dfs_cac_timer(unsigned long data);
 void ieee80211_dfs_cac_timer_work(struct work_struct *work);
 void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
 void ieee80211_dfs_radar_detected_work(struct work_struct *work);
+int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+			      struct cfg80211_csa_settings *csa_settings);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 133667c..5d12440 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2361,3 +2361,90 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
 
 	return ret;
 }
+
+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_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;
+
+	if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
+	skb = dev_alloc_skb(local->tx_headroom + hdr_len +
+			    5 + /* channel switch announcement element */
+			    3 + /* secondary channel offset element */
+			    8); /* mesh channel switch parameters element */
+	if (!skb)
+		return -ENOMEM;
+
+	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);
+	if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+	} else {
+		struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+		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;
+	}
+
+	if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+		__le16 pre_value;
+
+		skb_put(skb, 8);
+		*pos++ = WLAN_EID_CHAN_SWITCH_PARAM;		/* EID */
+		*pos++ = 6;					/* IE length */
+		*pos++ = sdata->u.mesh.mshcfg.dot11MeshTTL;	/* Mesh TTL */
+		*pos = 0x00;	/* Mesh Flag: Tx Restrict, Initiator, Reason */
+		*pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+		*pos++ |= csa_settings->block_tx ?
+			  WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
+		put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
+		pos += 2;
+		if (!ifmsh->pre_value)
+			ifmsh->pre_value = 1;
+		else
+			ifmsh->pre_value++;
+		pre_value = cpu_to_le16(ifmsh->pre_value);
+		memcpy(pos, &pre_value, 2);		/* Precedence Value */
+		pos += 2;
+		ifmsh->chsw_init = true;
+	}
+
+	ieee80211_tx_skb(sdata, skb);
+	return 0;
+}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index da8de5b..7bb5aca 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5650,6 +5650,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 			return -EINVAL;
 		break;
 	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
 		break;
 	default:
 		return -EOPNOTSUPP;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v5 0/5]  Add Mesh Channel Switch Support
From: Chun-Yeow Yeoh @ 2013-10-15  2:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh

These are the patches required to support Mesh Basic Service Set (MBSS)
channel switch.

The design is more or less same with the IBSS. Additional procedures
or elements that are required for mesh operation are as follow:
 * Add additional information element (IE) known as Mesh Channel Switch
   Parameters (MCSP) required in CSA action, beacon and probe response
   frames.
 * Forwarding of CSA frame if the conditions defined in the standard
   are met.

Limitations:
 * Channel switch is only allowed for the same band and also same channel
   width from the previous setting.

These patches are reviewed and commented by Bob Copeland, Thomas Pedersen
and Johannes Berg. Jean-Pierre has also commented on typos error. Any
further comments are welcomed.

These patches also include refactoring the ieee80211_parse_ch_switch_ie to
reduce the number of function parameters.

Testing:
The patches are tested using ath9k.

Chun-Yeow Yeoh (5):
  mac80211: process the CSA frame for mesh accordingly
  {nl,cfg,mac}80211: enable the triggering of CSA frame in mesh
  mac80211: refactor the parsing of chan switch ie
  {nl,cfg,mac}80211: implement mesh channel switch userspace API
  mac80211: process mesh channel switching using beacon

 include/linux/ieee80211.h  |   20 +++
 net/mac80211/Kconfig       |   11 ++
 net/mac80211/cfg.c         |   24 ++++
 net/mac80211/debug.h       |   10 ++
 net/mac80211/ibss.c        |   67 ++--------
 net/mac80211/ieee80211_i.h |   34 +++++-
 net/mac80211/mesh.c        |  292 +++++++++++++++++++++++++++++++++++++++++++-
 net/mac80211/mlme.c        |   32 +++--
 net/mac80211/rx.c          |    5 +-
 net/mac80211/spectmgmt.c   |   33 +++--
 net/mac80211/tx.c          |   16 +++
 net/mac80211/util.c        |   96 +++++++++++++++
 net/wireless/nl80211.c     |    4 +-
 13 files changed, 544 insertions(+), 100 deletions(-)

-- 
1.7.9.5


^ permalink raw reply

* [PATCH 6/6] ath9k: add TX99 support
From: Luis R. Rodriguez @ 2013-10-15  0:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez, Rajkumar Manoharan
In-Reply-To: <1381797731-2454-1-git-send-email-mcgrof@do-not-panic.com>

TX99 support enables Specific Absorption Rate (SAR) testing.
SAR is the unit of measurement for the amount of radio frequency(RF)
absorbed by the body when using a wireless device. The RF
exposure limits used are expressed in the terms of SAR, which is a
measure of the electric and magnetic field strength and power density
for transmitters operating at frequencies from 300 kHz to 100 GHz.

Regulatory bodies around the world require that wireless device
be evaluated to meet the RF exposure limits set forth in the
governmental SAR regulations.

In the examples below, for more bit rate options see the iw TX bitrate
setting documentation:

http://wireless.kernel.org/en/users/Documentation/iw#Modifying_transmit_bitrates

Example usage:

iw phy phy0 interface add moni0 type monitor
ip link set dev moni0 up

iw dev moni0 set channel 36 HT40+
iw set bitrates mcs-5 4

echo 10 > /sys/kernel/debug/ieee80211/phy0/ath9k/tx99_power
echo 1  > /sys/kernel/debug/ieee80211/phy0/ath9k/tx99

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
 drivers/net/wireless/ath/ath9k/Kconfig      |  20 ++++
 drivers/net/wireless/ath/ath9k/ar9002_phy.c |  22 ++++
 drivers/net/wireless/ath/ath9k/ar9003_phy.c |  95 +++++++++++++++++
 drivers/net/wireless/ath/ath9k/ath9k.h      |  10 ++
 drivers/net/wireless/ath/ath9k/debug.c      | 118 ++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/hw-ops.h     |  16 +++
 drivers/net/wireless/ath/ath9k/hw.h         |   4 +
 drivers/net/wireless/ath/ath9k/init.c       |  26 ++---
 drivers/net/wireless/ath/ath9k/link.c       |  12 ++-
 drivers/net/wireless/ath/ath9k/main.c       | 160 +++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath9k/recv.c       |   3 +
 drivers/net/wireless/ath/ath9k/xmit.c       |  53 ++++++++-
 12 files changed, 522 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 7944c25..32f139e 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -84,6 +84,26 @@ config ATH9K_DFS_CERTIFIED
 	  developed. At this point enabling this option won't do anything
 	  except increase code size.
 
+config ATH9K_TX99
+	bool "Atheros ath9k TX99 testing support"
+	depends on CFG80211_CERTIFICATION_ONUS
+	default n
+	---help---
+	  Say N. This should only be enabled on systems undergoing
+	  certification testing and evaluation in a controlled environment.
+	  Enabling this will only enable TX99 support, all other modes of
+	  operation will be disabled.
+
+	  TX99 support enables Specific Absorption Rate (SAR) testing.
+	  SAR is the unit of measurement for the amount of radio frequency(RF)
+	  absorbed by the body when using a wireless device. The RF exposure
+	  limits used are expressed in the terms of SAR, which is a measure
+	  of the electric and magnetic field strength and power density for
+	  transmitters operating at frequencies from 300 kHz to 100 GHz.
+	  Regulatory bodies around the world require that wireless device
+	  be evaluated to meet the RF exposure limits set forth in the
+	  governmental SAR regulations.
+
 config ATH9K_LEGACY_RATE_CONTROL
 	bool "Atheros ath9k rate control"
 	depends on ATH9K
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 17970d4..f087117 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -680,6 +680,26 @@ static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah)
 	}
 }
 
+static void ar9002_hw_tx99_start(struct ath_hw *ah, u32 qnum)
+{
+	REG_SET_BIT(ah, 0x9864, 0x7f000);
+	REG_SET_BIT(ah, 0x9924, 0x7f00fe);
+	REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+	REG_WRITE(ah, AR_CR, AR_CR_RXD);
+	REG_WRITE(ah, AR_DLCL_IFS(qnum), 0);
+	REG_WRITE(ah, AR_D_GBL_IFS_SIFS, 20);
+	REG_WRITE(ah, AR_D_GBL_IFS_EIFS, 20);
+	REG_WRITE(ah, AR_D_FPCTL, 0x10|qnum);
+	REG_WRITE(ah, AR_TIME_OUT, 0x00000400);
+	REG_WRITE(ah, AR_DRETRY_LIMIT(qnum), 0xffffffff);
+	REG_SET_BIT(ah, AR_QMISC(qnum), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+}
+
+static void ar9002_hw_tx99_stop(struct ath_hw *ah)
+{
+	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+}
+
 void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -701,6 +721,8 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity;
 #endif
+	ops->tx99_start = ar9002_hw_tx99_start;
+	ops->tx99_stop = ar9002_hw_tx99_stop;
 
 	ar9002_hw_set_nf_limits(ah);
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index f3adafd..11f5358 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1617,6 +1617,98 @@ static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah)
 	}
 }
 
+static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum)
+{
+	REG_SET_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR);
+	REG_SET_BIT(ah, 0x9864, 0x7f000);
+	REG_SET_BIT(ah, 0x9924, 0x7f00fe);
+	REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+	REG_WRITE(ah, AR_CR, AR_CR_RXD);
+	REG_WRITE(ah, AR_DLCL_IFS(qnum), 0);
+	REG_WRITE(ah, AR_D_GBL_IFS_SIFS, 20); /* 50 OK */
+	REG_WRITE(ah, AR_D_GBL_IFS_EIFS, 20);
+	REG_WRITE(ah, AR_TIME_OUT, 0x00000400);
+	REG_WRITE(ah, AR_DRETRY_LIMIT(qnum), 0xffffffff);
+	REG_SET_BIT(ah, AR_QMISC(qnum), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+}
+
+static void ar9003_hw_tx99_stop(struct ath_hw *ah)
+{
+	REG_CLR_BIT(ah, AR_PHY_TEST, PHY_AGC_CLR);
+	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+}
+
+static void ar9003_hw_tx99_set_txpower(struct ath_hw *ah, u8 txpower)
+{
+	static s16 p_pwr_array[ar9300RateSize] = { 0 };
+	unsigned int i;
+
+	if (txpower <= MAX_RATE_POWER) {
+		for (i = 0; i < ar9300RateSize; i++)
+			p_pwr_array[i] = txpower;
+	} else {
+		for (i = 0; i < ar9300RateSize; i++)
+			p_pwr_array[i] = MAX_RATE_POWER;
+	}
+
+	REG_WRITE(ah, 0xa458, 0);
+
+	REG_WRITE(ah, 0xa3c0,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24],  0));
+	REG_WRITE(ah, 0xa3c4,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_54],  24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_48],  16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_36],   8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_6_24], 0));
+	REG_WRITE(ah, 0xa3c8,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],  0));
+	REG_WRITE(ah, 0xa3cc,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11S],   24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_11L],   16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_5S],     8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_LEGACY_1L_5L],  0));
+	REG_WRITE(ah, 0xa3d0,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_5],  24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_4],  16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_1_3_9_11_17_19], 8)|
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_0_8_16], 0));
+	REG_WRITE(ah, 0xa3d4,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_13], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_12], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_7],   8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_6],   0));
+	REG_WRITE(ah, 0xa3e4,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_21], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_20], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_15],  8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_14],  0));
+	REG_WRITE(ah, 0xa3e8,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_23], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_22], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_23],  8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT20_22],  0));
+	REG_WRITE(ah, 0xa3d8,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_5], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_4], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_1_3_9_11_17_19], 8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_0_8_16], 0));
+	REG_WRITE(ah, 0xa3dc,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_13], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_12], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_7],   8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_6],   0));
+	REG_WRITE(ah, 0xa3ec,
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_21], 24) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_20], 16) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_15],  8) |
+		  ATH9K_POW_SM(p_pwr_array[ALL_TARGET_HT40_14],  0));
+}
+
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -1656,6 +1748,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity;
 #endif
+	ops->tx99_start = ar9003_hw_tx99_start;
+	ops->tx99_stop = ar9003_hw_tx99_stop;
+	ops->tx99_set_txpower = ar9003_hw_tx99_set_txpower;
 
 	ar9003_hw_set_nf_limits(ah);
 	ar9003_hw_set_radar_conf(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5492a0c..d0a6aa1 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -778,6 +778,11 @@ struct ath_softc {
 	enum spectral_mode spectral_mode;
 	struct ath_spec_scan spec_config;
 
+	struct ieee80211_vif *tx99_vif;
+	struct sk_buff *tx99_skb;
+	bool tx99_state;
+	s16 tx99_power;
+
 #ifdef CONFIG_PM_SLEEP
 	atomic_t wow_got_bmiss_intr;
 	atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */
@@ -912,6 +917,11 @@ struct fft_sample_ht20 {
 	u8 data[SPECTRAL_HT20_NUM_BINS];
 } __packed;
 
+int ath9k_tx99_init(struct ath_softc *sc);
+void ath9k_tx99_deinit(struct ath_softc *sc);
+int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
+		    struct ath_tx_control *txctl);
+
 void ath9k_tasklet(unsigned long data);
 int ath_cabq_update(struct ath_softc *);
 
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 1be2c78..83a2c59 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1050,6 +1050,9 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
 	char buf[32];
 	ssize_t len;
 
+	if (config_enabled(CONFIG_ATH9K_TX99))
+		return -EOPNOTSUPP;
+
 	len = min(count, sizeof(buf) - 1);
 	if (copy_from_user(buf, user_buf, len))
 		return -EFAULT;
@@ -1775,6 +1778,111 @@ void ath9k_deinit_debug(struct ath_softc *sc)
 	}
 }
 
+static ssize_t read_file_tx99(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[3];
+	unsigned int len;
+
+	len = sprintf(buf, "%d\n", sc->tx99_state);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	char buf[32];
+	bool start;
+	ssize_t len;
+	int r;
+
+	if (sc->nvifs > 1)
+		return -EOPNOTSUPP;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	if (strtobool(buf, &start))
+		return -EINVAL;
+
+	if (start == sc->tx99_state) {
+		if (!start)
+			return count;
+		ath_dbg(common, XMIT, "Resetting TX99\n");
+		ath9k_tx99_deinit(sc);
+	}
+
+	if (!start) {
+		ath9k_tx99_deinit(sc);
+		return count;
+	}
+
+	r = ath9k_tx99_init(sc);
+	if (r)
+		return r;
+
+	return count;
+}
+
+static const struct file_operations fops_tx99 = {
+	.read = read_file_tx99,
+	.write = write_file_tx99,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_tx99_power(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[32];
+	unsigned int len;
+
+	len = sprintf(buf, "%d (%d dBm)\n",
+		      sc->tx99_power,
+		      sc->tx99_power / 2);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_tx99_power(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	int r;
+	u8 tx_power;
+
+	r = kstrtou8_from_user(user_buf, count, 0, &tx_power);
+	if (r)
+		return r;
+
+	if (tx_power > MAX_RATE_POWER)
+		return -EINVAL;
+
+	sc->tx99_power = tx_power;
+
+	ath9k_ps_wakeup(sc);
+	ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);
+	ath9k_ps_restore(sc);
+
+	return count;
+}
+
+static const struct file_operations fops_tx99_power = {
+	.read = read_file_tx99_power,
+	.write = write_file_tx99_power,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
@@ -1866,5 +1974,15 @@ int ath9k_init_debug(struct ath_hw *ah)
 	debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
 			    &fops_btcoex);
 #endif
+	if (config_enabled(CONFIG_ATH9K_TX99) &&
+	    AR_SREV_9300_20_OR_LATER(ah)) {
+		debugfs_create_file("tx99", S_IRUSR | S_IWUSR,
+				    sc->debug.debugfs_phy, sc,
+				    &fops_tx99);
+		debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,
+				    sc->debug.debugfs_phy, sc,
+				    &fops_tx99_power);
+	}
+
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 83f4927..4f9378d 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -78,6 +78,22 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
 	ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
 }
 
+static inline void ath9k_hw_tx99_start(struct ath_hw *ah, u32 qnum)
+{
+	ath9k_hw_ops(ah)->tx99_start(ah, qnum);
+}
+
+static inline void ath9k_hw_tx99_stop(struct ath_hw *ah)
+{
+	ath9k_hw_ops(ah)->tx99_stop(ah);
+}
+
+static inline void ath9k_hw_tx99_set_txpower(struct ath_hw *ah, u8 power)
+{
+	if (ath9k_hw_ops(ah)->tx99_set_txpower)
+		ath9k_hw_ops(ah)->tx99_set_txpower(ah, power);
+}
+
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 
 static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 81fcbc7..9ea24f1 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -703,6 +703,10 @@ struct ath_hw_ops {
 	void (*spectral_scan_trigger)(struct ath_hw *ah);
 	void (*spectral_scan_wait)(struct ath_hw *ah);
 
+	void (*tx99_start)(struct ath_hw *ah, u32 qnum);
+	void (*tx99_stop)(struct ath_hw *ah);
+	void (*tx99_set_txpower)(struct ath_hw *ah, u8 power);
+
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 	void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable);
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 7df728f..1bd6db2 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -681,6 +681,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 	pCap = &ah->caps;
 
 	sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET);
+	sc->tx99_power = MAX_RATE_POWER + 1;
 
 	if (!pdata) {
 		ah->ah_flags |= AH_USE_EEPROM;
@@ -785,6 +786,7 @@ err_queues:
 	ath9k_hw_deinit(ah);
 err_hw:
 	ath9k_eeprom_release(sc);
+	dev_kfree_skb_any(sc->tx99_skb);
 	return ret;
 }
 
@@ -842,7 +844,6 @@ static const struct ieee80211_iface_limit if_limits[] = {
 				 BIT(NL80211_IFTYPE_P2P_GO) },
 };
 
-
 static const struct ieee80211_iface_limit if_dfs_limits[] = {
 	{ .max = 1,	.types = BIT(NL80211_IFTYPE_AP) },
 };
@@ -903,17 +904,18 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
 
-	hw->wiphy->interface_modes =
-		BIT(NL80211_IFTYPE_P2P_GO) |
-		BIT(NL80211_IFTYPE_P2P_CLIENT) |
-		BIT(NL80211_IFTYPE_AP) |
-		BIT(NL80211_IFTYPE_WDS) |
-		BIT(NL80211_IFTYPE_STATION) |
-		BIT(NL80211_IFTYPE_ADHOC) |
-		BIT(NL80211_IFTYPE_MESH_POINT);
-
-	hw->wiphy->iface_combinations = if_comb;
-	hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+	if (!config_enabled(CONFIG_ATH9K_TX99)) {
+		hw->wiphy->interface_modes =
+			BIT(NL80211_IFTYPE_P2P_GO) |
+			BIT(NL80211_IFTYPE_P2P_CLIENT) |
+			BIT(NL80211_IFTYPE_AP) |
+			BIT(NL80211_IFTYPE_WDS) |
+			BIT(NL80211_IFTYPE_STATION) |
+			BIT(NL80211_IFTYPE_ADHOC) |
+			BIT(NL80211_IFTYPE_MESH_POINT);
+		hw->wiphy->iface_combinations = if_comb;
+		hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+	}
 
 	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 84a6064..743ebb4 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -28,6 +28,13 @@ void ath_tx_complete_poll_work(struct work_struct *work)
 	int i;
 	bool needreset = false;
 
+
+	if (sc->tx99_state) {
+		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+			"skip tx hung detection on tx99\n");
+		return;
+	}
+
 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
 		txq = sc->tx.txq_map[i];
 
@@ -70,7 +77,7 @@ void ath_hw_check(struct work_struct *work)
 	ath9k_ps_wakeup(sc);
 	is_alive = ath9k_hw_check_alive(sc->sc_ah);
 
-	if (is_alive && !AR_SREV_9300(sc->sc_ah))
+	if ((is_alive && !AR_SREV_9300(sc->sc_ah)) || sc->tx99_state)
 		goto out;
 	else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
 		ath_dbg(common, RESET,
@@ -141,6 +148,9 @@ void ath_hw_pll_work(struct work_struct *work)
 	if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
 		return;
 
+	if (sc->tx99_state)
+		return;
+
 	ath9k_ps_wakeup(sc);
 	pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
 	ath9k_ps_restore(sc);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 20a2fbc..74f452c 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1046,6 +1046,14 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 
 	mutex_lock(&sc->mutex);
 
+	if (config_enabled(CONFIG_ATH9K_TX99)) {
+		if (sc->nvifs >= 1) {
+			mutex_unlock(&sc->mutex);
+			return -EOPNOTSUPP;
+		}
+		sc->tx99_vif = vif;
+	}
+
 	ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
 	sc->nvifs++;
 
@@ -1074,9 +1082,15 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
 	struct ath_softc *sc = hw->priv;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
-	ath_dbg(common, CONFIG, "Change Interface\n");
 	mutex_lock(&sc->mutex);
 
+	if (config_enabled(CONFIG_ATH9K_TX99)) {
+		mutex_unlock(&sc->mutex);
+		return -EOPNOTSUPP;
+	}
+
+	ath_dbg(common, CONFIG, "Change Interface\n");
+
 	if (ath9k_uses_beacons(vif->type))
 		ath9k_beacon_remove_slot(sc, vif);
 
@@ -1106,6 +1120,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 	mutex_lock(&sc->mutex);
 
 	sc->nvifs--;
+	sc->tx99_vif = NULL;
 
 	if (ath9k_uses_beacons(vif->type))
 		ath9k_beacon_remove_slot(sc, vif);
@@ -1127,6 +1142,9 @@ static void ath9k_enable_ps(struct ath_softc *sc)
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 
+	if (config_enabled(CONFIG_ATH9K_TX99))
+		return;
+
 	sc->ps_enabled = true;
 	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
 		if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
@@ -1143,6 +1161,9 @@ static void ath9k_disable_ps(struct ath_softc *sc)
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 
+	if (config_enabled(CONFIG_ATH9K_TX99))
+		return;
+
 	sc->ps_enabled = false;
 	ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
 	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
@@ -1166,6 +1187,9 @@ void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
 	struct ath_common *common = ath9k_hw_common(ah);
 	u32 rxfilter;
 
+	if (config_enabled(CONFIG_ATH9K_TX99))
+		return;
+
 	if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
 		ath_err(common, "spectrum analyzer not implemented on this hardware\n");
 		return;
@@ -1745,6 +1769,9 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
 	unsigned long flags;
 	int pos;
 
+	if (config_enabled(CONFIG_ATH9K_TX99))
+		return -EOPNOTSUPP;
+
 	spin_lock_irqsave(&common->cc_lock, flags);
 	if (idx == 0)
 		ath_update_survey_stats(sc);
@@ -1777,6 +1804,9 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
 	struct ath_softc *sc = hw->priv;
 	struct ath_hw *ah = sc->sc_ah;
 
+	if (config_enabled(CONFIG_ATH9K_TX99))
+		return;
+
 	mutex_lock(&sc->mutex);
 	ah->coverage_class = coverage_class;
 
@@ -2343,6 +2373,134 @@ static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
 	sc->csa_vif = vif;
 }
 
+static void ath9k_tx99_stop(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	ath_drain_all_txq(sc);
+	ath_startrecv(sc);
+
+	ath9k_hw_set_interrupts(ah);
+	ath9k_hw_enable_interrupts(ah);
+
+	ieee80211_wake_queues(sc->hw);
+
+	kfree_skb(sc->tx99_skb);
+	sc->tx99_skb = NULL;
+	sc->tx99_state = false;
+
+	ath9k_hw_tx99_stop(sc->sc_ah);
+	ath_dbg(common, XMIT, "TX99 stopped\n");
+}
+
+static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
+{
+	static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
+			       0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
+			       0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
+			       0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
+			       0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
+			       0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
+			       0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
+			       0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
+	u32 len = 1200;
+	struct ieee80211_hw *hw = sc->hw;
+	struct ieee80211_hdr *hdr;
+	struct ieee80211_tx_info *tx_info;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		return NULL;
+
+	skb_put(skb, len);
+
+	memset(skb->data, 0, len);
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
+	hdr->duration_id = 0;
+
+	memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
+	memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
+	memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
+
+	hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
+
+	tx_info = IEEE80211_SKB_CB(skb);
+	memset(tx_info, 0, sizeof(*tx_info));
+	tx_info->band = hw->conf.chandef.chan->band;
+	tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
+	tx_info->control.vif = sc->tx99_vif;
+
+	memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
+
+	return skb;
+}
+
+void ath9k_tx99_deinit(struct ath_softc *sc)
+{
+	ath_reset(sc);
+
+	ath9k_ps_wakeup(sc);
+	ath9k_tx99_stop(sc);
+	ath9k_ps_restore(sc);
+}
+
+int ath9k_tx99_init(struct ath_softc *sc)
+{
+	struct ieee80211_hw *hw = sc->hw;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_tx_control txctl;
+	int r;
+
+	if (sc->sc_flags & SC_OP_INVALID) {
+		ath_err(common,
+			"driver is in invalid state unable to use TX99");
+		return -EINVAL;
+	}
+
+	sc->tx99_skb = ath9k_build_tx99_skb(sc);
+	if (!sc->tx99_skb)
+		return -ENOMEM;
+
+	memset(&txctl, 0, sizeof(txctl));
+	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+
+	ath_reset(sc);
+
+	ath9k_ps_wakeup(sc);
+
+	ath9k_hw_disable_interrupts(ah);
+	atomic_set(&ah->intr_ref_cnt, -1);
+	ath_drain_all_txq(sc);
+	ath_stoprecv(sc);
+
+	sc->tx99_state = true;
+
+	ieee80211_stop_queues(hw);
+
+	if (sc->tx99_power == MAX_RATE_POWER + 1)
+		sc->tx99_power = MAX_RATE_POWER;
+
+	ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
+	r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
+	if (r) {
+		ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
+		return r;
+	}
+
+	ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
+		sc->tx99_power,
+		sc->tx99_power / 2);
+
+	/* We leave the harware awake as it will be chugging on */
+
+	return 0;
+}
+
 struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
 	.start 		    = ath9k_start,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 8b788ef..0e84bc1 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -375,6 +375,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
 {
 	u32 rfilt;
 
+	if (config_enabled(CONFIG_ATH9K_TX99))
+		return 0;
+
 	rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
 		| ATH9K_RX_FILTER_MCAST;
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index b9b0819..09cdbcd 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1241,12 +1241,13 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
 		if (bf->bf_next)
 			info.link = bf->bf_next->bf_daddr;
 		else
-			info.link = 0;
+			info.link = (sc->tx99_state) ? bf->bf_daddr : 0;
 
 		if (!bf_first) {
 			bf_first = bf;
 
-			info.flags = ATH9K_TXDESC_INTREQ;
+			if (!sc->tx99_state)
+				info.flags = ATH9K_TXDESC_INTREQ;
 			if ((tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) ||
 			    txq == sc->tx.uapsdq)
 				info.flags |= ATH9K_TXDESC_CLRDMASK;
@@ -1941,7 +1942,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 			txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
 	}
 
-	if (!edma) {
+	if (!edma || sc->tx99_state) {
 		TX_STAT_INC(txq->axq_qnum, txstart);
 		ath9k_hw_txstart(ah, txq->axq_qnum);
 	}
@@ -2374,6 +2375,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 
 	dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
 	bf->bf_buf_addr = 0;
+	if (sc->tx99_state)
+		goto skip_tx_complete;
 
 	if (bf->bf_state.bfs_paprd) {
 		if (time_after(jiffies,
@@ -2386,6 +2389,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 		ath_debug_stat_tx(sc, bf, ts, txq, tx_flags);
 		ath_tx_complete(sc, skb, tx_flags, txq);
 	}
+skip_tx_complete:
 	/* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
 	 * accidentally reference it later.
 	 */
@@ -2744,3 +2748,46 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
 		ath_txq_unlock(sc, txq);
 	}
 }
+
+int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
+		    struct ath_tx_control *txctl)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ath_frame_info *fi = get_frame_info(skb);
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_buf *bf;
+	int padpos, padsize;
+
+	padpos = ieee80211_hdrlen(hdr->frame_control);
+	padsize = padpos & 3;
+
+	if (padsize && skb->len > padpos) {
+		if (skb_headroom(skb) < padsize) {
+			ath_dbg(common, XMIT,
+				"tx99 padding failed\n");
+		return -EINVAL;
+		}
+
+		skb_push(skb, padsize);
+		memmove(skb->data, skb->data + padsize, padpos);
+	}
+
+	fi->keyix = ATH9K_TXKEYIX_INVALID;
+	fi->framelen = skb->len + FCS_LEN;
+	fi->keytype = ATH9K_KEY_TYPE_CLEAR;
+
+	bf = ath_tx_setup_buffer(sc, txctl->txq, NULL, skb);
+	if (!bf) {
+		ath_dbg(common, XMIT, "tx99 buffer setup failed\n");
+		return -EINVAL;
+	}
+
+	ath_set_rates(sc->tx99_vif, NULL, bf);
+
+	ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
+	ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
+
+	ath_tx_send_normal(sc, txctl->txq, NULL, skb);
+
+	return 0;
+}
-- 
1.8.4.rc3


^ permalink raw reply related

* [PATCH 5/6] ath9k: check for NULL rate when using ieee80211_get_rts_cts_rate()
From: Luis R. Rodriguez @ 2013-10-15  0:42 UTC (permalink / raw)
  To: linville, johannes; +Cc: linux-wireless, Luis R. Rodriguez, Rajkumar Manoharan
In-Reply-To: <1381797731-2454-1-git-send-email-mcgrof@do-not-panic.com>

ieee80211_get_rts_cts_rate() can return NULL, so don't rely
on its members when it does return NULL.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
 drivers/net/wireless/ath/ath9k/xmit.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 47696d2..b9b0819 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2020,6 +2020,9 @@ static void setup_frame_info(struct ieee80211_hw *hw,
 		fi->keyix = ATH9K_TXKEYIX_INVALID;
 	fi->keytype = keytype;
 	fi->framelen = framelen;
+
+	if (!rate)
+		return;
 	fi->rtscts_rate = rate->hw_value;
 	if (short_preamble)
 		fi->rtscts_rate |= rate->hw_value_short;
-- 
1.8.4.rc3


^ 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