>From Ivo van Doorn <[EMAIL PROTECTED]>

Support RTS.
When rts is required, create the frame and send it out
before the rest of the frames.

Signed-off-by: Ivo van Doorn <[EMAIL PROTECTED]>

---

diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2400pci.c 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2400pci.c 
2006-07-23 17:24:56.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2400pci.c     
2006-07-23 
18:16:35.000000000 +0200
@@ -863,6 +863,36 @@
 }
 
 /*
+ * RTS frame creation.
+ */
+static struct sk_buff* rt2400pci_create_rts(struct rt2x00_dev *rt2x00dev,
+       struct ieee80211_hdr *hdr, unsigned short duration)
+{
+       struct ieee80211_hdr *ieee80211hdr;
+       struct sk_buff *skb;
+       u16 temp;
+
+       skb = dev_alloc_skb(IEEE80211_HEADER);
+       if (!skb)
+               return NULL;
+
+       /*
+        * Copy the entire header over to RTS frame.
+        */
+       memcpy(skb_put(skb, IEEE80211_HEADER), hdr, IEEE80211_HEADER);
+       ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+
+       temp = (WLAN_FC_TYPE_CTRL  << 2) | (WLAN_FC_STYPE_RTS << 4);
+       ieee80211hdr->frame_control = cpu_to_le16(temp);
+
+       ieee80211hdr->duration_id += cpu_to_le16(duration);
+
+       ieee80211hdr->seq_ctrl = 0;
+
+       return skb;
+}
+
+/*
  * TX descriptor initialization
  */
 static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
@@ -876,15 +906,32 @@
        u16 length_low;
        u16 signal;
        u16 service;
+       u16 frame_control;
+       u8 bitrate;
+       int tx_rate;
+
+       /*
+        * Check which rate should be used for this frame.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS &&
+           control->rts_cts_rate)
+               tx_rate = control->rts_cts_rate;
+       else
+               tx_rate = control->tx_rate;
 
        rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 1);
        rt2x00_set_field32(&txd->word0, TXD_W0_ACK, !control->no_ack);
 
        /*
-        * TODO: IFS can be various values, where can we find
-        * which one we want to use?
+        * Set IFS to IFS_SIFS when the this is not the first fragment,
+        * or this fragment came after RTS/CTS.
         */
-       rt2x00_set_field32(&txd->word0, TXD_W0_IFS, 0);
+       if ((WLAN_GET_SEQ_FRAG(le16_to_cpu(ieee80211hdr->seq_ctrl)) > 0) ||
+           control->use_rts_cts)
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_SIFS);
+       else
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_BACKOFF);
 
        if (control->queue == IEEE80211_TX_QUEUE_BEACON)
                rt2x00_set_field32(&txd->word0, TXD_W0_TIMESTAMP, 1);
@@ -896,16 +943,15 @@
         */
        rt2x00_set_field32(&txd->word0, TXD_W0_RETRY_MODE, 0);
 
-       if (ieee80211hdr->frame_control & WLAN_FC_MOREFRAG)
+       if (frame_control & WLAN_FC_MOREFRAG)
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 1);
        else
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 0);
 
-       /*
-        * TODO: Does this field mean device will send RTS, or that this
-        * frame is an RTS frame?
-        */
-       rt2x00_set_field32(&txd->word0, TXD_W0_RTS, control->use_rts_cts);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS)
+               rt2x00_set_field32(&txd->word10, TXD_W10_RTS, 1);
+       else
+               rt2x00_set_field32(&txd->word10, TXD_W10_RTS, 0);
 
        rt2x00_set_field32(&txd->word2, TXD_W2_DATABYTE_COUNT, skb->len);
 
@@ -918,9 +964,9 @@
         * Convert length to microseconds.
         */
        residual = get_duration_res(length,
-               DEVICE_GET_RATE_FIELD(control->tx_rate, RATE));
+               DEVICE_GET_RATE_FIELD(tx_rate, RATE));
        length = get_duration(length,
-               DEVICE_GET_RATE_FIELD(control->tx_rate, RATE));
+               DEVICE_GET_RATE_FIELD(tx_rate, RATE));
 
        if (residual)
                length++;
@@ -938,8 +984,8 @@
        length_high = 0x8000 | 0x0700 | (length >> 8);
        length_low = 0x8000 | 0x0800 | (length & 0xff);
 
-       signal = 0x8500 | DEVICE_GET_RATE_FIELD(control->tx_rate, PLCP);
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, PREAMBLE))
+       signal = 0x8500 | DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+       if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
                signal |= 0x0008;
 
        service = 0x0600 | 0x0004;
@@ -1089,8 +1135,9 @@
                entry->tx_status.retry_count = rt2x00_get_field32(
                        txd->word0, TXD_W0_RETRY_COUNT);
 
-               ieee80211_tx_status(ring->net_dev,
-                       entry->skb, &entry->tx_status);
+               if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+                       ieee80211_tx_status(ring->net_dev,
+                               entry->skb, &entry->tx_status);
 
                rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0);
                entry->skb = NULL;
@@ -1574,10 +1621,14 @@
        struct ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
        struct data_ring *ring;
        struct data_entry *entry;
        struct txd *txd;
+       struct sk_buff *skb_rts;
+       u16 frame_control;
        u32 reg;
+       int res;
 
        /*
         * Determine which ring to put packet on.
@@ -1596,6 +1647,27 @@
                return NETDEV_TX_BUSY;
        }
 
+       /*
+        * If RTS is required. and this frame is not RTS,
+        * create and queue that frame first.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (control->use_rts_cts &&
+           WLAN_FC_GET_STYPE(frame_control) != WLAN_FC_STYPE_RTS) {
+               skb_rts = rt2400pci_create_rts(rt2x00dev,
+                               ieee80211hdr, control->rts_cts_duration);
+               if (!skb_rts) {
+                       WARNING("Failed to create RTS frame.\n");
+                       return NETDEV_TX_BUSY;
+               }
+
+               res = rt2400pci_tx(net_dev, skb_rts, control);
+               if (res) {
+                       WARNING("Failed to send RTS frame.\n");
+                       return res;
+               }
+       }
+
        entry = rt2x00_get_data_entry(ring);
        txd = entry->desc_addr;
 
@@ -1610,6 +1682,8 @@
 
        memcpy(entry->data_addr, skb->data, skb->len);
        rt2400pci_write_tx_desc(rt2x00dev, txd, skb, control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS)
+               SET_FLAG(entry, ENTRY_RTS_FRAME);
        entry->skb = skb;
 
        rt2x00_ring_index_inc(ring);
diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2500pci.c 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2500pci.c 
2006-07-23 17:31:27.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500pci.c     
2006-07-23 
18:16:41.000000000 +0200
@@ -936,6 +936,36 @@
 }
 
 /*
+ * RTS frame creation.
+ */
+static struct sk_buff* rt2500pci_create_rts(struct rt2x00_dev *rt2x00dev,
+       struct ieee80211_hdr *hdr, unsigned short duration)
+{
+       struct ieee80211_hdr *ieee80211hdr;
+       struct sk_buff *skb;
+       u16 temp;
+
+       skb = dev_alloc_skb(IEEE80211_HEADER);
+       if (!skb)
+               return NULL;
+
+       /*
+        * Copy the entire header over to RTS frame.
+        */
+       memcpy(skb_put(skb, IEEE80211_HEADER), hdr, IEEE80211_HEADER);
+       ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+
+       temp = (WLAN_FC_TYPE_CTRL  << 2) | (WLAN_FC_STYPE_RTS << 4);
+       ieee80211hdr->frame_control = cpu_to_le16(temp);
+
+       ieee80211hdr->duration_id += cpu_to_le16(duration);
+
+       ieee80211hdr->seq_ctrl = 0;
+
+       return skb;
+}
+
+/*
  * TX descriptor initialization
  */
 static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
@@ -951,6 +981,19 @@
        u16 signal;
        u16 service;
        u8 rate;
+       u16 frame_control;
+       u8 bitrate;
+       int tx_rate;
+
+       /*
+        * Check which rate should be used for this frame.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS &&
+           control->rts_cts_rate)
+               tx_rate = control->rts_cts_rate;
+       else
+               tx_rate = control->tx_rate;
 
        rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 1);
        rt2x00_set_field32(&txd->word0, TXD_W0_ACK, !control->no_ack);
@@ -965,26 +1008,29 @@
                rt2x00_set_field32(&txd->word0, TXD_W0_TIMESTAMP, 0);
 
        /*
-        * TODO: IFS can be various values, where can we find
-        * which one we want to use?
+        * Set IFS to IFS_SIFS when the this is not the first fragment,
+        * or this fragment came after RTS/CTS.
         */
-       rt2x00_set_field32(&txd->word0, TXD_W0_IFS, 0);
+       if ((WLAN_GET_SEQ_FRAG(le16_to_cpu(ieee80211hdr->seq_ctrl)) > 0) ||
+           control->use_rts_cts)
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_SIFS);
+       else
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_BACKOFF);
 
        /*
         * TODO: How can we determine if we want long retry or short retry?
         */
        rt2x00_set_field32(&txd->word0, TXD_W0_RETRY_MODE, 0);
 
-       if (ieee80211hdr->frame_control & WLAN_FC_MOREFRAG)
+       if (frame_control & WLAN_FC_MOREFRAG)
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 1);
        else
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 0);
 
-       /*
-        * TODO: Does this field mean device will send RTS, or that this
-        * frame is an RTS frame?
-        */
-       rt2x00_set_field32(&txd->word10, TXD_W10_RTS, control->use_rts_cts);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS)
+               rt2x00_set_field32(&txd->word10, TXD_W10_RTS, 1);
+       else
+               rt2x00_set_field32(&txd->word10, TXD_W10_RTS, 0);
 
        rt2x00_set_field32(&txd->word0, TXD_W0_DATABYTE_COUNT, skb->len);
 
@@ -1002,7 +1048,7 @@
         * this can be done by checking if bit 4 or higher
         * is set in the ratemask.
         */
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, RATEMASK) & 0x0ff0) {
+       if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & 0x0ff0) {
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 1);
                residual = 0;
 
@@ -1013,7 +1059,7 @@
                length_low = (length & 0x3f);
 
        } else {
-               rate = DEVICE_GET_RATE_FIELD(control->tx_rate, RATE);
+               rate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
 
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 0);
 
@@ -1027,8 +1073,8 @@
                length_low = length & 0xff;
        }
 
-       signal = 0x8500 | DEVICE_GET_RATE_FIELD(control->tx_rate, PLCP);
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, PREAMBLE))
+       signal = 0x8500 | DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+       if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
                signal |= 0x0008;
 
        service = 0x0600 | 0x0004;
@@ -1189,8 +1235,9 @@
                entry->tx_status.retry_count = rt2x00_get_field32(
                        txd->word0, TXD_W0_RETRY_COUNT);
 
-               ieee80211_tx_status(ring->net_dev,
-                       entry->skb, &entry->tx_status);
+               if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+                       ieee80211_tx_status(ring->net_dev,
+                               entry->skb, &entry->tx_status);
 
                rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0);
                entry->skb = NULL;
@@ -1709,10 +1756,14 @@
        struct ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
        struct data_ring *ring;
        struct data_entry *entry;
        struct txd *txd;
+       struct sk_buff *skb_rts;
+       u16 frame_control;
        u32 reg;
+       int res;
 
        /*
         * Determine which ring to put packet on.
@@ -1731,6 +1782,27 @@
                return NETDEV_TX_BUSY;
        }
 
+       /*
+        * If RTS is required. and this frame is not RTS,
+        * create and queue that frame first.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (control->use_rts_cts &&
+           WLAN_FC_GET_STYPE(frame_control) != WLAN_FC_STYPE_RTS) {
+               skb_rts = rt2500pci_create_rts(rt2x00dev,
+                               ieee80211hdr, control->rts_cts_duration);
+               if (!skb_rts) {
+                       WARNING("Failed to create RTS frame.\n");
+                       return NETDEV_TX_BUSY;
+               }
+
+               res = rt2500pci_tx(net_dev, skb_rts, control);
+               if (res) {
+                       WARNING("Failed to send RTS frame.\n");
+                       return res;
+               }
+       }
+
        entry = rt2x00_get_data_entry(ring);
        txd = entry->desc_addr;
 
@@ -1745,6 +1817,8 @@
 
        memcpy(entry->data_addr, skb->data, skb->len);
        rt2500pci_write_tx_desc(rt2x00dev, txd, skb, control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS)
+               SET_FLAG(entry, ENTRY_RTS_FRAME);
        entry->skb = skb;
 
        rt2x00_ring_index_inc(ring);
diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2500usb.c 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2500usb.c 
2006-07-23 17:31:13.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2500usb.c     
2006-07-23 
18:15:52.000000000 +0200
@@ -766,6 +766,36 @@
 }
 
 /*
+ * RTS frame creation.
+ */
+static struct sk_buff* rt2500usb_create_rts(struct rt2x00_dev *rt2x00dev,
+       struct ieee80211_hdr *hdr, unsigned short duration)
+{
+       struct ieee80211_hdr *ieee80211hdr;
+       struct sk_buff *skb;
+       u16 temp;
+
+       skb = dev_alloc_skb(IEEE80211_HEADER);
+       if (!skb)
+               return NULL;
+
+       /*
+        * Copy the entire header over to RTS frame.
+        */
+       memcpy(skb_put(skb, IEEE80211_HEADER), hdr, IEEE80211_HEADER);
+       ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+
+       temp = (WLAN_FC_TYPE_CTRL  << 2) | (WLAN_FC_STYPE_RTS << 4);
+       ieee80211hdr->frame_control = cpu_to_le16(temp);
+
+       ieee80211hdr->duration_id += cpu_to_le16(duration);
+
+       ieee80211hdr->seq_ctrl = 0;
+
+       return skb;
+}
+
+/*
  * TX descriptor initialization
  */
 static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
@@ -780,7 +810,19 @@
        u8 length_low;
        u8 signal;
        u8 service;
-       u8 rate;
+       u16 frame_control;
+       u8 bitrate;
+       int tx_rate;
+
+       /*
+        * Check which rate should be used for this frame.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS &&
+           control->rts_cts_rate)
+               tx_rate = control->rts_cts_rate;
+       else
+               tx_rate = control->tx_rate;
 
        rt2x00_set_field32(&txd->word0, TXD_W0_ACK, !control->no_ack);
 
@@ -794,15 +836,19 @@
                rt2x00_set_field32(&txd->word0, TXD_W0_TIMESTAMP, 0);
 
        /*
-        * TODO: IFS can be various values, where can we find
-        * which one we want to use?
+        * Set IFS to IFS_SIFS when the this is not the first fragment,
+        * or this fragment came after RTS/CTS.
         */
-       rt2x00_set_field32(&txd->word0, TXD_W0_IFS, 0);
+       if ((WLAN_GET_SEQ_FRAG(le16_to_cpu(ieee80211hdr->seq_ctrl)) > 0) ||
+           control->use_rts_cts)
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_SIFS);
+       else
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_BACKOFF);
 
        rt2x00_set_field32(&txd->word0, TXD_W0_RETRY_LIMIT,
                control->retry_limit);
 
-       if (ieee80211hdr->frame_control & WLAN_FC_MOREFRAG)
+       if (frame_control & WLAN_FC_MOREFRAG)
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 1);
        else
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 0);
@@ -828,7 +874,7 @@
         * this can be done by checking if bit 4 or higher
         * is set in the ratemask.
         */
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, RATEMASK) & 0x0ff0) {
+       if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & 0x0ff0) {
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 1);
                residual = 0;
 
@@ -839,7 +885,7 @@
                length_low = (length & 0x3f);
 
        } else {
-               rate = DEVICE_GET_RATE_FIELD(control->tx_rate, RATE);
+               rate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
 
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 0);
 
@@ -853,8 +899,8 @@
                length_low = length & 0xff;
        }
 
-       signal = DEVICE_GET_RATE_FIELD(control->tx_rate, PLCP);
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, PREAMBLE))
+       signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+       if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
                signal |= 0x08;
 
        service = 0x04;
@@ -1017,9 +1063,10 @@
 
                rt2x00_bbp_read(rt2x00dev, 0,
                        (u8*)&entry->tx_status.ack_signal);
-       
-               ieee80211_tx_status(ring->net_dev,
-                       entry->skb, &entry->tx_status);
+
+               if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+                       ieee80211_tx_status(ring->net_dev,
+                               entry->skb, &entry->tx_status);
 
                entry->skb = NULL;
 
@@ -1415,11 +1462,15 @@
        struct sk_buff *skb, struct ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
        struct usb_device *usb_dev =
                interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
        struct data_ring *ring;
        struct data_entry *entry;
        struct txd *txd;
+       struct sk_buff *skb_rts;
+       u16 frame_control;
+       int res;
 
        /*
         * Determine which ring to put packet on.
@@ -1438,6 +1489,27 @@
                return NETDEV_TX_BUSY;
        }
 
+       /*
+        * If RTS is required. and this frame is not RTS,
+        * create and queue that frame first.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (control->use_rts_cts &&
+           WLAN_FC_GET_STYPE(frame_control) != WLAN_FC_STYPE_RTS) {
+               skb_rts = rt2500usb_create_rts(rt2x00dev,
+                               ieee80211hdr, control->rts_cts_duration);
+               if (!skb_rts) {
+                       WARNING("Failed to create RTS frame.\n");
+                       return NETDEV_TX_BUSY;
+               }
+
+               res = rt2500usb_tx(net_dev, skb_rts, control);
+               if (res) {
+                       WARNING("Failed to send RTS frame.\n");
+                       return res;
+               }
+       }
+
        entry = rt2x00_get_data_entry(ring);
        txd = rt2x00usb_txdesc_addr(entry);
 
@@ -1451,6 +1523,8 @@
 
        memcpy(rt2x00usb_txdata_addr(entry), skb->data, skb->len);
        rt2500usb_write_tx_desc(rt2x00dev, txd, skb, control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS)
+               SET_FLAG(entry, ENTRY_RTS_FRAME);
        entry->skb = skb;
 
        SET_FLAG(entry, ENTRY_OWNER_NIC);
diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2x00.h 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2x00.h
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2x00.h    
2006-07-23 16:59:40.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2x00.h        
2006-07-23 
18:09:00.000000000 +0200
@@ -139,6 +139,16 @@
 };
 
 /*
+ * IFS backoff values
+ */
+enum ifs {
+       IFS_BACKOFF = 0,
+       IFS_SIFS = 1,
+       IFS_NEW_BACKOFF = 2,
+       IFS_NONE = 3,
+};
+
+/*
  * Macros for determining which is the lowest or highest bit
  * set in a 16 or 32 bit variable.
  */
diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h 
2006-07-23 15:53:34.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h     
2006-07-23 
17:59:04.000000000 +0200
@@ -84,6 +84,12 @@
  */
 struct data_entry {
        /*
+        * Status flag.
+        */
+       unsigned int flags;
+#define ENTRY_RTS_FRAME                0x00000001
+
+       /*
         * sk_buff for the packet which is being transmitted
         * in this entry (Only used with TX related rings).
         */
diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h 
2006-07-23 15:23:15.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h     
2006-07-23 
17:58:43.000000000 +0200
@@ -56,6 +56,7 @@
        unsigned int flags;
 #define ENTRY_OWNER_NIC                0x00000001
 #define ENTRY_TYPE_RX          0x00000002
+#define ENTRY_RTS_FRAME                0x00000004
 
        /*
         * Ring we belong to.
diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt61pci.c 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt61pci.c
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt61pci.c   
2006-07-23 17:31:05.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt61pci.c       
2006-07-23 
18:16:51.000000000 +0200
@@ -1202,6 +1202,36 @@
 }
 
 /*
+ * RTS frame creation.
+ */
+static struct sk_buff* rt61pci_create_rts(struct rt2x00_dev *rt2x00dev,
+       struct ieee80211_hdr *hdr, unsigned short duration)
+{
+       struct ieee80211_hdr *ieee80211hdr;
+       struct sk_buff *skb;
+       u16 temp;
+
+       skb = dev_alloc_skb(IEEE80211_HEADER);
+       if (!skb)
+               return NULL;
+
+       /*
+        * Copy the entire header over to RTS frame.
+        */
+       memcpy(skb_put(skb, IEEE80211_HEADER), hdr, IEEE80211_HEADER);
+       ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+
+       temp = (WLAN_FC_TYPE_CTRL  << 2) | (WLAN_FC_STYPE_RTS << 4);
+       ieee80211hdr->frame_control = cpu_to_le16(temp);
+
+       ieee80211hdr->duration_id += cpu_to_le16(duration);
+
+       ieee80211hdr->seq_ctrl = 0;
+
+       return skb;
+}
+
+/*
  * TX descriptor initialization
  */
 static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
@@ -1217,6 +1247,19 @@
        u16 signal;
        u16 service;
        u8 rate;
+       u16 frame_control;
+       u8 bitrate;
+       int tx_rate;
+
+       /*
+        * Check which rate should be used for this frame.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS &&
+           control->rts_cts_rate)
+               tx_rate = control->rts_cts_rate;
+       else
+               tx_rate = control->tx_rate;
 
        rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 1);
        rt2x00_set_field32(&txd->word0, TXD_W0_ACK, !control->no_ack);
@@ -1231,17 +1274,21 @@
                rt2x00_set_field32(&txd->word0, TXD_W0_TIMESTAMP, 0);
 
        /*
-        * TODO: IFS can be various values, where can we find
-        * which one we want to use?
+        * Set IFS to IFS_SIFS when the this is not the first fragment,
+        * or this fragment came after RTS/CTS.
         */
-       rt2x00_set_field32(&txd->word0, TXD_W0_IFS, 0);
+       if ((WLAN_GET_SEQ_FRAG(le16_to_cpu(ieee80211hdr->seq_ctrl)) > 0) ||
+           control->use_rts_cts)
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_SIFS);
+       else
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_BACKOFF);
 
        /*
         * TODO: How can we determine if we want long retry or short retry?
         */
        rt2x00_set_field32(&txd->word0, TXD_W0_RETRY_MODE, 0);
 
-       if (ieee80211hdr->frame_control & WLAN_FC_MOREFRAG)
+       if (frame_control & WLAN_FC_MOREFRAG)
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 1);
        else
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 0);
@@ -1277,7 +1324,7 @@
         * this can be done by checking if bit 4 or higher
         * is set in the ratemask.
         */
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, RATEMASK) & 0x0ff0) {
+       if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & 0x0ff0) {
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 1);
 
                /*
@@ -1288,7 +1335,7 @@
                length_low = (length & 0x3f);
 
        } else {
-               rate = DEVICE_GET_RATE_FIELD(control->tx_rate, RATE);
+               rate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
 
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 0);
 
@@ -1302,8 +1349,8 @@
                length_low = length & 0xff;
        }
 
-       signal = 0x8500 | DEVICE_GET_RATE_FIELD(control->tx_rate, PLCP);
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, PREAMBLE))
+       signal = 0x8500 | DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+       if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
                signal |= 0x0008;
 
        service = 0x04;
@@ -1470,8 +1517,9 @@
                entry->tx_status.retry_count = rt2x00_get_field32(
                        reg, STA_CSR4_RETRY_COUNT);
 
-               ieee80211_tx_status(ring->net_dev,
-                       entry->skb, &entry->tx_status);
+               if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+                       ieee80211_tx_status(ring->net_dev,
+                               entry->skb, &entry->tx_status);
 
                rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0);
                entry->skb = NULL;
@@ -2158,10 +2206,14 @@
        struct ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
        struct data_ring *ring;
        struct data_entry *entry;
        struct txd *txd;
+       struct sk_buff *skb_rts;
+       u16 frame_control;
        u32 reg;
+       int res;
 
        /*
         * Determine which ring to put packet on.
@@ -2180,6 +2232,27 @@
                return NETDEV_TX_BUSY;
        }
 
+       /*
+        * If RTS is required. and this frame is not RTS,
+        * create and queue that frame first.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (control->use_rts_cts &&
+           WLAN_FC_GET_STYPE(frame_control) != WLAN_FC_STYPE_RTS) {
+               skb_rts = rt61pci_create_rts(rt2x00dev,
+                               ieee80211hdr, control->rts_cts_duration);
+               if (!skb_rts) {
+                       WARNING("Failed to create RTS frame.\n");
+                       return NETDEV_TX_BUSY;
+               }
+
+               res = rt61pci_tx(net_dev, skb_rts, control);
+               if (res) {
+                       WARNING("Failed to send RTS frame.\n");
+                       return res;
+               }
+       }
+
        entry = rt2x00_get_data_entry(ring);
        txd = entry->desc_addr;
 
@@ -2194,6 +2267,8 @@
 
        memcpy(entry->data_addr, skb->data, skb->len);
        rt61pci_write_tx_desc(rt2x00dev, txd, skb, control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS)
+               SET_FLAG(entry, ENTRY_RTS_FRAME);
        entry->skb = skb;
 
        rt2x00_ring_index_inc(ring);
diff -rU3 wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt73usb.c 
wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt73usb.c
--- wireless-dev-txpower/drivers/net/wireless/d80211/rt2x00/rt73usb.c   
2006-07-23 17:30:57.000000000 +0200
+++ wireless-dev-rts/drivers/net/wireless/d80211/rt2x00/rt73usb.c       
2006-07-23 
18:17:01.000000000 +0200
@@ -932,6 +932,36 @@
 }
 
 /*
+ * RTS frame creation.
+ */
+static struct sk_buff* rt73usb_create_rts(struct rt2x00_dev *rt2x00dev,
+       struct ieee80211_hdr *hdr, unsigned short duration)
+{
+       struct ieee80211_hdr *ieee80211hdr;
+       struct sk_buff *skb;
+       u16 temp;
+
+       skb = dev_alloc_skb(IEEE80211_HEADER);
+       if (!skb)
+               return NULL;
+
+       /*
+        * Copy the entire header over to RTS frame.
+        */
+       memcpy(skb_put(skb, IEEE80211_HEADER), hdr, IEEE80211_HEADER);
+       ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+
+       temp = (WLAN_FC_TYPE_CTRL  << 2) | (WLAN_FC_STYPE_RTS << 4);
+       ieee80211hdr->frame_control = cpu_to_le16(temp);
+
+       ieee80211hdr->duration_id += cpu_to_le16(duration);
+
+       ieee80211hdr->seq_ctrl = 0;
+
+       return skb;
+}
+
+/*
  * TX descriptor initialization
  */
 static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
@@ -947,6 +977,19 @@
        u16 signal;
        u16 service;
        u8 rate;
+       u16 frame_control;
+       u8 bitrate;
+       int tx_rate;
+
+       /*
+        * Check which rate should be used for this frame.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS &&
+           control->rts_cts_rate)
+               tx_rate = control->rts_cts_rate;
+       else
+               tx_rate = control->tx_rate;
 
        rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 1);
        rt2x00_set_field32(&txd->word0, TXD_W0_ACK, !control->no_ack);
@@ -961,17 +1004,21 @@
                rt2x00_set_field32(&txd->word0, TXD_W0_TIMESTAMP, 0);
 
        /*
-        * TODO: IFS can be various values, where can we find
-        * which one we want to use?
+        * Set IFS to IFS_SIFS when the this is not the first fragment,
+        * or this fragment came after RTS/CTS.
         */
-       rt2x00_set_field32(&txd->word0, TXD_W0_IFS, 0);
+       if ((WLAN_GET_SEQ_FRAG(le16_to_cpu(ieee80211hdr->seq_ctrl)) > 0) ||
+           control->use_rts_cts)
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_SIFS);
+       else
+               rt2x00_set_field32(&txd->word0, TXD_W0_IFS, IFS_BACKOFF);
 
        /*
         * TODO: How can we determine if we want long retry or short retry?
         */
        rt2x00_set_field32(&txd->word0, TXD_W0_RETRY_MODE, 0);
 
-       if (ieee80211hdr->frame_control & WLAN_FC_MOREFRAG)
+       if (frame_control & WLAN_FC_MOREFRAG)
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 1);
        else
                rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 0);
@@ -1007,7 +1054,7 @@
         * this can be done by checking if bit 4 or higher
         * is set in the ratemask.
         */
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, RATEMASK) & 0x0ff0) {
+       if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & 0x0ff0) {
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 1);
 
                /*
@@ -1018,7 +1065,7 @@
                length_low = (length & 0x3f);
 
        } else {
-               rate = DEVICE_GET_RATE_FIELD(control->tx_rate, RATE);
+               rate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
 
                rt2x00_set_field32(&txd->word0, TXD_W0_OFDM, 0);
 
@@ -1032,8 +1079,8 @@
                length_low = length & 0xff;
        }
 
-       signal = 0x8500 | DEVICE_GET_RATE_FIELD(control->tx_rate, PLCP);
-       if (DEVICE_GET_RATE_FIELD(control->tx_rate, PREAMBLE))
+       signal = 0x8500 | DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+       if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
                signal |= 0x0008;
 
        service = 0x04;
@@ -1205,8 +1252,9 @@
                rt2x00_bbp_read(rt2x00dev, 32,
                        (u8*)&entry->tx_status.ack_signal);
 
-               ieee80211_tx_status(ring->net_dev,
-                       entry->skb, &entry->tx_status);
+               if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+                       ieee80211_tx_status(ring->net_dev,
+                               entry->skb, &entry->tx_status);
 
                entry->skb = NULL;
 
@@ -1728,11 +1776,15 @@
        struct sk_buff *skb, struct ieee80211_tx_control *control)
 {
        struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+       struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
        struct usb_device *usb_dev =
                interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
        struct data_ring *ring;
        struct data_entry *entry;
        struct txd *txd;
+       struct sk_buff *skb_rts;
+       u16 frame_control;
+       int res;
 
        /*
         * Determine which ring to put packet on.
@@ -1751,6 +1803,27 @@
                return NETDEV_TX_BUSY;
        }
 
+       /*
+        * If RTS is required. and this frame is not RTS,
+        * create and queue that frame first.
+        */
+       frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+       if (control->use_rts_cts &&
+           WLAN_FC_GET_STYPE(frame_control) != WLAN_FC_STYPE_RTS) {
+               skb_rts = rt73usb_create_rts(rt2x00dev,
+                               ieee80211hdr, control->rts_cts_duration);
+               if (!skb_rts) {
+                       WARNING("Failed to create RTS frame.\n");
+                       return NETDEV_TX_BUSY;
+               }
+
+               res = rt73usb_tx(net_dev, skb_rts, control);
+               if (res) {
+                       WARNING("Failed to send RTS frame.\n");
+                       return res;
+               }
+       }
+
        entry = rt2x00_get_data_entry(ring);
        txd = rt2x00usb_txdesc_addr(entry);
 
@@ -1764,6 +1837,8 @@
 
        memcpy(rt2x00usb_txdata_addr(entry), skb->data, skb->len);
        rt73usb_write_tx_desc(rt2x00dev, txd, skb, control);
+       if (WLAN_FC_GET_STYPE(frame_control) == WLAN_FC_STYPE_RTS)
+               SET_FLAG(entry, ENTRY_RTS_FRAME);
        entry->skb = skb;
 
        SET_FLAG(entry, ENTRY_OWNER_NIC);
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to