Skip to content

Commit

Permalink
ath9k: Fix sequence number assignment
Browse files Browse the repository at this point in the history
Currently, ath9k uses a global counter for all
frames that need to be assigned a sequence number.
QoS-data frames are handled properly since they
have a per-tid counter. But, beacons and other
management frames use the same counter even if
multiple interfaces or contexts are present.

Fix this issue by making the counter per-interface
and using it when mac80211 sets IEEE80211_TX_CTL_ASSIGN_SEQ.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Sujith Manoharan authored and John W. Linville committed Oct 8, 2014
1 parent 2f29fed commit ca14405
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 23 deletions.
4 changes: 3 additions & 1 deletion drivers/net/wireless/ath/ath9k/ath9k.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,6 @@ struct ath_tx_control {
* (axq_qnum).
*/
struct ath_tx {
u16 seq_no;
u32 txqsetup;
spinlock_t txbuflock;
struct list_head txbuf;
Expand Down Expand Up @@ -563,6 +562,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
void ath_assign_seq(struct ath_common *common, struct sk_buff *skb);
int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_tx_control *txctl);
void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Expand Down Expand Up @@ -592,6 +592,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ath_vif {
struct list_head list;

u16 seq_no;

/* BSS info */
u8 bssid[ETH_ALEN];
u16 aid;
Expand Down
12 changes: 2 additions & 10 deletions drivers/net/wireless/ath/ath9k/beacon.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;

info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
/*
* TODO: make sure the seq# gets assigned properly (vs. other
* TX frames)
*/
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
sc->tx.seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
}

ath_assign_seq(common, skb);

if (vif->p2p)
ath9k_beacon_add_noa(sc, avp, skb);
Expand Down
8 changes: 7 additions & 1 deletion drivers/net/wireless/ath/ath9k/tx99.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct sk_buff *skb;
struct ath_vif *avp;

if (!sc->tx99_vif)
return NULL;

avp = (struct ath_vif *)sc->tx99_vif->drv_priv;

skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
Expand All @@ -71,7 +77,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);

hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);

tx_info = IEEE80211_SKB_CB(skb);
memset(tx_info, 0, sizeof(*tx_info));
Expand Down
34 changes: 23 additions & 11 deletions drivers/net/wireless/ath/ath9k/xmit.c
Original file line number Diff line number Diff line change
Expand Up @@ -2139,6 +2139,28 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
return bf;
}

void ath_assign_seq(struct ath_common *common, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct ath_vif *avp;

if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
return;

if (!vif)
return;

avp = (struct ath_vif *)vif->drv_priv;

if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
avp->seq_no += 0x10;

hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
}

static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_tx_control *txctl)
{
Expand All @@ -2162,17 +2184,7 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
if (info->control.hw_key)
frmlen += info->control.hw_key->icv_len;

/*
* As a temporary workaround, assign seq# here; this will likely need
* to be cleaned up to work better with Beacon transmission and virtual
* BSSes.
*/
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
sc->tx.seq_no += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
}
ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb);

if ((vif && vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_AP_VLAN) ||
Expand Down

0 comments on commit ca14405

Please sign in to comment.