162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: station RX data handling 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <uapi/linux/ipv6.h> 962306a36Sopenharmony_ci#include <net/ndisc.h> 1062306a36Sopenharmony_ci#include "decl.h" 1162306a36Sopenharmony_ci#include "ioctl.h" 1262306a36Sopenharmony_ci#include "util.h" 1362306a36Sopenharmony_ci#include "fw.h" 1462306a36Sopenharmony_ci#include "main.h" 1562306a36Sopenharmony_ci#include "11n_aggr.h" 1662306a36Sopenharmony_ci#include "11n_rxreorder.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* This function checks if a frame is IPv4 ARP or IPv6 Neighbour advertisement 1962306a36Sopenharmony_ci * frame. If frame has both source and destination mac address as same, this 2062306a36Sopenharmony_ci * function drops such gratuitous frames. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_cistatic bool 2362306a36Sopenharmony_cimwifiex_discard_gratuitous_arp(struct mwifiex_private *priv, 2462306a36Sopenharmony_ci struct sk_buff *skb) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci const struct mwifiex_arp_eth_header *arp; 2762306a36Sopenharmony_ci struct ethhdr *eth; 2862306a36Sopenharmony_ci struct ipv6hdr *ipv6; 2962306a36Sopenharmony_ci struct icmp6hdr *icmpv6; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci eth = (struct ethhdr *)skb->data; 3262306a36Sopenharmony_ci switch (ntohs(eth->h_proto)) { 3362306a36Sopenharmony_ci case ETH_P_ARP: 3462306a36Sopenharmony_ci arp = (void *)(skb->data + sizeof(struct ethhdr)); 3562306a36Sopenharmony_ci if (arp->hdr.ar_op == htons(ARPOP_REPLY) || 3662306a36Sopenharmony_ci arp->hdr.ar_op == htons(ARPOP_REQUEST)) { 3762306a36Sopenharmony_ci if (!memcmp(arp->ar_sip, arp->ar_tip, 4)) 3862306a36Sopenharmony_ci return true; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci case ETH_P_IPV6: 4262306a36Sopenharmony_ci ipv6 = (void *)(skb->data + sizeof(struct ethhdr)); 4362306a36Sopenharmony_ci icmpv6 = (void *)(skb->data + sizeof(struct ethhdr) + 4462306a36Sopenharmony_ci sizeof(struct ipv6hdr)); 4562306a36Sopenharmony_ci if (NDISC_NEIGHBOUR_ADVERTISEMENT == icmpv6->icmp6_type) { 4662306a36Sopenharmony_ci if (!memcmp(&ipv6->saddr, &ipv6->daddr, 4762306a36Sopenharmony_ci sizeof(struct in6_addr))) 4862306a36Sopenharmony_ci return true; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci default: 5262306a36Sopenharmony_ci break; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return false; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * This function processes the received packet and forwards it 6062306a36Sopenharmony_ci * to kernel/upper layer. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * This function parses through the received packet and determines 6362306a36Sopenharmony_ci * if it is a debug packet or normal packet. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * For non-debug packets, the function chops off unnecessary leading 6662306a36Sopenharmony_ci * header bytes, reconstructs the packet as an ethernet frame or 6762306a36Sopenharmony_ci * 802.2/llc/snap frame as required, and sends it to kernel/upper layer. 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * The completion callback is called after processing in complete. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ciint mwifiex_process_rx_packet(struct mwifiex_private *priv, 7262306a36Sopenharmony_ci struct sk_buff *skb) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci int ret; 7562306a36Sopenharmony_ci struct rx_packet_hdr *rx_pkt_hdr; 7662306a36Sopenharmony_ci struct rxpd *local_rx_pd; 7762306a36Sopenharmony_ci int hdr_chop; 7862306a36Sopenharmony_ci struct ethhdr *eth; 7962306a36Sopenharmony_ci u16 rx_pkt_off, rx_pkt_len; 8062306a36Sopenharmony_ci u8 *offset; 8162306a36Sopenharmony_ci u8 adj_rx_rate = 0; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci local_rx_pd = (struct rxpd *) (skb->data); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci rx_pkt_off = le16_to_cpu(local_rx_pd->rx_pkt_offset); 8662306a36Sopenharmony_ci rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length); 8762306a36Sopenharmony_ci rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (sizeof(rx_pkt_hdr->eth803_hdr) + sizeof(rfc1042_header) + 9062306a36Sopenharmony_ci rx_pkt_off > skb->len) { 9162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 9262306a36Sopenharmony_ci "wrong rx packet offset: len=%d, rx_pkt_off=%d\n", 9362306a36Sopenharmony_ci skb->len, rx_pkt_off); 9462306a36Sopenharmony_ci priv->stats.rx_dropped++; 9562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 9662306a36Sopenharmony_ci return -1; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (sizeof(*rx_pkt_hdr) + rx_pkt_off <= skb->len && 10062306a36Sopenharmony_ci ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header, 10162306a36Sopenharmony_ci sizeof(bridge_tunnel_header))) || 10262306a36Sopenharmony_ci (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, 10362306a36Sopenharmony_ci sizeof(rfc1042_header)) && 10462306a36Sopenharmony_ci ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP && 10562306a36Sopenharmony_ci ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX))) { 10662306a36Sopenharmony_ci /* 10762306a36Sopenharmony_ci * Replace the 803 header and rfc1042 header (llc/snap) with an 10862306a36Sopenharmony_ci * EthernetII header, keep the src/dst and snap_type 10962306a36Sopenharmony_ci * (ethertype). 11062306a36Sopenharmony_ci * The firmware only passes up SNAP frames converting 11162306a36Sopenharmony_ci * all RX Data from 802.11 to 802.2/LLC/SNAP frames. 11262306a36Sopenharmony_ci * To create the Ethernet II, just move the src, dst address 11362306a36Sopenharmony_ci * right before the snap_type. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci eth = (struct ethhdr *) 11662306a36Sopenharmony_ci ((u8 *) &rx_pkt_hdr->eth803_hdr 11762306a36Sopenharmony_ci + sizeof(rx_pkt_hdr->eth803_hdr) + 11862306a36Sopenharmony_ci sizeof(rx_pkt_hdr->rfc1042_hdr) 11962306a36Sopenharmony_ci - sizeof(rx_pkt_hdr->eth803_hdr.h_dest) 12062306a36Sopenharmony_ci - sizeof(rx_pkt_hdr->eth803_hdr.h_source) 12162306a36Sopenharmony_ci - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci memcpy(eth->h_source, rx_pkt_hdr->eth803_hdr.h_source, 12462306a36Sopenharmony_ci sizeof(eth->h_source)); 12562306a36Sopenharmony_ci memcpy(eth->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, 12662306a36Sopenharmony_ci sizeof(eth->h_dest)); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Chop off the rxpd + the excess memory from the 802.2/llc/snap 12962306a36Sopenharmony_ci header that was removed. */ 13062306a36Sopenharmony_ci hdr_chop = (u8 *) eth - (u8 *) local_rx_pd; 13162306a36Sopenharmony_ci } else { 13262306a36Sopenharmony_ci /* Chop off the rxpd */ 13362306a36Sopenharmony_ci hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - 13462306a36Sopenharmony_ci (u8 *) local_rx_pd; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Chop off the leading header bytes so the it points to the start of 13862306a36Sopenharmony_ci either the reconstructed EthII frame or the 802.2/llc/snap frame */ 13962306a36Sopenharmony_ci skb_pull(skb, hdr_chop); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (priv->hs2_enabled && 14262306a36Sopenharmony_ci mwifiex_discard_gratuitous_arp(priv, skb)) { 14362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "Bypassed Gratuitous ARP\n"); 14462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 14962306a36Sopenharmony_ci ntohs(rx_pkt_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) { 15062306a36Sopenharmony_ci offset = (u8 *)local_rx_pd + rx_pkt_off; 15162306a36Sopenharmony_ci mwifiex_process_tdls_action_frame(priv, offset, rx_pkt_len); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Only stash RX bitrate for unicast packets. */ 15562306a36Sopenharmony_ci if (likely(!is_multicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest))) { 15662306a36Sopenharmony_ci priv->rxpd_rate = local_rx_pd->rx_rate; 15762306a36Sopenharmony_ci priv->rxpd_htinfo = local_rx_pd->ht_info; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || 16162306a36Sopenharmony_ci GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 16262306a36Sopenharmony_ci adj_rx_rate = mwifiex_adjust_data_rate(priv, 16362306a36Sopenharmony_ci local_rx_pd->rx_rate, 16462306a36Sopenharmony_ci local_rx_pd->ht_info); 16562306a36Sopenharmony_ci mwifiex_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr, 16662306a36Sopenharmony_ci local_rx_pd->nf); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ret = mwifiex_recv_packet(priv, skb); 17062306a36Sopenharmony_ci if (ret == -1) 17162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 17262306a36Sopenharmony_ci "recv packet failed\n"); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return ret; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* 17862306a36Sopenharmony_ci * This function processes the received buffer. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * The function looks into the RxPD and performs sanity tests on the 18162306a36Sopenharmony_ci * received buffer to ensure its a valid packet, before processing it 18262306a36Sopenharmony_ci * further. If the packet is determined to be aggregated, it is 18362306a36Sopenharmony_ci * de-aggregated accordingly. Non-unicast packets are sent directly to 18462306a36Sopenharmony_ci * the kernel/upper layers. Unicast packets are handed over to the 18562306a36Sopenharmony_ci * Rx reordering routine if 11n is enabled. 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * The completion callback is called after processing in complete. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ciint mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, 19062306a36Sopenharmony_ci struct sk_buff *skb) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 19362306a36Sopenharmony_ci int ret = 0; 19462306a36Sopenharmony_ci struct rxpd *local_rx_pd; 19562306a36Sopenharmony_ci struct rx_packet_hdr *rx_pkt_hdr; 19662306a36Sopenharmony_ci u8 ta[ETH_ALEN]; 19762306a36Sopenharmony_ci u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num; 19862306a36Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci local_rx_pd = (struct rxpd *) (skb->data); 20162306a36Sopenharmony_ci rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type); 20262306a36Sopenharmony_ci rx_pkt_offset = le16_to_cpu(local_rx_pd->rx_pkt_offset); 20362306a36Sopenharmony_ci rx_pkt_length = le16_to_cpu(local_rx_pd->rx_pkt_length); 20462306a36Sopenharmony_ci seq_num = le16_to_cpu(local_rx_pd->seq_num); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if ((rx_pkt_offset + rx_pkt_length) > skb->len || 20962306a36Sopenharmony_ci sizeof(rx_pkt_hdr->eth803_hdr) + rx_pkt_offset > skb->len) { 21062306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 21162306a36Sopenharmony_ci "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n", 21262306a36Sopenharmony_ci skb->len, rx_pkt_offset, rx_pkt_length); 21362306a36Sopenharmony_ci priv->stats.rx_dropped++; 21462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 21562306a36Sopenharmony_ci return ret; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (rx_pkt_type == PKT_TYPE_MGMT) { 21962306a36Sopenharmony_ci ret = mwifiex_process_mgmt_packet(priv, skb); 22062306a36Sopenharmony_ci if (ret) 22162306a36Sopenharmony_ci mwifiex_dbg(adapter, DATA, "Rx of mgmt packet failed"); 22262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 22362306a36Sopenharmony_ci return ret; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * If the packet is not an unicast packet then send the packet 22862306a36Sopenharmony_ci * directly to os. Don't pass thru rx reordering 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci if ((!IS_11N_ENABLED(priv) && 23162306a36Sopenharmony_ci !(ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 23262306a36Sopenharmony_ci !(local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET))) || 23362306a36Sopenharmony_ci !ether_addr_equal_unaligned(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest)) { 23462306a36Sopenharmony_ci mwifiex_process_rx_packet(priv, skb); 23562306a36Sopenharmony_ci return ret; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (mwifiex_queuing_ra_based(priv) || 23962306a36Sopenharmony_ci (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 24062306a36Sopenharmony_ci local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET)) { 24162306a36Sopenharmony_ci memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); 24262306a36Sopenharmony_ci if (local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET && 24362306a36Sopenharmony_ci local_rx_pd->priority < MAX_NUM_TID) { 24462306a36Sopenharmony_ci sta_ptr = mwifiex_get_sta_entry(priv, ta); 24562306a36Sopenharmony_ci if (sta_ptr) 24662306a36Sopenharmony_ci sta_ptr->rx_seq[local_rx_pd->priority] = 24762306a36Sopenharmony_ci le16_to_cpu(local_rx_pd->seq_num); 24862306a36Sopenharmony_ci mwifiex_auto_tdls_update_peer_signal(priv, ta, 24962306a36Sopenharmony_ci local_rx_pd->snr, 25062306a36Sopenharmony_ci local_rx_pd->nf); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci } else { 25362306a36Sopenharmony_ci if (rx_pkt_type != PKT_TYPE_BAR && 25462306a36Sopenharmony_ci local_rx_pd->priority < MAX_NUM_TID) 25562306a36Sopenharmony_ci priv->rx_seq[local_rx_pd->priority] = seq_num; 25662306a36Sopenharmony_ci memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, 25762306a36Sopenharmony_ci ETH_ALEN); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Reorder and send to OS */ 26162306a36Sopenharmony_ci ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority, 26262306a36Sopenharmony_ci ta, (u8) rx_pkt_type, skb); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (ret || (rx_pkt_type == PKT_TYPE_BAR)) 26562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (ret) 26862306a36Sopenharmony_ci priv->stats.rx_dropped++; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return ret; 27162306a36Sopenharmony_ci} 272