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 = ieee80211_hdrlen(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); }