aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2009-11-30 12:12:08 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-07 16:51:19 -0500
commit20f09c3df7a8a623c290f62596c1a6b0da088030 (patch)
treea65343d091be0ee4ba65f41bdb1fe99e4b5e0381 /drivers/net
parent140eb5e2c1978622d7cd979d59a1c0586fe3bbdb (diff)
mwl8k: prevent corruption of QoS field on receive
Packets exchanged between the mwl8k driver and the firmware always have a 4-address header without QoS field. For QoS packets, the QoS field is passed to/from the firmware via the tx/rx descriptors. We were handling this correctly on transmit, but not on receive -- if a QoS packet was received, we would leave garbage in the QoS field in the packet passed up to the stack, which is Bad(tm). Also, if the packet received on the air was a 4-address without QoS packet, we would forget to skb_pull the 2-byte DMA length prefix off. This patch adds an argument to the ->rxd_process() receive descriptor operation to retrieve the QoS field from the receive descriptor, and extends mwl8k_remove_dma_header() to insert this field back into the packet if the packet received is a QoS packet. It also fixes mwl8k_remove_dma_header() to strip off the length prefix in all cases. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/mwl8k.c46
1 files changed, 31 insertions, 15 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 0251b6144f57..6b12d81ba94b 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -84,7 +84,8 @@ struct rxd_ops {
84 int rxd_size; 84 int rxd_size;
85 void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); 85 void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr);
86 void (*rxd_refill)(void *rxd, dma_addr_t addr, int len); 86 void (*rxd_refill)(void *rxd, dma_addr_t addr, int len);
87 int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status); 87 int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status,
88 __le16 *qos);
88}; 89};
89 90
90struct mwl8k_device_info { 91struct mwl8k_device_info {
@@ -699,21 +700,29 @@ static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len)
699struct mwl8k_dma_data { 700struct mwl8k_dma_data {
700 __le16 fwlen; 701 __le16 fwlen;
701 struct ieee80211_hdr wh; 702 struct ieee80211_hdr wh;
703 char data[0];
702} __attribute__((packed)); 704} __attribute__((packed));
703 705
704/* Routines to add/remove DMA header from skb. */ 706/* Routines to add/remove DMA header from skb. */
705static inline void mwl8k_remove_dma_header(struct sk_buff *skb) 707static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
706{ 708{
707 struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data; 709 struct mwl8k_dma_data *tr;
708 void *dst, *src = &tr->wh; 710 int hdrlen;
709 int hdrlen = ieee80211_hdrlen(tr->wh.frame_control); 711
710 u16 space = sizeof(struct mwl8k_dma_data) - hdrlen; 712 tr = (struct mwl8k_dma_data *)skb->data;
713 hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
711 714
712 dst = (void *)tr + space; 715 if (hdrlen != sizeof(tr->wh)) {
713 if (dst != src) { 716 if (ieee80211_is_data_qos(tr->wh.frame_control)) {
714 memmove(dst, src, hdrlen); 717 memmove(tr->data - hdrlen, &tr->wh, hdrlen - 2);
715 skb_pull(skb, space); 718 *((__le16 *)(tr->data - 2)) = qos;
719 } else {
720 memmove(tr->data - hdrlen, &tr->wh, hdrlen);
721 }
716 } 722 }
723
724 if (hdrlen != sizeof(*tr))
725 skb_pull(skb, sizeof(*tr) - hdrlen);
717} 726}
718 727
719static inline void mwl8k_add_dma_header(struct sk_buff *skb) 728static inline void mwl8k_add_dma_header(struct sk_buff *skb)
@@ -793,7 +802,8 @@ static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
793} 802}
794 803
795static int 804static int
796mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status) 805mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
806 __le16 *qos)
797{ 807{
798 struct mwl8k_rxd_8366 *rxd = _rxd; 808 struct mwl8k_rxd_8366 *rxd = _rxd;
799 809
@@ -823,6 +833,8 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status)
823 status->band = IEEE80211_BAND_2GHZ; 833 status->band = IEEE80211_BAND_2GHZ;
824 status->freq = ieee80211_channel_to_frequency(rxd->channel); 834 status->freq = ieee80211_channel_to_frequency(rxd->channel);
825 835
836 *qos = rxd->qos_control;
837
826 return le16_to_cpu(rxd->pkt_len); 838 return le16_to_cpu(rxd->pkt_len);
827} 839}
828 840
@@ -881,7 +893,8 @@ static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
881} 893}
882 894
883static int 895static int
884mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status) 896mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
897 __le16 *qos)
885{ 898{
886 struct mwl8k_rxd_8687 *rxd = _rxd; 899 struct mwl8k_rxd_8687 *rxd = _rxd;
887 u16 rate_info; 900 u16 rate_info;
@@ -912,6 +925,8 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status)
912 status->band = IEEE80211_BAND_2GHZ; 925 status->band = IEEE80211_BAND_2GHZ;
913 status->freq = ieee80211_channel_to_frequency(rxd->channel); 926 status->freq = ieee80211_channel_to_frequency(rxd->channel);
914 927
928 *qos = rxd->qos_control;
929
915 return le16_to_cpu(rxd->pkt_len); 930 return le16_to_cpu(rxd->pkt_len);
916} 931}
917 932
@@ -1083,6 +1098,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
1083 void *rxd; 1098 void *rxd;
1084 int pkt_len; 1099 int pkt_len;
1085 struct ieee80211_rx_status status; 1100 struct ieee80211_rx_status status;
1101 __le16 qos;
1086 1102
1087 skb = rxq->buf[rxq->head].skb; 1103 skb = rxq->buf[rxq->head].skb;
1088 if (skb == NULL) 1104 if (skb == NULL)
@@ -1090,7 +1106,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
1090 1106
1091 rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size); 1107 rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size);
1092 1108
1093 pkt_len = priv->rxd_ops->rxd_process(rxd, &status); 1109 pkt_len = priv->rxd_ops->rxd_process(rxd, &status, &qos);
1094 if (pkt_len < 0) 1110 if (pkt_len < 0)
1095 break; 1111 break;
1096 1112
@@ -1108,7 +1124,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
1108 rxq->rxd_count--; 1124 rxq->rxd_count--;
1109 1125
1110 skb_put(skb, pkt_len); 1126 skb_put(skb, pkt_len);
1111 mwl8k_remove_dma_header(skb); 1127 mwl8k_remove_dma_header(skb, qos);
1112 1128
1113 /* 1129 /*
1114 * Check for a pending join operation. Save a 1130 * Check for a pending join operation. Save a
@@ -1354,7 +1370,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
1354 BUG_ON(skb == NULL); 1370 BUG_ON(skb == NULL);
1355 pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); 1371 pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
1356 1372
1357 mwl8k_remove_dma_header(skb); 1373 mwl8k_remove_dma_header(skb, tx_desc->qos_control);
1358 1374
1359 /* Mark descriptor as unused */ 1375 /* Mark descriptor as unused */
1360 tx_desc->pkt_phys_addr = 0; 1376 tx_desc->pkt_phys_addr = 0;