unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) { unsigned int hdrlen = 24; if (ieee80211_is_data(fc)) { if (ieee80211_has_a4(fc)) hdrlen = 30; if (ieee80211_is_data_qos(fc)) { hdrlen += IEEE80211_QOS_CTL_LEN; if (ieee80211_has_order(fc)) hdrlen += IEEE80211_HT_CTL_LEN; } goto out; } if (ieee80211_is_ctl(fc)) { /* * ACK and CTS are 10 bytes, all others 16. To see how * to get this condition consider * subtype mask: 0b0000000011110000 (0x00F0) * ACK subtype: 0b0000000011010000 (0x00D0) * CTS subtype: 0b0000000011000000 (0x00C0) * bits that matter: ^^^ (0x00E0) * value of those: 0b0000000011000000 (0x00C0) */ if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) hdrlen = 10; else hdrlen = 16; } out: return hdrlen; }
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 }
static struct sk_buff *carl9170_rx_copy_data(u8 *buf, int len) { struct sk_buff *skb; int reserved = 0; struct ieee80211_hdr *hdr = (void *) buf; if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); reserved += NET_IP_ALIGN; if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) reserved += NET_IP_ALIGN; } if (ieee80211_has_a4(hdr->frame_control)) reserved += NET_IP_ALIGN; reserved = 32 + (reserved & NET_IP_ALIGN); skb = dev_alloc_skb(len + reserved); if (likely(skb)) { skb_reserve(skb, reserved); memcpy(skb_put(skb, len), buf, len); } return skb; }
int ath9k_cmn_padpos(__le16 frame_control) { int padpos = 24; if (ieee80211_has_a4(frame_control)) { padpos += ETH_ALEN; } if (ieee80211_is_data_qos(frame_control)) { padpos += IEEE80211_QOS_CTL_LEN; } return padpos; }
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum nl80211_iftype type) { __le16 fc = hdr->frame_control; /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ if (len < 16) return NULL; if (ieee80211_is_data(fc)) { if (len < 24) /* drop incorrect hdr len (data) */ return NULL; if (ieee80211_has_a4(fc)) return NULL; if (ieee80211_has_tods(fc)) return hdr->addr1; if (ieee80211_has_fromds(fc)) return hdr->addr2; return hdr->addr3; } if (ieee80211_is_mgmt(fc)) { if (len < 24) /* drop incorrect hdr len (mgmt) */ return NULL; return hdr->addr3; } if (ieee80211_is_ctl(fc)) { if(ieee80211_is_pspoll(fc)) return hdr->addr1; if (ieee80211_is_back_req(fc)) { switch (type) { case NL80211_IFTYPE_STATION: return hdr->addr2; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: return hdr->addr1; default: break; /* fall through to the return */ } } } return NULL; }
static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, int encrypted) { __le16 mask_fc; int a4_included; u8 qos_tid; u8 *b_0, *aad; u16 data_len, len_a; unsigned int hdrlen; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; b_0 = scratch + 3 * AES_BLOCK_LEN; aad = scratch + 4 * AES_BLOCK_LEN; /* * Mask FC: zero subtype b4 b5 b6 * Retry, PwrMgt, MoreData; set Protected */ mask_fc = hdr->frame_control; mask_fc &= ~cpu_to_le16(0x0070 | IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); hdrlen = ieee80211_hdrlen(hdr->frame_control); len_a = hdrlen - 2; a4_included = ieee80211_has_a4(hdr->frame_control); if (ieee80211_is_data_qos(hdr->frame_control)) qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; else qos_tid = 0; data_len = skb->len - hdrlen - CCMP_HDR_LEN; if (encrypted) data_len -= CCMP_MIC_LEN; /* First block, b_0 */ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ /* Nonce: QoS Priority | A2 | PN */ b_0[1] = qos_tid; memcpy(&b_0[2], hdr->addr2, ETH_ALEN); memcpy(&b_0[8], pn, CCMP_PN_LEN); /* l(m) */ put_unaligned_be16(data_len, &b_0[14]); /* AAD (extra authenticate-only data) / masked 802.11 header * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ put_unaligned_be16(len_a, &aad[0]); put_unaligned(mask_fc, (__le16 *)&aad[2]); memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN); /* Mask Seq#, leave Frag# */ aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f; aad[23] = 0; if (a4_included) { memcpy(&aad[24], hdr->addr4, ETH_ALEN); aad[30] = qos_tid; aad[31] = 0; } else { memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN); aad[24] = qos_tid; } }
int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx, struct vnt_tx_desc *head_td, struct sk_buff *skb) { struct vnt_td_info *td_info = head_td->td_info; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *tx_rate = &info->control.rates[0]; struct ieee80211_rate *rate; struct ieee80211_key_conf *tx_key; struct ieee80211_hdr *hdr; struct vnt_tx_fifo_head *tx_buffer_head = (struct vnt_tx_fifo_head *)td_info->buf; u16 tx_body_size = skb->len, current_rate; u8 pkt_type; bool is_pspoll = false; memset(tx_buffer_head, 0, sizeof(*tx_buffer_head)); hdr = (struct ieee80211_hdr *)(skb->data); rate = ieee80211_get_tx_rate(priv->hw, info); current_rate = rate->hw_value; if (priv->wCurrentRate != current_rate && !(priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { priv->wCurrentRate = current_rate; RFbSetPower(priv, priv->wCurrentRate, priv->hw->conf.chandef.chan->hw_value); } if (current_rate > RATE_11M) { if (info->band == NL80211_BAND_5GHZ) { pkt_type = PK_TYPE_11A; } else { if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) pkt_type = PK_TYPE_11GB; else pkt_type = PK_TYPE_11GA; } } else { pkt_type = PK_TYPE_11B; } /*Set fifo controls */ if (pkt_type == PK_TYPE_11A) tx_buffer_head->fifo_ctl = 0; else if (pkt_type == PK_TYPE_11B) tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11B); else if (pkt_type == PK_TYPE_11GB) tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GB); else if (pkt_type == PK_TYPE_11GA) tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GA); /* generate interrupt */ tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_GENINT); if (!ieee80211_is_data(hdr->frame_control)) { tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_TMOEN); tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_ISDMA0); tx_buffer_head->time_stamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); } else { tx_buffer_head->time_stamp = cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us); } if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_NEEDACK); if (ieee80211_has_retry(hdr->frame_control)) tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LRETRY); if (tx_rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) priv->byPreambleType = PREAMBLE_SHORT; else priv->byPreambleType = PREAMBLE_LONG; if (tx_rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_RTS); if (ieee80211_has_a4(hdr->frame_control)) { tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LHEAD); priv->bLongHeader = true; } if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) is_pspoll = true; tx_buffer_head->frag_ctl = cpu_to_le16(ieee80211_get_hdrlen_from_skb(skb) << 10); if (info->control.hw_key) { tx_key = info->control.hw_key; switch (info->control.hw_key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_LEGACY); break; case WLAN_CIPHER_SUITE_TKIP: tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_TKIP); break; case WLAN_CIPHER_SUITE_CCMP: tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_AES); default: break; } } tx_buffer_head->current_rate = cpu_to_le16(current_rate); /* legacy rates TODO use ieee80211_tx_rate */ if (current_rate >= RATE_18M && ieee80211_is_data(hdr->frame_control)) { if (priv->byAutoFBCtrl == AUTO_FB_0) tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_AUTO_FB_0); else if (priv->byAutoFBCtrl == AUTO_FB_1) tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_AUTO_FB_1); } tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_NONFRAG); s_cbFillTxBufHead(priv, pkt_type, (u8 *)tx_buffer_head, dma_idx, head_td, is_pspoll); if (info->control.hw_key) { tx_key = info->control.hw_key; if (tx_key->keylen > 0) vnt_fill_txkey(hdr, tx_buffer_head->tx_key, tx_key, skb, tx_body_size, td_info->mic_hdr); } return 0; }
static void vnt_fill_txkey(struct ieee80211_hdr *hdr, u8 *key_buffer, struct ieee80211_key_conf *tx_key, struct sk_buff *skb, u16 payload_len, struct vnt_mic_hdr *mic_hdr) { u64 pn64; u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb)); /* strip header and icv len from payload */ payload_len -= ieee80211_get_hdrlen_from_skb(skb); payload_len -= tx_key->icv_len; switch (tx_key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: memcpy(key_buffer, iv, 3); memcpy(key_buffer + 3, tx_key->key, tx_key->keylen); if (tx_key->keylen == WLAN_KEY_LEN_WEP40) { memcpy(key_buffer + 8, iv, 3); memcpy(key_buffer + 11, tx_key->key, WLAN_KEY_LEN_WEP40); } break; case WLAN_CIPHER_SUITE_TKIP: ieee80211_get_tkip_p2k(tx_key, skb, key_buffer); break; case WLAN_CIPHER_SUITE_CCMP: if (!mic_hdr) return; mic_hdr->id = 0x59; mic_hdr->payload_len = cpu_to_be16(payload_len); ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2); pn64 = atomic64_read(&tx_key->tx_pn); mic_hdr->ccmp_pn[5] = pn64; mic_hdr->ccmp_pn[4] = pn64 >> 8; mic_hdr->ccmp_pn[3] = pn64 >> 16; mic_hdr->ccmp_pn[2] = pn64 >> 24; mic_hdr->ccmp_pn[1] = pn64 >> 32; mic_hdr->ccmp_pn[0] = pn64 >> 40; if (ieee80211_has_a4(hdr->frame_control)) mic_hdr->hlen = cpu_to_be16(28); else mic_hdr->hlen = cpu_to_be16(22); ether_addr_copy(mic_hdr->addr1, hdr->addr1); ether_addr_copy(mic_hdr->addr2, hdr->addr2); ether_addr_copy(mic_hdr->addr3, hdr->addr3); mic_hdr->frame_control = cpu_to_le16( le16_to_cpu(hdr->frame_control) & 0xc78f); mic_hdr->seq_ctrl = cpu_to_le16( le16_to_cpu(hdr->seq_ctrl) & 0xf); if (ieee80211_has_a4(hdr->frame_control)) ether_addr_copy(mic_hdr->addr4, hdr->addr4); memcpy(key_buffer, tx_key->key, WLAN_KEY_LEN_CCMP); break; default: break; } }
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 void ccmp_special_blocks(struct ieee80211_hdr *hdr, size_t hdrlen, const u64 pn, u8 *b_0, u8 *aad) { __le16 mask_fc; int a4_included, mgmt; u8 qos_tid; u16 len_a; /* Mask FC: zero subtype b4 b5 b6 (if not mgmt) * Retry, PwrMgt, MoreData; set Protected */ mgmt = ieee80211_is_mgmt(hdr->frame_control); mask_fc = hdr->frame_control; mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA); if (!mgmt) mask_fc &= ~cpu_to_le16(0x0070); mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); len_a = hdrlen - 2; a4_included = ieee80211_has_a4(hdr->frame_control); if (ieee80211_is_data_qos(hdr->frame_control)) qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; else qos_tid = 0; /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC * mode authentication are not allowed to collide, yet both are derived * from this vector b_0. We only set L := 1 here to indicate that the * data size can be represented in (L+1) bytes. The CCM layer will take * care of storing the data length in the top (L+1) bytes and setting * and clearing the other bits as is required to derive the two IVs. */ b_0[0] = 0x1; /* Nonce: Nonce Flags | A2 | PN * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) */ b_0[1] = qos_tid | (mgmt << 4); ether_addr_copy(&b_0[2], hdr->addr2); b_0[8] = pn >> 40; b_0[9] = pn >> 32; b_0[10] = pn >> 24; b_0[11] = pn >> 16; b_0[12] = pn >> 8; b_0[13] = pn; /* AAD (extra authenticate-only data) / masked 802.11 header * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ put_unaligned_be16(len_a, &aad[0]); put_unaligned(mask_fc, (__le16 *)&aad[2]); memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN); /* Mask Seq#, leave Frag# */ aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f; aad[23] = 0; if (a4_included) { ether_addr_copy(&aad[24], hdr->addr4); aad[30] = qos_tid; aad[31] = 0; } else { memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN); aad[24] = qos_tid; } }