// SPDX-License-Identifier: GPL-2.0 #include "softmac_core.h" #include "img_host_txrx_buffs_iface.h" #include "img_rx_multi_pkt_proc.h" #include "img_utils.h" void img_data_rx_2k_packet_destructor(struct sk_buff *skb); void stats_for_debugging(struct ieee80211_hdr *hdr, struct lmac_event_rx *rx_evnt ) { IMG_RX_DBG_PARAM_INCR(rx_packet_total_count, 1); if (ieee80211_is_data(hdr->frame_control)) { IMG_RX_DBG_PARAM_INCR(rx_packet_data_count, rx_evnt->rx_pkt_cnt); } if (ieee80211_is_data_qos(hdr->frame_control)) { IMG_RX_DBG_PARAM_INCR(rx_packet_qos_data_count, rx_evnt->rx_pkt_cnt); } if (ieee80211_has_protected(hdr->frame_control)) { IMG_RX_DBG_PARAM_INCR(rx_packet_protected_data_count, rx_evnt->rx_pkt_cnt); } if (ieee80211_is_mgmt(hdr->frame_control)) { IMG_RX_DBG_PARAM_INCR(rx_packet_mgmt_count, 1); switch (hdr->frame_control & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_BEACON: IMG_RX_DBG_PARAM_INCR(rx_packet_beacon_count, 1); break; case IEEE80211_STYPE_PROBE_RESP: IMG_RX_DBG_PARAM_INCR(rx_packet_probe_resp_count, 1); break; case IEEE80211_STYPE_AUTH: IMG_RX_DBG_PARAM_INCR(rx_packet_auth_count, 1); break; case IEEE80211_STYPE_DEAUTH: IMG_RX_DBG_PARAM_INCR(rx_packet_deauth_count, 1); break; case IEEE80211_STYPE_DISASSOC: IMG_RX_DBG_PARAM_INCR(rx_packet_disassoc_count, 1); break; case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: IMG_RX_DBG_PARAM_INCR(rx_packet_assoc_resp_count, 1); break; case IEEE80211_STYPE_ACTION: IMG_RX_DBG_PARAM_INCR(rx_packet_action_count, 1); break; case IEEE80211_STYPE_PROBE_REQ: IMG_RX_DBG_PARAM_INCR(rx_packet_probe_req_count, 1); break; default: IMG_RX_DBG_PARAM_INCR(rx_packet_other_mgmt_count, 1); break; } } } unsigned int img_handle_trigger_frame_rx(struct img_priv *priv, struct ieee80211_hdr *mac_hdr,struct sk_buff *skb) { unsigned int trig_type,hdrlen; if (ieee80211_is_ctl(mac_hdr->frame_control)){ if ((priv->vifs[0]->type == NL80211_IFTYPE_STATION) && (priv->vifs[0]->bss_conf.he_support == 1) && (is_trigger_frame(mac_hdr->frame_control))){ priv->rx_trigger_jiffie_value = jiffies; hdrlen = ieee80211_hdrlen(mac_hdr->frame_control); trig_type = *(skb->data+hdrlen); /* RU transmissions for basic trigger */ if ((trig_type&0xf) == 0){ priv->trig_recv_cnt++; priv->ru_tx = 1; } return 1; } } return 0; } void rpu_rx_frame(void *buff, void *context) { DEFINE_SPIN_LOCK_IRQ(oldIPL); struct lmac_event_rx *rx_evnt = (struct lmac_event_rx *)buff; struct img_priv *priv = (struct img_priv *)context; struct ieee80211_hdr *hdr; __le16 frame_control; struct ieee80211_rx_status rx_status; struct ieee80211_supported_band *band = NULL; int i; static unsigned int rssi_index; unsigned char mic_status; unsigned char *skb_data; struct primary_pkt_info *primary_pkt_info; struct sk_buff *skb; unsigned int ext_ram_access_addr; unsigned int ext_addr; int len = RX_MAC_HEADER_COPY_LEN; skb = alloc_skb(0, GFP_ATOMIC); if (skb == NULL) { printk("%s:%d alloc_skb failed\n", __FUNCTION__, __LINE__); return; } primary_pkt_info = kzalloc(sizeof(struct primary_pkt_info), GFP_KERNEL); if (primary_pkt_info == NULL) { printk("%s:%d malloc failed size %lu\n", __FUNCTION__, __LINE__, sizeof(struct primary_pkt_info)); return; } primary_pkt_info->info_type = RX_MULTI_PKT_INFO; primary_pkt_info->rx_evnt = rx_evnt; __skb_queue_head_init(&primary_pkt_info->released_frames); skb->pkt_info = (unsigned char *)primary_pkt_info; skb->destructor = img_data_rx_2k_packet_destructor; spin_lock_irqsave(&oldIPL, 0); memcpy_unaligned(primary_pkt_info->gram_ptr, (void *)(img_umac_ext_ram_access_addr(rx_evnt->mpdu_ctrl[0].skb_pointer)), rx_evnt->mpduOvrHead); spin_unlock_irqrestore(&oldIPL, 0); hdr = (struct ieee80211_hdr *)primary_pkt_info->gram_ptr; if (ieee80211_is_data(hdr->frame_control)) { skb->head = (unsigned char *)primary_pkt_info->gram_ptr; skb->data = skb->head; } else { unsigned char *data = malloc(rx_evnt->mpdu_ctrl[0].rx_pkt_len); if (data == NULL) { dev_kfree_skb_any(skb); return; } ext_addr = rx_evnt->mpdu_ctrl[0].skb_pointer; spin_lock_irqsave(&oldIPL, 0); ext_ram_access_addr = img_umac_ext_ram_access_addr(ext_addr); memcpy_unaligned(data, (void *)ext_ram_access_addr, rx_evnt->mpdu_ctrl[0].rx_pkt_len); spin_unlock_irqrestore(&oldIPL, 0); skb->head = data; skb->data = skb->head; } skb->tail = skb->data; skb->end = skb->data + 2048; skb_put(skb, rx_evnt->mpdu_ctrl[0].rx_pkt_len); if (img_handle_trigger_frame_rx(priv,hdr,skb)){ dev_kfree_skb_any(skb); return; } /* Stats for debugging */ stats_for_debugging(hdr,rx_evnt ); memset(&rx_status, 0, sizeof(struct ieee80211_rx_status)); /* Remove this once hardware supports bip(11w) is available*/ if ( ieee80211_is_data(hdr->frame_control) || (ieee80211_is_action(hdr->frame_control) && ieee80211_has_protected(hdr->frame_control) && !is_multicast_ether_addr(hdr->addr1)) || ((ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_has_protected(hdr->frame_control))) rx_status.flag |= RX_FLAG_DECRYPTED; if (ieee80211_is_auth(hdr->frame_control) && ieee80211_has_protected(hdr->frame_control) && is_unicast_ether_addr(hdr->addr1)){ rx_status.flag |= RX_FLAG_DECRYPTED; } rx_status.flag |= RX_FLAG_MMIC_STRIPPED; mic_status = rx_evnt->mpdu_ctrl[0].rxPktStatus; switch (mic_status) { case DECRYPTION_SUCCESS: break; case TKIP_MIC_FAILURE: rx_status.flag |= RX_FLAG_MMIC_ERROR; break; default: /*Drop the Frame*/ printk("Got MIC Failure Status, Dropping the frame\n"); dev_kfree_skb_any(skb); return; } if (rx_evnt->channel < 15) rx_status.band = NL80211_BAND_2GHZ; else rx_status.band = NL80211_BAND_5GHZ; rx_status.freq = ieee80211_channel_to_frequency(rx_evnt->channel, rx_status.band); rx_status.signal = rx_evnt->rssi; rx_status.antenna = 0; if (rx_evnt->rate_flags & ENABLE_VHT_FORMAT) { /* Rate */ if ((rx_evnt->rate_or_mcs & MARK_RATE_AS_MCS_INDEX) != 0x80) { printk("Invalid VHT MCS Information\n"); rx_evnt->rate_or_mcs = 0;/*default to MCS0*/ } else { rx_status.rate_idx = (rx_evnt->rate_or_mcs & 0x7f); } /* NSS */ if (!rx_evnt->nss || rx_evnt->nss > 8) rx_status.nss = 1; else rx_status.nss = rx_evnt->nss; /* CBW */ if (rx_evnt->rate_flags & ENABLE_CHNL_WIDTH_80MHZ) rx_status.bw |= RATE_INFO_BW_80; else if (rx_evnt->rate_flags & ENABLE_CHNL_WIDTH_40MHZ) rx_status.bw |= RATE_INFO_BW_40; /* SGI */ if (rx_evnt->rate_flags & ENABLE_SGI) rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; rx_status.encoding |= RX_ENC_VHT; } else if (rx_evnt->rate_flags & ENABLE_11N_FORMAT) { /* Rate */ if ((rx_evnt->rate_or_mcs & MARK_RATE_AS_MCS_INDEX) != 0x80) { rx_evnt->rate_or_mcs = 0;/*default to MCS0*/ } else { rx_status.rate_idx = (rx_evnt->rate_or_mcs & 0x7f); } /* CBW */ if (rx_evnt->rate_flags & ENABLE_CHNL_WIDTH_40MHZ) rx_status.bw |= RATE_INFO_BW_40; /* HT Greenfield */ if (rx_evnt->rate_flags & ENABLE_GREEN_FIELD) rx_status.enc_flags |= RX_ENC_FLAG_HT_GF; /* SGI */ if (rx_evnt->rate_flags & ENABLE_SGI) rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI; rx_status.encoding = RX_ENC_HT; } else { band = priv->hw->wiphy->bands[rx_status.band]; if (!WARN_ON_ONCE(!band)) { for (i = 0; i < band->n_bitrates; i++) { if (rx_evnt->rate_or_mcs == band->bitrates[i].hw_value) { rx_status.rate_idx = i; break; } } } else { dev_kfree_skb_any(skb); return; } } if (((hdr->frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && ((hdr->frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)) { rx_status.mactime = get_unaligned_le64(rx_evnt->timestamp); rx_status.flag |= RX_FLAG_MACTIME_START; } memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx(priv->hw, skb); }