Esempio n. 1
0
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));
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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;
	}
Esempio n. 5
0
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();
}
Esempio n. 6
0
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();
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
/*
 * 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 );
}
Esempio n. 10
0
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;
}
Esempio n. 12
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;
}