summaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c251
1 files changed, 161 insertions, 90 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 32f7a3b3d43c..22f2216b397e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -106,7 +106,7 @@ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
}
}
-int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
int rate, int erp, int short_preamble)
{
int dur;
@@ -120,7 +120,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
* DIV_ROUND_UP() operations.
*/
- if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
+ if (band == IEEE80211_BAND_5GHZ || erp) {
/*
* OFDM:
*
@@ -162,10 +162,10 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
/* Exported duration function for driver use */
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
+ enum ieee80211_band band,
size_t frame_len,
struct ieee80211_rate *rate)
{
- struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
u16 dur;
int erp;
@@ -179,7 +179,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
erp = rate->flags & IEEE80211_RATE_ERP_G;
}
- dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
+ dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp,
short_preamble);
return cpu_to_le16(dur);
@@ -198,7 +198,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
u16 dur;
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[frame_txctl->band];
short_preamble = false;
@@ -213,13 +213,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
}
/* CTS duration */
- dur = ieee80211_frame_duration(local, 10, rate->bitrate,
+ dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate,
erp, short_preamble);
/* Data frame duration */
- dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
+ dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
erp, short_preamble);
/* ACK duration */
- dur += ieee80211_frame_duration(local, 10, rate->bitrate,
+ dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
erp, short_preamble);
return cpu_to_le16(dur);
@@ -239,7 +239,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
u16 dur;
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[frame_txctl->band];
short_preamble = false;
@@ -253,11 +253,11 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
}
/* Data frame duration */
- dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
+ dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
erp, short_preamble);
if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ACK duration */
- dur += ieee80211_frame_duration(local, 10, rate->bitrate,
+ dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
erp, short_preamble);
}
@@ -265,17 +265,45 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_ctstoself_duration);
+void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ int ac;
+
+ if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+ continue;
+
+ if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
+ local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
+ continue;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ int ac_queue = sdata->vif.hw_queue[ac];
+
+ if (ac_queue == queue ||
+ (sdata->vif.cab_queue == queue &&
+ local->queue_stop_reasons[ac_queue] == 0 &&
+ skb_queue_empty(&local->pending[ac_queue])))
+ netif_wake_subqueue(sdata->dev, ac);
+ }
+ }
+}
+
static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata;
trace_wake_queue(local, queue, reason);
if (WARN_ON(queue >= hw->queues))
return;
+ if (!test_bit(reason, &local->queue_stop_reasons[queue]))
+ return;
+
__clear_bit(reason, &local->queue_stop_reasons[queue]);
if (local->queue_stop_reasons[queue] != 0)
@@ -284,11 +312,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
if (skb_queue_empty(&local->pending[queue])) {
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
- continue;
- netif_wake_subqueue(sdata->dev, queue);
- }
+ ieee80211_propagate_queue_wake(local, queue);
rcu_read_unlock();
} else
tasklet_schedule(&local->tx_pending_tasklet);
@@ -323,11 +347,21 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
if (WARN_ON(queue >= hw->queues))
return;
+ if (test_bit(reason, &local->queue_stop_reasons[queue]))
+ return;
+
__set_bit(reason, &local->queue_stop_reasons[queue]);
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- netif_stop_subqueue(sdata->dev, queue);
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ int ac;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ if (sdata->vif.hw_queue[ac] == queue ||
+ sdata->vif.cab_queue == queue)
+ netif_stop_subqueue(sdata->dev, ac);
+ }
+ }
rcu_read_unlock();
}
@@ -354,8 +388,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
{
struct ieee80211_hw *hw = &local->hw;
unsigned long flags;
- int queue = skb_get_queue_mapping(skb);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int queue = info->hw_queue;
if (WARN_ON(!info->control.vif)) {
kfree_skb(skb);
@@ -379,10 +413,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
int queue, i;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for (i = 0; i < hw->queues; i++)
- __ieee80211_stop_queue(hw, i,
- IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
-
while ((skb = skb_dequeue(skbs))) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -391,7 +421,11 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
continue;
}
- queue = skb_get_queue_mapping(skb);
+ queue = info->hw_queue;
+
+ __ieee80211_stop_queue(hw, queue,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+
__skb_queue_tail(&local->pending[queue], skb);
}
@@ -404,12 +438,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
-void ieee80211_add_pending_skbs(struct ieee80211_local *local,
- struct sk_buff_head *skbs)
-{
- ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
-}
-
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason)
{
@@ -684,9 +712,9 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
else
elem_parse_failed = true;
break;
- case WLAN_EID_HT_INFORMATION:
- if (elen >= sizeof(struct ieee80211_ht_info))
- elems->ht_info_elem = (void *)pos;
+ case WLAN_EID_HT_OPERATION:
+ if (elen >= sizeof(struct ieee80211_ht_operation))
+ elems->ht_operation = (void *)pos;
else
elem_parse_failed = true;
break;
@@ -775,19 +803,22 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
- int queue;
+ int ac;
bool use_11b;
int aCWmin, aCWmax;
if (!local->ops->conf_tx)
return;
+ if (local->hw.queues < IEEE80211_NUM_ACS)
+ return;
+
memset(&qparam, 0, sizeof(qparam));
use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
- for (queue = 0; queue < local->hw.queues; queue++) {
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
/* Set defaults according to 802.11-2007 Table 7-37 */
aCWmax = 1023;
if (use_11b)
@@ -795,21 +826,21 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
else
aCWmin = 15;
- switch (queue) {
- case 3: /* AC_BK */
+ switch (ac) {
+ case IEEE80211_AC_BK:
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
qparam.aifs = 7;
break;
default: /* never happens but let's not leave undefined */
- case 2: /* AC_BE */
+ case IEEE80211_AC_BE:
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
qparam.aifs = 3;
break;
- case 1: /* AC_VI */
+ case IEEE80211_AC_VI:
qparam.cw_max = aCWmin;
qparam.cw_min = (aCWmin + 1) / 2 - 1;
if (use_11b)
@@ -818,7 +849,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
qparam.txop = 3008/32;
qparam.aifs = 2;
break;
- case 0: /* AC_VO */
+ case IEEE80211_AC_VO:
qparam.cw_max = (aCWmin + 1) / 2 - 1;
qparam.cw_min = (aCWmin + 1) / 4 - 1;
if (use_11b)
@@ -831,8 +862,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
qparam.uapsd = false;
- sdata->tx_conf[queue] = qparam;
- drv_conf_tx(local, sdata, queue, &qparam);
+ sdata->tx_conf[ac] = qparam;
+ drv_conf_tx(local, sdata, ac, &qparam);
}
/* after reinitialize QoS TX queues setting to default,
@@ -878,10 +909,8 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
int i;
sband = local->hw.wiphy->bands[band];
- if (!sband) {
- WARN_ON(1);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- }
+ if (WARN_ON(!sband))
+ return 1;
if (band == IEEE80211_BAND_2GHZ)
mandatory_flag = IEEE80211_RATE_MANDATORY_B;
@@ -1106,7 +1135,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
struct ieee802_11_elems *elems,
- enum ieee80211_band band)
+ enum ieee80211_band band, u32 *basic_rates)
{
struct ieee80211_supported_band *sband;
struct ieee80211_rate *bitrates;
@@ -1115,10 +1144,8 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
int i, j;
sband = local->hw.wiphy->bands[band];
- if (!sband) {
- WARN_ON(1);
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- }
+ if (WARN_ON(!sband))
+ return 1;
bitrates = sband->bitrates;
num_rates = sband->n_bitrates;
@@ -1127,15 +1154,25 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
elems->ext_supp_rates_len; i++) {
u8 rate = 0;
int own_rate;
+ bool is_basic;
if (i < elems->supp_rates_len)
rate = elems->supp_rates[i];
else if (elems->ext_supp_rates)
rate = elems->ext_supp_rates
[i - elems->supp_rates_len];
own_rate = 5 * (rate & 0x7f);
- for (j = 0; j < num_rates; j++)
- if (bitrates[j].bitrate == own_rate)
+ is_basic = !!(rate & 0x80);
+
+ if (is_basic && (rate & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+ continue;
+
+ for (j = 0; j < num_rates; j++) {
+ if (bitrates[j].bitrate == own_rate) {
supp_rates |= BIT(j);
+ if (basic_rates && is_basic)
+ *basic_rates |= BIT(j);
+ }
+ }
}
return supp_rates;
}
@@ -1210,6 +1247,16 @@ int ieee80211_reconfig(struct ieee80211_local *local)
IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
/* add interfaces */
+ sdata = rtnl_dereference(local->monitor_sdata);
+ if (sdata) {
+ res = drv_add_interface(local, sdata);
+ if (WARN_ON(res)) {
+ rcu_assign_pointer(local->monitor_sdata, NULL);
+ synchronize_net();
+ kfree(sdata);
+ }
+ }
+
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
@@ -1232,14 +1279,17 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_unlock(&local->sta_mtx);
/* reconfigure tx conf */
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
- sdata->vif.type == NL80211_IFTYPE_MONITOR ||
- !ieee80211_sdata_running(sdata))
- continue;
+ if (hw->queues >= IEEE80211_NUM_ACS) {
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ !ieee80211_sdata_running(sdata))
+ continue;
- for (i = 0; i < hw->queues; i++)
- drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ drv_conf_tx(local, sdata, i,
+ &sdata->tx_conf[i]);
+ }
}
/* reconfigure hardware */
@@ -1611,57 +1661,55 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
return pos;
}
-u8 *ieee80211_ie_build_ht_info(u8 *pos,
- struct ieee80211_sta_ht_cap *ht_cap,
+u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type)
+ enum nl80211_channel_type channel_type,
+ u16 prot_mode)
{
- struct ieee80211_ht_info *ht_info;
+ struct ieee80211_ht_operation *ht_oper;
/* Build HT Information */
- *pos++ = WLAN_EID_HT_INFORMATION;
- *pos++ = sizeof(struct ieee80211_ht_info);
- ht_info = (struct ieee80211_ht_info *)pos;
- ht_info->control_chan =
+ *pos++ = WLAN_EID_HT_OPERATION;
+ *pos++ = sizeof(struct ieee80211_ht_operation);
+ ht_oper = (struct ieee80211_ht_operation *)pos;
+ ht_oper->primary_chan =
ieee80211_frequency_to_channel(channel->center_freq);
switch (channel_type) {
case NL80211_CHAN_HT40MINUS:
- ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
break;
case NL80211_CHAN_HT40PLUS:
- ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
break;
case NL80211_CHAN_HT20:
default:
- ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
break;
}
- if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
- ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+ if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
+ channel_type != NL80211_CHAN_NO_HT &&
+ channel_type != NL80211_CHAN_HT20)
+ ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
- /*
- * Note: According to 802.11n-2009 9.13.3.1, HT Protection field and
- * RIFS Mode are reserved in IBSS mode, therefore keep them at 0
- */
- ht_info->operation_mode = 0x0000;
- ht_info->stbc_param = 0x0000;
+ ht_oper->operation_mode = cpu_to_le16(prot_mode);
+ ht_oper->stbc_param = 0x0000;
/* It seems that Basic MCS set and Supported MCS set
are identical for the first 10 bytes */
- memset(&ht_info->basic_set, 0, 16);
- memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
+ memset(&ht_oper->basic_set, 0, 16);
+ memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10);
- return pos + sizeof(struct ieee80211_ht_info);
+ return pos + sizeof(struct ieee80211_ht_operation);
}
enum nl80211_channel_type
-ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
+ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
{
enum nl80211_channel_type channel_type;
- if (!ht_info)
+ if (!ht_oper)
return NL80211_CHAN_NO_HT;
- switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
channel_type = NL80211_CHAN_HT20;
break;
@@ -1678,13 +1726,15 @@ ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
return channel_type;
}
-int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+int ieee80211_add_srates_ie(struct ieee80211_vif *vif,
+ struct sk_buff *skb, bool need_basic)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
int rate;
u8 i, rates, *pos;
+ u32 basic_rates = vif->bss_conf.basic_rates;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
rates = sband->n_bitrates;
@@ -1698,20 +1748,25 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = rates;
for (i = 0; i < rates; i++) {
+ u8 basic = 0;
+ if (need_basic && basic_rates & BIT(i))
+ basic = 0x80;
rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
+ *pos++ = basic | (u8) (rate / 5);
}
return 0;
}
-int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
+int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
+ struct sk_buff *skb, bool need_basic)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
int rate;
u8 i, exrates, *pos;
+ u32 basic_rates = vif->bss_conf.basic_rates;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
exrates = sband->n_bitrates;
@@ -1728,9 +1783,25 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = exrates;
for (i = 8; i < sband->n_bitrates; i++) {
+ u8 basic = 0;
+ if (need_basic && basic_rates & BIT(i))
+ basic = 0x80;
rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
+ *pos++ = basic | (u8) (rate / 5);
}
}
return 0;
}
+
+int ieee80211_ave_rssi(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) {
+ /* non-managed type inferfaces */
+ return 0;
+ }
+ return ifmgd->ave_beacon_signal;
+}
+EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
OpenPOWER on IntegriCloud