Subject: [PATCH 16/26] rt2x00: Correctly handle RTS frames

From: Ivo van Doorn <[email-masked]>
Date: Sun, 3 Dec 2006 19:19:00 +0100

Correctly handle rts frames in txdone, by freeing the
packet. Also use the is_rts_frame to detect if the
frame was rts. This was done incorrectly previously.

Signed-off-by Ivo van Doorn <[email-masked]>

---

diff -rU3 wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt2400pci.c wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
--- wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt2400pci.c	2006-12-03 14:10:28.000000000 +0100
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2400pci.c	2006-12-03 14:19:54.000000000 +0100
@@ -1597,6 +1597,7 @@
 	int tx_status;
 	int ack;
 	int ring_full;
+	int rts;
 
 	/*
 	 * Store the current status of the ring.
@@ -1634,9 +1635,16 @@
 		entry->tx_status.retry_count = rt2x00_get_field32(
 			word, TXD_W0_RETRY_COUNT);
 
-		if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+		/*
+		 * If this is not an RTS frame send the tx_status to d80211,
+		 * that method also cleans up the skb structure. When this
+		 * is a RTS frame, that it is our job to clean this structure up.
+		 */
+		if (!rts)
 			ieee80211_tx_status(rt2x00dev->hw,
 				entry->skb, &entry->tx_status);
+		else
+			dev_kfree_skb(entry->skb);
 
 		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
 		rt2x00_desc_write(txd, 0, word);
@@ -1772,7 +1780,7 @@
 	 */
 	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
 	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
-	    (frame_control & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_RTS) {
+	    !is_rts_frame(frame_control)) {
 		skb_rts = rt2400pci_create_rts(rt2x00dev,
 				ieee80211hdr, control->rts_cts_duration);
 		if (!skb_rts) {
@@ -1808,8 +1816,7 @@
 	memcpy(rt2x00_data_addr(entry), skb->data, skb->len);
 	rt2400pci_write_tx_desc(rt2x00dev, txd, skb, control);
 	memcpy(&entry->tx_status.control, control, sizeof(*control));
-	if (((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-	    ((frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS))
+	if (is_rts_frame(frame_control))
 		SET_FLAG(entry, ENTRY_RTS_FRAME);
 	entry->skb = skb;
 
diff -rU3 wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt2500pci.c wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
--- wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt2500pci.c	2006-12-03 14:10:52.000000000 +0100
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500pci.c	2006-12-03 14:21:13.000000000 +0100
@@ -1760,6 +1760,7 @@
 	int tx_status;
 	int ack;
 	int ring_full;
+	int rts;
 
 	/*
 	 * Store the current status of the ring.
@@ -1797,9 +1798,16 @@
 		entry->tx_status.retry_count = rt2x00_get_field32(
 			word, TXD_W0_RETRY_COUNT);
 
-		if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+		/*
+		 * If this is not an RTS frame send the tx_status to d80211,
+		 * that method also cleans up the skb structure. When this
+		 * is a RTS frame, that it is our job to clean this structure up.
+		 */
+		if (!rts)
 			ieee80211_tx_status(rt2x00dev->hw,
 				entry->skb, &entry->tx_status);
+		else
+			dev_kfree_skb(entry->skb);
 
 		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
 		rt2x00_desc_write(txd, 0, word);
@@ -1935,7 +1943,7 @@
 	 */
 	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
 	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
-	    (frame_control & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_RTS) {
+	    !is_rts_frame(frame_control)) {
 		skb_rts = rt2500pci_create_rts(rt2x00dev,
 				ieee80211hdr, control->rts_cts_duration);
 		if (!skb_rts) {
@@ -1970,8 +1978,7 @@
 	memcpy(rt2x00_data_addr(entry), skb->data, skb->len);
 	rt2500pci_write_tx_desc(rt2x00dev, txd, skb, control);
 	memcpy(&entry->tx_status.control, control, sizeof(*control));
-	if (((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-	    ((frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS))
+	if (is_rts_frame(frame_control))
 		SET_FLAG(entry, ENTRY_RTS_FRAME);
 	entry->skb = skb;
 
diff -rU3 wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt2500usb.c wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
--- wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt2500usb.c	2006-12-03 14:11:15.000000000 +0100
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500usb.c	2006-12-03 14:21:53.000000000 +0100
@@ -1722,6 +1722,7 @@
 	u32 word;
 	int ack;
 	int ring_full;
+	int rts;
 
 	/*
 	 * Store the current status of the ring.
@@ -1755,9 +1756,16 @@
 		rt2x00_bbp_read(rt2x00dev, 0,
 			(u8*)&entry->tx_status.ack_signal);
 
-		if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+		/*
+		 * If this is not an RTS frame send the tx_status to d80211,
+		 * that method also cleans up the skb structure. When this
+		 * is a RTS frame, that it is our job to clean this structure up.
+		 */
+		if (!rts)
 			ieee80211_tx_status(rt2x00dev->hw,
 				entry->skb, &entry->tx_status);
+		else
+			dev_kfree_skb(entry->skb);
 
 		CLEAR_FLAG(entry, ENTRY_RTS_FRAME);
 		entry->skb = NULL;
@@ -1845,7 +1853,7 @@
 	 */
 	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
 	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
-	    (frame_control & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_RTS) {
+	    !is_rts_frame(frame_control)) {
 		skb_rts = rt2500usb_create_rts(rt2x00dev,
 				ieee80211hdr, control->rts_cts_duration);
 		if (!skb_rts) {
@@ -1874,8 +1882,7 @@
 	memcpy(rt2x00_txdata_addr(entry), skb->data, skb->len);
 	rt2500usb_write_tx_desc(rt2x00dev, txd, skb, control);
 	memcpy(&entry->tx_status.control, control, sizeof(*control));
-	if (((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-	    ((frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS))
+	if (is_rts_frame(frame_control))
 		SET_FLAG(entry, ENTRY_RTS_FRAME);
 	entry->skb = skb;
 
diff -rU3 wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt61pci.c wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt61pci.c
--- wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt61pci.c	2006-12-03 14:11:38.000000000 +0100
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt61pci.c	2006-12-03 14:22:40.000000000 +0100
@@ -2223,6 +2223,7 @@
 	int tx_status;
 	int ack;
 	int ring_full;
+	int rts;
 
 	txd = rt2x00_desc_addr(entry);
 	rt2x00_desc_read(txd, 0, &word);
@@ -2255,9 +2256,16 @@
 	entry->tx_status.retry_count = rt2x00_get_field32(
 		sta_csr4, STA_CSR4_RETRY_COUNT);
 
-	if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+	/*
+	 * If this is not an RTS frame send the tx_status to d80211,
+	 * that method also cleans up the skb structure. When this
+	 * is a RTS frame, that it is our job to clean this structure up.
+	 */
+	if (!rts)
 		ieee80211_tx_status(rt2x00dev->hw,
 			entry->skb, &entry->tx_status);
+	else
+		dev_kfree_skb(entry->skb);
 
 	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
 	rt2x00_desc_write(txd, 0, word);
@@ -2433,7 +2441,7 @@
 	 */
 	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
 	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
-	    (frame_control & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_RTS) {
+	    !is_rts_frame(frame_control)) {
 		skb_rts = rt61pci_create_rts(rt2x00dev,
 				ieee80211hdr, control->rts_cts_duration);
 		if (!skb_rts) {
@@ -2463,8 +2471,7 @@
 	memcpy(rt2x00_data_addr(entry), skb->data, skb->len);
 	rt61pci_write_tx_desc(rt2x00dev, txd, skb, control);
 	memcpy(&entry->tx_status.control, control, sizeof(*control));
-	if (((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-	    ((frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS))
+	if (is_rts_frame(frame_control))
 		SET_FLAG(entry, ENTRY_RTS_FRAME);
 	entry->skb = skb;
 
diff -rU3 wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt73usb.c wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt73usb.c
--- wireless-dev-timing/drivers/net/wireless/d80211/rt2x00/rt73usb.c	2006-12-03 14:11:59.000000000 +0100
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt73usb.c	2006-12-03 14:23:22.000000000 +0100
@@ -2001,6 +2001,7 @@
 	u32 word;
 	int ack;
 	int ring_full;
+	int rts;
 
 	/*
 	 * Store the current status of the ring.
@@ -2034,9 +2035,16 @@
 		rt2x00_bbp_read(rt2x00dev, 32,
 			(u8*)&entry->tx_status.ack_signal);
 
-		if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+		/*
+		 * If this is not an RTS frame send the tx_status to d80211,
+		 * that method also cleans up the skb structure. When this
+		 * is a RTS frame, that it is our job to clean this structure up.
+		 */
+		if (!rts)
 			ieee80211_tx_status(rt2x00dev->hw,
 				entry->skb, &entry->tx_status);
+		else
+			dev_kfree_skb(entry->skb);
 
 		CLEAR_FLAG(entry, ENTRY_RTS_FRAME);
 		entry->skb = NULL;
@@ -2123,7 +2131,7 @@
 	 */
 	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
 	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
-	    (frame_control & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_RTS) {
+	    !is_rts_frame(frame_control)) {
 		skb_rts = rt73usb_create_rts(rt2x00dev,
 				ieee80211hdr, control->rts_cts_duration);
 		if (!skb_rts) {
@@ -2152,8 +2160,7 @@
 	memcpy(rt2x00_data_addr(entry), skb->data, skb->len);
 	rt73usb_write_tx_desc(rt2x00dev, txd, skb, control);
 	memcpy(&entry->tx_status.control, control, sizeof(*control));
-	if (((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-	    ((frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS))
+	if (is_rts_frame(frame_control))
 		SET_FLAG(entry, ENTRY_RTS_FRAME);
 	entry->skb = skb;