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.c168
1 files changed, 136 insertions, 32 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 556647a910a..ddeb1b99838 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -799,6 +799,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
qparam.uapsd = false;
+ local->tx_conf[queue] = qparam;
drv_conf_tx(local, queue, &qparam);
}
@@ -1016,9 +1017,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
}
struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
- u8 *dst,
+ u8 *dst, u32 ratemask,
const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len)
+ const u8 *ie, size_t ie_len,
+ bool directed)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
@@ -1035,14 +1037,20 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
return NULL;
}
- chan = ieee80211_frequency_to_channel(
- local->hw.conf.channel->center_freq);
+ /*
+ * Do not send DS Channel parameter for directed probe requests
+ * in order to maximize the chance that we get a response. Some
+ * badly-behaved APs don't respond when this parameter is included.
+ */
+ if (directed)
+ chan = 0;
+ else
+ chan = ieee80211_frequency_to_channel(
+ local->hw.conf.channel->center_freq);
buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
local->hw.conf.channel->band,
- sdata->rc_rateidx_mask
- [local->hw.conf.channel->band],
- chan);
+ ratemask, chan);
skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
ssid, ssid_len,
@@ -1062,11 +1070,13 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len)
+ const u8 *ie, size_t ie_len,
+ u32 ratemask, bool directed)
{
struct sk_buff *skb;
- skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len);
+ skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
+ ie, ie_len, directed);
if (skb)
ieee80211_tx_skb(sdata, skb);
}
@@ -1123,32 +1133,60 @@ int ieee80211_reconfig(struct ieee80211_local *local)
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
- int res;
+ int res, i;
+#ifdef CONFIG_PM
if (local->suspended)
local->resuming = true;
- /* restart hardware */
- if (local->open_count) {
- /*
- * Upon resume hardware can sometimes be goofy due to
- * various platform / driver / bus issues, so restarting
- * the device may at times not work immediately. Propagate
- * the error.
- */
- res = drv_start(local);
- if (res) {
- WARN(local->suspended, "Hardware became unavailable "
- "upon resume. This could be a software issue "
- "prior to suspend or a hardware issue.\n");
+ if (local->wowlan) {
+ local->wowlan = false;
+ res = drv_resume(local);
+ if (res < 0) {
+ local->resuming = false;
return res;
}
+ if (res == 0)
+ goto wake_up;
+ WARN_ON(res > 1);
+ /*
+ * res is 1, which means the driver requested
+ * to go through a regular reset on wakeup.
+ */
+ }
+#endif
- ieee80211_led_radio(local, true);
- ieee80211_mod_tpt_led_trig(local,
- IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
+ /* setup fragmentation threshold */
+ drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
+
+ /* setup RTS threshold */
+ drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
+
+ /* reset coverage class */
+ drv_set_coverage_class(local, hw->wiphy->coverage_class);
+
+ /* everything else happens only if HW was up & running */
+ if (!local->open_count)
+ goto wake_up;
+
+ /*
+ * Upon resume hardware can sometimes be goofy due to
+ * various platform / driver / bus issues, so restarting
+ * the device may at times not work immediately. Propagate
+ * the error.
+ */
+ res = drv_start(local);
+ if (res) {
+ WARN(local->suspended, "Hardware became unavailable "
+ "upon resume. This could be a software issue "
+ "prior to suspend or a hardware issue.\n");
+ return res;
}
+ ieee80211_led_radio(local, true);
+ ieee80211_mod_tpt_led_trig(local,
+ IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
+
/* add interfaces */
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
@@ -1172,11 +1210,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
mutex_unlock(&local->sta_mtx);
- /* setup fragmentation threshold */
- drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
-
- /* setup RTS threshold */
- drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
+ /* reconfigure tx conf */
+ for (i = 0; i < hw->queues; i++)
+ drv_conf_tx(local, i, &local->tx_conf[i]);
/* reconfigure hardware */
ieee80211_hw_config(local, ~0);
@@ -1258,6 +1294,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (ieee80211_sdata_running(sdata))
ieee80211_enable_keys(sdata);
+ wake_up:
ieee80211_wake_queues_by_reason(hw,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
@@ -1290,7 +1327,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
}
- add_timer(&local->sta_cleanup);
+ mod_timer(&local->sta_cleanup, jiffies + 1);
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list)
@@ -1302,6 +1339,33 @@ int ieee80211_reconfig(struct ieee80211_local *local)
return 0;
}
+void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local;
+ struct ieee80211_key *key;
+
+ if (WARN_ON(!vif))
+ return;
+
+ sdata = vif_to_sdata(vif);
+ local = sdata->local;
+
+ if (WARN_ON(!local->resuming))
+ return;
+
+ if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+ return;
+
+ sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
+
+ mutex_lock(&local->key_mtx);
+ list_for_each_entry(key, &sdata->key_list, list)
+ key->flags |= KEY_FLAG_TAINTED;
+ mutex_unlock(&local->key_mtx);
+}
+EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
+
static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
enum ieee80211_smps_mode *smps_mode)
{
@@ -1418,3 +1482,43 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
return pos;
}
+
+static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata,
+ int rssi_min_thold,
+ int rssi_max_thold)
+{
+ trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold);
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return;
+
+ /*
+ * Scale up threshold values before storing it, as the RSSI averaging
+ * algorithm uses a scaled up value as well. Change this scaling
+ * factor if the RSSI averaging algorithm changes.
+ */
+ sdata->u.mgd.rssi_min_thold = rssi_min_thold*16;
+ sdata->u.mgd.rssi_max_thold = rssi_max_thold*16;
+}
+
+void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
+ int rssi_min_thold,
+ int rssi_max_thold)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ WARN_ON(rssi_min_thold == rssi_max_thold ||
+ rssi_min_thold > rssi_max_thold);
+
+ _ieee80211_enable_rssi_reports(sdata, rssi_min_thold,
+ rssi_max_thold);
+}
+EXPORT_SYMBOL(ieee80211_enable_rssi_reports);
+
+void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ _ieee80211_enable_rssi_reports(sdata, 0, 0);
+}
+EXPORT_SYMBOL(ieee80211_disable_rssi_reports);