/* * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler * * Handles the actual data of the Rx packet from the fw */ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb) { struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_phy_info *phy_info; struct iwl_rx_mpdu_res_start *rx_res; struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u32 len; u32 rate_n_flags; u32 rx_pkt_status; u8 crypt_len = 0; bool take_ref; phy_info = &mvm->last_phy_info; rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res)); len = le16_to_cpu(rx_res->byte_count); rx_pkt_status = le32_to_cpup((__le32 *) (pkt->data + sizeof(*rx_res) + len)); /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); return; } rx_status = IEEE80211_SKB_RXCB(skb); /* * drop the packet if it has failed being decrypted by HW */ if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status, &crypt_len)) { IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", rx_pkt_status); kfree_skb(skb); return; } /* * Keep packets with CRC errors (and with overrun) for monitor mode * (otherwise the firmware discards them) but mark them as bad. */ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; } /* This will be used in several places later */ rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); /* rx_status carries information about the packet to mac80211 */ rx_status->mactime = le64_to_cpu(phy_info->timestamp); rx_status->device_timestamp = le32_to_cpu(phy_info->system_timestamp); rx_status->band = (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; rx_status->freq = ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), rx_status->band); /* TSF as indicated by the firmware is at INA time */ rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; iwl_mvm_get_signal_strength(mvm, phy_info, rx_status); IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status->signal, (unsigned long long)rx_status->mactime); rcu_read_lock(); if (rx_pkt_status & RX_MPDU_RES_STATUS_SRC_STA_FOUND) { u32 id = rx_pkt_status & RX_MPDU_RES_STATUS_STA_ID_MSK; id >>= RX_MDPU_RES_STATUS_STA_ID_SHIFT; if (!WARN_ON_ONCE(id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) { sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); if (IS_ERR(sta)) sta = NULL; } } else if (!is_multicast_ether_addr(hdr->addr2)) {
static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 *rxdesc = skb->data; struct ieee80211_hdr *hdr; bool unicast = false; __le16 fc; struct ieee80211_rx_status rx_status = {0}; struct rtl_stats stats = { .signal = 0, .rate = 0, }; skb_pull(skb, RTL_RX_DESC_SIZE); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; if (!stats.crc) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); if (is_broadcast_ether_addr(hdr->addr1)) { /*TODO*/; } else if (is_multicast_ether_addr(hdr->addr1)) { /*TODO*/ } else { unicast = true; rtlpriv->stats.rxbytesunicast += skb->len; } if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); if (unicast) rtlpriv->link_info.num_rx_inperiod++; } /* static bcn for roaming */ rtl_beacon_statistic(hw, skb); } } static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 *rxdesc = skb->data; struct ieee80211_hdr *hdr; bool unicast = false; __le16 fc; struct ieee80211_rx_status rx_status = {0}; struct rtl_stats stats = { .signal = 0, .rate = 0, }; skb_pull(skb, RTL_RX_DESC_SIZE); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; if (!stats.crc) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); if (is_broadcast_ether_addr(hdr->addr1)) { /*TODO*/; } else if (is_multicast_ether_addr(hdr->addr1)) { /*TODO*/ } else { unicast = true; rtlpriv->stats.rxbytesunicast += skb->len; } if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); if (unicast) rtlpriv->link_info.num_rx_inperiod++; } /* static bcn for roaming */ rtl_beacon_statistic(hw, skb); if (likely(rtl_action_proc(hw, skb, false))) ieee80211_rx(hw, skb); else dev_kfree_skb_any(skb); } } static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *_skb; struct sk_buff_head rx_queue; struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); skb_queue_head_init(&rx_queue); if (rtlusb->usb_rx_segregate_hdl) rtlusb->usb_rx_segregate_hdl(hw, skb, &rx_queue); WARN_ON(skb_queue_empty(&rx_queue)); while (!skb_queue_empty(&rx_queue)) { _skb = skb_dequeue(&rx_queue); _rtl_usb_rx_process_agg(hw, _skb); ieee80211_rx(hw, _skb); } } #define __RX_SKB_MAX_QUEUED 64 static void _rtl_rx_work(unsigned long param) { struct rtl_usb *rtlusb = (struct rtl_usb *)param; struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); struct sk_buff *skb; while ((skb = skb_dequeue(&rtlusb->rx_queue))) { if (unlikely(IS_USB_STOP(rtlusb))) { dev_kfree_skb_any(skb); continue; } if (likely(!rtlusb->usb_rx_segregate_hdl)) { _rtl_usb_rx_process_noagg(hw, skb); } else { /* TO DO */ _rtl_rx_pre_process(hw, skb); pr_err("rx agg not supported\n"); } } } static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr, unsigned int len) { #if NET_IP_ALIGN != 0 unsigned int padding = 0; #endif /* make function no-op when possible */ if (NET_IP_ALIGN == 0 || len < sizeof(*hdr)) return 0; #if NET_IP_ALIGN != 0 /* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */ /* TODO: deduplicate common code, define helper function instead? */ if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); padding ^= NET_IP_ALIGN; /* Input might be invalid, avoid accessing memory outside * the buffer. */ if ((unsigned long)qc - (unsigned long)hdr < len && *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT) padding ^= NET_IP_ALIGN; } if (ieee80211_has_a4(hdr->frame_control)) padding ^= NET_IP_ALIGN; return padding; #endif } #define __RADIO_TAP_SIZE_RSV 32 static void _rtl_rx_completed(struct urb *_urb) { struct rtl_usb *rtlusb = (struct rtl_usb *)_urb->context; struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); struct rtl_priv *rtlpriv = rtl_priv(hw); int err = 0; if (unlikely(IS_USB_STOP(rtlusb))) goto free; if (likely(0 == _urb->status)) { unsigned int padding; struct sk_buff *skb; unsigned int qlen; unsigned int size = _urb->actual_length; struct ieee80211_hdr *hdr; if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) { RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Too short packet from bulk IN! (len: %d)\n", size); goto resubmit; } qlen = skb_queue_len(&rtlusb->rx_queue); if (qlen >= __RX_SKB_MAX_QUEUED) { RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Pending RX skbuff queue full! (qlen: %d)\n", qlen); goto resubmit; } hdr = (void *)(_urb->transfer_buffer + RTL_RX_DESC_SIZE); padding = _rtl_rx_get_padding(hdr, size - RTL_RX_DESC_SIZE); skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV + padding); if (!skb) { RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Can't allocate skb for bulk IN!\n"); goto resubmit; } _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep); /* Make sure the payload data is 4 byte aligned. */ skb_reserve(skb, padding); /* reserve some space for mac80211's radiotap */ skb_reserve(skb, __RADIO_TAP_SIZE_RSV); memcpy(skb_put(skb, size), _urb->transfer_buffer, size); skb_queue_tail(&rtlusb->rx_queue, skb); tasklet_schedule(&rtlusb->rx_work_tasklet); goto resubmit; } switch (_urb->status) { /* disconnect */ case -ENOENT: case -ECONNRESET: case -ENODEV: case -ESHUTDOWN: goto free; default: break; } resubmit: usb_anchor_urb(_urb, &rtlusb->rx_submitted); err = usb_submit_urb(_urb, GFP_ATOMIC); if (unlikely(err)) { usb_unanchor_urb(_urb); goto free; } return; free: /* On some architectures, usb_free_coherent must not be called from * hardirq context. Queue urb to cleanup list. */ usb_anchor_urb(_urb, &rtlusb->rx_cleanup_urbs); } #undef __RADIO_TAP_SIZE_RSV static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct urb *urb; usb_kill_anchored_urbs(&rtlusb->rx_submitted); tasklet_kill(&rtlusb->rx_work_tasklet); cancel_work_sync(&rtlpriv->works.lps_change_work); flush_workqueue(rtlpriv->works.rtl_wq); destroy_workqueue(rtlpriv->works.rtl_wq); skb_queue_purge(&rtlusb->rx_queue); while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) { usb_free_coherent(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); } } static int _rtl_usb_receive(struct ieee80211_hw *hw) { struct urb *urb; int err; int i; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); WARN_ON(0 == rtlusb->rx_urb_num); /* 1600 == 1514 + max WLAN header + rtk info */ WARN_ON(rtlusb->rx_max_size < 1600); for (i = 0; i < rtlusb->rx_urb_num; i++) { err = -ENOMEM; urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Failed to alloc URB!!\n"); goto err_out; } err = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); if (err < 0) { RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Failed to prep_rx_urb!!\n"); usb_free_urb(urb); goto err_out; } usb_anchor_urb(urb, &rtlusb->rx_submitted); err = usb_submit_urb(urb, GFP_KERNEL); if (err) goto err_out; usb_free_urb(urb); } return 0; err_out: usb_kill_anchored_urbs(&rtlusb->rx_submitted); _rtl_usb_cleanup_rx(hw); return err; } static int rtl_usb_start(struct ieee80211_hw *hw) { int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); err = rtlpriv->cfg->ops->hw_init(hw); if (!err) { rtl_init_rx_config(hw); /* Enable software */ SET_USB_START(rtlusb); /* should after adapter start and interrupt enable. */ set_hal_start(rtlhal); /* Start bulk IN */ err = _rtl_usb_receive(hw); } return err; }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, bool unaligned) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0; /* * In PLT mode we seem to get frames and mac80211 warns about them, * workaround this by not retrieving them at all. */ if (unlikely(wl->state == WL1271_STATE_PLT)) return -EINVAL; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { /* discard corrupted packets */ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: case WL1271_RX_DESC_DECRYPT_FAIL: wl1271_warning("corrupted packet in RX with status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; case WL1271_RX_DESC_SUCCESS: case WL1271_RX_DESC_MIC_FAIL: break; default: wl1271_error("invalid RX descriptor status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; } /* skb length not included rx descriptor */ skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); buf = skb_put(skb, length - sizeof(*desc)); /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len - desc->pad_len, beacon ? "beacon" : ""); skb_trim(skb, skb->len - desc->pad_len); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); #ifdef CONFIG_HAS_WAKELOCK /* let the frame some time to propagate to user-space */ wake_lock_timeout(&wl->rx_wake, HZ); #endif return is_data; }
static void adm8211_interrupt_rci(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; unsigned int entry = priv->cur_rx % priv->rx_ring_size; u32 status; unsigned int pktlen; struct sk_buff *skb, *newskb; unsigned int limit = priv->rx_ring_size; u8 rssi, rate; while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) { if (!limit--) break; status = le32_to_cpu(priv->rx_ring[entry].status); rate = (status & RDES0_STATUS_RXDR) >> 12; rssi = le32_to_cpu(priv->rx_ring[entry].length) & RDES1_STATUS_RSSI; pktlen = status & RDES0_STATUS_FL; if (pktlen > RX_PKT_SIZE) { if (net_ratelimit()) wiphy_debug(dev->wiphy, "frame too long (%d)\n", pktlen); pktlen = RX_PKT_SIZE; } if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) { skb = NULL; /* old buffer will be reused */ /* TODO: update RX error stats */ /* TODO: check RDES0_STATUS_CRC*E */ } else if (pktlen < RX_COPY_BREAK) { skb = dev_alloc_skb(pktlen); if (skb) { pci_dma_sync_single_for_cpu( priv->pdev, priv->rx_buffers[entry].mapping, pktlen, PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, pktlen), skb_tail_pointer(priv->rx_buffers[entry].skb), pktlen); pci_dma_sync_single_for_device( priv->pdev, priv->rx_buffers[entry].mapping, RX_PKT_SIZE, PCI_DMA_FROMDEVICE); } } else { newskb = dev_alloc_skb(RX_PKT_SIZE); if (newskb) { skb = priv->rx_buffers[entry].skb; skb_put(skb, pktlen); pci_unmap_single( priv->pdev, priv->rx_buffers[entry].mapping, RX_PKT_SIZE, PCI_DMA_FROMDEVICE); priv->rx_buffers[entry].skb = newskb; priv->rx_buffers[entry].mapping = pci_map_single(priv->pdev, skb_tail_pointer(newskb), RX_PKT_SIZE, PCI_DMA_FROMDEVICE); } else { skb = NULL; /* TODO: update rx dropped stats */ } priv->rx_ring[entry].buffer1 = cpu_to_le32(priv->rx_buffers[entry].mapping); } priv->rx_ring[entry].status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL); priv->rx_ring[entry].length = cpu_to_le32(RX_PKT_SIZE | (entry == priv->rx_ring_size - 1 ? RDES1_CONTROL_RER : 0)); if (skb) { struct ieee80211_rx_status rx_status = {0}; if (priv->pdev->revision < ADM8211_REV_CA) rx_status.signal = rssi; else rx_status.signal = 100 - rssi; rx_status.rate_idx = rate; rx_status.freq = adm8211_channels[priv->channel - 1].center_freq; rx_status.band = IEEE80211_BAND_2GHZ; memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(dev, skb); } entry = (++priv->cur_rx) % priv->rx_ring_size; } /* TODO: check LPC and update stats? */ }
static void rtl8180_handle_rx(struct ieee80211_hw *dev) { struct rtl8180_priv *priv = dev->priv; unsigned int count = 32; while (count--) { struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; u32 flags = le32_to_cpu(entry->flags); if (flags & RTL818X_RX_DESC_FLAG_OWN) return; if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | RTL818X_RX_DESC_FLAG_FOF | RTL818X_RX_DESC_FLAG_RX_ERR))) goto done; else { u32 flags2 = le32_to_cpu(entry->flags2); struct ieee80211_rx_status rx_status = {0}; struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE); if (unlikely(!new_skb)) goto done; pci_unmap_single(priv->pdev, *((dma_addr_t *)skb->cb), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); skb_put(skb, flags & 0xFFF); rx_status.antenna = (flags2 >> 15) & 1; /* TODO: improve signal/rssi reporting */ rx_status.qual = flags2 & 0xFF; rx_status.signal = (flags2 >> 8) & 0x7F; /* XXX: is this correct? */ rx_status.rate_idx = (flags >> 20) & 0xF; rx_status.freq = dev->conf.channel->center_freq; rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(entry->tsft); rx_status.flag |= RX_FLAG_TSFT; if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(dev, skb); skb = new_skb; priv->rx_buf[priv->rx_idx] = skb; *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb_tail_pointer(skb), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); } done: entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE); if (priv->rx_idx == 31) entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); priv->rx_idx = (priv->rx_idx + 1) % 32; } }
/* * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler * * Handles the actual data of the Rx packet from the fw */ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_phy_info *phy_info; struct iwl_rx_mpdu_res_start *rx_res; struct ieee80211_sta *sta; struct sk_buff *skb; u32 len; u32 ampdu_status; u32 rate_n_flags; u32 rx_pkt_status; u8 crypt_len = 0; phy_info = &mvm->last_phy_info; rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res)); len = le16_to_cpu(rx_res->byte_count); rx_pkt_status = le32_to_cpup((__le32 *) (pkt->data + sizeof(*rx_res) + len)); /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); return 0; } rx_status = IEEE80211_SKB_RXCB(skb); /* * drop the packet if it has failed being decrypted by HW */ if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status, &crypt_len)) { IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", rx_pkt_status); kfree_skb(skb); return 0; } if ((unlikely(phy_info->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", phy_info->cfg_phy_cnt); kfree_skb(skb); return 0; } /* * Keep packets with CRC errors (and with overrun) for monitor mode * (otherwise the firmware discards them) but mark them as bad. */ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) || !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) { IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status); rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; } /* This will be used in several places later */ rate_n_flags = le32_to_cpu(phy_info->rate_n_flags); /* rx_status carries information about the packet to mac80211 */ rx_status->mactime = le64_to_cpu(phy_info->timestamp); rx_status->device_timestamp = le32_to_cpu(phy_info->system_timestamp); rx_status->band = (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; rx_status->freq = ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel), rx_status->band); /* * TSF as indicated by the fw is at INA time, but mac80211 expects the * TSF at the beginning of the MPDU. */ /*rx_status->flag |= RX_FLAG_MACTIME_MPDU;*/ iwl_mvm_get_signal_strength(mvm, phy_info, rx_status); IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status->signal, (unsigned long long)rx_status->mactime); rcu_read_lock(); /* * We have tx blocked stations (with CS bit). If we heard frames from * a blocked station on a new channel we can TX to it again. */ if (unlikely(mvm->csa_tx_block_bcn_timeout)) { sta = ieee80211_find_sta( rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2); if (sta) iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); } /* This is fine since we don't support multiple AP interfaces */ sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); if (sta) { struct iwl_mvm_sta *mvmsta; mvmsta = iwl_mvm_sta_from_mac80211(sta); rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && ieee80211_is_beacon(hdr->frame_control)) { struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; bool trig_check; s32 rssi; trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_RSSI); rssi_trig = (void *)trig->data; rssi = le32_to_cpu(rssi_trig->rssi); trig_check = iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif, trig); if (trig_check && rx_status->signal < rssi) iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL, 0); } } rcu_read_unlock(); /* set the preamble flag if appropriate */ if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) rx_status->flag |= RX_FLAG_SHORTPRE; if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) { /* * We know which subframes of an A-MPDU belong * together since we get a single PHY response * from the firmware for all of them */ rx_status->flag |= RX_FLAG_AMPDU_DETAILS; rx_status->ampdu_reference = mvm->ampdu_ref; } /* Set up the HT phy flags */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: break; case RATE_MCS_CHAN_WIDTH_40: rx_status->flag |= RX_FLAG_40MHZ; break; case RATE_MCS_CHAN_WIDTH_80: rx_status->vht_flag |= RX_VHT_FLAG_80MHZ; break; case RATE_MCS_CHAN_WIDTH_160: rx_status->vht_flag |= RX_VHT_FLAG_160MHZ; break; } if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status->flag |= RX_FLAG_SHORT_GI; if (rate_n_flags & RATE_HT_MCS_GF_MSK) rx_status->flag |= RX_FLAG_HT_GF; if (rate_n_flags & RATE_MCS_LDPC_MSK) rx_status->flag |= RX_FLAG_LDPC; if (rate_n_flags & RATE_MCS_HT_MSK) { u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> RATE_MCS_STBC_POS; rx_status->flag |= RX_FLAG_HT; rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rxdone_entry_desc rxdesc; struct sk_buff *skb; struct ieee80211_rx_status *rx_status; unsigned int header_length; int rate_idx; if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || !test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) goto submit_entry; if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) goto submit_entry; /* * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. */ skb = rt2x00queue_alloc_rxskb(entry, gfp); if (!skb) goto submit_entry; /* * Unmap the skb. */ rt2x00queue_unmap_skb(entry); /* * Extract the RXD details. */ memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); /* * Check for valid size in case we get corrupted descriptor from * hardware. */ if (unlikely(rxdesc.size == 0 || rxdesc.size > entry->queue->data_size)) { WARNING(rt2x00dev, "Wrong frame size %d max %d.\n", rxdesc.size, entry->queue->data_size); dev_kfree_skb(entry->skb); goto renew_skb; } /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ header_length = ieee80211_get_hdrlen_from_skb(entry->skb); /* * Hardware might have stripped the IV/EIV/ICV data, * in that case it is possible that the data was * provided separately (through hardware descriptor) * in which case we should reinsert the data into the frame. */ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && (rxdesc.flags & RX_FLAG_IV_STRIPPED)) rt2x00crypto_rx_insert_iv(entry->skb, header_length, &rxdesc); else if (header_length && (rxdesc.size > header_length) && (rxdesc.dev_flags & RXDONE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); /* Trim buffer to correct size */ skb_trim(entry->skb, rxdesc.size); /* * Translate the signal to the correct bitrate index. */ rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); if (rxdesc.rate_mode == RATE_MODE_HT_MIX || rxdesc.rate_mode == RATE_MODE_HT_GREENFIELD) rxdesc.flags |= RX_FLAG_HT; /* * Check if this is a beacon, and more frames have been * buffered while we were in powersaving mode. */ rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); /* * Update extra components */ rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); rt2x00debug_update_crypto(rt2x00dev, &rxdesc); rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); /* * Initialize RX status information, and send frame * to mac80211. */ rx_status = IEEE80211_SKB_RXCB(entry->skb); rx_status->mactime = rxdesc.timestamp; rx_status->band = rt2x00dev->curr_band; rx_status->freq = rt2x00dev->curr_freq; rx_status->rate_idx = rate_idx; rx_status->signal = rxdesc.rssi; rx_status->flag = rxdesc.flags; rx_status->antenna = rt2x00dev->link.ant.active.rx; ieee80211_rx_ni(rt2x00dev->hw, entry->skb); renew_skb: /* * Replace the skb with the freshly allocated one. */ entry->skb = skb; submit_entry: entry->flags = 0; rt2x00queue_index_inc(entry, Q_INDEX_DONE); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00dev->ops->lib->clear_entry(entry); }
static void ar5523_data_rx_cb(struct urb *urb) { struct ar5523_rx_data *data = urb->context; struct ar5523 *ar = data->ar; struct ar5523_rx_desc *desc; struct ar5523_chunk *chunk; struct ieee80211_hw *hw = ar->hw; struct ieee80211_rx_status *rx_status; u32 rxlen; int usblen = urb->actual_length; int hdrlen, pad; ar5523_dbg(ar, "%s\n", __func__); /* sync/async unlink faults aren't errors */ if (urb->status) { if (urb->status != -ESHUTDOWN) ar5523_err(ar, "%s: USB err: %d\n", __func__, urb->status); goto skip; } if (usblen < AR5523_MIN_RXBUFSZ) { ar5523_err(ar, "RX: wrong xfer size (usblen=%d)\n", usblen); goto skip; } chunk = (struct ar5523_chunk *) data->skb->data; if (((chunk->flags & UATH_CFLAGS_FINAL) == 0) || chunk->seqnum != 0) { ar5523_dbg(ar, "RX: No final flag. s: %d f: %02x l: %d\n", chunk->seqnum, chunk->flags, be16_to_cpu(chunk->length)); goto skip; } /* Rx descriptor is located at the end, 32-bit aligned */ desc = (struct ar5523_rx_desc *) (data->skb->data + usblen - sizeof(struct ar5523_rx_desc)); rxlen = be32_to_cpu(desc->len); if (rxlen > ar->rxbufsz) { ar5523_dbg(ar, "RX: Bad descriptor (len=%d)\n", be32_to_cpu(desc->len)); goto skip; } if (!rxlen) { ar5523_dbg(ar, "RX: rxlen is 0\n"); goto skip; } if (be32_to_cpu(desc->status) != 0) { ar5523_dbg(ar, "Bad RX status (0x%x len = %d). Skip\n", be32_to_cpu(desc->status), be32_to_cpu(desc->len)); goto skip; } skb_reserve(data->skb, sizeof(*chunk)); skb_put(data->skb, rxlen - sizeof(struct ar5523_rx_desc)); hdrlen = ieee80211_get_hdrlen_from_skb(data->skb); if (!IS_ALIGNED(hdrlen, 4)) { ar5523_dbg(ar, "eek, alignment workaround activated\n"); pad = ALIGN(hdrlen, 4) - hdrlen; memmove(data->skb->data + pad, data->skb->data, hdrlen); skb_pull(data->skb, pad); skb_put(data->skb, pad); } rx_status = IEEE80211_SKB_RXCB(data->skb); memset(rx_status, 0, sizeof(*rx_status)); rx_status->freq = be32_to_cpu(desc->channel); rx_status->band = hw->conf.chandef.chan->band; rx_status->signal = -95 + be32_to_cpu(desc->rssi); ieee80211_rx_irqsafe(hw, data->skb); data->skb = NULL; skip: if (data->skb) { dev_kfree_skb_irq(data->skb); data->skb = NULL; } ar5523_rx_data_put(ar, data); if (atomic_inc_return(&ar->rx_data_free_cnt) >= AR5523_RX_DATA_REFILL_COUNT && test_bit(AR5523_HW_UP, &ar->flags)) queue_work(ar->wq, &ar->rx_refill_work); }
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, enum wl_rx_buf_align rx_align, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = 0, offset_to_data = 0; u16 seq_num; u32 pkt_data_len; /* * In PLT mode we seem to get frames and mac80211 warns about them, * workaround this by not retrieving them at all. */ if (unlikely(wl->plt)) return -EINVAL; pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length); if (!pkt_data_len) { wl1271_error("Invalid packet arrived from HW. length %d", length); return -EINVAL; } if (rx_align == WLCORE_RX_BUF_UNALIGNED) reserved = RX_BUF_ALIGN; else if (rx_align == WLCORE_RX_BUF_PADDED) offset_to_data = RX_BUF_ALIGN; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } /* discard corrupted packets */ if (desc->status & WL1271_RX_DESC_DECRYPT_FAIL) { hdr = (void *)(data + sizeof(*desc) + offset_to_data); wl1271_warning("corrupted packet in RX: status: 0x%x len: %d", desc->status & WL1271_RX_DESC_STATUS_MASK, pkt_data_len); wl1271_dump((DEBUG_RX|DEBUG_CMD), "PKT: ", data + sizeof(*desc), min(pkt_data_len, ieee80211_hdrlen(hdr->frame_control))); return -EINVAL; } /* skb length not including rx descriptor */ skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* reserve the unaligned payload(if any) */ skb_reserve(skb, reserved); buf = skb_put(skb, pkt_data_len); /* * Copy packets from aggregation buffer to the skbs without rx * descriptor and with packet payload aligned care. In case of unaligned * packets copy the packets in offset of 2 bytes guarantee IP header * payload aligned to 4 bytes. */ memcpy(buf, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) skb_pull(skb, RX_BUF_ALIGN); *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); wlcore_hw_set_rx_csum(wl, desc, skb); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", seq_num, *hlid); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); #ifdef CONFIG_HAS_WAKELOCK /* let the frame some time to propagate to user-space */ wake_lock_timeout(&wl->rx_wake, HZ); #endif return is_data; }
int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb, unsigned long bytes_received) { struct ieee80211_hw *hw = priv->hw; struct ieee80211_supported_band *sband; struct sk_buff *skb; struct ieee80211_rx_status rx_status = { 0 }; struct ieee80211_hdr *hdr; __le16 fc; u8 *rsr, *new_rsr, *rssi, *frame; __le64 *tsf_time; u32 frame_size; int ii, r; u8 *rx_sts, *rx_rate, *sq, *sq_3; u32 wbk_status; u8 *skb_data; u16 *pay_load_len; u16 pay_load_with_padding; u8 rate_idx = 0; u8 rate[MAX_RATE] = {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}; long rx_dbm; skb = ptr_rcb->skb; /* [31:16]RcvByteCount ( not include 4-byte Status ) */ wbk_status = *((u32 *)(skb->data)); frame_size = wbk_status >> 16; frame_size += 4; if (bytes_received != frame_size) { dev_dbg(&priv->usb->dev, "------- WRONG Length 1\n"); return false; } if ((bytes_received > 2372) || (bytes_received <= 40)) { /* Frame Size error drop this packet.*/ dev_dbg(&priv->usb->dev, "------ WRONG Length 2\n"); return false; } skb_data = (u8 *)skb->data; rx_sts = skb_data+4; rx_rate = skb_data+5; /* real Frame Size = USBframe_size -4WbkStatus - 4RxStatus */ /* -8TSF - 4RSR - 4SQ3 - ?Padding */ /* if SQ3 the range is 24~27, if no SQ3 the range is 20~23 */ pay_load_len = (u16 *) (skb_data + 6); /*Fix hardware bug => PLCP_Length error */ if (((bytes_received - (*pay_load_len)) > 27) || ((bytes_received - (*pay_load_len)) < 24) || (bytes_received < (*pay_load_len))) { dev_dbg(&priv->usb->dev, "Wrong PLCP Length %x\n", *pay_load_len); return false; } sband = hw->wiphy->bands[hw->conf.chandef.chan->band]; for (r = RATE_1M; r < MAX_RATE; r++) { if (*rx_rate == rate[r]) break; } priv->rx_rate = r; for (ii = 0; ii < sband->n_bitrates; ii++) { if (sband->bitrates[ii].hw_value == r) { rate_idx = ii; break; } } if (ii == sband->n_bitrates) { dev_dbg(&priv->usb->dev, "Wrong RxRate %x\n", *rx_rate); return false; } pay_load_with_padding = ((*pay_load_len / 4) + ((*pay_load_len % 4) ? 1 : 0)) * 4; tsf_time = (__le64 *)(skb_data + 8 + pay_load_with_padding); priv->tsf_time = le64_to_cpu(*tsf_time); if (priv->bb_type == BB_TYPE_11G) { sq_3 = skb_data + 8 + pay_load_with_padding + 12; sq = sq_3; } else { sq = skb_data + 8 + pay_load_with_padding + 8; sq_3 = sq; } new_rsr = skb_data + 8 + pay_load_with_padding + 9; rssi = skb_data + 8 + pay_load_with_padding + 10; rsr = skb_data + 8 + pay_load_with_padding + 11; if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN)) return false; frame_size = *pay_load_len; vnt_rf_rssi_to_dbm(priv, *rssi, &rx_dbm); priv->bb_pre_ed_rssi = (u8)rx_dbm + 1; priv->current_rssi = priv->bb_pre_ed_rssi; frame = skb_data + 8; skb_pull(skb, 8); skb_trim(skb, frame_size); rx_status.mactime = priv->tsf_time; rx_status.band = hw->conf.chandef.chan->band; rx_status.signal = rx_dbm; rx_status.flag = 0; rx_status.freq = hw->conf.chandef.chan->center_freq; if (!(*rsr & RSR_CRCOK)) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; rx_status.rate_idx = rate_idx; if (ieee80211_has_protected(fc)) { if (priv->local_id > REV_ID_VT3253_A1) { rx_status.flag |= RX_FLAG_DECRYPTED; /* Drop packet */ if (!(*new_rsr & NEWRSR_DECRYPTOK)) { dev_kfree_skb(skb); return true; } } } memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(priv->hw, skb); return true; }
void mwl_rx_recv(unsigned long data) { struct ieee80211_hw *hw = (struct ieee80211_hw *)data; struct mwl_priv *priv; struct mwl_rx_desc *curr_desc; int work_done = 0; struct sk_buff *prx_skb = NULL; int pkt_len; struct ieee80211_rx_status status; struct mwl_vif *mwl_vif = NULL; struct ieee80211_hdr *wh; u32 status_mask; WLDBG_ENTER(DBG_LEVEL_4); BUG_ON(!hw); priv = hw->priv; BUG_ON(!priv); curr_desc = priv->desc_data[0].pnext_rx_desc; if (curr_desc == NULL) { status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); priv->is_rx_schedule = false; WLDBG_EXIT_INFO(DBG_LEVEL_4, "busy or no receiving packets"); return; } while ((curr_desc->rx_control == EAGLE_RXD_CTRL_DMA_OWN) && (work_done < priv->recv_limit)) { prx_skb = curr_desc->psk_buff; if (prx_skb == NULL) goto out; pci_unmap_single(priv->pdev, ENDIAN_SWAP32(curr_desc->pphys_buff_data), priv->desc_data[0].rx_buf_size, PCI_DMA_FROMDEVICE); pkt_len = curr_desc->pkt_len; if (skb_tailroom(prx_skb) < pkt_len) { WLDBG_PRINT("Critical error: not enough tail room =%x pkt_len=%x, curr_desc=%x, curr_desc_data=%x", skb_tailroom(prx_skb), pkt_len, curr_desc, curr_desc->pbuff_data); dev_kfree_skb_any(prx_skb); goto out; } if (curr_desc->channel != hw->conf.chandef.chan->hw_value) { dev_kfree_skb_any(prx_skb); goto out; } mwl_rx_prepare_status(curr_desc, &status); priv->noise = -curr_desc->noise_floor; wh = &((struct mwl_dma_data *)prx_skb->data)->wh; if (ieee80211_has_protected(wh->frame_control)) { /* Check if hw crypto has been enabled for * this bss. If yes, set the status flags * accordingly */ if (ieee80211_has_tods(wh->frame_control)) mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list, wh->addr1); else mwl_vif = mwl_rx_find_vif_bss(&priv->vif_list, wh->addr2); if (mwl_vif != NULL && mwl_vif->is_hw_crypto_enabled) { /* * When MMIC ERROR is encountered * by the firmware, payload is * dropped and only 32 bytes of * mwl8k Firmware header is sent * to the host. * * We need to add four bytes of * key information. In it * MAC80211 expects keyidx set to * 0 for triggering Counter * Measure of MMIC failure. */ if (status.flag & RX_FLAG_MMIC_ERROR) { struct mwl_dma_data *tr; tr = (struct mwl_dma_data *)prx_skb->data; memset((void *)&(tr->data), 0, 4); pkt_len += 4; } if (!ieee80211_is_auth(wh->frame_control)) status.flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED; } } skb_put(prx_skb, pkt_len); mwl_rx_remove_dma_header(prx_skb, curr_desc->qos_ctrl); memcpy(IEEE80211_SKB_RXCB(prx_skb), &status, sizeof(status)); ieee80211_rx(hw, prx_skb); out: mwl_rx_refill(priv, curr_desc); curr_desc->rx_control = EAGLE_RXD_CTRL_DRIVER_OWN; curr_desc->qos_ctrl = 0; curr_desc = curr_desc->pnext; work_done++; } priv->desc_data[0].pnext_rx_desc = curr_desc; status_mask = readl(priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); writel(status_mask | MACREG_A2HRIC_BIT_RX_RDY, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); priv->is_rx_schedule = false; WLDBG_EXIT(DBG_LEVEL_4); }
void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry) { struct rxdone_entry_desc rxdesc; struct sk_buff *skb; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; unsigned int header_length; int rate_idx; /* * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. */ skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry); if (!skb) return; /* * Unmap the skb. */ rt2x00queue_unmap_skb(rt2x00dev, entry->skb); /* * Extract the RXD details. */ memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ header_length = ieee80211_get_hdrlen_from_skb(entry->skb); /* * Hardware might have stripped the IV/EIV/ICV data, * in that case it is possible that the data was * provided separately (through hardware descriptor) * in which case we should reinsert the data into the frame. */ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && (rxdesc.flags & RX_FLAG_IV_STRIPPED)) rt2x00crypto_rx_insert_iv(entry->skb, header_length, &rxdesc); else if (header_length && (rxdesc.size > header_length) && (rxdesc.dev_flags & RXDONE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); else rt2x00queue_align_payload(entry->skb, header_length); /* Trim buffer to correct size */ skb_trim(entry->skb, rxdesc.size); /* * Check if the frame was received using HT. In that case, * the rate is the MCS index and should be passed to mac80211 * directly. Otherwise we need to translate the signal to * the correct bitrate index. */ if (rxdesc.rate_mode == RATE_MODE_CCK || rxdesc.rate_mode == RATE_MODE_OFDM) { rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); } else { rxdesc.flags |= RX_FLAG_HT; rate_idx = rxdesc.signal; } /* * Update extra components */ rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); rt2x00debug_update_crypto(rt2x00dev, &rxdesc); rx_status->mactime = rxdesc.timestamp; rx_status->rate_idx = rate_idx; rx_status->signal = rxdesc.rssi; rx_status->noise = rxdesc.noise; rx_status->flag = rxdesc.flags; rx_status->antenna = rt2x00dev->link.ant.active.rx; /* * Send frame to mac80211 & debugfs. * mac80211 will clean up the skb structure. */ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); /* * Replace the skb with the freshly allocated one. */ entry->skb = skb; entry->flags = 0; rt2x00dev->ops->lib->clear_entry(entry); rt2x00queue_index_inc(entry->queue, Q_INDEX); }
static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_hdr *hdr, u16 len, u32 ampdu_status, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { struct sk_buff *skb; int ret = 0; __le16 fc = hdr->frame_control; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, "Dropping packet while interface is not open.\n"); return; } /* In case of HW accelerated crypto and bad decryption, drop */ if (!priv->cfg->mod_params->sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); if (!skb) { IWL_ERR(priv, "alloc_skb failed\n"); return; } skb_reserve(skb, IWL_LINK_HDR_MAX); skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); /* mac80211 currently doesn't support paged SKB. Convert it to * linear SKB for management frame and data frame requires * software decryption or software defragementation. */ if (ieee80211_is_mgmt(fc) || ieee80211_has_protected(fc) || ieee80211_has_morefrags(fc) || le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG || (ieee80211_is_data_qos(fc) && *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)) ret = skb_linearize(skb); else ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? 0 : -ENOMEM; if (ret) { kfree_skb(skb); goto out; } /* * XXX: We cannot touch the page and its virtual memory (hdr) after * here. It might have already been freed by the above skb change. */ iwl_update_stats(priv, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); out: priv->alloc_rxb_page--; rxb->page = NULL; }
static void ieee80211p_tasklet_rx(unsigned long data) { /* Driver's private data */ struct ieee80211p_priv *priv = (void *)data; /* RX skb */ struct sk_buff *skb = priv->rx_skb; /* RX status */ struct ieee80211_rx_status *rxs = NULL; struct ieee80211p_rx_status *rs = NULL; /* Netlink header */ struct nlmsghdr *nlh = NULL; /* Netlink command */ char *nlcmd = NULL; /* Received data rate index */ int rate_idx = -1; /* lock */ spin_lock(&priv->rxq_lock); /************************ * Netlink skb handling * ************************/ printk(KERN_ERR "ieee80211p_tasklet_rx: receiving data from PHY\n"); if (skb == NULL) { printk(KERN_ERR "ieee80211_tasklet_rx: received skb == NULL\n"); goto error; } /* Get the netlink message header */ nlh = (struct nlmsghdr *)skb->data; /* Check the command of the received msg */ nlcmd = (char *)NLMSG_DATA(nlh); if (*nlcmd == NLCMD_INIT) { /* Keep track of the softmodem pid */ priv->pid_softmodem = nlh->nlmsg_pid; printk(KERN_ERR "ieee80211_tasklet_rx: NLCMD_INIT received / softmodem pid = %u\n",priv->pid_softmodem); dev_kfree_skb_any(skb); goto error; } /* Remove the nlmsg header + netlink command */ rs = (struct ieee80211p_rx_status *)skb_pull(skb,sizeof(struct nlmsghdr)+NLCMD_SIZE); if (rs == NULL) { printk(KERN_ERR "ieee80211_tasklet_rx: rx status == NULL\n"); dev_kfree_skb_any(skb); goto error; } /********* * Stats * *********/ rxs = IEEE80211_SKB_RXCB(skb); if (rxs == NULL) { printk(KERN_ERR "ieee80211_tasklet_rx: rx status == NULL\n"); dev_kfree_skb_any(skb); goto error; } /* Keep track of the stats sent by the softmodem */ rxs->freq = priv->cur_chan->center_freq; rxs->signal = rs->rssi; rxs->band = rs->band; rxs->flag = 0; rate_idx = find_rate_idx(priv,rxs->band,rs->rate); if (rate_idx == -1) { printk(KERN_ERR "ieee80211_tasklet_rx: unknown data rate %u\n",rs->rate); dev_kfree_skb_any(skb); goto error; } else { rxs->rate_idx = rate_idx; } if (rs->flags & IEEE80211P_MMIC_ERROR) { rxs->flag |= RX_FLAG_MMIC_ERROR; } if (rs->flags & IEEE80211P_FAILED_FCS_CRC) { rxs->flag |= RX_FLAG_FAILED_FCS_CRC; } if (rs->flags & IEEE80211P_FAILED_PLCP_CRC) { rxs->flag |= RX_FLAG_FAILED_PLCP_CRC; } if (rs->flags & IEEE80211P_MACTIME_MPDU) { rxs->flag |= RX_FLAG_MACTIME_MPDU; } if (rs->flags & IEEE80211P_NO_SIGNAL_VAL) { rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; } /* Remove the rx status from the skb */ skb_pull(skb,sizeof(struct ieee80211p_rx_status)); printk(KERN_ERR "ieee80211p_tasklet_rx: sending data to ieee80211\n"); /* Give skb to the mac80211 subsystem */ ieee80211_rx(priv->hw, skb); error: /* unlock */ spin_unlock(&priv->rxq_lock); } /* ieee80211p_tasklet_rx */
static bool vnt_rx_data(struct vnt_private *priv, struct sk_buff *skb, u16 bytes_received) { struct ieee80211_hw *hw = priv->hw; struct ieee80211_supported_band *sband; struct ieee80211_rx_status rx_status = { 0 }; struct ieee80211_hdr *hdr; __le16 fc; u8 *rsr, *new_rsr, *rssi; __le64 *tsf_time; u16 frame_size; int ii, r; u8 *rx_sts, *rx_rate, *sq; u8 *skb_data; u8 rate_idx = 0; u8 rate[MAX_RATE] = {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}; long rx_dbm; /* [31:16]RcvByteCount ( not include 4-byte Status ) */ frame_size = le16_to_cpu(*((__le16 *)(skb->data + 2))); if (frame_size > 2346 || frame_size < 14) { dev_dbg(&priv->pcid->dev, "------- WRONG Length 1\n"); return false; } skb_data = (u8 *)skb->data; rx_sts = skb_data; rx_rate = skb_data + 1; sband = hw->wiphy->bands[hw->conf.chandef.chan->band]; for (r = RATE_1M; r < MAX_RATE; r++) { if (*rx_rate == rate[r]) break; } priv->rx_rate = r; for (ii = 0; ii < sband->n_bitrates; ii++) { if (sband->bitrates[ii].hw_value == r) { rate_idx = ii; break; } } if (ii == sband->n_bitrates) { dev_dbg(&priv->pcid->dev, "Wrong RxRate %x\n", *rx_rate); return false; } tsf_time = (__le64 *)(skb_data + bytes_received - 12); sq = skb_data + bytes_received - 4; new_rsr = skb_data + bytes_received - 3; rssi = skb_data + bytes_received - 2; rsr = skb_data + bytes_received - 1; if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN)) return false; RFvRSSITodBm(priv, *rssi, &rx_dbm); priv->byBBPreEDRSSI = (u8)rx_dbm + 1; priv->uCurrRSSI = *rssi; skb_pull(skb, 4); skb_trim(skb, frame_size); rx_status.mactime = le64_to_cpu(*tsf_time); rx_status.band = hw->conf.chandef.chan->band; rx_status.signal = rx_dbm; rx_status.flag = 0; rx_status.freq = hw->conf.chandef.chan->center_freq; if (!(*rsr & RSR_CRCOK)) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; rx_status.rate_idx = rate_idx; if (ieee80211_has_protected(fc)) { if (priv->byLocalID > REV_ID_VT3253_A1) rx_status.flag |= RX_FLAG_DECRYPTED; /* Drop packet */ if (!(*new_rsr & NEWRSR_DECRYPTOK)) return false; } memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(priv->hw, skb); return true; }
static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) { struct ar9170_rx_head *head; struct ar9170_rx_macstatus *mac; struct ar9170_rx_phystatus *phy = NULL; struct ieee80211_rx_status status; struct sk_buff *skb; int mpdu_len; u8 mac_status; if (!IS_STARTED(ar)) return; if (unlikely(len < sizeof(*mac))) goto drop; mpdu_len = len - sizeof(*mac); mac = (void *)(buf + mpdu_len); mac_status = mac->status; switch (mac_status & AR9170_RX_STATUS_MPDU) { case AR9170_RX_STATUS_MPDU_FIRST: /* Aggregated MPDUs start with an PLCP header */ if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { head = (void *) buf; /* * The PLCP header needs to be cached for the * following MIDDLE + LAST A-MPDU packets. * * So, if you are wondering why all frames seem * to share a common RX status information, * then you have the answer right here... */ memcpy(&ar->rx_plcp, (void *) buf, sizeof(struct ar9170_rx_head)); mpdu_len -= sizeof(struct ar9170_rx_head); buf += sizeof(struct ar9170_rx_head); ar->rx_has_plcp = true; } else { if (net_ratelimit()) { wiphy_err(ar->hw->wiphy, "plcp info " "is clipped.\n"); } goto drop; } break; case AR9170_RX_STATUS_MPDU_LAST: /* * The last frame of an A-MPDU has an extra tail * which does contain the phy status of the whole * aggregate. */ if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { mpdu_len -= sizeof(struct ar9170_rx_phystatus); phy = (void *)(buf + mpdu_len); } else { if (net_ratelimit()) { wiphy_err(ar->hw->wiphy, "frame tail " "is clipped.\n"); } goto drop; } case AR9170_RX_STATUS_MPDU_MIDDLE: /* These are just data + mac status */ if (unlikely(!ar->rx_has_plcp)) { if (!net_ratelimit()) return; wiphy_err(ar->hw->wiphy, "rx stream does not start " "with a first_mpdu frame tag.\n"); goto drop; } head = &ar->rx_plcp; break; case AR9170_RX_STATUS_MPDU_SINGLE: /* single mpdu has both: plcp (head) and phy status (tail) */ head = (void *) buf; mpdu_len -= sizeof(struct ar9170_rx_head); mpdu_len -= sizeof(struct ar9170_rx_phystatus); buf += sizeof(struct ar9170_rx_head); phy = (void *)(buf + mpdu_len); break; default: BUG_ON(1); break; } /* FC + DU + RA + FCS */ if (unlikely(mpdu_len < (2 + 2 + ETH_ALEN + FCS_LEN))) goto drop; memset(&status, 0, sizeof(status)); if (unlikely(carl9170_rx_mac_status(ar, head, mac, &status))) goto drop; if (!carl9170_ampdu_check(ar, buf, mac_status)) goto drop; if (phy) carl9170_rx_phy_status(ar, phy, &status); carl9170_ps_beacon(ar, buf, mpdu_len); skb = carl9170_rx_copy_data(buf, mpdu_len); if (!skb) goto drop; memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); ieee80211_rx(ar->hw, skb); return; drop: ar->rx_dropped++; }
static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 *rxdesc = skb->data; struct ieee80211_hdr *hdr; bool unicast = false; __le16 fc; struct ieee80211_rx_status rx_status = {0}; struct rtl_stats stats = { .signal = 0, .noise = -98, .rate = 0, }; skb_pull(skb, RTL_RX_DESC_SIZE); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; if (!stats.crc) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); if (is_broadcast_ether_addr(hdr->addr1)) { /*TODO*/; } else if (is_multicast_ether_addr(hdr->addr1)) { /*TODO*/ } else { unicast = true; rtlpriv->stats.rxbytesunicast += skb->len; } rtl_is_special_data(hw, skb, false); if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); if (unicast) rtlpriv->link_info.num_rx_inperiod++; } } } static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 *rxdesc = skb->data; struct ieee80211_hdr *hdr; bool unicast = false; __le16 fc; struct ieee80211_rx_status rx_status = {0}; struct rtl_stats stats = { .signal = 0, .noise = -98, .rate = 0, }; skb_pull(skb, RTL_RX_DESC_SIZE); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); hdr = (struct ieee80211_hdr *)(skb->data); fc = hdr->frame_control; if (!stats.crc) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); if (is_broadcast_ether_addr(hdr->addr1)) { /*TODO*/; } else if (is_multicast_ether_addr(hdr->addr1)) { /*TODO*/ } else { unicast = true; rtlpriv->stats.rxbytesunicast += skb->len; } rtl_is_special_data(hw, skb, false); if (ieee80211_is_data(fc)) { rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); if (unicast) rtlpriv->link_info.num_rx_inperiod++; } if (likely(rtl_action_proc(hw, skb, false))) { struct sk_buff *uskb = NULL; u8 *pdata; uskb = dev_alloc_skb(skb->len + 128); if (uskb) { /* drop packet on allocation failure */ memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status)); pdata = (u8 *)skb_put(uskb, skb->len); memcpy(pdata, skb->data, skb->len); ieee80211_rx_irqsafe(hw, uskb); } dev_kfree_skb_any(skb); } else { dev_kfree_skb_any(skb); } } } static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb) { struct sk_buff *_skb; struct sk_buff_head rx_queue; struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); skb_queue_head_init(&rx_queue); if (rtlusb->usb_rx_segregate_hdl) rtlusb->usb_rx_segregate_hdl(hw, skb, &rx_queue); WARN_ON(skb_queue_empty(&rx_queue)); while (!skb_queue_empty(&rx_queue)) { _skb = skb_dequeue(&rx_queue); _rtl_usb_rx_process_agg(hw, _skb); ieee80211_rx_irqsafe(hw, _skb); } } static void _rtl_rx_completed(struct urb *_urb) { struct sk_buff *skb = (struct sk_buff *)_urb->context; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0]; struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf); struct rtl_priv *rtlpriv = rtl_priv(hw); int err = 0; if (unlikely(IS_USB_STOP(rtlusb))) goto free; if (likely(0 == _urb->status)) { /* If this code were moved to work queue, would CPU * utilization be improved? NOTE: We shall allocate another skb * and reuse the original one. */ skb_put(skb, _urb->actual_length); if (likely(!rtlusb->usb_rx_segregate_hdl)) { struct sk_buff *_skb; _rtl_usb_rx_process_noagg(hw, skb); _skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC); if (IS_ERR(_skb)) { err = PTR_ERR(_skb); RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Can't allocate skb for bulk IN!\n"); return; } skb = _skb; } else{ /* TO DO */ _rtl_rx_pre_process(hw, skb); pr_err("rx agg not supported\n"); } goto resubmit; } switch (_urb->status) { /* disconnect */ case -ENOENT: case -ECONNRESET: case -ENODEV: case -ESHUTDOWN: goto free; default: break; } resubmit: skb_reset_tail_pointer(skb); skb_trim(skb, 0); usb_anchor_urb(_urb, &rtlusb->rx_submitted); err = usb_submit_urb(_urb, GFP_ATOMIC); if (unlikely(err)) { usb_unanchor_urb(_urb); goto free; } return; free: dev_kfree_skb_irq(skb); } static int _rtl_usb_receive(struct ieee80211_hw *hw) { struct urb *urb; struct sk_buff *skb; int err; int i; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); WARN_ON(0 == rtlusb->rx_urb_num); /* 1600 == 1514 + max WLAN header + rtk info */ WARN_ON(rtlusb->rx_max_size < 1600); for (i = 0; i < rtlusb->rx_urb_num; i++) { err = -ENOMEM; urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Failed to alloc URB!!\n"); goto err_out; } skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL); if (IS_ERR(skb)) { RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG, "Failed to prep_rx_urb!!\n"); err = PTR_ERR(skb); goto err_out; } usb_anchor_urb(urb, &rtlusb->rx_submitted); err = usb_submit_urb(urb, GFP_KERNEL); if (err) goto err_out; usb_free_urb(urb); } return 0; err_out: usb_kill_anchored_urbs(&rtlusb->rx_submitted); return err; } static int rtl_usb_start(struct ieee80211_hw *hw) { int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); err = rtlpriv->cfg->ops->hw_init(hw); if (!err) { rtl_init_rx_config(hw); /* Enable software */ SET_USB_START(rtlusb); /* should after adapter start and interrupt enable. */ set_hal_start(rtlhal); /* Start bulk IN */ err = _rtl_usb_receive(hw); } return err; } /** * * */ /*======================= tx =========================================*/ static void rtl_usb_cleanup(struct ieee80211_hw *hw) { u32 i; struct sk_buff *_skb; struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct ieee80211_tx_info *txinfo; SET_USB_STOP(rtlusb); /* clean up rx stuff. */ usb_kill_anchored_urbs(&rtlusb->rx_submitted); /* clean up tx stuff */ for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) { while ((_skb = skb_dequeue(&rtlusb->tx_skb_queue[i]))) { rtlusb->usb_tx_cleanup(hw, _skb); txinfo = IEEE80211_SKB_CB(_skb); ieee80211_tx_info_clear_status(txinfo); txinfo->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, _skb); } usb_kill_anchored_urbs(&rtlusb->tx_pending[i]); } usb_kill_anchored_urbs(&rtlusb->tx_submitted); }
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { struct ieee80211_rx_status *rx_status; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; struct ieee80211_hdr *hdr = (void *)(desc + 1); u32 len = le16_to_cpu(desc->mpdu_len); u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u8 crypt_len = 0; /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); return; } rx_status = IEEE80211_SKB_RXCB(skb); if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, queue, &crypt_len)) { kfree_skb(skb); return; } /* * Keep packets with CRC errors (and with overrun) for monitor mode * (otherwise the firmware discards them) but mark them as bad. */ if (!(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_CRC_OK)) || !(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_OVERRUN_OK))) { IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", le16_to_cpu(desc->status)); rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; } rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise); rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise); rx_status->band = desc->channel > 14 ? IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; rx_status->freq = ieee80211_channel_to_frequency(desc->channel, rx_status->band); iwl_mvm_get_signal_strength(mvm, desc, rx_status); rcu_read_lock(); if (le16_to_cpu(desc->status) & IWL_RX_MPDU_STATUS_SRC_STA_FOUND) { u8 id = desc->sta_id_flags & IWL_RX_MPDU_SIF_STA_ID_MASK; if (!WARN_ON_ONCE(id >= IWL_MVM_STATION_COUNT)) { sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); if (IS_ERR(sta)) sta = NULL; } } else if (!is_multicast_ether_addr(hdr->addr2)) { /* * This is fine since we prevent two stations with the same * address from being added. */ sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); } if (sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); /* * We have tx blocked stations (with CS bit). If we heard * frames from a blocked station on a new channel we can * TX to it again. */ if (unlikely(mvm->csa_tx_block_bcn_timeout)) iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && ieee80211_is_beacon(hdr->frame_control)) { struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; bool trig_check; s32 rssi; trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_RSSI); rssi_trig = (void *)trig->data; rssi = le32_to_cpu(rssi_trig->rssi); trig_check = iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif, trig); if (trig_check && rx_status->signal < rssi) iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); } /* TODO: multi queue TCM */ if (ieee80211_is_data(hdr->frame_control)) iwl_mvm_rx_csum(sta, skb, desc); } /* * TODO: PHY info. * Verify we don't have the information in the MPDU descriptor and * that it is not needed. * Make sure for monitor mode that we are on default queue, update * ampdu_ref and the rest of phy info then */ /* Set up the HT phy flags */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: break; case RATE_MCS_CHAN_WIDTH_40: rx_status->flag |= RX_FLAG_40MHZ; break; case RATE_MCS_CHAN_WIDTH_80: rx_status->vht_flag |= RX_VHT_FLAG_80MHZ; break; case RATE_MCS_CHAN_WIDTH_160: rx_status->vht_flag |= RX_VHT_FLAG_160MHZ; break; } if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status->flag |= RX_FLAG_SHORT_GI; if (rate_n_flags & RATE_HT_MCS_GF_MSK) rx_status->flag |= RX_FLAG_HT_GF; if (rate_n_flags & RATE_MCS_LDPC_MSK) rx_status->flag |= RX_FLAG_LDPC; if (rate_n_flags & RATE_MCS_HT_MSK) { u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> RATE_MCS_STBC_POS; rx_status->flag |= RX_FLAG_HT; rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, bool unaligned, u8 *hlid) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; struct ieee80211_hdr *hdr; u8 *buf; u8 beacon = 0; u8 is_data = 0; u8 reserved = unaligned ? NET_IP_ALIGN : 0; u16 seq_num; /* */ if (unlikely(wl->plt)) return -EINVAL; /* */ desc = (struct wl1271_rx_descriptor *) data; if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { size_t len = length - sizeof(*desc); wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); wake_up_interruptible(&wl->fwlog_waitq); return 0; } switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { /* */ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: case WL1271_RX_DESC_DECRYPT_FAIL: wl1271_warning("corrupted packet in RX with status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; case WL1271_RX_DESC_SUCCESS: case WL1271_RX_DESC_MIC_FAIL: break; default: wl1271_error("invalid RX descriptor status: 0x%x", desc->status & WL1271_RX_DESC_STATUS_MASK); return -EINVAL; } /* */ skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } /* */ skb_reserve(skb, reserved); buf = skb_put(skb, length - sizeof(*desc)); /* */ memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); *hlid = desc->hlid; hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) beacon = 1; if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, skb->len - desc->pad_len, beacon ? "beacon" : "", seq_num, *hlid); skb_trim(skb, skb->len - desc->pad_len); skb_queue_tail(&wl->deferred_rx_queue, skb); queue_work(wl->freezable_wq, &wl->netstack_work); return is_data; }
static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, int queue, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); struct iwl_mvm_key_pn *ptk_pn; u8 tid, keyidx; u8 pn[IEEE80211_CCMP_PN_LEN]; u8 *extiv; /* do PN checking */ /* multicast and non-data only arrives on default queue */ if (!ieee80211_is_data(hdr->frame_control) || is_multicast_ether_addr(hdr->addr1)) return 0; /* do not check PN for open AP */ if (!(stats->flag & RX_FLAG_DECRYPTED)) return 0; /* * avoid checking for default queue - we don't want to replicate * all the logic that's necessary for checking the PN on fragmented * frames, leave that to mac80211 */ if (queue == 0) return 0; /* if we are here - this for sure is either CCMP or GCMP */ if (IS_ERR_OR_NULL(sta)) { IWL_ERR(mvm, "expected hw-decrypted unicast frame for station\n"); return -1; } mvmsta = iwl_mvm_sta_from_mac80211(sta); extiv = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control); keyidx = extiv[3] >> 6; ptk_pn = rcu_dereference(mvmsta->ptk_pn[keyidx]); if (!ptk_pn) return -1; if (ieee80211_is_data_qos(hdr->frame_control)) tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; else tid = 0; /* we don't use HCCA/802.11 QoS TSPECs, so drop such frames */ if (tid >= IWL_MAX_TID_COUNT) return -1; /* load pn */ pn[0] = extiv[7]; pn[1] = extiv[6]; pn[2] = extiv[5]; pn[3] = extiv[4]; pn[4] = extiv[1]; pn[5] = extiv[0]; if (memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN) <= 0) return -1; memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN); stats->flag |= RX_FLAG_PN_VALIDATED; return 0; }
ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) { u8 *data, *key = NULL; size_t data_len; unsigned int hdrlen; u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; /* * it makes no sense to check for MIC errors on anything other * than data frames. */ if (!ieee80211_is_data_present(hdr->frame_control)) return RX_CONTINUE; /* * No way to verify the MIC if the hardware stripped it or * the IV with the key index. In this case we have solely rely * on the driver to set RX_FLAG_MMIC_ERROR in the event of a * MIC failure report. */ if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { if (status->flag & RX_FLAG_MMIC_ERROR) goto mic_fail; if (!(status->flag & RX_FLAG_IV_STRIPPED)) goto update_iv; return RX_CONTINUE; } /* * Some hardware seems to generate Michael MIC failure reports; even * though, the frame was not encrypted with TKIP and therefore has no * MIC. Ignore the flag them to avoid triggering countermeasures. */ if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || !(status->flag & RX_FLAG_DECRYPTED)) return RX_CONTINUE; if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { /* * APs with pairwise keys should never receive Michael MIC * errors for non-zero keyidx because these are reserved for * group keys and only the AP is sending real multicast * frames in the BSS. ( */ return RX_DROP_UNUSABLE; } if (status->flag & RX_FLAG_MMIC_ERROR) goto mic_fail; hdrlen = ieee80211_hdrlen(hdr->frame_control); if (skb->len < hdrlen + MICHAEL_MIC_LEN) return RX_DROP_UNUSABLE; data = skb->data + hdrlen; data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; michael_mic(key, hdr, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) goto mic_fail; /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); update_iv: /* update IV in key information to be able to detect replays */ rx->key->u.tkip.rx[rx->security_idx].iv32 = rx->tkip_iv32; rx->key->u.tkip.rx[rx->security_idx].iv16 = rx->tkip_iv16; return RX_CONTINUE; mic_fail: /* * In some cases the key can be unset - e.g. a multicast packet, in * a driver that supports HW encryption. Send up the key idx only if * the key is set. */ mac80211_ev_michael_mic_failure(rx->sdata, rx->key ? rx->key->conf.keyidx : -1, (void *) skb->data, NULL, GFP_ATOMIC); return RX_DROP_UNUSABLE; }
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { struct ieee80211_rx_status *rx_status; struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc)); u32 len = le16_to_cpu(desc->mpdu_len); u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); u16 phy_info = le16_to_cpu(desc->phy_info); struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u8 crypt_len = 0; /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); return; } rx_status = IEEE80211_SKB_RXCB(skb); if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, queue, &crypt_len)) { kfree_skb(skb); return; } /* * Keep packets with CRC errors (and with overrun) for monitor mode * (otherwise the firmware discards them) but mark them as bad. */ if (!(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_CRC_OK)) || !(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_OVERRUN_OK))) { IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", le16_to_cpu(desc->status)); rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; } /* set the preamble flag if appropriate */ if (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) rx_status->flag |= RX_FLAG_SHORTPRE; if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) { rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise); /* TSF as indicated by the firmware is at INA time */ rx_status->flag |= RX_FLAG_MACTIME_PLCP_START; } rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise); rx_status->band = desc->channel > 14 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; rx_status->freq = ieee80211_channel_to_frequency(desc->channel, rx_status->band); iwl_mvm_get_signal_strength(mvm, desc, rx_status); /* update aggregation data for monitor sake on default queue */ if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; rx_status->flag |= RX_FLAG_AMPDU_DETAILS; rx_status->ampdu_reference = mvm->ampdu_ref; /* toggle is switched whenever new aggregation starts */ if (toggle_bit != mvm->ampdu_toggle) { mvm->ampdu_ref++; mvm->ampdu_toggle = toggle_bit; } } rcu_read_lock(); if (le16_to_cpu(desc->status) & IWL_RX_MPDU_STATUS_SRC_STA_FOUND) { u8 id = desc->sta_id_flags & IWL_RX_MPDU_SIF_STA_ID_MASK; if (!WARN_ON_ONCE(id >= IWL_MVM_STATION_COUNT)) { sta = rcu_dereference(mvm->fw_id_to_mac_id[id]); if (IS_ERR(sta)) sta = NULL; } } else if (!is_multicast_ether_addr(hdr->addr2)) { /* * This is fine since we prevent two stations with the same * address from being added. */ sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); } if (sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_vif *tx_blocked_vif = rcu_dereference(mvm->csa_tx_blocked_vif); u8 baid = (u8)((le32_to_cpu(desc->reorder_data) & IWL_RX_MPDU_REORDER_BAID_MASK) >> IWL_RX_MPDU_REORDER_BAID_SHIFT); /* * We have tx blocked stations (with CS bit). If we heard * frames from a blocked station on a new channel we can * TX to it again. */ if (unlikely(tx_blocked_vif) && tx_blocked_vif == mvmsta->vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(tx_blocked_vif); if (mvmvif->csa_target_freq == rx_status->freq) iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false); } rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && ieee80211_is_beacon(hdr->frame_control)) { struct iwl_fw_dbg_trigger_tlv *trig; struct iwl_fw_dbg_trigger_low_rssi *rssi_trig; bool trig_check; s32 rssi; trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_RSSI); rssi_trig = (void *)trig->data; rssi = le32_to_cpu(rssi_trig->rssi); trig_check = iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif, trig); if (trig_check && rx_status->signal < rssi) iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); } if (ieee80211_is_data(hdr->frame_control)) iwl_mvm_rx_csum(sta, skb, desc); if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) { kfree_skb(skb); rcu_read_unlock(); return; } /* * Our hardware de-aggregates AMSDUs but copies the mac header * as it to the de-aggregated MPDUs. We need to turn off the * AMSDU bit in the QoS control ourselves. */ if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) && !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) { u8 *qc = ieee80211_get_qos_ctl(hdr); *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; } if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) iwl_mvm_agg_rx_received(mvm, baid); } /* Set up the HT phy flags */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: break; case RATE_MCS_CHAN_WIDTH_40: rx_status->flag |= RX_FLAG_40MHZ; break; case RATE_MCS_CHAN_WIDTH_80: rx_status->vht_flag |= RX_VHT_FLAG_80MHZ; break; case RATE_MCS_CHAN_WIDTH_160: rx_status->vht_flag |= RX_VHT_FLAG_160MHZ; break; } if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status->flag |= RX_FLAG_SHORT_GI; if (rate_n_flags & RATE_HT_MCS_GF_MSK) rx_status->flag |= RX_FLAG_HT_GF; if (rate_n_flags & RATE_MCS_LDPC_MSK) rx_status->flag |= RX_FLAG_LDPC; if (rate_n_flags & RATE_MCS_HT_MSK) { u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >> RATE_MCS_STBC_POS; rx_status->flag |= RX_FLAG_HT; rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT; } else if (rate_n_flags & RATE_MCS_VHT_MSK) {