2007-02-05 13:18:35

by Michael Büsch

[permalink] [raw]
Subject: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

This adds API calls to generate RTS and CTS-to-self frames.
To be called if the device firmware requires the host to
generate RTS/CTS frames.

Signed-off-by: Michael Buesch <[email protected]>

Index: bu3sch-wireless-dev/include/linux/ieee80211.h
===================================================================
--- bu3sch-wireless-dev.orig/include/linux/ieee80211.h 2007-02-05 13:59:34.000000000 +0100
+++ bu3sch-wireless-dev/include/linux/ieee80211.h 2007-02-05 14:01:30.000000000 +0100
@@ -189,6 +189,21 @@ struct ieee80211_mgmt {
} __attribute__ ((packed));


+/* Control frames */
+struct ieee80211_rts {
+ __le16 frame_control;
+ __le16 duration;
+ __u8 ra[6];
+ __u8 ta[6];
+} __attribute__ ((packed));
+
+struct ieee80211_cts {
+ __le16 frame_control;
+ __le16 duration;
+ __u8 ra[6];
+} __attribute__ ((packed));
+
+
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
Index: bu3sch-wireless-dev/include/net/d80211.h
===================================================================
--- bu3sch-wireless-dev.orig/include/net/d80211.h 2007-02-05 13:59:34.000000000 +0100
+++ bu3sch-wireless-dev/include/net/d80211.h 2007-02-05 14:01:30.000000000 +0100
@@ -194,7 +194,6 @@ struct ieee80211_tx_control {
#define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9)
u32 flags; /* tx control flags defined
* above */
- u16 rts_cts_duration; /* duration field for RTS/CTS frame */
u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. */
u8 power_level; /* per-packet transmit power level, in dBm */
u8 antenna_sel; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
@@ -208,7 +207,8 @@ struct ieee80211_tx_control {
u8 sw_retry_attempt; /* number of times hw has tried to
* transmit frame (not incl. hw retries) */

- int rateidx; /* internal 80211.o rateidx */
+ int rateidx; /* internal 80211.o rateidx */
+ int rts_rateidx; /* internal 80211.o rateidx for RTS/CTS */
int alt_retry_rate; /* retry rate for the last retries, given as the
* hw specific value for the rate (from
* struct ieee80211_rate). To be used to limit
@@ -829,6 +829,42 @@ struct sk_buff *ieee80211_beacon_get(str
struct ieee80211_tx_control *control);

/**
+ * ieee80211_rts_get - RTS frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame: pointer to the frame that is going to be protected by the RTS.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @rts: The buffer where to store the RTS frame.
+ *
+ * If the RTS frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next RTS frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and RTS frame is needed.
+ */
+void ieee80211_rts_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_rts *rts);
+
+/**
+ * ieee80211_ctstoself_get - CTS-to-self frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @cts: The buffer where to store the CTS-to-self frame.
+ *
+ * If the CTS-to-self frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next CTS-to-self frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and CTS-to-self frame is needed.
+ */
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_cts *cts);
+
+/**
* ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
* @hw: pointer as obtained from ieee80211_alloc_hw().
* @if_id: interface ID from &struct ieee80211_if_init_conf.
Index: bu3sch-wireless-dev/net/d80211/ieee80211.c
===================================================================
--- bu3sch-wireless-dev.orig/net/d80211/ieee80211.c 2007-02-05 13:59:34.000000000 +0100
+++ bu3sch-wireless-dev/net/d80211/ieee80211.c 2007-02-05 14:01:30.000000000 +0100
@@ -802,7 +802,6 @@ ieee80211_tx_h_misc(struct ieee80211_txr
if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
(control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
struct ieee80211_rate *rate;
- int erp = tx->u.tx.rate->flags & IEEE80211_RATE_ERP;

/* Do not use multiple retry rates when using RTS/CTS */
control->alt_retry_rate = -1;
@@ -813,16 +812,8 @@ ieee80211_tx_h_misc(struct ieee80211_txr
!(rate->flags & IEEE80211_RATE_BASIC))
rate--;

- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
- dur += ieee80211_frame_duration(tx->local, 10,
- rate->rate, erp,
- tx->local->
- short_preamble);
- dur += ieee80211_frame_duration(tx->local, tx->skb->len,
- tx->u.tx.rate->rate, erp,
- tx->u.tx.short_preamble);
- control->rts_cts_duration = dur;
control->rts_cts_rate = rate->val;
+ control->rts_rateidx = (int)(rate - tx->local->curr_rates);
}

if (tx->sta) {
@@ -1781,7 +1772,6 @@ struct sk_buff * ieee80211_beacon_get(st
control->power_level = local->hw.conf.power_level;
control->flags |= IEEE80211_TXCTL_NO_ACK;
control->retry_limit = 1;
- control->rts_cts_duration = 0;
control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
}

@@ -1790,6 +1780,87 @@ struct sk_buff * ieee80211_beacon_get(st
}
EXPORT_SYMBOL(ieee80211_beacon_get);

+static u16 ieee80211_rts_duration(struct ieee80211_local *local,
+ size_t frame_len, int rate,
+ int erp, int short_preamble)
+{
+ u16 dur;
+
+ /* Data frame duration */
+ dur = ieee80211_frame_duration(local, frame_len, rate, erp, short_preamble);
+ /* ACK duration */
+ dur += ieee80211_frame_duration(local, 14, rate, erp, short_preamble);
+ /* CTS duration */
+ dur += ieee80211_frame_duration(local, 14, rate, erp, short_preamble);
+
+ return dur;
+}
+
+static u16 ieee80211_ctstoself_duration(struct ieee80211_local *local,
+ size_t frame_len, int rate,
+ int erp, int short_preamble,
+ int data_requires_ack)
+{
+ u16 dur;
+
+ /* Data frame duration */
+ dur = ieee80211_frame_duration(local, frame_len, rate, erp, short_preamble);
+ if (data_requires_ack) {
+ /* ACK duration */
+ dur += ieee80211_frame_duration(local, 14, rate, erp, short_preamble);
+ }
+
+ return dur;
+}
+
+void ieee80211_rts_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_rts *rts)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ const struct ieee80211_hdr *hdr = frame;
+ struct ieee80211_rate *rate;
+ u16 fctl;
+ u16 duration;
+
+ fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
+ rate = &(local->curr_rates[frame_txctl->rts_rateidx]);
+ duration = ieee80211_rts_duration(local, frame_len, rate->rate,
+ !!(rate->flags & IEEE80211_RATE_ERP),
+ local->short_preamble);
+
+ rts->frame_control = cpu_to_le16(fctl);
+ rts->duration = cpu_to_le16(duration);
+ memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
+ memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
+}
+EXPORT_SYMBOL(ieee80211_rts_get);
+
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_cts *cts)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ const struct ieee80211_hdr *hdr = frame;
+ struct ieee80211_rate *rate;
+ u16 fctl;
+ u16 duration;
+
+ fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
+ rate = &(local->curr_rates[frame_txctl->rts_rateidx]);
+ duration = ieee80211_ctstoself_duration(local, frame_len, rate->rate,
+ !!(rate->flags & IEEE80211_RATE_ERP),
+ local->short_preamble,
+ !(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK));
+
+ cts->frame_control = cpu_to_le16(fctl);
+ cts->duration = cpu_to_le16(duration);
+ memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_get);
+
struct sk_buff *
ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
struct ieee80211_tx_control *control)
Index: bu3sch-wireless-dev/net/d80211/ieee80211_sta.c
===================================================================
--- bu3sch-wireless-dev.orig/net/d80211/ieee80211_sta.c 2007-02-05 13:59:34.000000000 +0100
+++ bu3sch-wireless-dev/net/d80211/ieee80211_sta.c 2007-02-05 14:01:30.000000000 +0100
@@ -2068,7 +2068,6 @@ static int ieee80211_sta_join_ibss(struc
control.power_level = local->hw.conf.power_level;
control.flags |= IEEE80211_TXCTL_NO_ACK;
control.retry_limit = 1;
- control.rts_cts_duration = 0;

ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
if (ifsta->probe_resp) {


--
Greetings Michael.


2007-02-05 13:46:31

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

On Mon, 2007-02-05 at 14:12 +0100, Michael Buesch wrote:

> - u16 rts_cts_duration; /* duration field for RTS/CTS frame */

I'd think this was here for a purpose. Maybe some hardware generates the
frame but not the duration field?

Then again, if that's the case we can always export the functions to
calculate it as library functions.

Looks good.

johannes


Attachments:
signature.asc (190.00 B)
This is a digitally signed message part

2007-02-05 13:18:35

by Michael Büsch

[permalink] [raw]
Subject: [PATCH] rt2x00-d80211: Use d80211 API to generate RTS/CTS frames

Use the new d80211 API to generate RTS and CTS-to-self frames.

Signed-off-by: Michael Buesch <[email protected]>

Index: bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/d80211/rt2x00/rt2400pci.c 2007-02-05 14:01:37.000000000 +0100
+++ bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2400pci.c 2007-02-05 14:08:19.000000000 +0100
@@ -1351,29 +1351,18 @@ static void rt2400pci_disable_radio(stru
/*
* RTS frame creation.
*/
-static struct sk_buff* rt2400pci_create_rts(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_hdr *hdr, unsigned short duration)
+static struct sk_buff* rt2400pci_create_rts(struct ieee80211_hw *hw,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
{
- struct ieee80211_hdr *ieee80211hdr;
struct sk_buff *skb;
- u16 frame_control;

- skb = dev_alloc_skb(IEEE80211_HEADER);
+ skb = dev_alloc_skb(sizeof(struct ieee80211_rts));
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;
-
- frame_control = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
- ieee80211hdr->frame_control = cpu_to_le16(frame_control);
-
- ieee80211hdr->duration_id = cpu_to_le16(duration);
-
- ieee80211hdr->seq_ctrl = 0;
+ skb_put(skb, sizeof(struct ieee80211_rts));
+ ieee80211_rts_get(hw, frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));

return skb;
}
@@ -1785,8 +1774,7 @@ static int rt2400pci_tx(struct ieee80211
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
!is_rts_frame(frame_control)) {
- skb_rts = rt2400pci_create_rts(rt2x00dev,
- ieee80211hdr, control->rts_cts_duration);
+ skb_rts = rt2400pci_create_rts(hw, skb, control);
if (!skb_rts) {
WARNING("Failed to create RTS frame.\n");
return NETDEV_TX_BUSY;
Index: bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/d80211/rt2x00/rt2500pci.c 2007-02-05 14:01:37.000000000 +0100
+++ bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2500pci.c 2007-02-05 14:08:19.000000000 +0100
@@ -1477,29 +1477,18 @@ static void rt2500pci_disable_radio(stru
/*
* RTS frame creation.
*/
-static struct sk_buff* rt2500pci_create_rts(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_hdr *hdr, unsigned short duration)
+static struct sk_buff* rt2500pci_create_rts(struct ieee80211_hw *hw,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
{
- struct ieee80211_hdr *ieee80211hdr;
struct sk_buff *skb;
- u16 frame_control;

- skb = dev_alloc_skb(IEEE80211_HEADER);
+ skb = dev_alloc_skb(sizeof(struct ieee80211_rts));
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;
-
- frame_control = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
- ieee80211hdr->frame_control = cpu_to_le16(frame_control);
-
- ieee80211hdr->duration_id = cpu_to_le16(duration);
-
- ieee80211hdr->seq_ctrl = 0;
+ skb_put(skb, sizeof(struct ieee80211_rts));
+ ieee80211_rts_get(hw, frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));

return skb;
}
@@ -1949,8 +1938,7 @@ static int rt2500pci_tx(struct ieee80211
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
!is_rts_frame(frame_control)) {
- skb_rts = rt2500pci_create_rts(rt2x00dev,
- ieee80211hdr, control->rts_cts_duration);
+ skb_rts = rt2500pci_create_rts(hw, skb, control);
if (!skb_rts) {
WARNING("Failed to create RTS frame.\n");
return NETDEV_TX_BUSY;
Index: bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/d80211/rt2x00/rt2500usb.c 2007-02-05 14:01:37.000000000 +0100
+++ bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt2500usb.c 2007-02-05 14:08:19.000000000 +0100
@@ -1442,29 +1442,18 @@ static void rt2500usb_disable_radio(stru
/*
* RTS frame creation.
*/
-static struct sk_buff* rt2500usb_create_rts(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_hdr *hdr, unsigned short duration)
+static struct sk_buff* rt2500usb_create_rts(struct ieee80211_hw *hw,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
{
- struct ieee80211_hdr *ieee80211hdr;
struct sk_buff *skb;
- u16 frame_control;

- skb = dev_alloc_skb(IEEE80211_HEADER);
+ skb = dev_alloc_skb(sizeof(struct ieee80211_rts));
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;
-
- frame_control = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
- ieee80211hdr->frame_control = cpu_to_le16(frame_control);
-
- ieee80211hdr->duration_id = cpu_to_le16(duration);
-
- ieee80211hdr->seq_ctrl = 0;
+ skb_put(skb, sizeof(struct ieee80211_rts));
+ ieee80211_rts_get(hw, frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));

return skb;
}
@@ -1882,8 +1871,7 @@ static int rt2500usb_tx(struct ieee80211
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
!is_rts_frame(frame_control)) {
- skb_rts = rt2500usb_create_rts(rt2x00dev,
- ieee80211hdr, control->rts_cts_duration);
+ skb_rts = rt2500usb_create_rts(hw, skb, control);
if (!skb_rts) {
WARNING("Failed to create RTS frame.\n");
return NETDEV_TX_BUSY;
Index: bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt61pci.c
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/d80211/rt2x00/rt61pci.c 2007-02-05 14:01:37.000000000 +0100
+++ bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt61pci.c 2007-02-05 14:08:19.000000000 +0100
@@ -1925,29 +1925,18 @@ static void rt61pci_disable_radio(struct
/*
* RTS frame creation.
*/
-static struct sk_buff* rt61pci_create_rts(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_hdr *hdr, unsigned short duration)
+static struct sk_buff* rt61pci_create_rts(struct ieee80211_hw *hw,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
{
- struct ieee80211_hdr *ieee80211hdr;
struct sk_buff *skb;
- u16 frame_control;

- skb = dev_alloc_skb(IEEE80211_HEADER);
+ skb = dev_alloc_skb(sizeof(struct ieee80211_rts));
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;
-
- frame_control = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
- ieee80211hdr->frame_control = cpu_to_le16(frame_control);
-
- ieee80211hdr->duration_id = cpu_to_le16(duration);
-
- ieee80211hdr->seq_ctrl = 0;
+ skb_put(skb, sizeof(struct ieee80211_rts));
+ ieee80211_rts_get(hw, frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));

return skb;
}
@@ -2445,8 +2434,7 @@ static int rt61pci_tx(struct ieee80211_h
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
!is_rts_frame(frame_control)) {
- skb_rts = rt61pci_create_rts(rt2x00dev,
- ieee80211hdr, control->rts_cts_duration);
+ skb_rts = rt61pci_create_rts(hw, skb, control);
if (!skb_rts) {
WARNING("Failed to create RTS frame.\n");
return NETDEV_TX_BUSY;
Index: bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt73usb.c
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/d80211/rt2x00/rt73usb.c 2007-02-05 14:01:37.000000000 +0100
+++ bu3sch-wireless-dev/drivers/net/wireless/d80211/rt2x00/rt73usb.c 2007-02-05 14:08:19.000000000 +0100
@@ -1704,29 +1704,18 @@ static void rt73usb_disable_radio(struct
/*
* RTS frame creation.
*/
-static struct sk_buff* rt73usb_create_rts(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_hdr *hdr, unsigned short duration)
+static struct sk_buff* rt73usb_create_rts(struct ieee80211_hw *hw,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
{
- struct ieee80211_hdr *ieee80211hdr;
struct sk_buff *skb;
- u16 frame_control;

- skb = dev_alloc_skb(IEEE80211_HEADER);
+ skb = dev_alloc_skb(sizeof(struct ieee80211_rts));
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;
-
- frame_control = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
- ieee80211hdr->frame_control = cpu_to_le16(frame_control);
-
- ieee80211hdr->duration_id = cpu_to_le16(duration);
-
- ieee80211hdr->seq_ctrl = 0;
+ skb_put(skb, sizeof(struct ieee80211_rts));
+ ieee80211_rts_get(hw, frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));

return skb;
}
@@ -2153,8 +2142,7 @@ static int rt73usb_tx(struct ieee80211_h
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
!is_rts_frame(frame_control)) {
- skb_rts = rt73usb_create_rts(rt2x00dev,
- ieee80211hdr, control->rts_cts_duration);
+ skb_rts = rt73usb_create_rts(hw, skb, control);
if (!skb_rts) {
WARNING("Failed to create RTS frame.\n");
return NETDEV_TX_BUSY;


--
Greetings Michael.

2007-02-05 14:58:29

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

On Mon, Feb 05, 2007 at 02:12:50PM +0100, Michael Buesch wrote:

> This adds API calls to generate RTS and CTS-to-self frames.
> To be called if the device firmware requires the host to
> generate RTS/CTS frames.

I understand the part of adding this. However..

> Index: bu3sch-wireless-dev/include/linux/ieee80211.h

> Index: bu3sch-wireless-dev/include/net/d80211.h
> ===================================================================
> --- bu3sch-wireless-dev.orig/include/net/d80211.h 2007-02-05 13:59:34.000000000 +0100
> +++ bu3sch-wireless-dev/include/net/d80211.h 2007-02-05 14:01:30.000000000 +0100
> @@ -194,7 +194,6 @@ struct ieee80211_tx_control {
> #define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9)
> u32 flags; /* tx control flags defined
> * above */
> - u16 rts_cts_duration; /* duration field for RTS/CTS frame */
> u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. */
> u8 power_level; /* per-packet transmit power level, in dBm */
> u8 antenna_sel; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */

NAK. Why are you removing this? It is needed for hardware that generates
RTS/CTS frames.

--
Jouni Malinen PGP id EFC895FA

2007-02-05 15:28:55

by Michael Büsch

[permalink] [raw]
Subject: Re: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

On Monday 05 February 2007 15:58, Jouni Malinen wrote:
> > Index: bu3sch-wireless-dev/include/net/d80211.h
> > ===================================================================
> > --- bu3sch-wireless-dev.orig/include/net/d80211.h 2007-02-05 13:59:34.000000000 +0100
> > +++ bu3sch-wireless-dev/include/net/d80211.h 2007-02-05 14:01:30.000000000 +0100
> > @@ -194,7 +194,6 @@ struct ieee80211_tx_control {
> > #define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9)
> > u32 flags; /* tx control flags defined
> > * above */
> > - u16 rts_cts_duration; /* duration field for RTS/CTS frame */
> > u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. */
> > u8 power_level; /* per-packet transmit power level, in dBm */
> > u8 antenna_sel; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
>
> NAK. Why are you removing this? It is needed for hardware that generates
> RTS/CTS frames.

As I said in response to Johannes' comment, if a driver needs just
the duration, we should export the functions to calculate it
and remove the calculation from the tx_control and the tx_control
setup path.

Currently there is no driver using it, so I simply removed it.

BTW: Which cards need the duration, but not the whole frame?

--
Greetings Michael.

2007-02-05 16:54:16

by Michael Büsch

[permalink] [raw]
Subject: Re: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

On Monday 05 February 2007 17:47, Jouni Malinen wrote:
> On Mon, Feb 05, 2007 at 04:28:46PM +0100, Michael Buesch wrote:
>
> > As I said in response to Johannes' comment, if a driver needs just
> > the duration, we should export the functions to calculate it
> > and remove the calculation from the tx_control and the tx_control
> > setup path.
>
> In that case, I would like to see this change being included in the same
> patch/patchset.. Without this, I can only NAK this kind of change since
> it removes functionality needed for some designs and that is not
> something I would like to see happening with net/d80211 since the goal
> is to allow all reasonable hardware designs to work with it.

Ok, I already resent the patchset. ;)

> > Currently there is no driver using it, so I simply removed it.
>
> There are, but maybe not in wireless-dev.git.
>
> > BTW: Which cards need the duration, but not the whole frame?
>
> Any card that supports different transmit rates for hw retries involving
> RTS/CTS/fragmentation (e.g., Atheros).

Ok, nice.
I just want to make sure that we don't have unused features (aka bloat)
in the stack.

--
Greetings Michael.

2007-02-05 13:31:30

by Michael Büsch

[permalink] [raw]
Subject: Re: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

On Monday 05 February 2007 14:12, Michael Buesch wrote:
> +static u16 ieee80211_rts_duration(struct ieee80211_local *local,
> + size_t frame_len, int rate,
> + int erp, int short_preamble)
> +{
> + u16 dur;
> +
> + /* Data frame duration */
> + dur = ieee80211_frame_duration(local, frame_len, rate, erp, short_preamble);
> + /* ACK duration */
> + dur += ieee80211_frame_duration(local, 14, rate, erp, short_preamble);
> + /* CTS duration */
> + dur += ieee80211_frame_duration(local, 14, rate, erp, short_preamble);

Ok, I just figured out that this is wrong.
It should be length 10, as the FCS length is added in ieee80211_frame_duration.

> + return dur;
> +}
> +
> +static u16 ieee80211_ctstoself_duration(struct ieee80211_local *local,
> + size_t frame_len, int rate,
> + int erp, int short_preamble,
> + int data_requires_ack)
> +{
> + u16 dur;
> +
> + /* Data frame duration */
> + dur = ieee80211_frame_duration(local, frame_len, rate, erp, short_preamble);
> + if (data_requires_ack) {
> + /* ACK duration */
> + dur += ieee80211_frame_duration(local, 14, rate, erp, short_preamble);
> + }

Same here.


I will submit a corrected patch, soon.
But please still review this one for other bugs.

--
Greetings Michael.

2007-02-05 13:18:35

by Michael Büsch

[permalink] [raw]
Subject: [PATCH] bcm43xx-d80211: Use d80211 API to generate RTS/CTS frames

Use the new d80211 API to generate RTS and CTS-to-self frames.

Signed-off-by: Michael Buesch <[email protected]>

Index: bu3sch-wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c 2007-02-05 14:01:40.000000000 +0100
+++ bu3sch-wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c 2007-02-05 14:05:55.000000000 +0100
@@ -198,85 +198,6 @@ __le16 bcm43xx_calc_duration(const struc
return duration_id;
}

-static inline
-u16 ceiling_div(u16 dividend, u16 divisor)
-{
- return ((dividend + divisor - 1) / divisor);
-}
-
-//TODO
-#if 0
-static void bcm43xx_generate_rts(const struct bcm43xx_phy *phy,
- struct bcm43xx_txhdr_fw3 *txhdr,
- u16 *flags,
- u8 bitrate,
- const struct ieee80211_hdr *wlhdr)
-{
- u16 fctl;
- u16 dur;
- u8 fallback_bitrate;
- int ofdm_modulation;
- int fallback_ofdm_modulation;
- u8 *sa, *da;
- u16 flen;
-
- sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr);
- da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr);
- fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
- ofdm_modulation = !(bcm43xx_is_cck_rate(bitrate));
- fallback_ofdm_modulation = !(bcm43xx_is_cck_rate(fallback_bitrate));
-
- flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + FCS_LEN,
- bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
- flen, bitrate);
- bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
- flen, fallback_bitrate);
- fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
- dur = le16_to_cpu(wlhdr->duration_id);
-/*FIXME: should we test for dur==0 here and let it unmodified in this case?
- * The following assert checks for this case...
- */
-assert(dur);
-/*FIXME: The duration calculation is not really correct.
- * I am not 100% sure which bitrate to use. We use the RTS rate here,
- * but this is likely to be wrong.
- */
- if (phy->type == BCM43xx_PHYTYPE_A) {
- /* Three times SIFS */
- dur += 16 * 3;
- /* Add ACK duration. */
- dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
- bitrate * 4);
- /* Add CTS duration. */
- dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10,
- bitrate * 4);
- } else {
- /* Three times SIFS */
- dur += 10 * 3;
- /* Add ACK duration. */
- dur += ceiling_div(8 * (14 /*bytes*/) * 10,
- bitrate);
- /* Add CTS duration. */
- dur += ceiling_div(8 * (14 /*bytes*/) * 10,
- bitrate);
- }
-
- txhdr->rts_cts_frame_control = cpu_to_le16(fctl);
- txhdr->rts_cts_dur = cpu_to_le16(dur);
-//printk(MAC_FMT " " MAC_FMT " " MAC_FMT "\n", MAC_ARG(wlhdr->addr1), MAC_ARG(wlhdr->addr2), MAC_ARG(wlhdr->addr3));
-//printk(MAC_FMT " " MAC_FMT "\n", MAC_ARG(sa), MAC_ARG(da));
- memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME!
- memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN);
-
- *flags |= BCM43xx_TXHDRFLAG_RTSCTS;
- *flags |= BCM43xx_TXHDRFLAG_RTS;
- if (ofdm_modulation)
- *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM;
- if (fallback_ofdm_modulation)
- *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM;
-}
-#endif
-
static void generate_txhdr_fw4(struct bcm43xx_wldev *dev,
struct bcm43xx_txhdr_fw4 *txhdr,
const unsigned char *fragment_data,
@@ -307,7 +228,6 @@ static void generate_txhdr_fw4(struct bc
txhdr->phy_rate = bcm43xx_plcp_get_ratecode_ofdm(rate);
else
txhdr->phy_rate = bcm43xx_plcp_get_ratecode_cck(rate);
- //TODO RTS phyrate
txhdr->mac_frame_ctl = wlhdr->frame_control;
memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
txhdr->dur_fb = bcm43xx_calc_duration(wlhdr, rate_fb);
@@ -386,8 +306,47 @@ static void generate_txhdr_fw4(struct bc
if (phy->type == BCM43xx_PHYTYPE_A)
mac_ctl |= BCM43xx_TX4_MAC_5GHZ;

- if (txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
- //TODO
+ /* Generate the RTS or CTS-to-self frame */
+ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+ (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ unsigned int len;
+ struct ieee80211_hdr *hdr;
+ int rts_rate, rts_rate_fb;
+ int rts_rate_ofdm, rts_rate_fb_ofdm;
+
+ rts_rate = txctl->rts_cts_rate;
+ rts_rate_ofdm = bcm43xx_is_ofdm_rate(rts_rate);
+ rts_rate_fb = bcm43xx_calc_fallback_rate(rts_rate);
+ rts_rate_fb_ofdm = bcm43xx_is_ofdm_rate(rts_rate_fb);
+
+ if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ ieee80211_ctstoself_get(dev->wl->hw,
+ fragment_data, fragment_len, txctl,
+ (struct ieee80211_cts *)(txhdr->rts_frame));
+ mac_ctl |= BCM43xx_TX4_MAC_SENDCTS;
+ len = sizeof(struct ieee80211_cts);
+ } else {
+ ieee80211_rts_get(dev->wl->hw,
+ fragment_data, fragment_len, txctl,
+ (struct ieee80211_rts *)(txhdr->rts_frame));
+ mac_ctl |= BCM43xx_TX4_MAC_SENDRTS;
+ len = sizeof(struct ieee80211_rts);
+ }
+ len += FCS_LEN;
+ bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_plcp),
+ len, rts_rate);
+ bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_plcp_fb),
+ len, rts_rate_fb);
+ hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+ txhdr->rts_dur_fb = hdr->duration_id;
+ if (rts_rate_ofdm) {
+ extra_ft |= BCM43xx_TX4_EFT_RTSOFDM;
+ txhdr->phy_rate_rts = bcm43xx_plcp_get_ratecode_ofdm(rts_rate);
+ } else
+ txhdr->phy_rate_rts = bcm43xx_plcp_get_ratecode_cck(rts_rate);
+ if (rts_rate_fb_ofdm)
+ extra_ft |= BCM43xx_TX4_EFT_RTSFBOFDM;
+ mac_ctl |= BCM43xx_TX4_MAC_LONGFRAME;
}

/* Magic cookie */


--
Greetings Michael.

2007-02-05 17:01:55

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

On Mon, Feb 05, 2007 at 04:28:46PM +0100, Michael Buesch wrote:

> As I said in response to Johannes' comment, if a driver needs just
> the duration, we should export the functions to calculate it
> and remove the calculation from the tx_control and the tx_control
> setup path.

In that case, I would like to see this change being included in the same
patch/patchset.. Without this, I can only NAK this kind of change since
it removes functionality needed for some designs and that is not
something I would like to see happening with net/d80211 since the goal
is to allow all reasonable hardware designs to work with it.

> Currently there is no driver using it, so I simply removed it.

There are, but maybe not in wireless-dev.git.

> BTW: Which cards need the duration, but not the whole frame?

Any card that supports different transmit rates for hw retries involving
RTS/CTS/fragmentation (e.g., Atheros).

--
Jouni Malinen PGP id EFC895FA

2007-02-05 13:54:09

by Michael Büsch

[permalink] [raw]
Subject: Re: [PATCH] d80211: Add API to generate RTS and CTS-to-self frames

On Monday 05 February 2007 14:43, Johannes Berg wrote:
> On Mon, 2007-02-05 at 14:12 +0100, Michael Buesch wrote:
>
> > - u16 rts_cts_duration; /* duration field for RTS/CTS frame */
>
> I'd think this was here for a purpose. Maybe some hardware generates the
> frame but not the duration field?
>
> Then again, if that's the case we can always export the functions to
> calculate it as library functions.

Only rt2x00 used it to generate an rts frame with it own custom
generation function. So after switching to the d80211 RTS API
it's unneeded now.

If some driver needs the duration field in future, we should
simply export ieee80211_rts_duration().

--
Greetings Michael.