int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_device_cmd *dev_cmd; struct iwl_tx_cmd *tx_cmd; u8 sta_id; if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU)) return -1; if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && (!info->control.vif || info->hw_queue != info->control.vif->cab_queue))) return -1; /* * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel * queue. STATION (HS2.0) uses the auxiliary context of the FW, * and hence needs to be sent on the aux queue */ if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && info->control.vif->type == NL80211_IFTYPE_STATION) IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue; /* * If the interface on which frame is sent is the P2P_DEVICE * or an AP/GO interface use the broadcast station associated * with it; otherwise use the AUX station. */ if (info->control.vif && (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || info->control.vif->type == NL80211_IFTYPE_AP)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); sta_id = mvmvif->bcast_sta.sta_id; } else { sta_id = mvm->aux_sta.sta_id; } IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id); if (!dev_cmd) return -1; /* From now on, we cannot access info->control */ tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; /* Copy MAC header from skb into command buffer */ memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control)); if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) { iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); return -1; } return 0; }
int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_device_cmd *dev_cmd; struct iwl_tx_cmd *tx_cmd; u8 sta_id; if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU)) return -1; if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && (!info->control.vif || info->hw_queue != info->control.vif->cab_queue))) return -1; /* * If the interface on which frame is sent is the P2P_DEVICE * or an AP/GO interface use the broadcast station associated * with it; otherwise use the AUX station. */ if (info->control.vif && (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || info->control.vif->type == NL80211_IFTYPE_AP)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); sta_id = mvmvif->bcast_sta.sta_id; } else { sta_id = mvm->aux_sta.sta_id; } IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id); if (!dev_cmd) return -1; /* From now on, we cannot access info->control */ tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; /* Copy MAC header from skb into command buffer */ memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control)); if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) { iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); return -1; } return 0; }
/* * Sets the fields in the Tx cmd that are crypto related */ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_sta *sta) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_mvm_sta *mvmsta; struct iwl_device_cmd *dev_cmd; struct iwl_tx_cmd *tx_cmd; __le16 fc; u16 seq_number = 0; u8 tid = IWL_MAX_TID_COUNT; u8 txq_id = info->hw_queue; bool is_data_qos = false, is_ampdu = false; mvmsta = (void *)sta->drv_priv; fc = hdr->frame_control; if (WARN_ON_ONCE(!mvmsta)) return -1; if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) return -1; dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); if (!dev_cmd) goto drop; tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; /* From now on, we cannot access info->control */ spin_lock(&mvmsta->lock); if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { u8 *qc = NULL; qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) goto drop_unlock_sta; seq_number = mvmsta->tid_data[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl |= cpu_to_le16(seq_number); seq_number += 0x10; is_data_qos = true; is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; } /* Copy MAC header from skb into command buffer */ memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc)); WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); if (is_ampdu) { if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) goto drop_unlock_sta; txq_id = mvmsta->tid_data[tid].txq_id; } IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id, tid, txq_id, seq_number); if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id)) goto drop_unlock_sta; if (is_data_qos && !ieee80211_has_morefrags(fc)) mvmsta->tid_data[tid].seq_number = seq_number; spin_unlock(&mvmsta->lock); if (txq_id < mvm->first_agg_queue) atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); return 0; drop_unlock_sta: iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); spin_unlock(&mvmsta->lock); drop: return -1; }