static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_target_rate trate; struct ieee80211_sta *sta; int ret; memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); rcu_read_lock(); sta = ieee80211_find_sta(vif, bss_conf->bssid); if (!sta) { rcu_read_unlock(); return; } ath9k_htc_setup_rate(priv, sta, &trate); rcu_read_unlock(); ret = ath9k_htc_send_rate_cmd(priv, &trate); if (!ret) ath_dbg(common, CONFIG, "Updated target sta: %pM, rate caps: 0x%X\n", bss_conf->bssid, be32_to_cpu(trate.capflags)); }
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) { struct ieee80211_sta *sta; if (test_bit(hlid, &wl->ap_ps_map)) return; wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d " "clean_queues %d", hlid, wl->links[hlid].allocated_pkts, clean_queues); rcu_read_lock(); sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); if (!sta) { wl1271_error("could not find sta %pM for starting ps", wl->links[hlid].addr); rcu_read_unlock(); return; } ieee80211_sta_ps_transition_ni(sta, true); rcu_read_unlock(); /* do we want to filter all frames from this link's queues? */ if (clean_queues) wl1271_ps_filter_frames(wl, hlid); __set_bit(hlid, &wl->ap_ps_map); }
static int ar5523_get_wlan_mode(struct ar5523 *ar, struct ieee80211_bss_conf *bss_conf) { struct ieee80211_supported_band *band; int bit; struct ieee80211_sta *sta; u32 sta_rate_set; band = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band]; sta = ieee80211_find_sta(ar->vif, bss_conf->bssid); if (!sta) { ar5523_info(ar, "STA not found!\n"); return WLAN_MODE_11b; } sta_rate_set = sta->supp_rates[ar->hw->conf.chandef.chan->band]; for (bit = 0; bit < band->n_bitrates; bit++) { if (sta_rate_set & 1) { int rate = band->bitrates[bit].bitrate; switch (rate) { case 60: case 90: case 120: case 180: case 240: case 360: case 480: case 540: return WLAN_MODE_11g; } } sta_rate_set >>= 1; } return WLAN_MODE_11b; }
static void iwl_ht_conf(struct iwl_priv *priv, struct ieee80211_vif *vif) { struct iwl_ht_config *ht_conf = &priv->current_ht_config; struct ieee80211_sta *sta; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); IWL_DEBUG_ASSOC(priv, "enter:\n"); if (!ctx->ht.enabled) return; ctx->ht.protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); ht_conf->single_chain_sufficient = false; switch (vif->type) { case NL80211_IFTYPE_STATION: rcu_read_lock(); sta = ieee80211_find_sta(vif, bss_conf->bssid); if (sta) { struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; int maxstreams; maxstreams = (ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; maxstreams += 1; if ((ht_cap->mcs.rx_mask[1] == 0) && (ht_cap->mcs.rx_mask[2] == 0)) ht_conf->single_chain_sufficient = true; if (maxstreams <= 1) ht_conf->single_chain_sufficient = true; } else { /* * If at all, this can only happen through a race * when the AP disconnects us while we're still * setting up the connection, in that case mac80211 * will soon tell us about that. */ ht_conf->single_chain_sufficient = true; } rcu_read_unlock(); break; case NL80211_IFTYPE_ADHOC: ht_conf->single_chain_sufficient = true; break; default: break; }
static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, struct iwl_rxon_context *ctx, const u8 *addr1) { struct ieee80211_sta *sta; struct iwl_station_priv *sta_priv; rcu_read_lock(); sta = ieee80211_find_sta(ctx->vif, addr1); if (sta) { sta_priv = (void *)sta->drv_priv; /* avoid atomic ops if this isn't a client */ if (sta_priv->client && atomic_dec_return(&sta_priv->pending_frames) == 0) ieee80211_sta_block_awake(priv->hw, sta, false); } rcu_read_unlock(); }
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid) { struct ieee80211_sta *sta; if (!test_bit(hlid, &wl->ap_ps_map)) return; wl1271_debug(DEBUG_PSM, "end mac80211 PSM on hlid %d", hlid); __clear_bit(hlid, &wl->ap_ps_map); rcu_read_lock(); sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr); if (!sta) { wl1271_error("could not find sta %pM for ending ps", wl->links[hlid].addr); goto end; } ieee80211_sta_ps_transition_ni(sta, false); end: rcu_read_unlock(); }
static void ar5523_create_rateset(struct ar5523 *ar, struct ieee80211_bss_conf *bss_conf, struct ar5523_cmd_rateset *rs, bool basic) { struct ieee80211_supported_band *band; struct ieee80211_sta *sta; int bit, i = 0; u32 sta_rate_set, basic_rate_set; sta = ieee80211_find_sta(ar->vif, bss_conf->bssid); basic_rate_set = bss_conf->basic_rates; if (!sta) { ar5523_info(ar, "STA not found. Cannot set rates\n"); sta_rate_set = bss_conf->basic_rates; } else sta_rate_set = sta->supp_rates[ar->hw->conf.chandef.chan->band]; ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set); band = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band]; for (bit = 0; bit < band->n_bitrates; bit++) { BUG_ON(i >= AR5523_MAX_NRATES); ar5523_dbg(ar, "Considering rate %d : %d\n", band->bitrates[bit].hw_value, sta_rate_set & 1); if (sta_rate_set & 1) { rs->set[i] = band->bitrates[bit].hw_value; if (basic_rate_set & 1 && basic) rs->set[i] |= 0x80; i++; } sta_rate_set >>= 1; basic_rate_set >>= 1; } rs->length = i; }
/* * 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); } } 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) {
static void rtl_op_bss_info_changed( struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changed ) { struct rtl_priv *rtlpriv = rtl_priv( hw ); struct rtl_hal *rtlhal = rtl_hal( rtlpriv ); struct rtl_mac *mac = rtl_mac( rtl_priv( hw ) ); struct rtl_ps_ctl *ppsc = rtl_psc( rtl_priv( hw ) ); struct ieee80211_sta *sta = NULL; mutex_lock( &rtlpriv->locks.conf_mutex ); if ( ( vif->type == NL80211_IFTYPE_ADHOC ) || ( vif->type == NL80211_IFTYPE_AP ) || ( vif->type == NL80211_IFTYPE_MESH_POINT ) ) { if ( ( changed & BSS_CHANGED_BEACON ) || ( changed & BSS_CHANGED_BEACON_ENABLED && bss_conf->enable_beacon ) ) { if ( mac->beacon_enabled == 0 ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_DMESG, "BSS_CHANGED_BEACON_ENABLED\n" ); /*start hw beacon interrupt. */ /*rtlpriv->cfg->ops->set_bcn_reg( hw ); */ mac->beacon_enabled = 1; rtlpriv->cfg->ops->update_interrupt_mask( hw, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS], 0 ); if ( rtlpriv->cfg->ops->linked_set_reg ) rtlpriv->cfg->ops->linked_set_reg( hw ); } } if ( ( changed & BSS_CHANGED_BEACON_ENABLED && !bss_conf->enable_beacon ) ) { if ( mac->beacon_enabled == 1 ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_DMESG, "ADHOC DISABLE BEACON\n" ); mac->beacon_enabled = 0; rtlpriv->cfg->ops->update_interrupt_mask( hw, 0, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS] ); } } if ( changed & BSS_CHANGED_BEACON_INT ) { RT_TRACE( rtlpriv, COMP_BEACON, DBG_TRACE, "BSS_CHANGED_BEACON_INT\n" ); mac->beacon_interval = bss_conf->beacon_int; rtlpriv->cfg->ops->set_bcn_intv( hw ); } } /*TODO: reference to enum ieee80211_bss_change */ if ( changed & BSS_CHANGED_ASSOC ) { if ( bss_conf->assoc ) { struct ieee80211_sta *sta = NULL; /* we should reset all sec info & cam * before set cam after linked, we should not * reset in disassoc, that will cause tkip->wep * fail because some flag will be wrong */ /* reset sec info */ rtl_cam_reset_sec_info( hw ); /* reset cam to fix wep fail issue * when change from wpa to wep */ rtl_cam_reset_all_entry( hw ); mac->link_state = MAC80211_LINKED; mac->cnt_after_linked = 0; mac->assoc_id = bss_conf->aid; memcpy( mac->bssid, bss_conf->bssid, ETH_ALEN ); if ( rtlpriv->cfg->ops->linked_set_reg ) rtlpriv->cfg->ops->linked_set_reg( hw ); rcu_read_lock(); sta = ieee80211_find_sta( vif, ( u8 * )bss_conf->bssid ); if ( !sta ) { pr_err( "ieee80211_find_sta returned NULL\n" ); rcu_read_unlock(); goto out; } if ( vif->type == NL80211_IFTYPE_STATION && sta ) rtlpriv->cfg->ops->update_rate_tbl( hw, sta, 0 ); RT_TRACE( rtlpriv, COMP_EASY_CONCURRENT, DBG_LOUD, "send PS STATIC frame\n" ); if ( rtlpriv->dm.supp_phymode_switch ) { if ( sta->ht_cap.ht_supported ) rtl_send_smps_action( hw, sta, IEEE80211_SMPS_STATIC ); } rcu_read_unlock(); RT_TRACE( rtlpriv, COMP_MAC80211, DBG_DMESG, "BSS_CHANGED_ASSOC\n" ); } else { if ( mac->link_state == MAC80211_LINKED ) { rtlpriv->enter_ps = false; schedule_work( &rtlpriv->works.lps_change_work ); } if ( ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE ) rtl_p2p_ps_cmd( hw, P2P_PS_DISABLE ); mac->link_state = MAC80211_NOLINK; memset( mac->bssid, 0, ETH_ALEN ); mac->vendor = PEER_UNKNOWN; if ( rtlpriv->dm.supp_phymode_switch ) { if ( rtlpriv->cfg->ops->chk_switch_dmdp ) rtlpriv->cfg->ops->chk_switch_dmdp( hw ); } RT_TRACE( rtlpriv, COMP_MAC80211, DBG_DMESG, "BSS_CHANGED_UN_ASSOC\n" ); } } if ( changed & BSS_CHANGED_ERP_CTS_PROT ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_TRACE, "BSS_CHANGED_ERP_CTS_PROT\n" ); mac->use_cts_protect = bss_conf->use_cts_prot; } if ( changed & BSS_CHANGED_ERP_PREAMBLE ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_LOUD, "BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n", bss_conf->use_short_preamble ); mac->short_preamble = bss_conf->use_short_preamble; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_ACK_PREAMBLE, &mac->short_preamble ); } if ( changed & BSS_CHANGED_ERP_SLOT ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_TRACE, "BSS_CHANGED_ERP_SLOT\n" ); if ( bss_conf->use_short_slot ) mac->slot_time = RTL_SLOT_TIME_9; else mac->slot_time = RTL_SLOT_TIME_20; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_SLOT_TIME, &mac->slot_time ); } if ( changed & BSS_CHANGED_HT ) { RT_TRACE( rtlpriv, COMP_MAC80211, DBG_TRACE, "BSS_CHANGED_HT\n" ); rcu_read_lock(); sta = get_sta( hw, vif, bss_conf->bssid ); if ( sta ) { if ( sta->ht_cap.ampdu_density > mac->current_ampdu_density ) mac->current_ampdu_density = sta->ht_cap.ampdu_density; if ( sta->ht_cap.ampdu_factor < mac->current_ampdu_factor ) mac->current_ampdu_factor = sta->ht_cap.ampdu_factor; } rcu_read_unlock(); rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_SHORTGI_DENSITY, &mac->max_mss_density ); rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_AMPDU_FACTOR, &mac->current_ampdu_factor ); rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_AMPDU_MIN_SPACE, &mac->current_ampdu_density ); } if ( changed & BSS_CHANGED_BSSID ) { u32 basic_rates; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_BSSID, ( u8 * ) bss_conf->bssid ); RT_TRACE( rtlpriv, COMP_MAC80211, DBG_DMESG, "%pM\n", bss_conf->bssid ); mac->vendor = PEER_UNKNOWN; memcpy( mac->bssid, bss_conf->bssid, ETH_ALEN ); rtlpriv->cfg->ops->set_network_type( hw, vif->type ); rcu_read_lock(); sta = get_sta( hw, vif, bss_conf->bssid ); if ( !sta ) { rcu_read_unlock(); goto out; } if ( rtlhal->current_bandtype == BAND_ON_5G ) { mac->mode = WIRELESS_MODE_A; } else { if ( sta->supp_rates[0] <= 0xf ) mac->mode = WIRELESS_MODE_B; else mac->mode = WIRELESS_MODE_G; } if ( sta->ht_cap.ht_supported ) { if ( rtlhal->current_bandtype == BAND_ON_2_4G ) mac->mode = WIRELESS_MODE_N_24G; else mac->mode = WIRELESS_MODE_N_5G; } /* just station need it, because ibss & ap mode will * set in sta_add, and will be NULL here */ if ( mac->opmode == NL80211_IFTYPE_STATION ) { struct rtl_sta_info *sta_entry; sta_entry = ( struct rtl_sta_info * ) sta->drv_priv; sta_entry->wireless_mode = mac->mode; } if ( sta->ht_cap.ht_supported ) { mac->ht_enable = true; /* * for cisco 1252 bw20 it's wrong * if ( ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ) { * mac->bw_40 = true; * } * */ } if ( changed & BSS_CHANGED_BASIC_RATES ) { /* for 5G must << RATE_6M_INDEX = 4, * because 5G have no cck rate*/ if ( rtlhal->current_bandtype == BAND_ON_5G ) basic_rates = sta->supp_rates[1] << 4; else basic_rates = sta->supp_rates[0]; mac->basic_rates = basic_rates; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_BASIC_RATE, ( u8 * )( &basic_rates ) ); } rcu_read_unlock(); } /* * For FW LPS: * To tell firmware we have connected * to an AP. For 92SE/CE power save v2. */ if ( changed & BSS_CHANGED_ASSOC ) { if ( bss_conf->assoc ) { if ( ppsc->fwctrl_lps ) { u8 mstatus = RT_MEDIA_CONNECT; u8 keep_alive = 10; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_KEEP_ALIVE, &keep_alive ); rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_H2C_FW_JOINBSSRPT, &mstatus ); ppsc->report_linked = true; } } else { if ( ppsc->fwctrl_lps ) { u8 mstatus = RT_MEDIA_DISCONNECT; rtlpriv->cfg->ops->set_hw_reg( hw, HW_VAR_H2C_FW_JOINBSSRPT, &mstatus ); ppsc->report_linked = false; } } if ( rtlpriv->cfg->ops->bt_wifi_media_status_notify ) rtlpriv->cfg->ops->bt_wifi_media_status_notify( hw, ppsc->report_linked ); } out: mutex_unlock( &rtlpriv->locks.conf_mutex ); }
void ath9k_tx_tasklet(unsigned long data) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb = NULL; __le16 fc; while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; tx_info = IEEE80211_SKB_CB(skb); memset(&tx_info->status, 0, sizeof(tx_info->status)); rcu_read_lock(); sta = ieee80211_find_sta(priv->vif, hdr->addr1); if (!sta) { rcu_read_unlock(); ieee80211_tx_status(priv->hw, skb); continue; } /* Check if we need to start aggregation */ if (sta && conf_is_ht(&priv->hw->conf) && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { if (ieee80211_is_data_qos(fc)) { u8 *qc, tid; struct ath9k_htc_sta *ista; qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; ista = (struct ath9k_htc_sta *)sta->drv_priv; if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { ieee80211_start_tx_ba_session(sta, tid); spin_lock_bh(&priv->tx_lock); ista->tid_state[tid] = AGGR_PROGRESS; spin_unlock_bh(&priv->tx_lock); } } } rcu_read_unlock(); /* Send status to mac80211 */ ieee80211_tx_status(priv->hw, skb); } /* Wake TX queues if needed */ spin_lock_bh(&priv->tx_lock); if (priv->tx_queues_stop) { priv->tx_queues_stop = false; spin_unlock_bh(&priv->tx_lock); ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Waking up TX queues\n"); ieee80211_wake_queues(priv->hw); return; } spin_unlock_bh(&priv->tx_lock); }
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { int ret; u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool disconnect_sta = false; unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); vector = le32_to_cpu(mbox->events_vector); vector &= ~(le32_to_cpu(mbox->events_mask)); wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); wl1271_scan_stm(wl); } if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); wl1271_scan_sched_scan_results(wl); } if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); if (wl->sched_scanning) { ieee80211_sched_scan_stopped(wl->hw); wl->sched_scanning = false; } } if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) wl12xx_event_soft_gemini_sense(wl, mbox->soft_gemini_sense_info); if (vector & CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { int timeout = 0; if (mbox->change_auto_mode_timeout) timeout = 500; ieee80211_set_dyn_ps_timeout(wl->vif, timeout); } /* * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. * * As there's possibility that the driver disables PSM before receiving * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * */ if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) { wl1271_info("Beacon loss detected."); /* indicate to the stack, that beacons have been lost */ beacon_loss = true; } if ((vector & PS_REPORT_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); if (ret < 0) return ret; } if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap) wl1271_event_pspoll_delivery_fail(wl); if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); if (wl->vif) wl1271_event_rssi_trigger(wl, mbox); } if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " "ba_allowed = 0x%x", mbox->rx_ba_allowed); wl->ba_allowed = !!mbox->rx_ba_allowed; if (wl->vif && !wl->ba_allowed) wl1271_stop_ba_event(wl); } if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " "channel_switch_status = 0x%x", mbox->channel_switch_status); /* * That event uses for two cases: * 1) channel switch complete with channel_switch_status=0 * 2) fixing beacon actual TSF with channel_switch_status=1 * calling chswitch_done only for the first option */ if (!mbox->channel_switch_status && test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) && (wl->vif)) ieee80211_chswitch_done(wl->vif, true); } if ((vector & DUMMY_PACKET_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) wl1271_tx_dummy_packet(wl); } if (vector & DISCONNECT_EVENT_COMPLETE_ID) wl1271_debug(DEBUG_EVENT, "disconnect event"); /* * "TX retries exceeded" has a different meaning according to mode. * In AP mode the offending station is disconnected. */ if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) { wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); disconnect_sta = true; } if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); disconnect_sta = true; } if (is_ap && disconnect_sta) { u32 num_packets = wl->conf.tx.max_tx_retries; struct ieee80211_sta *sta; const u8 *addr; int h; for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); h < AP_MAX_LINKS; h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { if (!wl1271_is_active_sta(wl, h)) continue; addr = wl->links[h].addr; rcu_read_lock(); sta = ieee80211_find_sta(wl->vif, addr); if (sta) { wl1271_debug(DEBUG_EVENT, "remove sta %d", h); ieee80211_report_low_ack(sta, num_packets); } rcu_read_unlock(); } } if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); return 0; }
static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { int ret; u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool disconnect_sta = false; unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); vector = le32_to_cpu(mbox->events_vector); vector &= ~(le32_to_cpu(mbox->events_mask)); wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); wl1271_scan_stm(wl); } /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { if (mbox->soft_gemini_sense_info) ieee80211_disable_dyn_ps(wl->vif); else ieee80211_enable_dyn_ps(wl->vif); } /* * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon * filtering) is enabled. Without PSM, the stack will receive all * beacons and can detect beacon loss by itself. * * As there's possibility that the driver disables PSM before receiving * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. * */ if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) { wl1271_info("Beacon loss detected."); /* indicate to the stack, that beacons have been lost */ beacon_loss = true; } if ((vector & PS_REPORT_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); if (ret < 0) return ret; } if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap) wl1271_event_pspoll_delivery_fail(wl); if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT"); if (wl->vif) wl1271_event_rssi_trigger(wl, mbox); } if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) wl1271_tx_dummy_packet(wl); } /* * "TX retries exceeded" has a different meaning according to mode. * In AP mode the offending station is disconnected. In STA mode we * report connection loss. */ if (vector & MAX_TX_RETRY_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); if (is_ap) { sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); disconnect_sta = true; } else { beacon_loss = true; } } if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); disconnect_sta = true; } if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); if (is_ap && disconnect_sta) { u32 num_packets = wl->conf.tx.max_tx_retries; struct ieee80211_sta *sta; const u8 *addr; int h; for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); h < AP_MAX_LINKS; h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { if (!wl1271_is_active_sta(wl, h)) continue; addr = wl->links[h].addr; rcu_read_lock(); sta = ieee80211_find_sta(wl->vif, addr); if (sta) { wl1271_debug(DEBUG_EVENT, "remove sta %d", h); #if 0 ieee80211_report_low_ack(sta, num_packets); #endif } rcu_read_unlock(); } } return 0; }