18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: station RX data handling 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991 88c2ecf20Sopenharmony_ci * (the "License"). You may use, redistribute and/or modify this File in 98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which 108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc., 118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 178c2ecf20Sopenharmony_ci * this warranty disclaimer. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <uapi/linux/ipv6.h> 218c2ecf20Sopenharmony_ci#include <net/ndisc.h> 228c2ecf20Sopenharmony_ci#include "decl.h" 238c2ecf20Sopenharmony_ci#include "ioctl.h" 248c2ecf20Sopenharmony_ci#include "util.h" 258c2ecf20Sopenharmony_ci#include "fw.h" 268c2ecf20Sopenharmony_ci#include "main.h" 278c2ecf20Sopenharmony_ci#include "11n_aggr.h" 288c2ecf20Sopenharmony_ci#include "11n_rxreorder.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* This function checks if a frame is IPv4 ARP or IPv6 Neighbour advertisement 318c2ecf20Sopenharmony_ci * frame. If frame has both source and destination mac address as same, this 328c2ecf20Sopenharmony_ci * function drops such gratuitous frames. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic bool 358c2ecf20Sopenharmony_cimwifiex_discard_gratuitous_arp(struct mwifiex_private *priv, 368c2ecf20Sopenharmony_ci struct sk_buff *skb) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci const struct mwifiex_arp_eth_header *arp; 398c2ecf20Sopenharmony_ci struct ethhdr *eth; 408c2ecf20Sopenharmony_ci struct ipv6hdr *ipv6; 418c2ecf20Sopenharmony_ci struct icmp6hdr *icmpv6; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci eth = (struct ethhdr *)skb->data; 448c2ecf20Sopenharmony_ci switch (ntohs(eth->h_proto)) { 458c2ecf20Sopenharmony_ci case ETH_P_ARP: 468c2ecf20Sopenharmony_ci arp = (void *)(skb->data + sizeof(struct ethhdr)); 478c2ecf20Sopenharmony_ci if (arp->hdr.ar_op == htons(ARPOP_REPLY) || 488c2ecf20Sopenharmony_ci arp->hdr.ar_op == htons(ARPOP_REQUEST)) { 498c2ecf20Sopenharmony_ci if (!memcmp(arp->ar_sip, arp->ar_tip, 4)) 508c2ecf20Sopenharmony_ci return true; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci case ETH_P_IPV6: 548c2ecf20Sopenharmony_ci ipv6 = (void *)(skb->data + sizeof(struct ethhdr)); 558c2ecf20Sopenharmony_ci icmpv6 = (void *)(skb->data + sizeof(struct ethhdr) + 568c2ecf20Sopenharmony_ci sizeof(struct ipv6hdr)); 578c2ecf20Sopenharmony_ci if (NDISC_NEIGHBOUR_ADVERTISEMENT == icmpv6->icmp6_type) { 588c2ecf20Sopenharmony_ci if (!memcmp(&ipv6->saddr, &ipv6->daddr, 598c2ecf20Sopenharmony_ci sizeof(struct in6_addr))) 608c2ecf20Sopenharmony_ci return true; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci default: 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return false; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * This function processes the received packet and forwards it 728c2ecf20Sopenharmony_ci * to kernel/upper layer. 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * This function parses through the received packet and determines 758c2ecf20Sopenharmony_ci * if it is a debug packet or normal packet. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * For non-debug packets, the function chops off unnecessary leading 788c2ecf20Sopenharmony_ci * header bytes, reconstructs the packet as an ethernet frame or 798c2ecf20Sopenharmony_ci * 802.2/llc/snap frame as required, and sends it to kernel/upper layer. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * The completion callback is called after processing in complete. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ciint mwifiex_process_rx_packet(struct mwifiex_private *priv, 848c2ecf20Sopenharmony_ci struct sk_buff *skb) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int ret; 878c2ecf20Sopenharmony_ci struct rx_packet_hdr *rx_pkt_hdr; 888c2ecf20Sopenharmony_ci struct rxpd *local_rx_pd; 898c2ecf20Sopenharmony_ci int hdr_chop; 908c2ecf20Sopenharmony_ci struct ethhdr *eth; 918c2ecf20Sopenharmony_ci u16 rx_pkt_off, rx_pkt_len; 928c2ecf20Sopenharmony_ci u8 *offset; 938c2ecf20Sopenharmony_ci u8 adj_rx_rate = 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci local_rx_pd = (struct rxpd *) (skb->data); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci rx_pkt_off = le16_to_cpu(local_rx_pd->rx_pkt_offset); 988c2ecf20Sopenharmony_ci rx_pkt_len = le16_to_cpu(local_rx_pd->rx_pkt_length); 998c2ecf20Sopenharmony_ci rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_off; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (sizeof(rx_pkt_hdr->eth803_hdr) + sizeof(rfc1042_header) + 1028c2ecf20Sopenharmony_ci rx_pkt_off > skb->len) { 1038c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 1048c2ecf20Sopenharmony_ci "wrong rx packet offset: len=%d, rx_pkt_off=%d\n", 1058c2ecf20Sopenharmony_ci skb->len, rx_pkt_off); 1068c2ecf20Sopenharmony_ci priv->stats.rx_dropped++; 1078c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 1088c2ecf20Sopenharmony_ci return -1; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (sizeof(*rx_pkt_hdr) + rx_pkt_off <= skb->len && 1128c2ecf20Sopenharmony_ci ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header, 1138c2ecf20Sopenharmony_ci sizeof(bridge_tunnel_header))) || 1148c2ecf20Sopenharmony_ci (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header, 1158c2ecf20Sopenharmony_ci sizeof(rfc1042_header)) && 1168c2ecf20Sopenharmony_ci ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_AARP && 1178c2ecf20Sopenharmony_ci ntohs(rx_pkt_hdr->rfc1042_hdr.snap_type) != ETH_P_IPX))) { 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * Replace the 803 header and rfc1042 header (llc/snap) with an 1208c2ecf20Sopenharmony_ci * EthernetII header, keep the src/dst and snap_type 1218c2ecf20Sopenharmony_ci * (ethertype). 1228c2ecf20Sopenharmony_ci * The firmware only passes up SNAP frames converting 1238c2ecf20Sopenharmony_ci * all RX Data from 802.11 to 802.2/LLC/SNAP frames. 1248c2ecf20Sopenharmony_ci * To create the Ethernet II, just move the src, dst address 1258c2ecf20Sopenharmony_ci * right before the snap_type. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci eth = (struct ethhdr *) 1288c2ecf20Sopenharmony_ci ((u8 *) &rx_pkt_hdr->eth803_hdr 1298c2ecf20Sopenharmony_ci + sizeof(rx_pkt_hdr->eth803_hdr) + 1308c2ecf20Sopenharmony_ci sizeof(rx_pkt_hdr->rfc1042_hdr) 1318c2ecf20Sopenharmony_ci - sizeof(rx_pkt_hdr->eth803_hdr.h_dest) 1328c2ecf20Sopenharmony_ci - sizeof(rx_pkt_hdr->eth803_hdr.h_source) 1338c2ecf20Sopenharmony_ci - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci memcpy(eth->h_source, rx_pkt_hdr->eth803_hdr.h_source, 1368c2ecf20Sopenharmony_ci sizeof(eth->h_source)); 1378c2ecf20Sopenharmony_ci memcpy(eth->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, 1388c2ecf20Sopenharmony_ci sizeof(eth->h_dest)); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Chop off the rxpd + the excess memory from the 802.2/llc/snap 1418c2ecf20Sopenharmony_ci header that was removed. */ 1428c2ecf20Sopenharmony_ci hdr_chop = (u8 *) eth - (u8 *) local_rx_pd; 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci /* Chop off the rxpd */ 1458c2ecf20Sopenharmony_ci hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - 1468c2ecf20Sopenharmony_ci (u8 *) local_rx_pd; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Chop off the leading header bytes so the it points to the start of 1508c2ecf20Sopenharmony_ci either the reconstructed EthII frame or the 802.2/llc/snap frame */ 1518c2ecf20Sopenharmony_ci skb_pull(skb, hdr_chop); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (priv->hs2_enabled && 1548c2ecf20Sopenharmony_ci mwifiex_discard_gratuitous_arp(priv, skb)) { 1558c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "Bypassed Gratuitous ARP\n"); 1568c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 1618c2ecf20Sopenharmony_ci ntohs(rx_pkt_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) { 1628c2ecf20Sopenharmony_ci offset = (u8 *)local_rx_pd + rx_pkt_off; 1638c2ecf20Sopenharmony_ci mwifiex_process_tdls_action_frame(priv, offset, rx_pkt_len); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Only stash RX bitrate for unicast packets. */ 1678c2ecf20Sopenharmony_ci if (likely(!is_multicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest))) { 1688c2ecf20Sopenharmony_ci priv->rxpd_rate = local_rx_pd->rx_rate; 1698c2ecf20Sopenharmony_ci priv->rxpd_htinfo = local_rx_pd->ht_info; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || 1738c2ecf20Sopenharmony_ci GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 1748c2ecf20Sopenharmony_ci adj_rx_rate = mwifiex_adjust_data_rate(priv, 1758c2ecf20Sopenharmony_ci local_rx_pd->rx_rate, 1768c2ecf20Sopenharmony_ci local_rx_pd->ht_info); 1778c2ecf20Sopenharmony_ci mwifiex_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr, 1788c2ecf20Sopenharmony_ci local_rx_pd->nf); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ret = mwifiex_recv_packet(priv, skb); 1828c2ecf20Sopenharmony_ci if (ret == -1) 1838c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 1848c2ecf20Sopenharmony_ci "recv packet failed\n"); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return ret; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* 1908c2ecf20Sopenharmony_ci * This function processes the received buffer. 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * The function looks into the RxPD and performs sanity tests on the 1938c2ecf20Sopenharmony_ci * received buffer to ensure its a valid packet, before processing it 1948c2ecf20Sopenharmony_ci * further. If the packet is determined to be aggregated, it is 1958c2ecf20Sopenharmony_ci * de-aggregated accordingly. Non-unicast packets are sent directly to 1968c2ecf20Sopenharmony_ci * the kernel/upper layers. Unicast packets are handed over to the 1978c2ecf20Sopenharmony_ci * Rx reordering routine if 11n is enabled. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * The completion callback is called after processing in complete. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ciint mwifiex_process_sta_rx_packet(struct mwifiex_private *priv, 2028c2ecf20Sopenharmony_ci struct sk_buff *skb) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 2058c2ecf20Sopenharmony_ci int ret = 0; 2068c2ecf20Sopenharmony_ci struct rxpd *local_rx_pd; 2078c2ecf20Sopenharmony_ci struct rx_packet_hdr *rx_pkt_hdr; 2088c2ecf20Sopenharmony_ci u8 ta[ETH_ALEN]; 2098c2ecf20Sopenharmony_ci u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num; 2108c2ecf20Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci local_rx_pd = (struct rxpd *) (skb->data); 2138c2ecf20Sopenharmony_ci rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type); 2148c2ecf20Sopenharmony_ci rx_pkt_offset = le16_to_cpu(local_rx_pd->rx_pkt_offset); 2158c2ecf20Sopenharmony_ci rx_pkt_length = le16_to_cpu(local_rx_pd->rx_pkt_length); 2168c2ecf20Sopenharmony_ci seq_num = le16_to_cpu(local_rx_pd->seq_num); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if ((rx_pkt_offset + rx_pkt_length) > skb->len || 2218c2ecf20Sopenharmony_ci sizeof(rx_pkt_hdr->eth803_hdr) + rx_pkt_offset > skb->len) { 2228c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 2238c2ecf20Sopenharmony_ci "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n", 2248c2ecf20Sopenharmony_ci skb->len, rx_pkt_offset, rx_pkt_length); 2258c2ecf20Sopenharmony_ci priv->stats.rx_dropped++; 2268c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (rx_pkt_type == PKT_TYPE_MGMT) { 2318c2ecf20Sopenharmony_ci ret = mwifiex_process_mgmt_packet(priv, skb); 2328c2ecf20Sopenharmony_ci if (ret) 2338c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, DATA, "Rx of mgmt packet failed"); 2348c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * If the packet is not an unicast packet then send the packet 2408c2ecf20Sopenharmony_ci * directly to os. Don't pass thru rx reordering 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci if ((!IS_11N_ENABLED(priv) && 2438c2ecf20Sopenharmony_ci !(ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 2448c2ecf20Sopenharmony_ci !(local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET))) || 2458c2ecf20Sopenharmony_ci !ether_addr_equal_unaligned(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest)) { 2468c2ecf20Sopenharmony_ci mwifiex_process_rx_packet(priv, skb); 2478c2ecf20Sopenharmony_ci return ret; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (mwifiex_queuing_ra_based(priv) || 2518c2ecf20Sopenharmony_ci (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 2528c2ecf20Sopenharmony_ci local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET)) { 2538c2ecf20Sopenharmony_ci memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); 2548c2ecf20Sopenharmony_ci if (local_rx_pd->flags & MWIFIEX_RXPD_FLAGS_TDLS_PACKET && 2558c2ecf20Sopenharmony_ci local_rx_pd->priority < MAX_NUM_TID) { 2568c2ecf20Sopenharmony_ci sta_ptr = mwifiex_get_sta_entry(priv, ta); 2578c2ecf20Sopenharmony_ci if (sta_ptr) 2588c2ecf20Sopenharmony_ci sta_ptr->rx_seq[local_rx_pd->priority] = 2598c2ecf20Sopenharmony_ci le16_to_cpu(local_rx_pd->seq_num); 2608c2ecf20Sopenharmony_ci mwifiex_auto_tdls_update_peer_signal(priv, ta, 2618c2ecf20Sopenharmony_ci local_rx_pd->snr, 2628c2ecf20Sopenharmony_ci local_rx_pd->nf); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci if (rx_pkt_type != PKT_TYPE_BAR && 2668c2ecf20Sopenharmony_ci local_rx_pd->priority < MAX_NUM_TID) 2678c2ecf20Sopenharmony_ci priv->rx_seq[local_rx_pd->priority] = seq_num; 2688c2ecf20Sopenharmony_ci memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, 2698c2ecf20Sopenharmony_ci ETH_ALEN); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Reorder and send to OS */ 2738c2ecf20Sopenharmony_ci ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority, 2748c2ecf20Sopenharmony_ci ta, (u8) rx_pkt_type, skb); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (ret || (rx_pkt_type == PKT_TYPE_BAR)) 2778c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (ret) 2808c2ecf20Sopenharmony_ci priv->stats.rx_dropped++; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci} 284