Search Linux Wireless

[PATCH 1/4] mac80211: Return a status for tx operations

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

 



For off-channel operation we would like to know whether or not frames
submitted for tx are dropped, but most tx interfaces don't return
any status. The low-level interfaces do return bool but make no
distinction between dropping a packet and sucessfully handing it off to
the driver.

Add an enum named ieee80211_tx_status which defines status codes to
indicate whether a tx request results in successfully handing the frame
off to the driver, queueing the frame, or dropping it. Convert all tx
interfaces to return one of the values.

Signed-off-by: Seth Forshee <seth.forshee@xxxxxxxxxxxxx>
---
 net/mac80211/ieee80211_i.h |   53 ++++++++++++++++-------
 net/mac80211/tx.c          |  103 +++++++++++++++++++++++---------------------
 2 files changed, 92 insertions(+), 64 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5fba867..edea19e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1494,46 +1494,69 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
 				     gfp_t gfp);
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 			       bool bss_notify);
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-		    enum ieee80211_band band);
 
-void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
-				 struct sk_buff *skb, int tid,
-				 enum ieee80211_band band);
+/**
+ * enum ieee80211_tx_status - Tx request status
+ * @IEEE80211_TX_OK: Tx request handed off to driver
+ * @IEEE80211_TX_DROPPED: Tx request dropped
+ * @IEEE80211_TX_QUEUED: Tx requeust queued
+ */
+enum ieee80211_tx_status {
+	IEEE80211_TX_OK,
+	IEEE80211_TX_DROPPED,
+	IEEE80211_TX_QUEUED,
+};
 
-static inline void
+enum ieee80211_tx_status
+ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+	       enum ieee80211_band band);
+
+enum ieee80211_tx_status
+__ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
+			    struct sk_buff *skb, int tid,
+			    enum ieee80211_band band);
+
+static inline enum ieee80211_tx_status
 ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 			  struct sk_buff *skb, int tid,
 			  enum ieee80211_band band)
 {
+	enum ieee80211_tx_status ret;
+
 	rcu_read_lock();
-	__ieee80211_tx_skb_tid_band(sdata, skb, tid, band);
+	ret = __ieee80211_tx_skb_tid_band(sdata, skb, tid, band);
 	rcu_read_unlock();
+
+	return ret;
 }
 
-static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
-					struct sk_buff *skb, int tid)
+static inline enum ieee80211_tx_status
+ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+		     int tid)
 {
 	struct ieee80211_chanctx_conf *chanctx_conf;
+	enum ieee80211_tx_status ret;
 
 	rcu_read_lock();
 	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 	if (WARN_ON(!chanctx_conf)) {
 		rcu_read_unlock();
 		kfree_skb(skb);
-		return;
+		return IEEE80211_TX_DROPPED;
 	}
 
-	__ieee80211_tx_skb_tid_band(sdata, skb, tid,
-				    chanctx_conf->def.chan->band);
+	ret = __ieee80211_tx_skb_tid_band(sdata, skb, tid,
+					  chanctx_conf->def.chan->band);
 	rcu_read_unlock();
+
+	return ret;
 }
 
-static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
-				    struct sk_buff *skb)
+static inline enum ieee80211_tx_status
+ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
 	/* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
-	ieee80211_tx_skb_tid(sdata, skb, 7);
+	return ieee80211_tx_skb_tid(sdata, skb, 7);
 }
 
 void ieee802_11_parse_elems(u8 *start, size_t len,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a2cb6a3..fde1bc9 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1200,11 +1200,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 	return TX_CONTINUE;
 }
 
-static bool ieee80211_tx_frags(struct ieee80211_local *local,
-			       struct ieee80211_vif *vif,
-			       struct ieee80211_sta *sta,
-			       struct sk_buff_head *skbs,
-			       bool txpending)
+static enum ieee80211_tx_status
+ieee80211_tx_frags(struct ieee80211_local *local, struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta, struct sk_buff_head *skbs,
+		   bool txpending)
 {
 	struct ieee80211_tx_control control;
 	struct sk_buff *skb, *tmp;
@@ -1238,7 +1237,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
 
 			spin_unlock_irqrestore(&local->queue_stop_reason_lock,
 					       flags);
-			return false;
+			return IEEE80211_TX_QUEUED;
 		}
 		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
@@ -1249,26 +1248,23 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
 		drv_tx(local, &control, skb);
 	}
 
-	return true;
+	return IEEE80211_TX_OK;
 }
 
-/*
- * Returns false if the frame couldn't be transmitted but was queued instead.
- */
-static bool __ieee80211_tx(struct ieee80211_local *local,
-			   struct sk_buff_head *skbs, int led_len,
-			   struct sta_info *sta, bool txpending)
+static enum ieee80211_tx_status
+__ieee80211_tx(struct ieee80211_local *local, struct sk_buff_head *skbs,
+	       int led_len, struct sta_info *sta, bool txpending)
 {
 	struct ieee80211_tx_info *info;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_vif *vif;
 	struct ieee80211_sta *pubsta;
 	struct sk_buff *skb;
-	bool result = true;
+	enum ieee80211_tx_status result;
 	__le16 fc;
 
 	if (WARN_ON(skb_queue_empty(skbs)))
-		return true;
+		return IEEE80211_TX_OK;
 
 	skb = skb_peek(skbs);
 	fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
@@ -1291,7 +1287,7 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
 				vif->hw_queue[skb_get_queue_mapping(skb)];
 		} else if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
 			dev_kfree_skb(skb);
-			return true;
+			return IEEE80211_TX_DROPPED;
 		} else
 			vif = NULL;
 		break;
@@ -1371,23 +1367,20 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
 	return 0;
 }
 
-/*
- * Returns false if the frame couldn't be transmitted but was queued instead.
- */
-static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
-			 struct sk_buff *skb, bool txpending,
-			 enum ieee80211_band band)
+static enum ieee80211_tx_status
+ieee80211_tx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+	     bool txpending, enum ieee80211_band band)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_tx_data tx;
 	ieee80211_tx_result res_prepare;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	bool result = true;
+	enum ieee80211_tx_status result = IEEE80211_TX_OK;
 	int led_len;
 
 	if (unlikely(skb->len < 10)) {
 		dev_kfree_skb(skb);
-		return true;
+		return IEEE80211_TX_DROPPED;
 	}
 
 	/* initialises tx */
@@ -1396,9 +1389,17 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 
 	if (unlikely(res_prepare == TX_DROP)) {
 		ieee80211_free_txskb(&local->hw, skb);
-		return true;
+		return IEEE80211_TX_DROPPED;
 	} else if (unlikely(res_prepare == TX_QUEUED)) {
-		return true;
+		/*
+		 * TX_QUEUED here means that the frame was queued in
+		 * tid_tx while aggregation is being set up. This need
+		 * not prevent tx of other pending frames, so indicate
+		 * success if txpending is true.
+		 */
+		if (txpending)
+			return IEEE80211_TX_OK;
+		return IEEE80211_TX_QUEUED;
 	}
 
 	info->band = band;
@@ -1447,8 +1448,9 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
 	return 0;
 }
 
-void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-		    enum ieee80211_band band)
+enum ieee80211_tx_status
+ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+	       enum ieee80211_band band)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1466,7 +1468,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 
 	if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
 		ieee80211_free_txskb(&local->hw, skb);
-		return;
+		return IEEE80211_TX_DROPPED;
 	}
 
 	hdr = (struct ieee80211_hdr *) skb->data;
@@ -1477,11 +1479,11 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 	    !is_multicast_ether_addr(hdr->addr1) &&
 	    mesh_nexthop_resolve(skb, sdata)) {
 		/* skb queued: don't free */
-		return;
+		return IEEE80211_TX_QUEUED;
 	}
 
 	ieee80211_set_qos_hdr(sdata, skb);
-	ieee80211_tx(sdata, skb, false, band);
+	return ieee80211_tx(sdata, skb, false, band);
 }
 
 static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
@@ -2174,18 +2176,17 @@ void ieee80211_clear_tx_pending(struct ieee80211_local *local)
 }
 
 /*
- * Returns false if the frame couldn't be transmitted but was queued instead,
- * which in this case means re-queued -- take as an indication to stop sending
- * more pending frames.
+ * A return value of IEEE80211_TX_QUEUED in this case means re-queued --
+ * take as an indication to stop sending more pending frames.
  */
-static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
-				     struct sk_buff *skb)
+static enum ieee80211_tx_status
+ieee80211_tx_pending_skb(struct ieee80211_local *local, struct sk_buff *skb)
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
 	struct ieee80211_hdr *hdr;
-	bool result;
+	enum ieee80211_tx_status tx_stat;
 	struct ieee80211_chanctx_conf *chanctx_conf;
 
 	sdata = vif_to_sdata(info->control.vif);
@@ -2194,10 +2195,10 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
 		chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 		if (unlikely(!chanctx_conf)) {
 			dev_kfree_skb(skb);
-			return true;
+			return IEEE80211_TX_DROPPED;
 		}
-		result = ieee80211_tx(sdata, skb, true,
-				      chanctx_conf->def.chan->band);
+		tx_stat = ieee80211_tx(sdata, skb, true,
+				       chanctx_conf->def.chan->band);
 	} else {
 		struct sk_buff_head skbs;
 
@@ -2207,10 +2208,10 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
 		hdr = (struct ieee80211_hdr *)skb->data;
 		sta = sta_info_get(sdata, hdr->addr1);
 
-		result = __ieee80211_tx(local, &skbs, skb->len, sta, true);
+		tx_stat = __ieee80211_tx(local, &skbs, skb->len, sta, true);
 	}
 
-	return result;
+	return tx_stat;
 }
 
 /*
@@ -2221,7 +2222,7 @@ void ieee80211_tx_pending(unsigned long data)
 	struct ieee80211_local *local = (struct ieee80211_local *)data;
 	unsigned long flags;
 	int i;
-	bool txok;
+	enum ieee80211_tx_status tx_stat;
 
 	rcu_read_lock();
 
@@ -2247,10 +2248,10 @@ void ieee80211_tx_pending(unsigned long data)
 			spin_unlock_irqrestore(&local->queue_stop_reason_lock,
 						flags);
 
-			txok = ieee80211_tx_pending_skb(local, skb);
+			tx_stat = ieee80211_tx_pending_skb(local, skb);
 			spin_lock_irqsave(&local->queue_stop_reason_lock,
 					  flags);
-			if (!txok)
+			if (tx_stat == IEEE80211_TX_QUEUED)
 				break;
 		}
 
@@ -2775,11 +2776,13 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
 
-void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
-				 struct sk_buff *skb, int tid,
-				 enum ieee80211_band band)
+enum ieee80211_tx_status
+__ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
+			    struct sk_buff *skb, int tid,
+			    enum ieee80211_band band)
 {
 	int ac = ieee802_1d_to_ac[tid & 7];
+	enum ieee80211_tx_status ret;
 
 	skb_set_mac_header(skb, 0);
 	skb_set_network_header(skb, 0);
@@ -2794,6 +2797,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 	 * requirements are that we do not come into tx with bhs on.
 	 */
 	local_bh_disable();
-	ieee80211_xmit(sdata, skb, band);
+	ret = ieee80211_xmit(sdata, skb, band);
 	local_bh_enable();
+
+	return ret;
 }
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux