162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
462306a36Sopenharmony_ci	<http://rt2x00.serialmonkey.com>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci	Module: rt2x00mac
1062306a36Sopenharmony_ci	Abstract: rt2x00 generic mac80211 routines.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "rt2x00.h"
1762306a36Sopenharmony_ci#include "rt2x00lib.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
2062306a36Sopenharmony_ci				struct data_queue *queue,
2162306a36Sopenharmony_ci				struct sk_buff *frag_skb)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
2462306a36Sopenharmony_ci	struct ieee80211_tx_info *rts_info;
2562306a36Sopenharmony_ci	struct sk_buff *skb;
2662306a36Sopenharmony_ci	unsigned int data_length;
2762306a36Sopenharmony_ci	int retval = 0;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
3062306a36Sopenharmony_ci		data_length = sizeof(struct ieee80211_cts);
3162306a36Sopenharmony_ci	else
3262306a36Sopenharmony_ci		data_length = sizeof(struct ieee80211_rts);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom);
3562306a36Sopenharmony_ci	if (unlikely(!skb)) {
3662306a36Sopenharmony_ci		rt2x00_warn(rt2x00dev, "Failed to create RTS/CTS frame\n");
3762306a36Sopenharmony_ci		return -ENOMEM;
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
4162306a36Sopenharmony_ci	skb_put(skb, data_length);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/*
4462306a36Sopenharmony_ci	 * Copy TX information over from original frame to
4562306a36Sopenharmony_ci	 * RTS/CTS frame. Note that we set the no encryption flag
4662306a36Sopenharmony_ci	 * since we don't want this frame to be encrypted.
4762306a36Sopenharmony_ci	 * RTS frames should be acked, while CTS-to-self frames
4862306a36Sopenharmony_ci	 * should not. The ready for TX flag is cleared to prevent
4962306a36Sopenharmony_ci	 * it being automatically send when the descriptor is
5062306a36Sopenharmony_ci	 * written to the hardware.
5162306a36Sopenharmony_ci	 */
5262306a36Sopenharmony_ci	memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
5362306a36Sopenharmony_ci	rts_info = IEEE80211_SKB_CB(skb);
5462306a36Sopenharmony_ci	rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
5562306a36Sopenharmony_ci	rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
5862306a36Sopenharmony_ci		rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
5962306a36Sopenharmony_ci	else
6062306a36Sopenharmony_ci		rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* Disable hardware encryption */
6362306a36Sopenharmony_ci	rts_info->control.hw_key = NULL;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * RTS/CTS frame should use the length of the frame plus any
6762306a36Sopenharmony_ci	 * encryption overhead that will be added by the hardware.
6862306a36Sopenharmony_ci	 */
6962306a36Sopenharmony_ci	data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
7262306a36Sopenharmony_ci		ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
7362306a36Sopenharmony_ci					frag_skb->data, data_length, tx_info,
7462306a36Sopenharmony_ci					(struct ieee80211_cts *)(skb->data));
7562306a36Sopenharmony_ci	else
7662306a36Sopenharmony_ci		ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
7762306a36Sopenharmony_ci				  frag_skb->data, data_length, tx_info,
7862306a36Sopenharmony_ci				  (struct ieee80211_rts *)(skb->data));
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	retval = rt2x00queue_write_tx_frame(queue, skb, NULL, true);
8162306a36Sopenharmony_ci	if (retval) {
8262306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
8362306a36Sopenharmony_ci		rt2x00_warn(rt2x00dev, "Failed to send RTS/CTS frame\n");
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return retval;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_civoid rt2x00mac_tx(struct ieee80211_hw *hw,
9062306a36Sopenharmony_ci		  struct ieee80211_tx_control *control,
9162306a36Sopenharmony_ci		  struct sk_buff *skb)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
9462306a36Sopenharmony_ci	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
9562306a36Sopenharmony_ci	enum data_queue_qid qid = skb_get_queue_mapping(skb);
9662306a36Sopenharmony_ci	struct data_queue *queue = NULL;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/*
9962306a36Sopenharmony_ci	 * Mac80211 might be calling this function while we are trying
10062306a36Sopenharmony_ci	 * to remove the device or perhaps suspending it.
10162306a36Sopenharmony_ci	 * Note that we can only stop the TX queues inside the TX path
10262306a36Sopenharmony_ci	 * due to possible race conditions in mac80211.
10362306a36Sopenharmony_ci	 */
10462306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
10562306a36Sopenharmony_ci		goto exit_free_skb;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/*
10862306a36Sopenharmony_ci	 * Use the ATIM queue if appropriate and present.
10962306a36Sopenharmony_ci	 */
11062306a36Sopenharmony_ci	if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
11162306a36Sopenharmony_ci	    rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE))
11262306a36Sopenharmony_ci		qid = QID_ATIM;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
11562306a36Sopenharmony_ci	if (unlikely(!queue)) {
11662306a36Sopenharmony_ci		rt2x00_err(rt2x00dev,
11762306a36Sopenharmony_ci			   "Attempt to send packet over invalid queue %d\n"
11862306a36Sopenharmony_ci			   "Please file bug report to %s\n", qid, DRV_PROJECT);
11962306a36Sopenharmony_ci		goto exit_free_skb;
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/*
12362306a36Sopenharmony_ci	 * If CTS/RTS is required. create and queue that frame first.
12462306a36Sopenharmony_ci	 * Make sure we have at least enough entries available to send
12562306a36Sopenharmony_ci	 * this CTS/RTS frame as well as the data frame.
12662306a36Sopenharmony_ci	 * Note that when the driver has set the set_rts_threshold()
12762306a36Sopenharmony_ci	 * callback function it doesn't need software generation of
12862306a36Sopenharmony_ci	 * either RTS or CTS-to-self frame and handles everything
12962306a36Sopenharmony_ci	 * inside the hardware.
13062306a36Sopenharmony_ci	 */
13162306a36Sopenharmony_ci	if (!rt2x00dev->ops->hw->set_rts_threshold &&
13262306a36Sopenharmony_ci	    (tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
13362306a36Sopenharmony_ci						IEEE80211_TX_RC_USE_CTS_PROTECT))) {
13462306a36Sopenharmony_ci		if (rt2x00queue_available(queue) <= 1) {
13562306a36Sopenharmony_ci			/*
13662306a36Sopenharmony_ci			 * Recheck for full queue under lock to avoid race
13762306a36Sopenharmony_ci			 * conditions with rt2x00lib_txdone().
13862306a36Sopenharmony_ci			 */
13962306a36Sopenharmony_ci			spin_lock(&queue->tx_lock);
14062306a36Sopenharmony_ci			if (rt2x00queue_threshold(queue))
14162306a36Sopenharmony_ci				rt2x00queue_pause_queue(queue);
14262306a36Sopenharmony_ci			spin_unlock(&queue->tx_lock);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci			goto exit_free_skb;
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb))
14862306a36Sopenharmony_ci			goto exit_free_skb;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false)))
15262306a36Sopenharmony_ci		goto exit_free_skb;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci exit_free_skb:
15762306a36Sopenharmony_ci	ieee80211_free_txskb(hw, skb);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_tx);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ciint rt2x00mac_start(struct ieee80211_hw *hw)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
16662306a36Sopenharmony_ci		return 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) {
16962306a36Sopenharmony_ci		/*
17062306a36Sopenharmony_ci		 * This is special case for ieee80211_restart_hw(), otherwise
17162306a36Sopenharmony_ci		 * mac80211 never call start() two times in row without stop();
17262306a36Sopenharmony_ci		 */
17362306a36Sopenharmony_ci		set_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
17462306a36Sopenharmony_ci		rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev);
17562306a36Sopenharmony_ci		rt2x00lib_stop(rt2x00dev);
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci	return rt2x00lib_start(rt2x00dev);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_start);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_civoid rt2x00mac_stop(struct ieee80211_hw *hw)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
18662306a36Sopenharmony_ci		return;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	rt2x00lib_stop(rt2x00dev);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_stop);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_civoid
19362306a36Sopenharmony_cirt2x00mac_reconfig_complete(struct ieee80211_hw *hw,
19462306a36Sopenharmony_ci			    enum ieee80211_reconfig_type reconfig_type)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART)
19962306a36Sopenharmony_ci		clear_bit(DEVICE_STATE_RESET, &rt2x00dev->flags);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_reconfig_complete);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ciint rt2x00mac_add_interface(struct ieee80211_hw *hw,
20462306a36Sopenharmony_ci			    struct ieee80211_vif *vif)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
20762306a36Sopenharmony_ci	struct rt2x00_intf *intf = vif_to_intf(vif);
20862306a36Sopenharmony_ci	struct data_queue *queue = rt2x00dev->bcn;
20962306a36Sopenharmony_ci	struct queue_entry *entry = NULL;
21062306a36Sopenharmony_ci	unsigned int i;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/*
21362306a36Sopenharmony_ci	 * Don't allow interfaces to be added
21462306a36Sopenharmony_ci	 * the device has disappeared.
21562306a36Sopenharmony_ci	 */
21662306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
21762306a36Sopenharmony_ci	    !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
21862306a36Sopenharmony_ci		return -ENODEV;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/*
22162306a36Sopenharmony_ci	 * Loop through all beacon queues to find a free
22262306a36Sopenharmony_ci	 * entry. Since there are as much beacon entries
22362306a36Sopenharmony_ci	 * as the maximum interfaces, this search shouldn't
22462306a36Sopenharmony_ci	 * fail.
22562306a36Sopenharmony_ci	 */
22662306a36Sopenharmony_ci	for (i = 0; i < queue->limit; i++) {
22762306a36Sopenharmony_ci		entry = &queue->entries[i];
22862306a36Sopenharmony_ci		if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags))
22962306a36Sopenharmony_ci			break;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (unlikely(i == queue->limit))
23362306a36Sopenharmony_ci		return -ENOBUFS;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/*
23662306a36Sopenharmony_ci	 * We are now absolutely sure the interface can be created,
23762306a36Sopenharmony_ci	 * increase interface count and start initialization.
23862306a36Sopenharmony_ci	 */
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_AP)
24162306a36Sopenharmony_ci		rt2x00dev->intf_ap_count++;
24262306a36Sopenharmony_ci	else
24362306a36Sopenharmony_ci		rt2x00dev->intf_sta_count++;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	mutex_init(&intf->beacon_skb_mutex);
24662306a36Sopenharmony_ci	intf->beacon = entry;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * The MAC address must be configured after the device
25062306a36Sopenharmony_ci	 * has been initialized. Otherwise the device can reset
25162306a36Sopenharmony_ci	 * the MAC registers.
25262306a36Sopenharmony_ci	 * The BSSID address must only be configured in AP mode,
25362306a36Sopenharmony_ci	 * however we should not send an empty BSSID address for
25462306a36Sopenharmony_ci	 * STA interfaces at this time, since this can cause
25562306a36Sopenharmony_ci	 * invalid behavior in the device.
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
25862306a36Sopenharmony_ci			      vif->addr, NULL);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * Some filters depend on the current working mode. We can force
26262306a36Sopenharmony_ci	 * an update during the next configure_filter() run by mac80211 by
26362306a36Sopenharmony_ci	 * resetting the current packet_filter state.
26462306a36Sopenharmony_ci	 */
26562306a36Sopenharmony_ci	rt2x00dev->packet_filter = 0;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	return 0;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_civoid rt2x00mac_remove_interface(struct ieee80211_hw *hw,
27262306a36Sopenharmony_ci				struct ieee80211_vif *vif)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
27562306a36Sopenharmony_ci	struct rt2x00_intf *intf = vif_to_intf(vif);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/*
27862306a36Sopenharmony_ci	 * Don't allow interfaces to be remove while
27962306a36Sopenharmony_ci	 * either the device has disappeared or when
28062306a36Sopenharmony_ci	 * no interface is present.
28162306a36Sopenharmony_ci	 */
28262306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
28362306a36Sopenharmony_ci	    (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
28462306a36Sopenharmony_ci	    (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
28562306a36Sopenharmony_ci		return;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_AP)
28862306a36Sopenharmony_ci		rt2x00dev->intf_ap_count--;
28962306a36Sopenharmony_ci	else
29062306a36Sopenharmony_ci		rt2x00dev->intf_sta_count--;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/*
29362306a36Sopenharmony_ci	 * Release beacon entry so it is available for
29462306a36Sopenharmony_ci	 * new interfaces again.
29562306a36Sopenharmony_ci	 */
29662306a36Sopenharmony_ci	clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/*
29962306a36Sopenharmony_ci	 * Make sure the bssid and mac address registers
30062306a36Sopenharmony_ci	 * are cleared to prevent false ACKing of frames.
30162306a36Sopenharmony_ci	 */
30262306a36Sopenharmony_ci	rt2x00lib_config_intf(rt2x00dev, intf,
30362306a36Sopenharmony_ci			      NL80211_IFTYPE_UNSPECIFIED, NULL, NULL);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ciint rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
31062306a36Sopenharmony_ci	struct ieee80211_conf *conf = &hw->conf;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/*
31362306a36Sopenharmony_ci	 * mac80211 might be calling this function while we are trying
31462306a36Sopenharmony_ci	 * to remove the device or perhaps suspending it.
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
31762306a36Sopenharmony_ci		return 0;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/*
32062306a36Sopenharmony_ci	 * Some configuration parameters (e.g. channel and antenna values) can
32162306a36Sopenharmony_ci	 * only be set when the radio is enabled, but do require the RX to
32262306a36Sopenharmony_ci	 * be off. During this period we should keep link tuning enabled,
32362306a36Sopenharmony_ci	 * if for any reason the link tuner must be reset, this will be
32462306a36Sopenharmony_ci	 * handled by rt2x00lib_config().
32562306a36Sopenharmony_ci	 */
32662306a36Sopenharmony_ci	rt2x00queue_stop_queue(rt2x00dev->rx);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* Do not race with link tuner. */
32962306a36Sopenharmony_ci	mutex_lock(&rt2x00dev->conf_mutex);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/*
33262306a36Sopenharmony_ci	 * When we've just turned on the radio, we want to reprogram
33362306a36Sopenharmony_ci	 * everything to ensure a consistent state
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	rt2x00lib_config(rt2x00dev, conf, changed);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/*
33862306a36Sopenharmony_ci	 * After the radio has been enabled we need to configure
33962306a36Sopenharmony_ci	 * the antenna to the default settings. rt2x00lib_config_antenna()
34062306a36Sopenharmony_ci	 * should determine if any action should be taken based on
34162306a36Sopenharmony_ci	 * checking if diversity has been enabled or no antenna changes
34262306a36Sopenharmony_ci	 * have been made since the last configuration change.
34362306a36Sopenharmony_ci	 */
34462306a36Sopenharmony_ci	rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	mutex_unlock(&rt2x00dev->conf_mutex);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* Turn RX back on */
34962306a36Sopenharmony_ci	rt2x00queue_start_queue(rt2x00dev->rx);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_config);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_civoid rt2x00mac_configure_filter(struct ieee80211_hw *hw,
35662306a36Sopenharmony_ci				unsigned int changed_flags,
35762306a36Sopenharmony_ci				unsigned int *total_flags,
35862306a36Sopenharmony_ci				u64 multicast)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/*
36362306a36Sopenharmony_ci	 * Mask off any flags we are going to ignore
36462306a36Sopenharmony_ci	 * from the total_flags field.
36562306a36Sopenharmony_ci	 */
36662306a36Sopenharmony_ci	*total_flags &=
36762306a36Sopenharmony_ci	    FIF_ALLMULTI |
36862306a36Sopenharmony_ci	    FIF_FCSFAIL |
36962306a36Sopenharmony_ci	    FIF_PLCPFAIL |
37062306a36Sopenharmony_ci	    FIF_CONTROL |
37162306a36Sopenharmony_ci	    FIF_PSPOLL |
37262306a36Sopenharmony_ci	    FIF_OTHER_BSS;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/*
37562306a36Sopenharmony_ci	 * Apply some rules to the filters:
37662306a36Sopenharmony_ci	 * - Some filters imply different filters to be set.
37762306a36Sopenharmony_ci	 * - Some things we can't filter out at all.
37862306a36Sopenharmony_ci	 * - Multicast filter seems to kill broadcast traffic so never use it.
37962306a36Sopenharmony_ci	 */
38062306a36Sopenharmony_ci	*total_flags |= FIF_ALLMULTI;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/*
38362306a36Sopenharmony_ci	 * If the device has a single filter for all control frames,
38462306a36Sopenharmony_ci	 * FIF_CONTROL and FIF_PSPOLL flags imply each other.
38562306a36Sopenharmony_ci	 * And if the device has more than one filter for control frames
38662306a36Sopenharmony_ci	 * of different types, but has no a separate filter for PS Poll frames,
38762306a36Sopenharmony_ci	 * FIF_CONTROL flag implies FIF_PSPOLL.
38862306a36Sopenharmony_ci	 */
38962306a36Sopenharmony_ci	if (!rt2x00_has_cap_control_filters(rt2x00dev)) {
39062306a36Sopenharmony_ci		if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
39162306a36Sopenharmony_ci			*total_flags |= FIF_CONTROL | FIF_PSPOLL;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci	if (!rt2x00_has_cap_control_filter_pspoll(rt2x00dev)) {
39462306a36Sopenharmony_ci		if (*total_flags & FIF_CONTROL)
39562306a36Sopenharmony_ci			*total_flags |= FIF_PSPOLL;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	rt2x00dev->packet_filter = *total_flags;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic void rt2x00mac_set_tim_iter(void *data, u8 *mac,
40562306a36Sopenharmony_ci				   struct ieee80211_vif *vif)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct rt2x00_intf *intf = vif_to_intf(vif);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_AP &&
41062306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_ADHOC &&
41162306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_MESH_POINT)
41262306a36Sopenharmony_ci		return;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	set_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciint rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
41862306a36Sopenharmony_ci		      bool set)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
42362306a36Sopenharmony_ci		return 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(
42662306a36Sopenharmony_ci		rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
42762306a36Sopenharmony_ci		rt2x00mac_set_tim_iter, rt2x00dev);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* queue work to upodate the beacon template */
43062306a36Sopenharmony_ci	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_CRYPTO
43662306a36Sopenharmony_cistatic void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	if (key_len > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
43962306a36Sopenharmony_ci		memcpy(crypto->key,
44062306a36Sopenharmony_ci		       &key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
44162306a36Sopenharmony_ci		       sizeof(crypto->key));
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (key_len > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
44462306a36Sopenharmony_ci		memcpy(crypto->tx_mic,
44562306a36Sopenharmony_ci		       &key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
44662306a36Sopenharmony_ci		       sizeof(crypto->tx_mic));
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (key_len > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
44962306a36Sopenharmony_ci		memcpy(crypto->rx_mic,
45062306a36Sopenharmony_ci		       &key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
45162306a36Sopenharmony_ci		       sizeof(crypto->rx_mic));
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ciint rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
45562306a36Sopenharmony_ci		      struct ieee80211_vif *vif, struct ieee80211_sta *sta,
45662306a36Sopenharmony_ci		      struct ieee80211_key_conf *key)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
45962306a36Sopenharmony_ci	int (*set_key) (struct rt2x00_dev *rt2x00dev,
46062306a36Sopenharmony_ci			struct rt2x00lib_crypto *crypto,
46162306a36Sopenharmony_ci			struct ieee80211_key_conf *key);
46262306a36Sopenharmony_ci	struct rt2x00lib_crypto crypto;
46362306a36Sopenharmony_ci	static const u8 bcast_addr[ETH_ALEN] =
46462306a36Sopenharmony_ci		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, };
46562306a36Sopenharmony_ci	struct rt2x00_sta *sta_priv = NULL;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
46862306a36Sopenharmony_ci		return 0;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* The hardware can't do MFP */
47162306a36Sopenharmony_ci	if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || (sta && sta->mfp))
47262306a36Sopenharmony_ci		return -EOPNOTSUPP;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/*
47562306a36Sopenharmony_ci	 * To support IBSS RSN, don't program group keys in IBSS, the
47662306a36Sopenharmony_ci	 * hardware will then not attempt to decrypt the frames.
47762306a36Sopenharmony_ci	 */
47862306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_ADHOC &&
47962306a36Sopenharmony_ci	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
48062306a36Sopenharmony_ci		return -EOPNOTSUPP;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (key->keylen > 32)
48362306a36Sopenharmony_ci		return -ENOSPC;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	memset(&crypto, 0, sizeof(crypto));
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	crypto.bssidx = rt2x00lib_get_bssidx(rt2x00dev, vif);
48862306a36Sopenharmony_ci	crypto.cipher = rt2x00crypto_key_to_cipher(key);
48962306a36Sopenharmony_ci	if (crypto.cipher == CIPHER_NONE)
49062306a36Sopenharmony_ci		return -EOPNOTSUPP;
49162306a36Sopenharmony_ci	if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev))
49262306a36Sopenharmony_ci		return -EOPNOTSUPP;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	crypto.cmd = cmd;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (sta) {
49762306a36Sopenharmony_ci		crypto.address = sta->addr;
49862306a36Sopenharmony_ci		sta_priv = sta_to_rt2x00_sta(sta);
49962306a36Sopenharmony_ci		crypto.wcid = sta_priv->wcid;
50062306a36Sopenharmony_ci	} else
50162306a36Sopenharmony_ci		crypto.address = bcast_addr;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (crypto.cipher == CIPHER_TKIP)
50462306a36Sopenharmony_ci		memcpy_tkip(&crypto, &key->key[0], key->keylen);
50562306a36Sopenharmony_ci	else
50662306a36Sopenharmony_ci		memcpy(crypto.key, &key->key[0], key->keylen);
50762306a36Sopenharmony_ci	/*
50862306a36Sopenharmony_ci	 * Each BSS has a maximum of 4 shared keys.
50962306a36Sopenharmony_ci	 * Shared key index values:
51062306a36Sopenharmony_ci	 *	0) BSS0 key0
51162306a36Sopenharmony_ci	 *	1) BSS0 key1
51262306a36Sopenharmony_ci	 *	...
51362306a36Sopenharmony_ci	 *	4) BSS1 key0
51462306a36Sopenharmony_ci	 *	...
51562306a36Sopenharmony_ci	 *	8) BSS2 key0
51662306a36Sopenharmony_ci	 *	...
51762306a36Sopenharmony_ci	 * Both pairwise as shared key indeces are determined by
51862306a36Sopenharmony_ci	 * driver. This is required because the hardware requires
51962306a36Sopenharmony_ci	 * keys to be assigned in correct order (When key 1 is
52062306a36Sopenharmony_ci	 * provided but key 0 is not, then the key is not found
52162306a36Sopenharmony_ci	 * by the hardware during RX).
52262306a36Sopenharmony_ci	 */
52362306a36Sopenharmony_ci	if (cmd == SET_KEY)
52462306a36Sopenharmony_ci		key->hw_key_idx = 0;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
52762306a36Sopenharmony_ci		set_key = rt2x00dev->ops->lib->config_pairwise_key;
52862306a36Sopenharmony_ci	else
52962306a36Sopenharmony_ci		set_key = rt2x00dev->ops->lib->config_shared_key;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (!set_key)
53262306a36Sopenharmony_ci		return -EOPNOTSUPP;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return set_key(rt2x00dev, &crypto, key);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_set_key);
53762306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_CRYPTO */
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_civoid rt2x00mac_sw_scan_start(struct ieee80211_hw *hw,
54062306a36Sopenharmony_ci			     struct ieee80211_vif *vif,
54162306a36Sopenharmony_ci			     const u8 *mac_addr)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
54462306a36Sopenharmony_ci	set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
54562306a36Sopenharmony_ci	rt2x00link_stop_tuner(rt2x00dev);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_civoid rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw,
55062306a36Sopenharmony_ci				struct ieee80211_vif *vif)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
55362306a36Sopenharmony_ci	clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
55462306a36Sopenharmony_ci	rt2x00link_start_tuner(rt2x00dev);
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ciint rt2x00mac_get_stats(struct ieee80211_hw *hw,
55962306a36Sopenharmony_ci			struct ieee80211_low_level_stats *stats)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/*
56462306a36Sopenharmony_ci	 * The dot11ACKFailureCount, dot11RTSFailureCount and
56562306a36Sopenharmony_ci	 * dot11RTSSuccessCount are updated in interrupt time.
56662306a36Sopenharmony_ci	 * dot11FCSErrorCount is updated in the link tuner.
56762306a36Sopenharmony_ci	 */
56862306a36Sopenharmony_ci	memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_civoid rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
57562306a36Sopenharmony_ci				struct ieee80211_vif *vif,
57662306a36Sopenharmony_ci				struct ieee80211_bss_conf *bss_conf,
57762306a36Sopenharmony_ci				u64 changes)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
58062306a36Sopenharmony_ci	struct rt2x00_intf *intf = vif_to_intf(vif);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/*
58362306a36Sopenharmony_ci	 * mac80211 might be calling this function while we are trying
58462306a36Sopenharmony_ci	 * to remove the device or perhaps suspending it.
58562306a36Sopenharmony_ci	 */
58662306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
58762306a36Sopenharmony_ci		return;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/*
59062306a36Sopenharmony_ci	 * Update the BSSID.
59162306a36Sopenharmony_ci	 */
59262306a36Sopenharmony_ci	if (changes & BSS_CHANGED_BSSID)
59362306a36Sopenharmony_ci		rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
59462306a36Sopenharmony_ci				      bss_conf->bssid);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/*
59762306a36Sopenharmony_ci	 * Start/stop beaconing.
59862306a36Sopenharmony_ci	 */
59962306a36Sopenharmony_ci	if (changes & BSS_CHANGED_BEACON_ENABLED) {
60062306a36Sopenharmony_ci		mutex_lock(&intf->beacon_skb_mutex);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		/*
60362306a36Sopenharmony_ci		 * Clear the 'enable_beacon' flag and clear beacon because
60462306a36Sopenharmony_ci		 * the beacon queue has been stopped after hardware reset.
60562306a36Sopenharmony_ci		 */
60662306a36Sopenharmony_ci		if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags) &&
60762306a36Sopenharmony_ci		    intf->enable_beacon) {
60862306a36Sopenharmony_ci			intf->enable_beacon = false;
60962306a36Sopenharmony_ci			rt2x00queue_clear_beacon(rt2x00dev, vif);
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci		if (!bss_conf->enable_beacon && intf->enable_beacon) {
61362306a36Sopenharmony_ci			rt2x00dev->intf_beaconing--;
61462306a36Sopenharmony_ci			intf->enable_beacon = false;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci			if (rt2x00dev->intf_beaconing == 0) {
61762306a36Sopenharmony_ci				/*
61862306a36Sopenharmony_ci				 * Last beaconing interface disabled
61962306a36Sopenharmony_ci				 * -> stop beacon queue.
62062306a36Sopenharmony_ci				 */
62162306a36Sopenharmony_ci				rt2x00queue_stop_queue(rt2x00dev->bcn);
62262306a36Sopenharmony_ci			}
62362306a36Sopenharmony_ci			/*
62462306a36Sopenharmony_ci			 * Clear beacon in the H/W for this vif. This is needed
62562306a36Sopenharmony_ci			 * to disable beaconing on this particular interface
62662306a36Sopenharmony_ci			 * and keep it running on other interfaces.
62762306a36Sopenharmony_ci			 */
62862306a36Sopenharmony_ci			rt2x00queue_clear_beacon(rt2x00dev, vif);
62962306a36Sopenharmony_ci		} else if (bss_conf->enable_beacon && !intf->enable_beacon) {
63062306a36Sopenharmony_ci			rt2x00dev->intf_beaconing++;
63162306a36Sopenharmony_ci			intf->enable_beacon = true;
63262306a36Sopenharmony_ci			/*
63362306a36Sopenharmony_ci			 * Upload beacon to the H/W. This is only required on
63462306a36Sopenharmony_ci			 * USB devices. PCI devices fetch beacons periodically.
63562306a36Sopenharmony_ci			 */
63662306a36Sopenharmony_ci			if (rt2x00_is_usb(rt2x00dev))
63762306a36Sopenharmony_ci				rt2x00queue_update_beacon(rt2x00dev, vif);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci			if (rt2x00dev->intf_beaconing == 1) {
64062306a36Sopenharmony_ci				/*
64162306a36Sopenharmony_ci				 * First beaconing interface enabled
64262306a36Sopenharmony_ci				 * -> start beacon queue.
64362306a36Sopenharmony_ci				 */
64462306a36Sopenharmony_ci				rt2x00queue_start_queue(rt2x00dev->bcn);
64562306a36Sopenharmony_ci			}
64662306a36Sopenharmony_ci		}
64762306a36Sopenharmony_ci		mutex_unlock(&intf->beacon_skb_mutex);
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/*
65162306a36Sopenharmony_ci	 * When the association status has changed we must reset the link
65262306a36Sopenharmony_ci	 * tuner counter. This is because some drivers determine if they
65362306a36Sopenharmony_ci	 * should perform link tuning based on the number of seconds
65462306a36Sopenharmony_ci	 * while associated or not associated.
65562306a36Sopenharmony_ci	 */
65662306a36Sopenharmony_ci	if (changes & BSS_CHANGED_ASSOC) {
65762306a36Sopenharmony_ci		rt2x00dev->link.count = 0;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		if (vif->cfg.assoc)
66062306a36Sopenharmony_ci			rt2x00dev->intf_associated++;
66162306a36Sopenharmony_ci		else
66262306a36Sopenharmony_ci			rt2x00dev->intf_associated--;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	/*
66862306a36Sopenharmony_ci	 * When the erp information has changed, we should perform
66962306a36Sopenharmony_ci	 * additional configuration steps. For all other changes we are done.
67062306a36Sopenharmony_ci	 */
67162306a36Sopenharmony_ci	if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE |
67262306a36Sopenharmony_ci		       BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES |
67362306a36Sopenharmony_ci		       BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT))
67462306a36Sopenharmony_ci		rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes);
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ciint rt2x00mac_conf_tx(struct ieee80211_hw *hw,
67962306a36Sopenharmony_ci		      struct ieee80211_vif *vif,
68062306a36Sopenharmony_ci		      unsigned int link_id, u16 queue_idx,
68162306a36Sopenharmony_ci		      const struct ieee80211_tx_queue_params *params)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
68462306a36Sopenharmony_ci	struct data_queue *queue;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
68762306a36Sopenharmony_ci	if (unlikely(!queue))
68862306a36Sopenharmony_ci		return -EINVAL;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/*
69162306a36Sopenharmony_ci	 * The passed variables are stored as real value ((2^n)-1).
69262306a36Sopenharmony_ci	 * Ralink registers require to know the bit number 'n'.
69362306a36Sopenharmony_ci	 */
69462306a36Sopenharmony_ci	if (params->cw_min > 0)
69562306a36Sopenharmony_ci		queue->cw_min = fls(params->cw_min);
69662306a36Sopenharmony_ci	else
69762306a36Sopenharmony_ci		queue->cw_min = 5; /* cw_min: 2^5 = 32. */
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (params->cw_max > 0)
70062306a36Sopenharmony_ci		queue->cw_max = fls(params->cw_max);
70162306a36Sopenharmony_ci	else
70262306a36Sopenharmony_ci		queue->cw_max = 10; /* cw_min: 2^10 = 1024. */
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	queue->aifs = params->aifs;
70562306a36Sopenharmony_ci	queue->txop = params->txop;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	rt2x00_dbg(rt2x00dev,
70862306a36Sopenharmony_ci		   "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d\n",
70962306a36Sopenharmony_ci		   queue_idx, queue->cw_min, queue->cw_max, queue->aifs,
71062306a36Sopenharmony_ci		   queue->txop);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	return 0;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_civoid rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
71962306a36Sopenharmony_ci	bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	wiphy_rfkill_set_hw_state(hw->wiphy, !active);
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_civoid rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
72662306a36Sopenharmony_ci		     u32 queues, bool drop)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
72962306a36Sopenharmony_ci	struct data_queue *queue;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
73262306a36Sopenharmony_ci		return;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	set_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue)
73762306a36Sopenharmony_ci		rt2x00queue_flush_queue(queue, drop);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	clear_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_flush);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ciint rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
74662306a36Sopenharmony_ci	struct link_ant *ant = &rt2x00dev->link.ant;
74762306a36Sopenharmony_ci	struct antenna_setup *def = &rt2x00dev->default_ant;
74862306a36Sopenharmony_ci	struct antenna_setup setup;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	// The antenna value is not supposed to be 0,
75162306a36Sopenharmony_ci	// or exceed the maximum number of antenna's.
75262306a36Sopenharmony_ci	if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3))
75362306a36Sopenharmony_ci		return -EINVAL;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	// When the client tried to configure the antenna to or from
75662306a36Sopenharmony_ci	// diversity mode, we must reset the default antenna as well
75762306a36Sopenharmony_ci	// as that controls the diversity switch.
75862306a36Sopenharmony_ci	if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3)
75962306a36Sopenharmony_ci		ant->flags &= ~ANTENNA_TX_DIVERSITY;
76062306a36Sopenharmony_ci	if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3)
76162306a36Sopenharmony_ci		ant->flags &= ~ANTENNA_RX_DIVERSITY;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	// If diversity is being enabled, check if we need hardware
76462306a36Sopenharmony_ci	// or software diversity. In the latter case, reset the value,
76562306a36Sopenharmony_ci	// and make sure we update the antenna flags to have the
76662306a36Sopenharmony_ci	// link tuner pick up the diversity tuning.
76762306a36Sopenharmony_ci	if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) {
76862306a36Sopenharmony_ci		tx_ant = ANTENNA_SW_DIVERSITY;
76962306a36Sopenharmony_ci		ant->flags |= ANTENNA_TX_DIVERSITY;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) {
77362306a36Sopenharmony_ci		rx_ant = ANTENNA_SW_DIVERSITY;
77462306a36Sopenharmony_ci		ant->flags |= ANTENNA_RX_DIVERSITY;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	setup.tx = tx_ant;
77862306a36Sopenharmony_ci	setup.rx = rx_ant;
77962306a36Sopenharmony_ci	setup.rx_chain_num = 0;
78062306a36Sopenharmony_ci	setup.tx_chain_num = 0;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	rt2x00lib_config_antenna(rt2x00dev, setup);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return 0;
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_set_antenna);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ciint rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
79162306a36Sopenharmony_ci	struct link_ant *ant = &rt2x00dev->link.ant;
79262306a36Sopenharmony_ci	struct antenna_setup *active = &rt2x00dev->link.ant.active;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	// When software diversity is active, we must report this to the
79562306a36Sopenharmony_ci	// client and not the current active antenna state.
79662306a36Sopenharmony_ci	if (ant->flags & ANTENNA_TX_DIVERSITY)
79762306a36Sopenharmony_ci		*tx_ant = ANTENNA_HW_DIVERSITY;
79862306a36Sopenharmony_ci	else
79962306a36Sopenharmony_ci		*tx_ant = active->tx;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (ant->flags & ANTENNA_RX_DIVERSITY)
80262306a36Sopenharmony_ci		*rx_ant = ANTENNA_HW_DIVERSITY;
80362306a36Sopenharmony_ci	else
80462306a36Sopenharmony_ci		*rx_ant = active->rx;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	return 0;
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_get_antenna);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_civoid rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
81162306a36Sopenharmony_ci			     u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
81462306a36Sopenharmony_ci	struct data_queue *queue;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue) {
81762306a36Sopenharmony_ci		*tx += queue->length;
81862306a36Sopenharmony_ci		*tx_max += queue->limit;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	*rx = rt2x00dev->rx->length;
82262306a36Sopenharmony_ci	*rx_max = rt2x00dev->rx->limit;
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cibool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = hw->priv;
82962306a36Sopenharmony_ci	struct data_queue *queue;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue) {
83262306a36Sopenharmony_ci		if (!rt2x00queue_empty(queue))
83362306a36Sopenharmony_ci			return true;
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return false;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_tx_frames_pending);
839