Commit cca84799 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

ar9170: rework rxstream code

With this patch ar9170 is capable of receiving aggregated 802.11n frames
and sniffing on most networks without having a "debug message overhead".

(Includes phy initialization requested by
Johannes Berg <johannes@sipsolutions.net> -- JWL)
Signed-off-by: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e7ec86f5
...@@ -104,10 +104,16 @@ enum ar9170_device_state { ...@@ -104,10 +104,16 @@ enum ar9170_device_state {
AR9170_ASSOCIATED, AR9170_ASSOCIATED,
}; };
struct ar9170_rxstream_mpdu_merge {
struct ar9170_rx_head plcp;
bool has_plcp;
};
struct ar9170 { struct ar9170 {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct mutex mutex; struct mutex mutex;
enum ar9170_device_state state; enum ar9170_device_state state;
unsigned long bad_hw_nagger;
int (*open)(struct ar9170 *); int (*open)(struct ar9170 *);
void (*stop)(struct ar9170 *); void (*stop)(struct ar9170 *);
...@@ -135,6 +141,7 @@ struct ar9170 { ...@@ -135,6 +141,7 @@ struct ar9170 {
u64 cur_mc_hash, want_mc_hash; u64 cur_mc_hash, want_mc_hash;
u32 cur_filter, want_filter; u32 cur_filter, want_filter;
unsigned int filter_changed; unsigned int filter_changed;
unsigned int filter_state;
bool sniffer_enabled; bool sniffer_enabled;
/* PHY */ /* PHY */
...@@ -174,6 +181,11 @@ struct ar9170 { ...@@ -174,6 +181,11 @@ struct ar9170 {
struct sk_buff_head global_tx_status; struct sk_buff_head global_tx_status;
struct sk_buff_head global_tx_status_waste; struct sk_buff_head global_tx_status_waste;
struct delayed_work tx_status_janitor; struct delayed_work tx_status_janitor;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
struct sk_buff *rx_failover;
int rx_failover_missing;
}; };
struct ar9170_sta_info { struct ar9170_sta_info {
......
...@@ -312,7 +312,7 @@ struct ar9170_rx_head { ...@@ -312,7 +312,7 @@ struct ar9170_rx_head {
u8 plcp[12]; u8 plcp[12];
} __packed; } __packed;
struct ar9170_rx_tail { struct ar9170_rx_phystatus {
union { union {
struct { struct {
u8 rssi_ant0, rssi_ant1, rssi_ant2, u8 rssi_ant0, rssi_ant1, rssi_ant2,
...@@ -324,6 +324,9 @@ struct ar9170_rx_tail { ...@@ -324,6 +324,9 @@ struct ar9170_rx_tail {
u8 evm_stream0[6], evm_stream1[6]; u8 evm_stream0[6], evm_stream1[6];
u8 phy_err; u8 phy_err;
} __packed;
struct ar9170_rx_macstatus {
u8 SAidx, DAidx; u8 SAidx, DAidx;
u8 error; u8 error;
u8 status; u8 status;
...@@ -339,7 +342,7 @@ struct ar9170_rx_tail { ...@@ -339,7 +342,7 @@ struct ar9170_rx_tail {
#define AR9170_RX_ENC_SOFTWARE 0x8 #define AR9170_RX_ENC_SOFTWARE 0x8
static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
{ {
return (t->SAidx & 0xc0) >> 4 | return (t->SAidx & 0xc0) >> 4 |
(t->DAidx & 0xc0) >> 6; (t->DAidx & 0xc0) >> 6;
...@@ -357,10 +360,9 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) ...@@ -357,10 +360,9 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
#define AR9170_RX_STATUS_MPDU_MASK 0x30 #define AR9170_RX_STATUS_MPDU_MASK 0x30
#define AR9170_RX_STATUS_MPDU_SINGLE 0x00 #define AR9170_RX_STATUS_MPDU_SINGLE 0x00
#define AR9170_RX_STATUS_MPDU_FIRST 0x10 #define AR9170_RX_STATUS_MPDU_FIRST 0x20
#define AR9170_RX_STATUS_MPDU_MIDDLE 0x20 #define AR9170_RX_STATUS_MPDU_MIDDLE 0x30
#define AR9170_RX_STATUS_MPDU_LAST 0x30 #define AR9170_RX_STATUS_MPDU_LAST 0x10
#define AR9170_RX_ERROR_RXTO 0x01 #define AR9170_RX_ERROR_RXTO 0x01
#define AR9170_RX_ERROR_OVERRUN 0x02 #define AR9170_RX_ERROR_OVERRUN 0x02
...@@ -369,6 +371,7 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) ...@@ -369,6 +371,7 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t)
#define AR9170_RX_ERROR_WRONG_RA 0x10 #define AR9170_RX_ERROR_WRONG_RA 0x10
#define AR9170_RX_ERROR_PLCP 0x20 #define AR9170_RX_ERROR_PLCP 0x20
#define AR9170_RX_ERROR_MMIC 0x40 #define AR9170_RX_ERROR_MMIC 0x40
#define AR9170_RX_ERROR_FATAL 0x80
struct ar9170_cmd_tx_status { struct ar9170_cmd_tx_status {
__le16 unkn; __le16 unkn;
......
...@@ -454,214 +454,430 @@ static void ar9170_handle_command_response(struct ar9170 *ar, ...@@ -454,214 +454,430 @@ static void ar9170_handle_command_response(struct ar9170 *ar,
} }
} }
/* static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar)
* If the frame alignment is right (or the kernel has
* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
* is only a single MPDU in the USB frame, then we can
* submit to mac80211 the SKB directly. However, since
* there may be multiple packets in one SKB in stream
* mode, and we need to observe the proper ordering,
* this is non-trivial.
*/
static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
{ {
struct sk_buff *skb; memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head));
struct ar9170_rx_head *head = (void *)buf; ar->rx_mpdu.has_plcp = false;
struct ar9170_rx_tail *tail; }
struct ieee80211_rx_status status;
int mpdu_len, i;
u8 error, antennas = 0, decrypt;
__le16 fc;
int reserved;
if (unlikely(!IS_STARTED(ar))) static int ar9170_nag_limiter(struct ar9170 *ar)
return ; {
bool print_message;
/*
* we expect all sorts of errors in promiscuous mode.
* don't bother with it, it's OK!
*/
if (ar->sniffer_enabled)
return false;
/*
* only go for frequent errors! The hardware tends to
* do some stupid thing once in a while under load, in
* noisy environments or just for fun!
*/
if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit())
print_message = true;
else
print_message = false;
/* reset threshold for "once in a while" */
ar->bad_hw_nagger = jiffies + HZ / 4;
return print_message;
}
static int ar9170_rx_mac_status(struct ar9170 *ar,
struct ar9170_rx_head *head,
struct ar9170_rx_macstatus *mac,
struct ieee80211_rx_status *status)
{
u8 error, decrypt;
/* Received MPDU */
mpdu_len = len;
mpdu_len -= sizeof(struct ar9170_rx_head);
mpdu_len -= sizeof(struct ar9170_rx_tail);
BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24); BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
if (mpdu_len <= FCS_LEN) error = mac->error;
return; if (error & AR9170_RX_ERROR_MMIC) {
status->flag |= RX_FLAG_MMIC_ERROR;
error &= ~AR9170_RX_ERROR_MMIC;
}
tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len); if (error & AR9170_RX_ERROR_PLCP) {
status->flag |= RX_FLAG_FAILED_PLCP_CRC;
error &= ~AR9170_RX_ERROR_PLCP;
for (i = 0; i < 3; i++) if (!(ar->filter_state & FIF_PLCPFAIL))
if (tail->rssi[i] != 0x80) return -EINVAL;
antennas |= BIT(i); }
/* post-process RSSI */ if (error & AR9170_RX_ERROR_FCS) {
for (i = 0; i < 7; i++) status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (tail->rssi[i] & 0x80) error &= ~AR9170_RX_ERROR_FCS;
tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f;
memset(&status, 0, sizeof(status)); if (!(ar->filter_state & FIF_FCSFAIL))
return -EINVAL;
}
decrypt = ar9170_get_decrypt_type(mac);
if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
decrypt != AR9170_ENC_ALG_NONE)
status->flag |= RX_FLAG_DECRYPTED;
/* ignore wrong RA errors */
error &= ~AR9170_RX_ERROR_WRONG_RA;
if (error & AR9170_RX_ERROR_DECRYPT) {
error &= ~AR9170_RX_ERROR_DECRYPT;
/*
* Rx decryption is done in place,
* the original data is lost anyway.
*/
return -EINVAL;
}
/* drop any other error frames */
if (unlikely(error)) {
/* TODO: update netdevice's RX dropped/errors statistics */
if (ar9170_nag_limiter(ar))
printk(KERN_DEBUG "%s: received frame with "
"suspicious error code (%#x).\n",
wiphy_name(ar->hw->wiphy), error);
status.band = ar->channel->band; return -EINVAL;
status.freq = ar->channel->center_freq; }
status.signal = ar->noise[0] + tail->rssi_combined;
status.noise = ar->noise[0]; status->band = ar->channel->band;
status.antenna = antennas; status->freq = ar->channel->center_freq;
switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) { switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) {
case AR9170_RX_STATUS_MODULATION_CCK: case AR9170_RX_STATUS_MODULATION_CCK:
if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE) if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
status.flag |= RX_FLAG_SHORTPRE; status->flag |= RX_FLAG_SHORTPRE;
switch (head->plcp[0]) { switch (head->plcp[0]) {
case 0x0a: case 0x0a:
status.rate_idx = 0; status->rate_idx = 0;
break; break;
case 0x14: case 0x14:
status.rate_idx = 1; status->rate_idx = 1;
break; break;
case 0x37: case 0x37:
status.rate_idx = 2; status->rate_idx = 2;
break; break;
case 0x6e: case 0x6e:
status.rate_idx = 3; status->rate_idx = 3;
break; break;
default: default:
if ((!ar->sniffer_enabled) && (net_ratelimit())) if (ar9170_nag_limiter(ar))
printk(KERN_ERR "%s: invalid plcp cck rate " printk(KERN_ERR "%s: invalid plcp cck rate "
"(%x).\n", wiphy_name(ar->hw->wiphy), "(%x).\n", wiphy_name(ar->hw->wiphy),
head->plcp[0]); head->plcp[0]);
return; return -EINVAL;
} }
break; break;
case AR9170_RX_STATUS_MODULATION_OFDM: case AR9170_RX_STATUS_MODULATION_OFDM:
switch (head->plcp[0] & 0xF) { switch (head->plcp[0] & 0xf) {
case 0xB: case 0xb:
status.rate_idx = 0; status->rate_idx = 0;
break; break;
case 0xF: case 0xf:
status.rate_idx = 1; status->rate_idx = 1;
break; break;
case 0xA: case 0xa:
status.rate_idx = 2; status->rate_idx = 2;
break; break;
case 0xE: case 0xe:
status.rate_idx = 3; status->rate_idx = 3;
break; break;
case 0x9: case 0x9:
status.rate_idx = 4; status->rate_idx = 4;
break; break;
case 0xD: case 0xd:
status.rate_idx = 5; status->rate_idx = 5;
break; break;
case 0x8: case 0x8:
status.rate_idx = 6; status->rate_idx = 6;
break; break;
case 0xC: case 0xc:
status.rate_idx = 7; status->rate_idx = 7;
break; break;
default: default:
if ((!ar->sniffer_enabled) && (net_ratelimit())) if (ar9170_nag_limiter(ar))
printk(KERN_ERR "%s: invalid plcp ofdm rate " printk(KERN_ERR "%s: invalid plcp ofdm rate "
"(%x).\n", wiphy_name(ar->hw->wiphy), "(%x).\n", wiphy_name(ar->hw->wiphy),
head->plcp[0]); head->plcp[0]);
return; return -EINVAL;
} }
if (status.band == IEEE80211_BAND_2GHZ) if (status->band == IEEE80211_BAND_2GHZ)
status.rate_idx += 4; status->rate_idx += 4;
break; break;
case AR9170_RX_STATUS_MODULATION_HT: case AR9170_RX_STATUS_MODULATION_HT:
if (head->plcp[3] & 0x80)
status->flag |= RX_FLAG_40MHZ;
if (head->plcp[6] & 0x80)
status->flag |= RX_FLAG_SHORT_GI;
status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f);
status->flag |= RX_FLAG_HT;
break;
case AR9170_RX_STATUS_MODULATION_DUPOFDM: case AR9170_RX_STATUS_MODULATION_DUPOFDM:
/* XXX */ /* XXX */
if (ar9170_nag_limiter(ar))
if (net_ratelimit())
printk(KERN_ERR "%s: invalid modulation\n", printk(KERN_ERR "%s: invalid modulation\n",
wiphy_name(ar->hw->wiphy)); wiphy_name(ar->hw->wiphy));
return; return -EINVAL;
} }
error = tail->error; return 0;
}
if (error & AR9170_RX_ERROR_MMIC) { static void ar9170_rx_phy_status(struct ar9170 *ar,
status.flag |= RX_FLAG_MMIC_ERROR; struct ar9170_rx_phystatus *phy,
error &= ~AR9170_RX_ERROR_MMIC; struct ieee80211_rx_status *status)
{
int i;
BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
for (i = 0; i < 3; i++)
if (phy->rssi[i] != 0x80)
status->antenna |= BIT(i);
/* post-process RSSI */
for (i = 0; i < 7; i++)
if (phy->rssi[i] & 0x80)
phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
/* TODO: we could do something with phy_errors */
status->signal = ar->noise[0] + phy->rssi_combined;
status->noise = ar->noise[0];
}
static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len)
{
struct sk_buff *skb;
int reserved = 0;
struct ieee80211_hdr *hdr = (void *) buf;
if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *qc = ieee80211_get_qos_ctl(hdr);
reserved += NET_IP_ALIGN;
if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
reserved += NET_IP_ALIGN;
} }
if (error & AR9170_RX_ERROR_PLCP) { if (ieee80211_has_a4(hdr->frame_control))
status.flag |= RX_FLAG_FAILED_PLCP_CRC; reserved += NET_IP_ALIGN;
error &= ~AR9170_RX_ERROR_PLCP;
reserved = 32 + (reserved & NET_IP_ALIGN);
skb = dev_alloc_skb(len + reserved);
if (likely(skb)) {
skb_reserve(skb, reserved);
memcpy(skb_put(skb, len), buf, len);
} }
if (error & AR9170_RX_ERROR_FCS) { return skb;
status.flag |= RX_FLAG_FAILED_FCS_CRC; }
error &= ~AR9170_RX_ERROR_FCS;
/*
* If the frame alignment is right (or the kernel has
* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
* is only a single MPDU in the USB frame, then we could
* submit to mac80211 the SKB directly. However, since
* there may be multiple packets in one SKB in stream
* mode, and we need to observe the proper ordering,
* this is non-trivial.
*/
static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
{
struct ar9170_rx_head *head;
struct ar9170_rx_macstatus *mac;
struct ar9170_rx_phystatus *phy = NULL;
struct ieee80211_rx_status status;
struct sk_buff *skb;
int mpdu_len;
if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac))))
return ;
/* Received MPDU */
mpdu_len = len - sizeof(*mac);
mac = (void *)(buf + mpdu_len);
if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) {
/* this frame is too damaged and can't be used - drop it */
return ;
} }
decrypt = ar9170_get_decrypt_type(tail); switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) {
if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && case AR9170_RX_STATUS_MPDU_FIRST:
decrypt != AR9170_ENC_ALG_NONE) /* first mpdu packet has the plcp header */
status.flag |= RX_FLAG_DECRYPTED; if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
head = (void *) buf;
memcpy(&ar->rx_mpdu.plcp, (void *) buf,
sizeof(struct ar9170_rx_head));
/* ignore wrong RA errors */ mpdu_len -= sizeof(struct ar9170_rx_head);
error &= ~AR9170_RX_ERROR_WRONG_RA; buf += sizeof(struct ar9170_rx_head);
ar->rx_mpdu.has_plcp = true;
} else {
if (ar9170_nag_limiter(ar))
printk(KERN_ERR "%s: plcp info is clipped.\n",
wiphy_name(ar->hw->wiphy));
return ;
}
break;
if (error & AR9170_RX_ERROR_DECRYPT) { case AR9170_RX_STATUS_MPDU_LAST:
error &= ~AR9170_RX_ERROR_DECRYPT; /* last mpdu has a extra tail with phy status information */
/* if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
* Rx decryption is done in place, mpdu_len -= sizeof(struct ar9170_rx_phystatus);
* the original data is lost anyway. phy = (void *)(buf + mpdu_len);
*/ } else {
if (ar9170_nag_limiter(ar))
printk(KERN_ERR "%s: frame tail is clipped.\n",
wiphy_name(ar->hw->wiphy));
return ; return ;
} }
/* drop any other error frames */ case AR9170_RX_STATUS_MPDU_MIDDLE:
if ((error) && (net_ratelimit())) { /* middle mpdus are just data */
printk(KERN_DEBUG "%s: errors: %#x\n", if (unlikely(!ar->rx_mpdu.has_plcp)) {
wiphy_name(ar->hw->wiphy), error); if (!ar9170_nag_limiter(ar))
return; return ;
printk(KERN_ERR "%s: rx stream did not start "
"with a first_mpdu frame tag.\n",
wiphy_name(ar->hw->wiphy));
return ;
} }
head = &ar->rx_mpdu.plcp;
break;
case AR9170_RX_STATUS_MPDU_SINGLE:
/* single mpdu - has plcp (head) and phy status (tail) */
head = (void *) buf;
mpdu_len -= sizeof(struct ar9170_rx_head);
mpdu_len -= sizeof(struct ar9170_rx_phystatus);
buf += sizeof(struct ar9170_rx_head); buf += sizeof(struct ar9170_rx_head);
fc = *(__le16 *)buf; phy = (void *)(buf + mpdu_len);
break;
if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc)) default:
reserved = 32 + 2; BUG_ON(1);
else break;
reserved = 32; }
skb = dev_alloc_skb(mpdu_len + reserved); if (unlikely(mpdu_len < FCS_LEN))
if (!skb) return ;
return;
skb_reserve(skb, reserved); memset(&status, 0, sizeof(status));
memcpy(skb_put(skb, mpdu_len), buf, mpdu_len); if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status)))
return ;
if (phy)
ar9170_rx_phy_status(ar, phy, &status);
skb = ar9170_rx_copy_data(buf, mpdu_len);
if (likely(skb))
ieee80211_rx_irqsafe(ar->hw, skb, &status); ieee80211_rx_irqsafe(ar->hw, skb, &status);
} }
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
{ {
unsigned int i, tlen, resplen; unsigned int i, tlen, resplen, wlen = 0, clen = 0;
u8 *tbuf, *respbuf; u8 *tbuf, *respbuf;
tbuf = skb->data; tbuf = skb->data;
tlen = skb->len; tlen = skb->len;
while (tlen >= 4) { while (tlen >= 4) {
int clen = tbuf[1] << 8 | tbuf[0]; clen = tbuf[1] << 8 | tbuf[0];
int wlen = (clen + 3) & ~3; wlen = ALIGN(clen, 4);
/* check if this is stream has a valid tag.*/
if (tbuf[2] != 0 || tbuf[3] != 0x4e) {
/* /*
* parse stream (if any) * TODO: handle the highly unlikely event that the
* corrupted stream has the TAG at the right position.
*/ */
if (tbuf[2] != 0 || tbuf[3] != 0x4e) {
/* check if the frame can be repaired. */
if (!ar->rx_failover_missing) {
/* this is no "short read". */
if (ar9170_nag_limiter(ar)) {
printk(KERN_ERR "%s: missing tag!\n", printk(KERN_ERR "%s: missing tag!\n",
wiphy_name(ar->hw->wiphy)); wiphy_name(ar->hw->wiphy));
goto err_telluser;
} else
goto err_silent;
}
if (ar->rx_failover_missing > tlen) {
if (ar9170_nag_limiter(ar)) {
printk(KERN_ERR "%s: possible multi "
"stream corruption!\n",
wiphy_name(ar->hw->wiphy));
goto err_telluser;
} else
goto err_silent;
}
memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
ar->rx_failover_missing -= tlen;
if (ar->rx_failover_missing <= 0) {
/*
* nested ar9170_rx call!
* termination is guranteed, even when the
* combined frame also have a element with
* a bad tag.
*/
ar->rx_failover_missing = 0;
ar9170_rx(ar, ar->rx_failover);
skb_reset_tail_pointer(ar->rx_failover);
skb_trim(ar->rx_failover, 0);
}
return ; return ;
} }
/* check if stream is clipped */
if (wlen > tlen - 4) { if (wlen > tlen - 4) {
printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n", if (ar->rx_failover_missing) {
wiphy_name(ar->hw->wiphy), clen, wlen, tlen); /* TODO: handle double stream corruption. */
print_hex_dump(KERN_DEBUG, "data: ", if (ar9170_nag_limiter(ar)) {
DUMP_PREFIX_OFFSET, printk(KERN_ERR "%s: double rx stream "
16, 1, tbuf, tlen, true); "corruption!\n",
wiphy_name(ar->hw->wiphy));
goto err_telluser;
} else
goto err_silent;
}
/*
* save incomplete data set.
* the firmware will resend the missing bits when
* the rx - descriptor comes round again.
*/
memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
ar->rx_failover_missing = clen - tlen;
return ; return ;
} }
resplen = clen; resplen = clen;
...@@ -686,12 +902,44 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) ...@@ -686,12 +902,44 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
if (i == 12) if (i == 12)
ar9170_handle_command_response(ar, respbuf, resplen); ar9170_handle_command_response(ar, respbuf, resplen);
else else
ar9170_handle_mpdu(ar, respbuf, resplen); ar9170_handle_mpdu(ar, respbuf, clen);
} }
if (tlen) if (tlen) {
printk(KERN_ERR "%s: buffer remains!\n", if (net_ratelimit())
printk(KERN_ERR "%s: %d bytes of unprocessed "
"data left in rx stream!\n",
wiphy_name(ar->hw->wiphy), tlen);
goto err_telluser;
}
return ;
err_telluser:
printk(KERN_ERR "%s: damaged RX stream data [want:%d, "
"data:%d, rx:%d, pending:%d ]\n",
wiphy_name(ar->hw->wiphy), clen, wlen, tlen,
ar->rx_failover_missing);
if (ar->rx_failover_missing)
print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET,
ar->rx_failover->data,
ar->rx_failover->len);
print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
skb->data, skb->len);
printk(KERN_ERR "%s: please check your hardware and cables, if "
"you see this message frequently.\n",
wiphy_name(ar->hw->wiphy)); wiphy_name(ar->hw->wiphy));
err_silent:
if (ar->rx_failover_missing) {
skb_reset_tail_pointer(ar->rx_failover);
skb_trim(ar->rx_failover, 0);
ar->rx_failover_missing = 0;
}
} }
#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ #define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \
...@@ -721,6 +969,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw) ...@@ -721,6 +969,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
ar->bad_hw_nagger = jiffies;
err = ar->open(ar); err = ar->open(ar);
if (err) if (err)
goto out; goto out;
...@@ -1175,8 +1425,8 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw, ...@@ -1175,8 +1425,8 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
/* mask supported flags */ /* mask supported flags */
*new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC |
FIF_PROMISC_IN_BSS; FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL;
ar->filter_state = *new_flags;
/* /*
* We can support more by setting the sniffer bit and * We can support more by setting the sniffer bit and
* then checking the error flags, later. * then checking the error flags, later.
...@@ -1559,20 +1809,33 @@ void *ar9170_alloc(size_t priv_size) ...@@ -1559,20 +1809,33 @@ void *ar9170_alloc(size_t priv_size)
{ {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct ar9170 *ar; struct ar9170 *ar;
struct sk_buff *skb;
int i; int i;
/*
* this buffer is used for rx stream reconstruction.
* Under heavy load this device (or the transport layer?)
* tends to split the streams into seperate rx descriptors.
*/
skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL);
if (!skb)
goto err_nomem;
hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); hw = ieee80211_alloc_hw(priv_size, &ar9170_ops);
if (!hw) if (!hw)
return ERR_PTR(-ENOMEM); goto err_nomem;
ar = hw->priv; ar = hw->priv;
ar->hw = hw; ar->hw = hw;
ar->rx_failover = skb;
mutex_init(&ar->mutex); mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock); spin_lock_init(&ar->tx_stats_lock);
skb_queue_head_init(&ar->global_tx_status); skb_queue_head_init(&ar->global_tx_status);
skb_queue_head_init(&ar->global_tx_status_waste); skb_queue_head_init(&ar->global_tx_status_waste);
ar9170_rx_reset_rx_mpdu(ar);
INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor);
...@@ -1600,6 +1863,10 @@ void *ar9170_alloc(size_t priv_size) ...@@ -1600,6 +1863,10 @@ void *ar9170_alloc(size_t priv_size)
ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
return ar; return ar;
err_nomem:
kfree_skb(skb);
return ERR_PTR(-ENOMEM);
} }
static int ar9170_read_eeprom(struct ar9170 *ar) static int ar9170_read_eeprom(struct ar9170 *ar)
...@@ -1725,6 +1992,7 @@ void ar9170_unregister(struct ar9170 *ar) ...@@ -1725,6 +1992,7 @@ void ar9170_unregister(struct ar9170 *ar)
ar9170_unregister_leds(ar); ar9170_unregister_leds(ar);
#endif /* CONFIG_AR9170_LEDS */ #endif /* CONFIG_AR9170_LEDS */
kfree_skb(ar->rx_failover);
ieee80211_unregister_hw(ar->hw); ieee80211_unregister_hw(ar->hw);
mutex_destroy(&ar->mutex); mutex_destroy(&ar->mutex);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment