static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_hdr *hdr, u16 len, u32 ampdu_status, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, "Dropping packet while interface is not open.\n"); return; } /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; /* Resize SKB from mac header to end of packet */ skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); skb_put(rxb->skb, len); iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); ieee80211_rx_irqsafe(priv->hw, rxb->skb); priv->alloc_rxb_skb--; rxb->skb = NULL; }
static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_hdr *hdr, u16 len, u32 ampdu_status, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { struct sk_buff *skb; int ret = 0; __le16 fc = hdr->frame_control; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, "Dropping packet while interface is not open.\n"); return; } /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); if (!skb) { IWL_ERR(priv, "alloc_skb failed\n"); return; } skb_reserve(skb, IWL_LINK_HDR_MAX); skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); /* mac80211 currently doesn't support paged SKB. Convert it to * linear SKB for management frame and data frame requires * software decryption or software defragementation. */ if (ieee80211_is_mgmt(fc) || ieee80211_has_protected(fc) || ieee80211_has_morefrags(fc) || le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG || (ieee80211_is_data_qos(fc) && *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)) ret = skb_linearize(skb); else ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? 0 : -ENOMEM; if (ret) { kfree_skb(skb); goto out; } /* * XXX: We cannot touch the page and its virtual memory (hdr) after * here. It might have already been freed by the above skb change. */ iwl_update_stats(priv, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); out: priv->alloc_rxb_page--; rxb->page = NULL; }
/* * start REPLY_TX command process */ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_station_priv *sta_priv = NULL; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_device_cmd *dev_cmd = NULL; struct iwl_tx_cmd *tx_cmd; __le16 fc; u8 hdr_len; u16 len; u8 sta_id; unsigned long flags; bool is_agg = false; if (info->control.vif) ctx = iwl_rxon_ctx_from_vif(info->control.vif); spin_lock_irqsave(&priv->shrd->lock, flags); if (iwl_is_rfkill(priv->shrd)) { IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); goto drop_unlock_priv; } fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG if (ieee80211_is_auth(fc)) IWL_DEBUG_TX(priv, "Sending AUTH frame\n"); else if (ieee80211_is_assoc_req(fc)) IWL_DEBUG_TX(priv, "Sending ASSOC frame\n"); else if (ieee80211_is_reassoc_req(fc)) IWL_DEBUG_TX(priv, "Sending REASSOC frame\n"); #endif if (unlikely(ieee80211_is_probe_resp(fc))) { struct iwl_wipan_noa_data *noa_data = rcu_dereference(priv->noa_data); if (noa_data && pskb_expand_head(skb, 0, noa_data->length, GFP_ATOMIC) == 0) { memcpy(skb_put(skb, noa_data->length), noa_data->data, noa_data->length); hdr = (struct ieee80211_hdr *)skb->data; } } hdr_len = ieee80211_hdrlen(fc); /* For management frames use broadcast id to do not break aggregation */ if (!ieee80211_is_data(fc)) sta_id = ctx->bcast_sta_id; else { /* Find index into station table for destination station */ sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); goto drop_unlock_priv; } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); if (info->control.sta) sta_priv = (void *)info->control.sta->drv_priv; if (sta_priv && sta_priv->asleep && (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the * next frame is processed -- and the next frame to * this station is the one that will consume this * counter. * For now set the counter to just 1 since we do not * support uAPSD yet. */ iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); } if (info->flags & IEEE80211_TX_CTL_AMPDU) is_agg = true; /* irqs already disabled/saved above when locking priv->shrd->lock */ spin_lock(&priv->shrd->sta_lock); dev_cmd = kmem_cache_alloc(priv->tx_cmd_pool, GFP_ATOMIC); if (unlikely(!dev_cmd)) goto drop_unlock_sta; memset(dev_cmd, 0, sizeof(*dev_cmd)); tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; /* Total # bytes to be transmitted */ len = (u16)skb->len; tx_cmd->len = cpu_to_le16(len); if (info->control.hw_key) iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id); /* TODO need this for burst mode later on */ iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id); iwl_dbg_log_tx_data_frame(priv, len, hdr); iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc); iwl_update_stats(priv, true, fc, len); memset(&info->status, 0, sizeof(info->status)); info->driver_data[0] = ctx; info->driver_data[1] = dev_cmd; if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id)) goto drop_unlock_sta; spin_unlock(&priv->shrd->sta_lock); spin_unlock_irqrestore(&priv->shrd->lock, flags); /* * Avoid atomic ops if it isn't an associated client. * Also, if this is a packet for aggregation, don't * increase the counter because the ucode will stop * aggregation queues when their respective station * goes to sleep. */ if (sta_priv && sta_priv->client && !is_agg) atomic_inc(&sta_priv->pending_frames); return 0; drop_unlock_sta: if (dev_cmd) kmem_cache_free(priv->tx_cmd_pool, dev_cmd); spin_unlock(&priv->shrd->sta_lock); drop_unlock_priv: spin_unlock_irqrestore(&priv->shrd->lock, flags); return -1; }