static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, int slot) { struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_vif *vif; struct sk_buff *skb; struct ieee80211_hdr *hdr; int padpos, padsize, ret, tx_slot; spin_lock_bh(&priv->beacon_lock); vif = priv->cur_beacon_conf.bslot[slot]; skb = ieee80211_get_buffered_bc(priv->hw, vif); while(skb) { hdr = (struct ieee80211_hdr *) skb->data; padpos = ath9k_cmn_padpos(hdr->frame_control); padsize = padpos & 3; if (padsize && skb->len > padpos) { if (skb_headroom(skb) < padsize) { dev_kfree_skb_any(skb); goto next; } skb_push(skb, padsize); memmove(skb->data, skb->data + padsize, padpos); } tx_slot = ath9k_htc_tx_get_slot(priv); if (tx_slot < 0) { ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n"); dev_kfree_skb_any(skb); goto next; } ret = ath9k_htc_tx_start(priv, skb, tx_slot, true); if (ret != 0) { ath9k_htc_tx_clear_slot(priv, tx_slot); dev_kfree_skb_any(skb); ath_dbg(common, ATH_DBG_XMIT, "Failed to send CAB frame\n"); } else { spin_lock_bh(&priv->tx.tx_lock); priv->tx.queued_cnt++; spin_unlock_bh(&priv->tx.tx_lock); } next: skb = ieee80211_get_buffered_bc(priv->hw, vif); } spin_unlock_bh(&priv->beacon_lock); }
static void ath9k_htc_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct ieee80211_hdr *hdr; struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); int padpos, padsize, ret, slot; hdr = (struct ieee80211_hdr *) skb->data; /* Add the padding after the header if this is not already done */ padpos = ath9k_cmn_padpos(hdr->frame_control); padsize = padpos & 3; if (padsize && skb->len > padpos) { if (skb_headroom(skb) < padsize) { ath_dbg(common, XMIT, "No room for padding\n"); goto fail_tx; } skb_push(skb, padsize); memmove(skb->data, skb->data + padsize, padpos); } slot = ath9k_htc_tx_get_slot(priv); if (slot < 0) { ath_dbg(common, XMIT, "No free TX slot\n"); goto fail_tx; } ret = ath9k_htc_tx_start(priv, control->sta, skb, slot, false); if (ret != 0) { ath_dbg(common, XMIT, "Tx failed\n"); goto clear_slot; } ath9k_htc_check_stop_queues(priv); return; clear_slot: ath9k_htc_tx_clear_slot(priv, slot); fail_tx: dev_kfree_skb_any(skb); }
void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, struct sk_buff *skb, struct ath_rx_status *rx_stats, struct ieee80211_rx_status *rxs, bool decrypt_error) { struct ath_hw *ah = common->ah; struct ieee80211_hdr *hdr; 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); fc = hdr->frame_control; 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 * padsize would take into account odd header lengths: * 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 = padpos & 3; if (padsize && skb->len>=padpos+padsize+FCS_LEN) { memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); } keyix = rx_stats->rs_keyix; if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && ieee80211_has_protected(fc)) { rxs->flag |= RX_FLAG_DECRYPTED; } else if (ieee80211_has_protected(fc) && !decrypt_error && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; if (test_bit(keyix, common->keymap)) rxs->flag |= RX_FLAG_DECRYPTED; }
static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_hdr *hdr; struct ath9k_htc_priv *priv = hw->priv; int padpos, padsize, ret; hdr = (struct ieee80211_hdr *) skb->data; /* Add the padding after the header if this is not already done */ 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, padpos); } ret = ath9k_htc_tx_start(priv, skb); if (ret != 0) { if (ret == -ENOMEM) { ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Stopping TX queues\n"); ieee80211_stop_queues(hw); spin_lock_bh(&priv->tx_lock); priv->tx_queues_stop = true; spin_unlock_bh(&priv->tx_lock); } else { ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Tx failed\n"); } goto fail_tx; } return 0; fail_tx: dev_kfree_skb_any(skb); return 0; }
static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ath9k_htc_rxbuf *rxbuf, struct ieee80211_rx_status *rx_status) { struct ieee80211_hdr *hdr; struct ieee80211_hw *hw = priv->hw; struct sk_buff *skb = rxbuf->skb; struct ath_common *common = ath9k_hw_common(priv->ah); struct ath_htc_rx_status *rxstatus; int hdrlen, padpos, padsize; int last_rssi = ATH_RSSI_DUMMY_MARKER; __le16 fc; if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { ath_print(common, ATH_DBG_FATAL, "Corrupted RX frame, dropping\n"); goto rx_next; } rxstatus = (struct ath_htc_rx_status *)skb->data; if (be16_to_cpu(rxstatus->rs_datalen) - (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { ath_print(common, ATH_DBG_FATAL, "Corrupted RX data len, dropping " "(dlen: %d, skblen: %d)\n", rxstatus->rs_datalen, skb->len); goto rx_next; } /* Get the RX status information */ memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; hdrlen = ieee80211_get_hdrlen_from_skb(skb); padpos = ath9k_cmn_padpos(fc); padsize = padpos & 3; if (padsize && skb->len >= padpos+padsize+FCS_LEN) { memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); } memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); if (rxbuf->rxstatus.rs_status != 0) { if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) goto rx_next; if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { /* FIXME */ } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { if (ieee80211_is_ctl(fc)) /* * Sometimes, we get invalid * MIC failures on valid control frames. * Remove these mic errors. */ rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; else rx_status->flag |= RX_FLAG_MMIC_ERROR; } /* * Reject error frames with the exception of * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { if (rxbuf->rxstatus.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) goto rx_next; } else { if (rxbuf->rxstatus.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { goto rx_next; } } } if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { u8 keyix; keyix = rxbuf->rxstatus.rs_keyix; if (keyix != ATH9K_RXKEYIX_INVALID) { rx_status->flag |= RX_FLAG_DECRYPTED; } else if (ieee80211_has_protected(fc) && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; if (test_bit(keyix, common->keymap)) rx_status->flag |= RX_FLAG_DECRYPTED; }