// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2024 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
#include <linux/unaligned.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "iwl-trans.h"
#include "mvm.h"
#include "fw-api.h"
/*
* iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler
*
* Copies the phy information in mvm->last_phy_info, it will be used when the
* actual data will come from the fw in the next packet.
*/
void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
if (unlikely(pkt_len < sizeof(mvm->last_phy_info)))
return;
memcpy(&mvm->last_phy_info, pkt->data, sizeof(mvm->last_phy_info));
mvm->ampdu_ref++;
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
spin_lock(&mvm->drv_stats_lock);
mvm->drv_rx_stats.ampdu_count++;
spin_unlock(&mvm->drv_stats_lock);
}
#endif
}
/*
* iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211
*
* Adds the rxb to a new skb and give it to mac80211
*/
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct napi_struct *napi,
struct sk_buff *skb,
struct ieee80211_hdr *hdr, u16 len,
u8 crypt_len,
struct iwl_rx_cmd_buffer *rxb)
{
unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
unsigned int fraglen;
/*
* The 'hdrlen' (plus the 8 bytes for the SNAP and the crypt_len,
* but those are all multiples of 4 long) all goes away, but we
* want the *end* of it, which is going to be the start of the IP
* header, to be aligned when it gets pulled in.
* The beginning of the skb->data is aligned on at least a 4-byte
* boundary after allocation. Everything here is aligned at least
* on a 2-byte boundary so we can just take hdrlen & 3 and pad by
* the result.
*/
skb_reserve(skb, hdrlen & 3);
/* If frame is small enough to fit in skb->head, pull it completely.
* If not, only pull ieee80211_hdr (including crypto if present, and
* an additional 8 bytes for SNAP/ethertype, see below) so that
* splice() or TCP coalesce are more efficient.
*
* Since, in addition, ieee80211_data_to_8023() always pull in at
* least 8 bytes (possibly more for mesh) we can do the same here
* to save the cost of doing it later. That still doesn't pull in
* the actual IP header since the typical case has a SNAP header.
* If the latter changes (there are efforts in the standards group
* to do so) we should revisit this and ieee80211_data_to_8023().
*/
hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8;
skb_put_data(skb, hdr, hdrlen);
fraglen = len - hdrlen;
if (fraglen) {
int offset = (u8 *)hdr + hdrlen -
(u8 *)rxb_addr(rxb) + rxb_offset(rxb);