From d4a1bd480003f3e1a0590bc46fbcb24f05652ca7 Mon Sep 17 00:00:00 2001 From: tzh <tanzhtanzh@gmail.com> Date: Thu, 15 Aug 2024 06:56:47 +0000 Subject: [PATCH] feat(wfit/bt): update aic8800 wifi/bt drive and hal --- longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c | 706 ++++++++++++++++++++++------------------------------------ 1 files changed, 272 insertions(+), 434 deletions(-) diff --git a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c old mode 100644 new mode 100755 index a88cb0a..7c32ca0 --- a/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c +++ b/longan/kernel/linux-4.9/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c @@ -369,11 +369,14 @@ rx_skb->dev = rwnx_vif->ndev; skb_reset_mac_header(rx_skb); + /* Update statistics */ + rwnx_vif->net_stats.rx_packets++; + rwnx_vif->net_stats.rx_bytes += rx_skb->len; + //printk("forward\n"); rx_skb->protocol = eth_type_trans(rx_skb, rwnx_vif->ndev); memset(rx_skb->cb, 0, sizeof(rx_skb->cb)); - REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX); #if 0 //modify by aic netif_receive_skb(rx_skb); #else @@ -395,11 +398,7 @@ #endif } #endif - REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX); - /* Update statistics */ - rwnx_vif->net_stats.rx_packets++; - rwnx_vif->net_stats.rx_bytes += rx_skb->len; rwnx_hw->stats.last_rx = jiffies; } @@ -505,13 +504,16 @@ /* forward pkt to upper layer */ if (forward) { + /* Update statistics */ + rwnx_vif->net_stats.rx_packets++; + rwnx_vif->net_stats.rx_bytes += rx_skb->len; + rx_skb->protocol = eth_type_trans(rx_skb, rwnx_vif->ndev); #ifdef AICWF_ARP_OFFLOAD if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION || RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT) arpoffload_proc(rx_skb, rwnx_vif); #endif memset(rx_skb->cb, 0, sizeof(rx_skb->cb)); - REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX); #if 0 //modify by aic netif_receive_skb(rx_skb); #else @@ -533,11 +535,7 @@ #endif } #endif - REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX); - /* Update statistics */ - rwnx_vif->net_stats.rx_packets++; - rwnx_vif->net_stats.rx_bytes += rx_skb->len; rwnx_hw->stats.last_rx = jiffies; } } @@ -562,6 +560,11 @@ struct rx_vector_1 *rxvect = &hw_rxhdr->hwvect.rx_vect1; //printk("rwnx_rx_mgmt\n"); + if (ieee80211_is_mgmt(mgmt->frame_control) && + (skb->len <= 24 || skb->len > 768)) { + printk("mgmt err\n"); + return; + } if (ieee80211_is_beacon(mgmt->frame_control)) { if ((RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT) && hw_rxhdr->flags_new_peer) { @@ -623,10 +626,10 @@ { struct rwnx_vif *rwnx_vif; int vif_idx = hw_rxhdr->flags_vif_idx; - +#ifdef CREATE_TRACE_POINTS trace_mgmt_rx(hw_rxhdr->phy_info.phy_prim20_freq, vif_idx, hw_rxhdr->flags_sta_idx, (struct ieee80211_mgmt *)skb->data); - +#endif if (vif_idx == RWNX_INVALID_VIF) { list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) { if (!rwnx_vif->up) @@ -1077,400 +1080,6 @@ return 0; } -/** - * rwnx_unsup_rx_vec_ind() - IRQ handler callback for %IPC_IRQ_E2A_UNSUP_RX_VEC - * - * LMAC has triggered an IT saying that a rx vector of an unsupported frame has been - * captured and sent to upper layer. Then we need to fill the rx status, create a vendor - * specific header and fill it with the HT packet length. Finally, we need to specify at - * least 2 bytes of data and send the sk_buff to mac80211. - * - * @pthis: Pointer to main driver data - * @hostid: Pointer to IPC elem from e2aradars_pool - */ -u8 rwnx_unsup_rx_vec_ind(void *pthis, void *hostid) -{ - struct rwnx_hw *rwnx_hw = pthis; - struct rwnx_ipc_skb_elem *elem = hostid; - struct rx_vector_desc *rx_desc; - struct sk_buff *skb; - struct rx_vector_1 *rx_vect1; - struct phy_channel_info_desc *phy_info; - struct vendor_radiotap_hdr *rtap; - u16 ht_length; - struct rwnx_vif *rwnx_vif; - struct rx_vector_desc rx_vect_desc; - u8 rtap_len, vend_rtap_len = sizeof(*rtap); - - dma_sync_single_for_cpu(rwnx_hw->dev, elem->dma_addr, - sizeof(struct rx_vector_desc), DMA_FROM_DEVICE); - - skb = elem->skb; - if (((struct rx_vector_desc *) (skb->data))->pattern == 0) { - /*sync is needed even if the driver did not modify the memory*/ - dma_sync_single_for_device(rwnx_hw->dev, elem->dma_addr, - sizeof(struct rx_vector_desc), DMA_FROM_DEVICE); - return -1; - } - - if (rwnx_hw->monitor_vif == RWNX_INVALID_VIF) { - /* Unmap will synchronize buffer for CPU */ - dma_unmap_single(rwnx_hw->dev, elem->dma_addr, rwnx_hw->ipc_env->unsuprxvec_bufsz, - DMA_FROM_DEVICE); - elem->skb = NULL; - - /* Free skb */ - dev_kfree_skb(skb); - - /* Allocate and push a new buffer to fw to replace this one */ - if (rwnx_ipc_unsup_rx_vec_elem_allocs(rwnx_hw, elem)) - dev_err(rwnx_hw->dev, "Failed to alloc new unsupported rx vector buf\n"); - return -1; - } - - rwnx_vif = rwnx_hw->vif_table[rwnx_hw->monitor_vif]; - skb->dev = rwnx_vif->ndev; - memcpy(&rx_vect_desc, skb->data, sizeof(rx_vect_desc)); - rx_desc = &rx_vect_desc; - - rx_vect1 = (struct rx_vector_1 *) (rx_desc->rx_vect1); - rwnx_rx_vector_convert(rwnx_hw, rx_vect1, NULL); - phy_info = (struct phy_channel_info_desc *) (&rx_desc->phy_info); - if (rx_vect1->format_mod >= FORMATMOD_VHT) - ht_length = 0; - else - ht_length = (u16) le32_to_cpu(rx_vect1->ht.length); - - // Reserve space for radiotap - skb_reserve(skb, RADIOTAP_HDR_MAX_LEN); - - /* Fill vendor specific header with fake values */ - rtap = (struct vendor_radiotap_hdr *) skb->data; - rtap->oui[0] = 0x00; - rtap->oui[1] = 0x25; - rtap->oui[2] = 0x3A; - rtap->subns = 0; - rtap->len = sizeof(ht_length); - put_unaligned_le16(ht_length, rtap->data); - vend_rtap_len += rtap->len; - skb_put(skb, vend_rtap_len); - - /* Copy fake data */ - put_unaligned_le16(0, skb->data + vend_rtap_len); - skb_put(skb, UNSUP_RX_VEC_DATA_LEN); - - /* Get RadioTap Header length */ - rtap_len = rwnx_rx_rtap_hdrlen(rx_vect1, true); - - /* Check headroom space */ - if (skb_headroom(skb) < rtap_len) { - netdev_err(rwnx_vif->ndev, "not enough headroom %d need %d\n", skb_headroom(skb), rtap_len); - return -1; - } - - /* Add RadioTap Header */ - rwnx_rx_add_rtap_hdr(rwnx_hw, skb, rx_vect1, phy_info, NULL, - rtap_len, vend_rtap_len, BIT(0)); - - skb_reset_mac_header(skb); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - - /* Unmap will synchronize buffer for CPU */ - dma_unmap_single(rwnx_hw->dev, elem->dma_addr, rwnx_hw->ipc_env->unsuprxvec_bufsz, - DMA_FROM_DEVICE); - elem->skb = NULL; - - netif_receive_skb(skb); - - /* Allocate and push a new buffer to fw to replace this one */ - if (rwnx_ipc_unsup_rx_vec_elem_allocs(rwnx_hw, elem)) - netdev_err(rwnx_vif->ndev, "Failed to alloc new unsupported rx vector buf\n"); - return 0; -} - -/** - * rwnx_rxdataind - Process rx buffer - * - * @pthis: Pointer to the object attached to the IPC structure - * (points to struct rwnx_hw is this case) - * @hostid: Address of the RX descriptor - * - * This function is called for each buffer received by the fw - * - */ -u8 rwnx_rxdataind(void *pthis, void *hostid) -{ - struct rwnx_hw *rwnx_hw = pthis; - struct rwnx_ipc_elem *elem = hostid; - struct hw_rxhdr *hw_rxhdr; - struct rxdesc_tag *rxdesc; - struct rwnx_vif *rwnx_vif; - struct sk_buff *skb = NULL; - int rx_buff_idx; - int msdu_offset = sizeof(struct hw_rxhdr) + 2; - int peek_len = msdu_offset + sizeof(struct ethhdr); - u16_l status; - - REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND); - - /* Get the ownership of the descriptor */ - dma_sync_single_for_cpu(rwnx_hw->dev, elem->dma_addr, - sizeof(struct rxdesc_tag), DMA_FROM_DEVICE); - - rxdesc = elem->addr; - status = rxdesc->status; - - /* check that frame is completely uploaded */ - if (!status) { - /* Get the ownership of the descriptor */ - dma_sync_single_for_device(rwnx_hw->dev, elem->dma_addr, - sizeof(struct rxdesc_tag), DMA_FROM_DEVICE); - return -1; - } - - /* Get the buffer linked with the received descriptor */ - rx_buff_idx = RWNX_RXBUFF_HOSTID_TO_IDX(rxdesc->host_id); - if (RWNX_RXBUFF_VALID_IDX(rx_buff_idx)) - skb = rwnx_hw->rxbuf_elems.skb[rx_buff_idx]; - - if (!skb) { - dev_err(rwnx_hw->dev, "RX Buff invalid idx [%d]\n", rx_buff_idx); - return -1; - } - - /* Check the pattern */ - if (RWNX_RXBUFF_PATTERN_GET(skb) != rwnx_rxbuff_pattern) { - dev_err(rwnx_hw->dev, "RX Buff Pattern not correct\n"); - BUG(); - } - - /* Check if we need to delete the buffer */ - if (status & RX_STAT_DELETE) { - /* Remove the SK buffer from the rxbuf_elems table */ - rwnx_ipc_rxbuf_elem_pull(rwnx_hw, skb); - /* Free the buffer */ - dev_kfree_skb(skb); - goto end; - } - - /* Check if we need to forward the buffer coming from a monitor interface */ - if (status & RX_STAT_MONITOR) { - struct sk_buff *skb_monitor; - struct hw_rxhdr hw_rxhdr_copy; - u8 rtap_len; - u16 frm_len; - - //Check if monitor interface exists and is open - rwnx_vif = rwnx_rx_get_vif(rwnx_hw, rwnx_hw->monitor_vif); - if (!rwnx_vif) { - dev_err(rwnx_hw->dev, "Received monitor frame but there is no monitor interface open\n"); - goto check_len_update; - } - - hw_rxhdr = (struct hw_rxhdr *)skb->data; - rwnx_rx_vector_convert(rwnx_hw, - &hw_rxhdr->hwvect.rx_vect1, - &hw_rxhdr->hwvect.rx_vect2); - rtap_len = rwnx_rx_rtap_hdrlen(&hw_rxhdr->hwvect.rx_vect1, false); - - // Move skb->data pointer to MAC Header or Ethernet header - skb->data += msdu_offset; - - //Save frame length - frm_len = le32_to_cpu(hw_rxhdr->hwvect.len); - - // Reserve space for frame - skb->len = frm_len; - - if (status == RX_STAT_MONITOR) { - /* Remove the SK buffer from the rxbuf_elems table. It will also - unmap the buffer and then sync the buffer for the cpu */ - rwnx_ipc_rxbuf_elem_pull(rwnx_hw, skb); - - //Check if there is enough space to add the radiotap header - if (skb_headroom(skb) > rtap_len) { - - skb_monitor = skb; - - //Duplicate the HW Rx Header to override with the radiotap header - memcpy(&hw_rxhdr_copy, hw_rxhdr, sizeof(hw_rxhdr_copy)); - - hw_rxhdr = &hw_rxhdr_copy; - } else { - //Duplicate the skb and extend the headroom - skb_monitor = skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC); - - //Reset original skb->data pointer - skb->data = (void *)hw_rxhdr; - } - } else { - //#ifdef CONFIG_RWNX_MON_DATA - #if 0 - // Check if MSDU - if (!hw_rxhdr->flags_is_80211_mpdu) { - // MSDU - //Extract MAC header - u16 machdr_len = hw_rxhdr->mac_hdr_backup.buf_len; - u8 *machdr_ptr = hw_rxhdr->mac_hdr_backup.buffer; - - //Pull Ethernet header from skb - skb_pull(skb, sizeof(struct ethhdr)); - - // Copy skb and extend for adding the radiotap header and the MAC header - skb_monitor = skb_copy_expand(skb, - rtap_len + machdr_len, - 0, GFP_ATOMIC); - - //Reserve space for the MAC Header - skb_push(skb_monitor, machdr_len); - - //Copy MAC Header - memcpy(skb_monitor->data, machdr_ptr, machdr_len); - - //Update frame length - frm_len += machdr_len - sizeof(struct ethhdr); - } else { - // MPDU - skb_monitor = skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC); - } - - //Reset original skb->data pointer - skb->data = (void *)hw_rxhdr; - #else - //Reset original skb->data pointer - skb->data = (void *)hw_rxhdr; - - wiphy_err(rwnx_hw->wiphy, "RX status %d is invalid when MON_DATA is disabled\n", status); - goto check_len_update; - #endif - } - - skb_reset_tail_pointer(skb); - skb->len = 0; - skb_reset_tail_pointer(skb_monitor); - skb_monitor->len = 0; - - skb_put(skb_monitor, frm_len); - if (rwnx_rx_monitor(rwnx_hw, rwnx_vif, skb_monitor, hw_rxhdr, rtap_len)) - dev_kfree_skb(skb_monitor); - - if (status == RX_STAT_MONITOR) { - status |= RX_STAT_ALLOC; - if (skb_monitor != skb) { - dev_kfree_skb(skb); - } - } - } - -check_len_update: - /* Check if we need to update the length */ - if (status & RX_STAT_LEN_UPDATE) { - dma_addr_t dma_addr = RWNX_RXBUFF_DMA_ADDR_GET(skb); - dma_sync_single_for_cpu(rwnx_hw->dev, dma_addr, - peek_len, DMA_FROM_DEVICE); - - hw_rxhdr = (struct hw_rxhdr *)skb->data; - - hw_rxhdr->hwvect.len = rxdesc->frame_len; - - if (status & RX_STAT_ETH_LEN_UPDATE) { - /* Update Length Field inside the Ethernet Header */ - struct ethhdr *hdr = (struct ethhdr *)((u8 *)hw_rxhdr + msdu_offset); - - hdr->h_proto = htons(rxdesc->frame_len - sizeof(struct ethhdr)); - } - - dma_sync_single_for_device(rwnx_hw->dev, dma_addr, - peek_len, DMA_BIDIRECTIONAL); - goto end; - } - - /* Check if it must be discarded after informing upper layer */ - if (status & RX_STAT_SPURIOUS) { - struct ieee80211_hdr *hdr; - - /* Read mac header to obtain Transmitter Address */ - rwnx_ipc_rxbuf_elem_sync(rwnx_hw, skb, msdu_offset + sizeof(*hdr)); - - hw_rxhdr = (struct hw_rxhdr *)skb->data; - hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset); - rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx); - if (rwnx_vif) { - rwnx_cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, GFP_ATOMIC); - } - rwnx_ipc_rxbuf_elem_repush(rwnx_hw, skb); - goto end; - } - - /* Check if we need to forward the buffer */ - if (status & RX_STAT_FORWARD) { - - /* Remove the SK buffer from the rxbuf_elems table. It will also - unmap the buffer and then sync the buffer for the cpu */ - rwnx_ipc_rxbuf_elem_pull(rwnx_hw, skb); - hw_rxhdr = (struct hw_rxhdr *)skb->data; - rwnx_rx_vector_convert(rwnx_hw, - &hw_rxhdr->hwvect.rx_vect1, - &hw_rxhdr->hwvect.rx_vect2); - skb_reserve(skb, msdu_offset); - skb_put(skb, le32_to_cpu(hw_rxhdr->hwvect.len)); - - if (hw_rxhdr->flags_is_80211_mpdu) { - rwnx_rx_mgmt_any(rwnx_hw, skb, hw_rxhdr); - } else { - rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx); - - if (!rwnx_vif) { - dev_err(rwnx_hw->dev, "Frame received but no active vif (%d)", - hw_rxhdr->flags_vif_idx); - dev_kfree_skb(skb); - goto check_alloc; - } - - if (hw_rxhdr->flags_sta_idx != RWNX_INVALID_STA) { - struct rwnx_sta *sta; - - sta = &rwnx_hw->sta_table[hw_rxhdr->flags_sta_idx]; - rwnx_rx_statistic(rwnx_hw, hw_rxhdr, sta); - - if (sta->vlan_idx != rwnx_vif->vif_index) { - rwnx_vif = rwnx_hw->vif_table[sta->vlan_idx]; - if (!rwnx_vif) { - dev_kfree_skb(skb); - goto check_alloc; - } - } - - if (hw_rxhdr->flags_is_4addr && !rwnx_vif->use_4addr) { - rwnx_cfg80211_rx_unexpected_4addr_frame(rwnx_vif->ndev, - sta->mac_addr, GFP_ATOMIC); - } - } - - skb->priority = 256 + hw_rxhdr->flags_user_prio; - if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, hw_rxhdr)) - dev_kfree_skb(skb); - } - } - -check_alloc: - /* Check if we need to allocate a new buffer */ - if ((status & RX_STAT_ALLOC) && - rwnx_ipc_rxbuf_elem_allocs(rwnx_hw)) { - dev_err(rwnx_hw->dev, "Failed to alloc new RX buf\n"); - } - -end: - REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND); - - /* Reset and repush descriptor to FW */ - rwnx_ipc_rxdesc_elem_repush(rwnx_hw, elem); - - return 0; -} - #ifdef AICWF_ARP_OFFLOAD void arpoffload_proc(struct sk_buff *skb, struct rwnx_vif *rwnx_vif) { @@ -1493,8 +1102,11 @@ if (option[offset] == DHCP_OPTION_MESSAGE_TYPE) { if (option[offset+2] == DHCP_ACK) { dhcped = 1; - printk("group=%x, should=%x\n", rwnx_vif->sta.group_cipher_type, WLAN_CIPHER_SUITE_CCMP); - if (rwnx_vif->sta.group_cipher_type == WLAN_CIPHER_SUITE_CCMP || rwnx_vif->sta.group_cipher_type == WLAN_CIPHER_SUITE_AES_CMAC) + printk("paired=%x, should=%x\n", rwnx_vif->sta.paired_cipher_type, WLAN_CIPHER_SUITE_CCMP); + if (rwnx_vif->sta.paired_cipher_type == WLAN_CIPHER_SUITE_CCMP || \ + rwnx_vif->sta.paired_cipher_type == WLAN_CIPHER_SUITE_AES_CMAC || \ + ((rwnx_vif->sta.group_cipher_type == 0xff) && \ + (rwnx_vif->sta.paired_cipher_type == 0xff))) rwnx_send_arpoffload_en_req(rwnx_vif->rwnx_hw, rwnx_vif, dhcph->yiaddr, 1); else rwnx_send_arpoffload_en_req(rwnx_vif->rwnx_hw, rwnx_vif, dhcph->yiaddr, 0); @@ -1648,6 +1260,7 @@ return; } + printk("reord_deinit_sta\n"); for (i = 0; i < 8; i++) { struct recv_msdu *req, *next; preorder_ctrl = &reord_info->preorder_ctrl[i]; @@ -1659,13 +1272,13 @@ req->pkt = NULL; reord_rxframe_free(&rx_priv->freeq_lock, &rx_priv->rxframes_freequeue, &req->rxframe_list); } - printk("reord dinit"); spin_unlock_irqrestore(&preorder_ctrl->reord_list_lock, flags); if (timer_pending(&preorder_ctrl->reord_timer)) { ret = del_timer_sync(&preorder_ctrl->reord_timer); } cancel_work_sync(&preorder_ctrl->reord_timer_work); } + list_del(&reord_info->list); kfree(reord_info); } @@ -1683,9 +1296,19 @@ return -1; } + if (!prframe->forward) { + dev_kfree_skb(skb); + prframe->pkt = NULL; + reord_rxframe_free(&rx_priv->freeq_lock, rxframes_freequeue, &prframe->rxframe_list); + return 0; + } + skb->data = prframe->rx_data; skb_set_tail_pointer(skb, prframe->len); skb->len = prframe->len; + + rwnx_vif->net_stats.rx_packets++; + rwnx_vif->net_stats.rx_bytes += skb->len; //printk("netif sn=%d, len=%d\n", precv_frame->attrib.seq_num, skb->len); skb->dev = rwnx_vif->ndev; @@ -1700,23 +1323,21 @@ if (in_interrupt()) { netif_rx(skb); } else { - /* - * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ. - * * In 2.6 kernels, this is handledby netif_rx_ni(), but in earlier kernels, we need to do it manually. - */ + /* + * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ. + * * In 2.6 kernels, this is handledby netif_rx_ni(), but in earlier kernels, we need to do it manually. + */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); + netif_rx_ni(skb); #else - ulong flags; - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); + ulong flags; + netif_rx(skb); + local_irq_save(flags); + RAISE_RX_SOFTIRQ(); + local_irq_restore(flags); #endif } - rwnx_vif->net_stats.rx_packets++; - rwnx_vif->net_stats.rx_bytes += skb->len; prframe->pkt = NULL; reord_rxframe_free(&rx_priv->freeq_lock, rxframes_freequeue, &prframe->rxframe_list); @@ -1817,7 +1438,7 @@ return ; } -int reord_process_unit(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u16 seq_num, u8 tid) +int reord_process_unit(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u16 seq_num, u8 tid, u8 forward) { int ret = 0; u8 *mac; @@ -1846,6 +1467,7 @@ pframe->rx_data = skb->data; pframe->len = skb->len; pframe->pkt = skb; + pframe->forward = forward; preorder_ctrl = pframe->preorder_ctrl; if ((ntohs(eh->h_proto) == ETH_P_PAE) || is_mcast) @@ -2000,6 +1622,25 @@ } } +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) +void defrag_timeout_cb(ulong data) +#else +void defrag_timeout_cb(struct timer_list *t) +#endif +{ + struct defrag_ctrl_info *defrag_ctrl = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + defrag_ctrl = (struct defrag_ctrl_info *)data; +#else + defrag_ctrl = from_timer(defrag_ctrl, t, defrag_timer); +#endif + + printk("%s:%p\r\n", __func__, defrag_ctrl); + list_del_init(&defrag_ctrl->list); + dev_kfree_skb(defrag_ctrl->skb); + kfree(defrag_ctrl); +} + u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv) { struct hw_rxhdr *hw_rxhdr; @@ -2015,12 +1656,22 @@ u8 ether_type[2] = {0}; u8 pull_len = 0; u16 seq_num = 0; + u8_l frag_num = 0; u8 tid = 0; u8 is_qos = 0; + u8 is_frag = 0; + struct defrag_ctrl_info *defrag_info = NULL; + struct defrag_ctrl_info *defrag_info_tmp = NULL; + int ret; + u8 sta_idx = 0; + u16_l frame_ctrl; + u8 is_amsdu = 0; + u16 len_alligned = 0; + u16 sublen = 0; + struct sk_buff *sub_skb = NULL; bool resend = false, forward = true; const struct ethhdr *eth; - REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND); hw_rxhdr = (struct hw_rxhdr *)skb->data; if (hw_rxhdr->is_monitor_vif) { @@ -2186,13 +1837,23 @@ &hw_rxhdr->hwvect.rx_vect2); skb_pull(skb, msdu_offset + 2); //+2 since sdio allign 58->60 +#define MAC_FCTRL_MOREFRAG 0x0400 + frame_ctrl = (skb->data[1] << 8) | skb->data[0]; + seq_num = ((skb->data[22] & 0xf0) >> 4) | (skb->data[23] << 4); + frag_num = (skb->data[22] & 0x0f); + is_amsdu = 0; + if ((skb->data[0] & 0x0f) == 0x08) { if ((skb->data[0] & 0x80) == 0x80) {//qos data hdr_len = 26; tid = skb->data[24] & 0x0F; is_qos = 1; + if (skb->data[24] & 0x80) + is_amsdu = 1; } + if (skb->data[1] & 0x80)//htc + hdr_len += 4; if ((skb->data[1] & 0x3) == 0x1) {// to ds memcpy(ra, &skb->data[16], MAC_ADDR_LEN); memcpy(ta, &skb->data[10], MAC_ADDR_LEN); @@ -2202,9 +1863,7 @@ } pull_len += (hdr_len + 8); -#ifdef AICWF_RX_REORDER - seq_num = ((skb->data[22]&0xf0)>>4) | (skb->data[23]<<4); -#endif + switch (hw_rxhdr->hwvect.decr_status) { case RWNX_RX_HD_DECR_CCMP128: pull_len += 8;//ccmp_header @@ -2225,11 +1884,184 @@ break; } - skb_pull(skb, pull_len); - skb_push(skb, 14); - memcpy(skb->data, ra, MAC_ADDR_LEN); - memcpy(&skb->data[6], ta, MAC_ADDR_LEN); - memcpy(&skb->data[12], ether_type, 2); + if (is_amsdu) { + skb_pull(skb, pull_len-8); + /* |amsdu sub1 | amsdu sub2 | ... */ + len_alligned = 0; + sublen = 0; + sub_skb = NULL; + //printk("is_len:%d, pull:%d\n", skb->len, pull_len); + while (skb->len > 16) { + sublen = (skb->data[12]<<8)|(skb->data[13]); + if (skb->len > (sublen+14)) + len_alligned = roundup(sublen + 14, 4); + else if (skb->len == (sublen+14)) + len_alligned = sublen+14; + else { + printk("accroding to amsdu: this will not happen\n"); + break; + } + //printk("sublen = %d, %x, %x, %x, %x\r\n", sublen,skb->data[0], skb->data[1], skb->data[12], skb->data[13]); +#if 1 + sub_skb = __dev_alloc_skb(sublen - 6 + 12, GFP_KERNEL); + skb_put(sub_skb, sublen - 6 + 12); + memcpy(sub_skb->data, skb->data, MAC_ADDR_LEN); + memcpy(&sub_skb->data[6], &skb->data[6], MAC_ADDR_LEN); + memcpy(&sub_skb->data[12], &skb->data[14 + 6], sublen - 6); + + rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx); + if (!rwnx_vif) { + printk("Frame received but no active vif (%d)", hw_rxhdr->flags_vif_idx); + dev_kfree_skb(sub_skb); + break; + } + + if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, sub_skb, hw_rxhdr)) + dev_kfree_skb(sub_skb); +#endif + skb_pull(skb, len_alligned); + } + dev_kfree_skb(skb); + return 0; + } + + if (hw_rxhdr->flags_dst_idx != RWNX_INVALID_STA) + sta_idx = hw_rxhdr->flags_dst_idx; + + if (!hw_rxhdr->flags_need_reord && ((frame_ctrl & MAC_FCTRL_MOREFRAG) || frag_num)) { + printk("rxfrag:%d,%d\r\n", (frame_ctrl & MAC_FCTRL_MOREFRAG), frag_num); + if (frame_ctrl & MAC_FCTRL_MOREFRAG) { + spin_lock_bh(&rwnx_hw->defrag_lock); + if (!list_empty(&rwnx_hw->defrag_list)) { + list_for_each_entry(defrag_info_tmp, &rwnx_hw->defrag_list, list) { + if ((defrag_info_tmp->sn == seq_num) && (defrag_info_tmp->tid == tid) && \ + defrag_info_tmp->sta_idx == sta_idx) { + defrag_info = defrag_info_tmp; + break; + } + } + } + spin_unlock_bh(&rwnx_hw->defrag_lock); + //printk("rx frag: sn=%d, fn=%d\r\n", seq_num, frag_num); + if (defrag_info) { + is_frag = 1; + if (defrag_info->next_fn != frag_num) { + //printk("discard:%d:%d\n", defrag_info->next_fn, frag_num); + dev_kfree_skb(skb); + return 0; + } + + skb_put(defrag_info->skb, skb->len-(pull_len-8)); + memcpy(&defrag_info->skb->data[defrag_info->frm_len], \ + &skb->data[pull_len-8], skb->len - (pull_len-8)); + //printk("middle:%d,%d\n", skb->len-(pull_len-8), skb->len); + defrag_info->frm_len += (skb->len - (pull_len - 8)); + defrag_info->next_fn++; + dev_kfree_skb(skb); + return 0; + } else { + defrag_info = kzalloc(sizeof(struct defrag_ctrl_info), GFP_ATOMIC); + if (defrag_info == NULL) { + printk("no defrag_ctrl_info\r\n"); + dev_kfree_skb(skb); + return 0; + } + defrag_info->skb = __dev_alloc_skb(2000, GFP_ATOMIC); + if (defrag_info->skb == NULL) { + printk("no fragment skb\r\n"); + dev_kfree_skb(skb); + kfree(defrag_info); + return 0; + } + is_frag = 1; + skb_pull(skb, pull_len); + skb_push(skb, 14); + memcpy(skb->data, ra, MAC_ADDR_LEN); + memcpy(&skb->data[6], ta, MAC_ADDR_LEN); + memcpy(&skb->data[12], ether_type, 2); + + defrag_info->sn = seq_num; + defrag_info->next_fn = 1; + defrag_info->tid = tid; + defrag_info->sta_idx = sta_idx; + + skb_put(defrag_info->skb, skb->len); + memcpy(defrag_info->skb->data, skb->data, skb->len); + defrag_info->frm_len = skb->len; + //printk("first:%p,%d\r\n", defrag_info, defrag_info->frm_len); + spin_lock_bh(&rwnx_hw->defrag_lock); + list_add_tail(&defrag_info->list, &rwnx_hw->defrag_list); + spin_unlock_bh(&rwnx_hw->defrag_lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) + init_timer(&defrag_info->defrag_timer); + defrag_info->defrag_timer.data = (unsigned long)defrag_info; + defrag_info->defrag_timer.function = defrag_timeout_cb; +#else + timer_setup(&defrag_info->defrag_timer, defrag_timeout_cb, 0); +#endif + ret = mod_timer(&defrag_info->defrag_timer, jiffies + msecs_to_jiffies(DEFRAG_MAX_WAIT)); + dev_kfree_skb(skb); + return 0; + } + } else { + //check whether the last fragment + if (!list_empty(&rwnx_hw->defrag_list)) { + spin_lock_bh(&rwnx_hw->defrag_lock); + list_for_each_entry(defrag_info_tmp, &rwnx_hw->defrag_list, list) { + if (((defrag_info_tmp->sn == seq_num) && (defrag_info_tmp->tid == tid) && \ + defrag_info_tmp->sta_idx == sta_idx)) { + defrag_info = defrag_info_tmp; + break; + } + } + spin_unlock_bh(&rwnx_hw->defrag_lock); + + if (defrag_info) { + if (defrag_info->next_fn != frag_num) { + printk("discard:%d:%d\n", defrag_info->next_fn, frag_num); + dev_kfree_skb(skb); + return 0; + } + + skb_put(defrag_info->skb, skb->len - (pull_len-8)); + memcpy(&defrag_info->skb->data[defrag_info->frm_len], \ + &skb->data[pull_len-8], skb->len - (pull_len-8)); + defrag_info->frm_len += (skb->len - (pull_len-8)); + is_frag = 1; + //printk("last: sn=%d, fn=%d, %d, %d\r\n", seq_num, frag_num, defrag_info->frm_len, skb->len); + dev_kfree_skb(skb); + + rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx); + if (!rwnx_vif) { + printk("Frame received but no active vif (%d)", hw_rxhdr->flags_vif_idx); + dev_kfree_skb(skb); + return 0; + } + + if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, defrag_info->skb, hw_rxhdr)) + dev_kfree_skb(defrag_info->skb); + + spin_lock_bh(&rwnx_hw->defrag_lock); + list_del_init(&defrag_info->list); + spin_unlock_bh(&rwnx_hw->defrag_lock); + if (timer_pending(&defrag_info->defrag_timer)) { + ret = del_timer(&defrag_info->defrag_timer); + } + kfree(defrag_info); + + return 0; + } + } + } + } + + if (!is_frag) { + skb_pull(skb, pull_len); + skb_push(skb, 14); + memcpy(skb->data, ra, MAC_ADDR_LEN); + memcpy(&skb->data[6], ta, MAC_ADDR_LEN); + memcpy(&skb->data[12], ether_type, 2); + } } if (hw_rxhdr->flags_is_80211_mpdu) { @@ -2273,7 +2105,7 @@ if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) { if (is_qos && hw_rxhdr->flags_need_reord) - reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid); + reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid, 1); else if (is_qos && !hw_rxhdr->flags_need_reord) { reord_flush_tid((struct aicwf_rx_priv *)rx_priv, skb, tid); if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, hw_rxhdr)) @@ -2309,12 +2141,19 @@ if (forward) { if (is_qos && hw_rxhdr->flags_need_reord) - reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid); + reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid, 1); else if (is_qos && !hw_rxhdr->flags_need_reord) { reord_flush_tid((struct aicwf_rx_priv *)rx_priv, skb, tid); rwnx_rx_data_skb_forward(rwnx_hw, rwnx_vif, skb, hw_rxhdr); } else rwnx_rx_data_skb_forward(rwnx_hw, rwnx_vif, skb, hw_rxhdr); + } else if (resend) { + if (is_qos && hw_rxhdr->flags_need_reord) + reord_process_unit((struct aicwf_rx_priv *)rx_priv, skb, seq_num, tid, 0); + else if (is_qos && !hw_rxhdr->flags_need_reord) { + reord_flush_tid((struct aicwf_rx_priv *)rx_priv, skb, tid); + dev_kfree_skb(skb); + } } else dev_kfree_skb(skb); #else @@ -2330,7 +2169,6 @@ } end: - REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND); return 0; } -- Gitblit v1.6.2