diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index ebe7e41e5eaf..5e11ccf8a763 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -690,6 +690,7 @@ enum ieee80211_state { #define CFG_IEEE80211_RESERVE_FCS (1<<0) #define CFG_IEEE80211_COMPUTE_FCS (1<<1) +#define CFG_IEEE80211_RTS (1<<2) struct ieee80211_device { struct net_device *dev; @@ -747,6 +748,7 @@ struct ieee80211_device { struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN]; unsigned int frag_next_idx; u16 fts; /* Fragmentation Threshold */ + u16 rts; /* RTS threshold */ /* Association info */ u8 bssid[ETH_ALEN]; diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 82a4fd713b28..67d6bdd2e3f2 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -126,6 +126,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv) /* Default fragmentation threshold is maximum payload size */ ieee->fts = DEFAULT_FTS; + ieee->rts = DEFAULT_FTS; ieee->scan_age = DEFAULT_MAX_SCAN_AGE; ieee->open_wep = 1; diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 29770cfefc3d..cdee41cefb26 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -222,13 +222,15 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, return txb; } -/* SKBs are added to the ieee->tx_queue. */ +/* Incoming skb is converted to a txb which consist of + * a block of 802.11 fragment packets (stored as skbs) */ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); struct ieee80211_txb *txb = NULL; struct ieee80211_hdr_3addr *frag_hdr; - int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; + int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, + rts_required; unsigned long flags; struct net_device_stats *stats = &ieee->stats; int ether_type, encrypt, host_encrypt; @@ -334,6 +336,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) else bytes_last_frag = bytes_per_frag; + rts_required = (frag_size > ieee->rts + && ieee->config & CFG_IEEE80211_RTS); + if (rts_required) + nr_frags++; + else + bytes_last_frag = bytes_per_frag; + /* When we allocate the TXB we allocate enough space for the reserve * and full fragment bytes (bytes_per_frag doesn't include prefix, * postfix, header, FCS, etc.) */ @@ -346,7 +355,33 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) txb->encrypted = encrypt; txb->payload_size = bytes; - for (i = 0; i < nr_frags; i++) { + if (rts_required) { + skb_frag = txb->fragments[0]; + frag_hdr = + (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); + + /* + * Set header frame_ctl to the RTS. + */ + header.frame_ctl = + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); + memcpy(frag_hdr, &header, hdr_len); + + /* + * Restore header frame_ctl to the original data setting. + */ + header.frame_ctl = cpu_to_le16(fc); + + if (ieee->config & + (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) + skb_put(skb_frag, 4); + + txb->rts_included = 1; + i = 1; + } else + i = 0; + + for (; i < nr_frags; i++) { skb_frag = txb->fragments[i]; if (host_encrypt)