From: Benoit PAPILLAULT <benoit@benoit-laptop.(none)>
It has been tested with a 802.11 frame generator and by checking the FCS field
of each received frame with the value reported by the Atheros hardware. This
patch is useful if you are trying to analyze non standard 802.11 frame going
over the air.
Signed-off-by: Benoit PAPILLAULT <benoit@benoit-laptop.(none)>
---
drivers/net/wireless/ath/ath9k/common.c | 19 ++++++++++++++-----
1 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 2f1e161..4a13632 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -231,26 +231,35 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
{
struct ath_hw *ah = common->ah;
struct ieee80211_hdr *hdr;
- int hdrlen, padsize;
+ int hdrlen, padpos, padsize;
u8 keyix;
__le16 fc;
/* see if any padding is done by the hw and remove it */
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ padpos = 24;
fc = hdr->frame_control;
+ if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) ==
+ cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) {
+ padpos += 6; /* ETH_ALEN */
+ }
+ if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) ==
+ cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) {
+ padpos += 2;
+ }
/* The MAC header is padded to have 32-bit boundary if the
* packet payload is non-zero. The general calculation for
* padsize would take into account odd header lengths:
- * padsize = (4 - hdrlen % 4) % 4; However, since only
+ * padsize = (4 - padpos % 4) % 4; However, since only
* even-length headers are used, padding can only be 0 or 2
* bytes and we can optimize this a bit. In addition, we must
* not try to remove padding from short control frames that do
* not have payload. */
- padsize = hdrlen & 3;
- if (padsize && hdrlen >= 24) {
- memmove(skb->data + padsize, skb->data, hdrlen);
+ padsize = padpos & 3;
+ if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+ memmove(skb->data + padsize, skb->data, padpos);
skb_pull(skb, padsize);
}
--
1.6.3.3
Oops... Disregard this one, it has been already applied.
Regards, Benoit.
Benoit Papillault a ?crit :
> From: Benoit PAPILLAULT <benoit@benoit-laptop.(none)>
>
> It has been tested with a 802.11 frame generator and by checking the FCS field
> of each received frame with the value reported by the Atheros hardware. This
> patch is useful if you are trying to analyze non standard 802.11 frame going
> over the air.
>
> Signed-off-by: Benoit PAPILLAULT <benoit@benoit-laptop.(none)>
> ---
> drivers/net/wireless/ath/ath9k/common.c | 19 ++++++++++++++-----
> 1 files changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
> index 2f1e161..4a13632 100644
> --- a/drivers/net/wireless/ath/ath9k/common.c
> +++ b/drivers/net/wireless/ath/ath9k/common.c
> @@ -231,26 +231,35 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
> {
> struct ath_hw *ah = common->ah;
> struct ieee80211_hdr *hdr;
> - int hdrlen, padsize;
> + int hdrlen, padpos, padsize;
> u8 keyix;
> __le16 fc;
>
> /* see if any padding is done by the hw and remove it */
> hdr = (struct ieee80211_hdr *) skb->data;
> hdrlen = ieee80211_get_hdrlen_from_skb(skb);
> + padpos = 24;
> fc = hdr->frame_control;
> + if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) ==
> + cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) {
> + padpos += 6; /* ETH_ALEN */
> + }
> + if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) ==
> + cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) {
> + padpos += 2;
> + }
>
> /* The MAC header is padded to have 32-bit boundary if the
> * packet payload is non-zero. The general calculation for
> * padsize would take into account odd header lengths:
> - * padsize = (4 - hdrlen % 4) % 4; However, since only
> + * padsize = (4 - padpos % 4) % 4; However, since only
> * even-length headers are used, padding can only be 0 or 2
> * bytes and we can optimize this a bit. In addition, we must
> * not try to remove padding from short control frames that do
> * not have payload. */
> - padsize = hdrlen & 3;
> - if (padsize && hdrlen >= 24) {
> - memmove(skb->data + padsize, skb->data, hdrlen);
> + padsize = padpos & 3;
> + if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
> + memmove(skb->data + padsize, skb->data, padpos);
> skb_pull(skb, padsize);
> }
>
>
Software padding is done on the TX path and software unpadding is done on the
RX path. This patch corrects the position where the padding occurs. A specific
function computes the pad position and this function is used in the TX and RX
path. This patch has been tested by generating every possible 802.11 frames
with every possible frame_control field and a varying length. This patch is
useful for analyzing non standard 802.11 frames going over the air
Signed-off-by: Benoit Papillault <[email protected]>
---
drivers/net/wireless/ath/ath9k/common.c | 24 +++++++++++++++---------
drivers/net/wireless/ath/ath9k/common.h | 2 ++
drivers/net/wireless/ath/ath9k/main.c | 14 ++++++--------
drivers/net/wireless/ath/ath9k/xmit.c | 9 ++++++++-
4 files changed, 31 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 4a13632..d363bb3 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -238,16 +238,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
/* see if any padding is done by the hw and remove it */
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- padpos = 24;
fc = hdr->frame_control;
- if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) ==
- cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) {
- padpos += 6; /* ETH_ALEN */
- }
- if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) ==
- cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) {
- padpos += 2;
- }
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
/* The MAC header is padded to have 32-bit boundary if the
* packet payload is non-zero. The general calculation for
@@ -282,6 +274,20 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
}
EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
+int ath9k_cmn_padpos(__le16 frame_control)
+{
+ int padpos = 24;
+ if (ieee80211_has_a4(frame_control)) {
+ padpos += ETH_ALEN;
+ }
+ if (ieee80211_is_data_qos(frame_control)) {
+ padpos += IEEE80211_QOS_CTL_LEN;
+ }
+
+ return padpos;
+}
+EXPORT_SYMBOL(ath9k_cmn_padpos);
+
static int __init ath9k_cmn_init(void)
{
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index 4e11760..b188fc3 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -122,3 +122,5 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs,
bool decrypt_error);
+
+int ath9k_cmn_padpos(__le16 frame_control);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index cbf5d2a..df2e2ae 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2394,7 +2394,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_tx_control txctl;
- int hdrlen, padsize;
+ int padpos, padsize;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
ath_print(common, ATH_DBG_XMIT,
@@ -2404,7 +2405,6 @@ static int ath9k_tx(struct ieee80211_hw *hw,
}
if (sc->ps_enabled) {
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
/*
* mac80211 does not set PM field for normal data frames, so we
* need to update that based on the current PS mode.
@@ -2424,7 +2424,6 @@ static int ath9k_tx(struct ieee80211_hw *hw,
* power save mode. Need to wake up hardware for the TX to be
* completed and if needed, also for RX of buffered frames.
*/
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
ath9k_ps_wakeup(sc);
ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
@@ -2452,7 +2451,6 @@ static int ath9k_tx(struct ieee80211_hw *hw,
* BSSes.
*/
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
sc->tx.seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
@@ -2460,13 +2458,13 @@ static int ath9k_tx(struct ieee80211_hw *hw,
}
/* Add the padding after the header if this is not already done */
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- if (hdrlen & 3) {
- padsize = hdrlen % 4;
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padsize = padpos & 3;
+ if (padsize && skb->len>padpos) {
if (skb_headroom(skb) < padsize)
return -1;
skb_push(skb, padsize);
- memmove(skb->data, skb->data + padsize, hdrlen);
+ memmove(skb->data, skb->data + padsize, padpos);
}
/* Check if a tx queue is available */
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 745d919..046986e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1554,6 +1554,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
int hdrlen;
__le16 fc;
+ int padpos, padsize;
tx_info->pad[0] = 0;
switch (txctl->frame_type) {
@@ -1572,7 +1573,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
ATH_TXBUF_RESET(bf);
bf->aphy = aphy;
- bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
+ bf->bf_frmlen = skb->len + FCS_LEN;
+ /* Remove the padding size from bf_frmlen, if any */
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padsize = padpos & 3;
+ if (padsize && skb->len>padpos+padsize) {
+ bf->bf_frmlen -= padsize;
+ }
if (conf_is_ht(&hw->conf) && !is_pae(skb))
bf->bf_state.bf_type |= BUF_HT;
--
1.6.3.3