aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBenoit Papillault <benoit.papillault@free.fr>2010-02-27 17:05:26 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-10 17:44:06 -0500
commit8127fbdc417b5916b82e91400a4be1d9555feee7 (patch)
treede519dbb9bfd805769e9c13ad3cd086a57ac4ea0 /drivers
parentc2ef355bf3ef0b8006b96128726684fba47ac928 (diff)
ath5k: Fix TX/RX padding for all frames
Currently, the padding position is based on ieee80211_get_hdrlen_from_skb(). This is not correct since the HW does padding on RX (and expect the same padding to be present on TX) at the following position : - management : 24 + 6 if 4-addr format - control : 24 + 6 if 4-addr format - data : 24 + 6 if 4-addr format + 2 if QoS - invalid : 24 + 6 if 4-addr format whereas ieee80211_get_hdrlen_from_skb() is : - management : 24 - control : 16 except for ACK/CTS where it is 10 - data : 24 + 6 if 4-addr format + 2 if QoS + 2 if QoS & order - invalid : 24 So, correct frames are not affected : management frames do not use 4-addr format, control frames have no body and invalid frames are ... not valid by definition. However, in order to use monitor interface for debugging purpose, one must be able to send/receive any frames, be it correct or not. Such frames are affected by incorrect padding. Moreover, since padding is added on TX, we need to remove it before calling ieee80211_tx_status. This affect TX packets received by monitor interfaces. It has been tested between an ath5k based card (AR5212) and an ar9170usb based card (netgear WNDA3100) using a frame generator and a monitor interface for each card. v2: Added ath5k_add_padding / ath5k_remove_padding Signed-off-by: Benoit Papillault <benoit.papillault@free.fr> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h9
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c105
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c10
3 files changed, 88 insertions, 36 deletions
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 4de7fe03b9f..22f9f59397c 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1141,9 +1141,9 @@ struct ath5k_hw {
1141 int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc, 1141 int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
1142 u32 size, unsigned int flags); 1142 u32 size, unsigned int flags);
1143 int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, 1143 int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
1144 unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, 1144 unsigned int, unsigned int, int, enum ath5k_pkt_type,
1145 unsigned int, unsigned int, unsigned int, unsigned int, 1145 unsigned int, unsigned int, unsigned int, unsigned int,
1146 unsigned int, unsigned int, unsigned int); 1146 unsigned int, unsigned int, unsigned int, unsigned int);
1147 int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, 1147 int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
1148 unsigned int, unsigned int, unsigned int, unsigned int, 1148 unsigned int, unsigned int, unsigned int, unsigned int,
1149 unsigned int, unsigned int); 1149 unsigned int, unsigned int);
@@ -1342,9 +1342,4 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
1342 return retval; 1342 return retval;
1343} 1343}
1344 1344
1345static inline int ath5k_pad_size(int hdrlen)
1346{
1347 return (hdrlen < 24) ? 0 : hdrlen & 3;
1348}
1349
1350#endif 1345#endif
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index c889d4992a6..7c08434ebd1 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -307,7 +307,7 @@ static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
307 struct ath5k_buf *bf); 307 struct ath5k_buf *bf);
308static int ath5k_txbuf_setup(struct ath5k_softc *sc, 308static int ath5k_txbuf_setup(struct ath5k_softc *sc,
309 struct ath5k_buf *bf, 309 struct ath5k_buf *bf,
310 struct ath5k_txq *txq); 310 struct ath5k_txq *txq, int padsize);
311static inline void ath5k_txbuf_free(struct ath5k_softc *sc, 311static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
312 struct ath5k_buf *bf) 312 struct ath5k_buf *bf)
313{ 313{
@@ -1271,7 +1271,7 @@ static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb)
1271 1271
1272static int 1272static int
1273ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, 1273ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
1274 struct ath5k_txq *txq) 1274 struct ath5k_txq *txq, int padsize)
1275{ 1275{
1276 struct ath5k_hw *ah = sc->ah; 1276 struct ath5k_hw *ah = sc->ah;
1277 struct ath5k_desc *ds = bf->desc; 1277 struct ath5k_desc *ds = bf->desc;
@@ -1323,7 +1323,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
1323 sc->vif, pktlen, info)); 1323 sc->vif, pktlen, info));
1324 } 1324 }
1325 ret = ah->ah_setup_tx_desc(ah, ds, pktlen, 1325 ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
1326 ieee80211_get_hdrlen_from_skb(skb), 1326 ieee80211_get_hdrlen_from_skb(skb), padsize,
1327 get_hw_packet_type(skb), 1327 get_hw_packet_type(skb),
1328 (sc->power_level * 2), 1328 (sc->power_level * 2),
1329 hw_rate, 1329 hw_rate,
@@ -1805,6 +1805,67 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
1805 } 1805 }
1806} 1806}
1807 1807
1808/*
1809 * Compute padding position. skb must contains an IEEE 802.11 frame
1810 */
1811static int ath5k_common_padpos(struct sk_buff *skb)
1812{
1813 struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
1814 __le16 frame_control = hdr->frame_control;
1815 int padpos = 24;
1816
1817 if (ieee80211_has_a4(frame_control)) {
1818 padpos += ETH_ALEN;
1819 }
1820 if (ieee80211_is_data_qos(frame_control)) {
1821 padpos += IEEE80211_QOS_CTL_LEN;
1822 }
1823
1824 return padpos;
1825}
1826
1827/*
1828 * This function expects a 802.11 frame and returns the number of
1829 * bytes added, or -1 if we don't have enought header room.
1830 */
1831
1832static int ath5k_add_padding(struct sk_buff *skb)
1833{
1834 int padpos = ath5k_common_padpos(skb);
1835 int padsize = padpos & 3;
1836
1837 if (padsize && skb->len>padpos) {
1838
1839 if (skb_headroom(skb) < padsize)
1840 return -1;
1841
1842 skb_push(skb, padsize);
1843 memmove(skb->data, skb->data+padsize, padpos);
1844 return padsize;
1845 }
1846
1847 return 0;
1848}
1849
1850/*
1851 * This function expects a 802.11 frame and returns the number of
1852 * bytes removed
1853 */
1854
1855static int ath5k_remove_padding(struct sk_buff *skb)
1856{
1857 int padpos = ath5k_common_padpos(skb);
1858 int padsize = padpos & 3;
1859
1860 if (padsize && skb->len>=padpos+padsize) {
1861 memmove(skb->data + padsize, skb->data, padpos);
1862 skb_pull(skb, padsize);
1863 return padsize;
1864 }
1865
1866 return 0;
1867}
1868
1808static void 1869static void
1809ath5k_tasklet_rx(unsigned long data) 1870ath5k_tasklet_rx(unsigned long data)
1810{ 1871{
@@ -1818,8 +1879,6 @@ ath5k_tasklet_rx(unsigned long data)
1818 struct ath5k_buf *bf; 1879 struct ath5k_buf *bf;
1819 struct ath5k_desc *ds; 1880 struct ath5k_desc *ds;
1820 int ret; 1881 int ret;
1821 int hdrlen;
1822 int padsize;
1823 int rx_flag; 1882 int rx_flag;
1824 1883
1825 spin_lock(&sc->rxbuflock); 1884 spin_lock(&sc->rxbuflock);
@@ -1904,12 +1963,8 @@ accept:
1904 * bytes and we can optimize this a bit. In addition, we must 1963 * bytes and we can optimize this a bit. In addition, we must
1905 * not try to remove padding from short control frames that do 1964 * not try to remove padding from short control frames that do
1906 * not have payload. */ 1965 * not have payload. */
1907 hdrlen = ieee80211_get_hdrlen_from_skb(skb); 1966 ath5k_remove_padding(skb);
1908 padsize = ath5k_pad_size(hdrlen); 1967
1909 if (padsize) {
1910 memmove(skb->data + padsize, skb->data, hdrlen);
1911 skb_pull(skb, padsize);
1912 }
1913 rxs = IEEE80211_SKB_RXCB(skb); 1968 rxs = IEEE80211_SKB_RXCB(skb);
1914 1969
1915 /* 1970 /*
@@ -2029,6 +2084,12 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
2029 info->status.ack_signal = ts.ts_rssi; 2084 info->status.ack_signal = ts.ts_rssi;
2030 } 2085 }
2031 2086
2087 /*
2088 * Remove MAC header padding before giving the frame
2089 * back to mac80211.
2090 */
2091 ath5k_remove_padding(skb);
2092
2032 ieee80211_tx_status(sc->hw, skb); 2093 ieee80211_tx_status(sc->hw, skb);
2033 2094
2034 spin_lock(&sc->txbuflock); 2095 spin_lock(&sc->txbuflock);
@@ -2072,6 +2133,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
2072 int ret = 0; 2133 int ret = 0;
2073 u8 antenna; 2134 u8 antenna;
2074 u32 flags; 2135 u32 flags;
2136 const int padsize = 0;
2075 2137
2076 bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, 2138 bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
2077 PCI_DMA_TODEVICE); 2139 PCI_DMA_TODEVICE);
@@ -2119,7 +2181,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
2119 * from tx power (value is in dB units already) */ 2181 * from tx power (value is in dB units already) */
2120 ds->ds_data = bf->skbaddr; 2182 ds->ds_data = bf->skbaddr;
2121 ret = ah->ah_setup_tx_desc(ah, ds, skb->len, 2183 ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
2122 ieee80211_get_hdrlen_from_skb(skb), 2184 ieee80211_get_hdrlen_from_skb(skb), padsize,
2123 AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), 2185 AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
2124 ieee80211_get_tx_rate(sc->hw, info)->hw_value, 2186 ieee80211_get_tx_rate(sc->hw, info)->hw_value,
2125 1, AR5K_TXKEYIX_INVALID, 2187 1, AR5K_TXKEYIX_INVALID,
@@ -2679,7 +2741,6 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
2679 struct ath5k_softc *sc = hw->priv; 2741 struct ath5k_softc *sc = hw->priv;
2680 struct ath5k_buf *bf; 2742 struct ath5k_buf *bf;
2681 unsigned long flags; 2743 unsigned long flags;
2682 int hdrlen;
2683 int padsize; 2744 int padsize;
2684 2745
2685 ath5k_debug_dump_skb(sc, skb, "TX ", 1); 2746 ath5k_debug_dump_skb(sc, skb, "TX ", 1);
@@ -2691,17 +2752,11 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
2691 * the hardware expects the header padded to 4 byte boundaries 2752 * the hardware expects the header padded to 4 byte boundaries
2692 * if this is not the case we add the padding after the header 2753 * if this is not the case we add the padding after the header
2693 */ 2754 */
2694 hdrlen = ieee80211_get_hdrlen_from_skb(skb); 2755 padsize = ath5k_add_padding(skb);
2695 padsize = ath5k_pad_size(hdrlen); 2756 if (padsize < 0) {
2696 if (padsize) { 2757 ATH5K_ERR(sc, "tx hdrlen not %%4: not enough"
2697 2758 " headroom to pad");
2698 if (skb_headroom(skb) < padsize) { 2759 goto drop_packet;
2699 ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
2700 " headroom to pad %d\n", hdrlen, padsize);
2701 goto drop_packet;
2702 }
2703 skb_push(skb, padsize);
2704 memmove(skb->data, skb->data+padsize, hdrlen);
2705 } 2760 }
2706 2761
2707 spin_lock_irqsave(&sc->txbuflock, flags); 2762 spin_lock_irqsave(&sc->txbuflock, flags);
@@ -2720,7 +2775,7 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
2720 2775
2721 bf->skb = skb; 2776 bf->skb = skb;
2722 2777
2723 if (ath5k_txbuf_setup(sc, bf, txq)) { 2778 if (ath5k_txbuf_setup(sc, bf, txq, padsize)) {
2724 bf->skb = NULL; 2779 bf->skb = NULL;
2725 spin_lock_irqsave(&sc->txbuflock, flags); 2780 spin_lock_irqsave(&sc->txbuflock, flags);
2726 list_add_tail(&bf->list, &sc->txbuf); 2781 list_add_tail(&bf->list, &sc->txbuf);
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index dc30a2b70a6..d26126bfacd 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -35,7 +35,8 @@
35 */ 35 */
36static int 36static int
37ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, 37ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
38 unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, 38 unsigned int pkt_len, unsigned int hdr_len, int padsize,
39 enum ath5k_pkt_type type,
39 unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, 40 unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
40 unsigned int key_index, unsigned int antenna_mode, unsigned int flags, 41 unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
41 unsigned int rtscts_rate, unsigned int rtscts_duration) 42 unsigned int rtscts_rate, unsigned int rtscts_duration)
@@ -71,7 +72,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
71 /* Verify and set frame length */ 72 /* Verify and set frame length */
72 73
73 /* remove padding we might have added before */ 74 /* remove padding we might have added before */
74 frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; 75 frame_len = pkt_len - padsize + FCS_LEN;
75 76
76 if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) 77 if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
77 return -EINVAL; 78 return -EINVAL;
@@ -100,7 +101,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
100 AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); 101 AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
101 } 102 }
102 103
103 /*Diferences between 5210-5211*/ 104 /*Differences between 5210-5211*/
104 if (ah->ah_version == AR5K_AR5210) { 105 if (ah->ah_version == AR5K_AR5210) {
105 switch (type) { 106 switch (type) {
106 case AR5K_PKT_TYPE_BEACON: 107 case AR5K_PKT_TYPE_BEACON:
@@ -165,6 +166,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
165 */ 166 */
166static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, 167static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
167 struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, 168 struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
169 int padsize,
168 enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, 170 enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
169 unsigned int tx_tries0, unsigned int key_index, 171 unsigned int tx_tries0, unsigned int key_index,
170 unsigned int antenna_mode, unsigned int flags, 172 unsigned int antenna_mode, unsigned int flags,
@@ -206,7 +208,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
206 /* Verify and set frame length */ 208 /* Verify and set frame length */
207 209
208 /* remove padding we might have added before */ 210 /* remove padding we might have added before */
209 frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; 211 frame_len = pkt_len - padsize + FCS_LEN;
210 212
211 if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) 213 if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
212 return -EINVAL; 214 return -EINVAL;