/* *Finds the highest rate index we can use *if skb is special data like DHCP/EAPOL, we set should *it to lowest rate CCK_1M, otherwise we set rate to *CCK11M or OFDM_54M based on wireless mode. */ static u8 _rtl_rc_get_highest_rix( struct rtl_priv *rtlpriv, struct ieee80211_sta *sta, struct sk_buff *skb, bool not_data ) { struct rtl_mac *rtlmac = rtl_mac( rtlpriv ); struct rtl_hal *rtlhal = rtl_hal( rtlpriv ); struct rtl_phy *rtlphy = &( rtlpriv->phy ); struct rtl_sta_info *sta_entry = NULL; u8 wireless_mode = 0; /* *this rate is no use for true rate, firmware *will control rate at all it just used for *1.show in iwconfig in B/G mode *2.in rtl_get_tcb_desc when we check rate is * 1M we will not use FW rate but user rate. */ if ( rtlmac->opmode == NL80211_IFTYPE_AP || rtlmac->opmode == NL80211_IFTYPE_ADHOC || rtlmac->opmode == NL80211_IFTYPE_MESH_POINT ) { if ( sta ) { sta_entry = ( struct rtl_sta_info * ) sta->drv_priv; wireless_mode = sta_entry->wireless_mode; } else { return 0; } } else { wireless_mode = rtlmac->mode; } if ( rtl_is_special_data( rtlpriv->mac80211.hw, skb, true ) || not_data ) { return 0; } else { if ( rtlhal->current_bandtype == BAND_ON_2_4G ) { if ( wireless_mode == WIRELESS_MODE_B ) { return B_MODE_MAX_RIX; } else if ( wireless_mode == WIRELESS_MODE_G ) { return G_MODE_MAX_RIX; } else { if ( get_rf_type( rtlphy ) != RF_2T2R ) return N_MODE_MCS7_RIX; else return N_MODE_MCS15_RIX; } } else { if ( wireless_mode == WIRELESS_MODE_A ) { return A_MODE_MAX_RIX; } else { if ( get_rf_type( rtlphy ) != RF_2T2R ) return N_MODE_MCS7_RIX; else return N_MODE_MCS15_RIX; } } } }
/*mac80211 Rate Control callbacks*/ static void rtl_tx_status(void *ppriv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { struct rtl_priv *rtlpriv = ppriv; struct rtl_mac *mac = rtl_mac(rtlpriv); struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = rtl_get_fc(skb); struct rtl_sta_info *sta_entry; if (!priv_sta || !ieee80211_is_data(fc)) return; if (rtl_is_special_data(mac->hw, skb, true)) return; if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) return; if (sta) { /* Check if aggregation has to be enabled for this tid */ sta_entry = (struct rtl_sta_info *) sta->drv_priv; if ((sta->ht_cap.ht_supported == true) && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { if (ieee80211_is_data_qos(fc)) { u8 tid = rtl_get_tid(skb); if (_rtl_tx_aggr_check(rtlpriv, sta_entry, tid)) { sta_entry->tids[tid].agg.agg_state = RTL_AGG_PROGRESS; /*<delete in kernel start>*/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) /*<delete in kernel end>*/ ieee80211_start_tx_ba_session(sta, tid, 5000); /*<delete in kernel start>*/ #else ieee80211_start_tx_ba_session(sta, tid); #endif /*<delete in kernel end>*/ } } } } }
static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); int rx_queue_idx = RTL_PCI_RX_MPDU_QUEUE; struct ieee80211_rx_status rx_status = { 0 }; unsigned int count = rtlpci->rxringcount; u8 own; u8 tmp_one; u32 bufferaddress; bool unicast = false; struct rtl_stats stats = { .signal = 0, .noise = -98, .rate = 0, }; /*RX NORMAL PKT */ while (count--) { /*rx descriptor */ struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[ rtlpci->rx_ring[rx_queue_idx].idx]; /*rx pkt */ struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[ rtlpci->rx_ring[rx_queue_idx].idx]; own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false, HW_DESC_OWN); if (own) { /*wait data to be filled by hardware */ return; } else { struct ieee80211_hdr *hdr; __le16 fc; struct sk_buff *new_skb = NULL; rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, (u8 *) pdesc, skb); pci_unmap_single(rtlpci->pdev, *((dma_addr_t *) skb->cb), rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false, HW_DESC_RXPKT_LEN)); skb_reserve(skb, stats.rx_drvinfo_size + stats.rx_bufshift); /* *NOTICE This can not be use for mac80211, *this is done in mac80211 code, *if you done here sec DHCP will fail *skb_trim(skb, skb->len - 4); */ 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 (unlikely(!rtl_action_proc(hw, skb, false))) { dev_kfree_skb_any(skb); } else { struct sk_buff *uskb = NULL; u8 *pdata; uskb = dev_alloc_skb(skb->len + 128); if (!uskb) { RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_EMERG, ("can't alloc rx skb\n")); goto done; } memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status)); pdata = (u8 *)skb_put(uskb, skb->len); memcpy(pdata, skb->data, skb->len); dev_kfree_skb_any(skb); ieee80211_rx_irqsafe(hw, uskb); } } else { dev_kfree_skb_any(skb); } if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) { rtl_lps_leave(hw); } new_skb = dev_alloc_skb(rtlpci->rxbuffersize); if (unlikely(!new_skb)) { RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_EMERG, ("can't alloc skb for rx\n")); goto done; } skb = new_skb; /*skb->dev = dev; */ rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci-> rx_ring [rx_queue_idx]. idx] = skb; *((dma_addr_t *) skb->cb) = pci_map_single(rtlpci->pdev, skb_tail_pointer(skb), rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); } done: bufferaddress = (u32)(*((dma_addr_t *) skb->cb)); tmp_one = 1; rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, (u8 *)&tmp_one); rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXPKT_LEN, (u8 *)&rtlpci->rxbuffersize); if (rtlpci->rx_ring[rx_queue_idx].idx == rtlpci->rxringcount - 1) rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXERO, (u8 *)&tmp_one); rtlpci->rx_ring[rx_queue_idx].idx = (rtlpci->rx_ring[rx_queue_idx].idx + 1) % rtlpci->rxringcount; } } static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) { struct ieee80211_hw *hw = dev_id; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); unsigned long flags; u32 inta = 0; u32 intb = 0; if (rtlpci->irq_enabled == 0) return IRQ_HANDLED; spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); /*read ISR: 4/8bytes */ rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb); /*Shared IRQ or HW disappared */ if (!inta || inta == 0xffff) goto done; /*<1> beacon related */ if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("beacon ok interrupt!\n")); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("beacon err interrupt!\n")); } if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("beacon interrupt!\n")); } if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("prepare beacon for interrupt!\n")); tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet); } /*<3> Tx related */ if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TXFOVW])) RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("IMR_TXFOVW!\n")); if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Manage ok interrupt!\n")); _rtl_pci_tx_isr(hw, MGNT_QUEUE); } if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("HIGH_QUEUE ok interrupt!\n")); _rtl_pci_tx_isr(hw, HIGH_QUEUE); } if (inta & rtlpriv->cfg->maps[RTL_IMR_BKDOK]) { rtlpriv->link_info.num_tx_inperiod++; RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("BK Tx OK interrupt!\n")); _rtl_pci_tx_isr(hw, BK_QUEUE); } if (inta & rtlpriv->cfg->maps[RTL_IMR_BEDOK]) { rtlpriv->link_info.num_tx_inperiod++; RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("BE TX OK interrupt!\n")); _rtl_pci_tx_isr(hw, BE_QUEUE); } if (inta & rtlpriv->cfg->maps[RTL_IMR_VIDOK]) { rtlpriv->link_info.num_tx_inperiod++; RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("VI TX OK interrupt!\n")); _rtl_pci_tx_isr(hw, VI_QUEUE); } if (inta & rtlpriv->cfg->maps[RTL_IMR_VODOK]) { rtlpriv->link_info.num_tx_inperiod++; RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Vo TX OK interrupt!\n")); _rtl_pci_tx_isr(hw, VO_QUEUE); } /*<2> Rx related */ if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); tasklet_schedule(&rtlpriv->works.irq_tasklet); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx descriptor unavailable!\n")); tasklet_schedule(&rtlpriv->works.irq_tasklet); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n")); tasklet_schedule(&rtlpriv->works.irq_tasklet); } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); return IRQ_HANDLED; done: spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); return IRQ_HANDLED; } static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) { _rtl_pci_rx_interrupt(hw); }
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 */ _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); }
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++; } /* 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 32 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) { unsigned int padding = 0; /* make function no-op when possible */ if (NET_IP_ALIGN == 0 || len < sizeof(*hdr)) return 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; } #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_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct urb *urb; usb_kill_anchored_urbs(&rtlusb->rx_submitted); tasklet_kill(&rtlusb->rx_work_tasklet); 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; }