/* * returns true if a packet outside BA session is a duplicate and * should be dropped */ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue, struct ieee80211_rx_status *rx_status, struct ieee80211_hdr *hdr, struct iwl_rx_mpdu_desc *desc) { struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_rxq_dup_data *dup_data; u8 baid, tid, sub_frame_idx; if (WARN_ON(IS_ERR_OR_NULL(sta))) return false; baid = (le32_to_cpu(desc->reorder_data) & IWL_RX_MPDU_REORDER_BAID_MASK) >> IWL_RX_MPDU_REORDER_BAID_SHIFT; if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) return false; mvm_sta = iwl_mvm_sta_from_mac80211(sta); dup_data = &mvm_sta->dup_data[queue]; /* * Drop duplicate 802.11 retransmissions * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") */ if (ieee80211_is_ctl(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control) || is_multicast_ether_addr(hdr->addr1)) { rx_status->flag |= RX_FLAG_DUP_VALIDATED; return false; } if (ieee80211_is_data_qos(hdr->frame_control)) /* frame has qos control */ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; else tid = IWL_MAX_TID_COUNT; /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ sub_frame_idx = desc->amsdu_info & IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; if (unlikely(ieee80211_has_retry(hdr->frame_control) && dup_data->last_seq[tid] == hdr->seq_ctrl && dup_data->last_sub_frame[tid] >= sub_frame_idx)) return true; dup_data->last_seq[tid] = hdr->seq_ctrl; dup_data->last_sub_frame[tid] = sub_frame_idx; rx_status->flag |= RX_FLAG_DUP_VALIDATED; return false; }
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; }
/** * iwl_dbg_report_frame - dump frame to syslog during debug sessions * * You may hack this function to show different aspects of received frames, * including selective frame dumps. * group100 parameter selects whether to show 1 out of 100 good data frames. * All beacon and probe response frames are printed. */ static void iwl_dbg_report_frame(struct iwl_priv *priv, struct iwl_rx_phy_res *phy_res, u16 length, struct ieee80211_hdr *header, int group100) { u32 to_us; u32 print_summary = 0; u32 print_dump = 0; /* set to 1 to dump all frames' contents */ u32 hundred = 0; u32 dataframe = 0; __le16 fc; u16 seq_ctl; u16 channel; u16 phy_flags; u32 rate_n_flags; u32 tsf_low; int rssi; if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) return; /* MAC header */ fc = header->frame_control; seq_ctl = le16_to_cpu(header->seq_ctrl); /* metadata */ channel = le16_to_cpu(phy_res->channel); phy_flags = le16_to_cpu(phy_res->phy_flags); rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); /* signal statistics */ rssi = iwl_calc_rssi(priv, phy_res); tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; to_us = !compare_ether_addr(header->addr1, priv->mac_addr); /* if data frame is to us and all is good, * (optionally) print summary for only 1 out of every 100 */ if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { dataframe = 1; if (!group100) print_summary = 1; /* print each frame */ else if (priv->framecnt_to_us < 100) { priv->framecnt_to_us++; print_summary = 0; } else { priv->framecnt_to_us = 0; print_summary = 1; hundred = 1; } } else { /* print summary for all other frames */ print_summary = 1; } if (print_summary) { char *title; int rate_idx; u32 bitrate; if (hundred) title = "100Frames"; else if (ieee80211_has_retry(fc)) title = "Retry"; else if (ieee80211_is_assoc_resp(fc)) title = "AscRsp"; else if (ieee80211_is_reassoc_resp(fc)) title = "RasRsp"; else if (ieee80211_is_probe_resp(fc)) { title = "PrbRsp"; print_dump = 1; /* dump frame contents */ } else if (ieee80211_is_beacon(fc)) { title = "Beacon"; print_dump = 1; /* dump frame contents */ } else if (ieee80211_is_atim(fc)) title = "ATIM"; else if (ieee80211_is_auth(fc)) title = "Auth"; else if (ieee80211_is_deauth(fc)) title = "DeAuth"; else if (ieee80211_is_disassoc(fc)) title = "DisAssoc"; else title = "Frame"; rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { bitrate = 0; WARN_ON_ONCE(1); } else { bitrate = iwl_rates[rate_idx].ieee / 2; } /* print frame summary. * MAC addresses show just the last byte (for brevity), * but you can hack it to show more, if you'd like to. */ if (dataframe) IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, " "len=%u, rssi=%d, chnl=%d, rate=%u, \n", title, le16_to_cpu(fc), header->addr1[5], length, rssi, channel, bitrate); else { /* src/dst addresses assume managed mode */ IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, " "len=%u, rssi=%d, tim=%lu usec, " "phy=0x%02x, chnl=%d\n", title, le16_to_cpu(fc), header->addr1[5], header->addr3[5], length, rssi, tsf_low - priv->scan_start_tsf, phy_flags, channel); } } if (print_dump) iwl_print_hex_dump(priv, IWL_DL_RX, header, length); }