summaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c79
1 files changed, 67 insertions, 12 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e821d1ac5b00..84999791a332 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -595,8 +595,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta, int deauth)
{
- if (deauth)
+ if (deauth) {
+ ifsta->direct_probe_tries = 0;
ifsta->auth_tries = 0;
+ }
ifsta->assoc_scan_tries = 0;
ifsta->assoc_tries = 0;
ieee80211_set_associated(sdata, ifsta, 0);
@@ -654,6 +656,36 @@ static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_tx(sdata, skb, encrypt);
}
+static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta)
+{
+ DECLARE_MAC_BUF(mac);
+
+ ifsta->direct_probe_tries++;
+ if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
+ printk(KERN_DEBUG "%s: direct probe to AP %s timed out\n",
+ sdata->dev->name, print_mac(mac, ifsta->bssid));
+ ifsta->state = IEEE80211_STA_MLME_DISABLED;
+ return;
+ }
+
+ printk(KERN_DEBUG "%s: direct probe to AP %s try %d\n",
+ sdata->dev->name, print_mac(mac, ifsta->bssid),
+ ifsta->direct_probe_tries);
+
+ ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+
+ set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request);
+
+ /* Direct probe is sent to broadcast address as some APs
+ * will not answer to direct packet in unassociated state.
+ */
+ ieee80211_send_probe_req(sdata, NULL,
+ ifsta->ssid, ifsta->ssid_len);
+
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+}
+
static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
@@ -1947,7 +1979,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE ||
ifsta->state == IEEE80211_STA_MLME_ASSOCIATE ||
ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
- ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+ ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
mod_timer(&ifsta->timer, jiffies +
IEEE80211_RETRY_AUTH_INTERVAL);
}
@@ -2540,8 +2572,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status,
- struct ieee802_11_elems *elems,
- int beacon)
+ struct ieee802_11_elems *elems)
{
struct ieee80211_local *local = sdata->local;
int freq, clen;
@@ -2549,6 +2580,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta;
u64 beacon_timestamp, rx_timestamp;
struct ieee80211_channel *channel;
+ bool beacon = ieee80211_is_beacon(mgmt->frame_control);
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);
@@ -2705,15 +2737,14 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
bss->signal = rx_status->signal;
bss->noise = rx_status->noise;
bss->qual = rx_status->qual;
- if (!beacon && !bss->probe_resp)
- bss->probe_resp = true;
-
+ if (!beacon)
+ bss->last_probe_resp = jiffies;
/*
* In STA mode, the remaining parameters should not be overridden
* by beacons because they're not necessarily accurate there.
*/
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- bss->probe_resp && beacon) {
+ bss->last_probe_resp && beacon) {
ieee80211_rx_bss_put(local, bss);
return;
}
@@ -2868,6 +2899,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
{
size_t baselen;
struct ieee802_11_elems elems;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
return; /* ignore ProbeResp to foreign address */
@@ -2879,7 +2911,15 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
&elems);
- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, 0);
+ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
+
+ /* direct probe may be part of the association flow */
+ if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE,
+ &ifsta->request)) {
+ printk(KERN_DEBUG "%s direct probe responded\n",
+ sdata->dev->name);
+ ieee80211_authenticate(sdata, ifsta);
+ }
}
@@ -2902,7 +2942,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, 1);
+ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
return;
@@ -3329,7 +3369,8 @@ void ieee80211_sta_work(struct work_struct *work)
mesh_path_start_discovery(sdata);
#endif
- if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
+ if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
+ ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
if (ifsta->scan_ssid_len)
@@ -3349,6 +3390,9 @@ void ieee80211_sta_work(struct work_struct *work)
switch (ifsta->state) {
case IEEE80211_STA_MLME_DISABLED:
break;
+ case IEEE80211_STA_MLME_DIRECT_PROBE:
+ ieee80211_direct_probe(sdata, ifsta);
+ break;
case IEEE80211_STA_MLME_AUTHENTICATE:
ieee80211_authenticate(sdata, ifsta);
break;
@@ -3408,6 +3452,7 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata,
ifsta->auth_transaction = -1;
ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
ifsta->assoc_scan_tries = 0;
+ ifsta->direct_probe_tries = 0;
ifsta->auth_tries = 0;
ifsta->assoc_tries = 0;
netif_carrier_off(sdata->dev);
@@ -3509,8 +3554,18 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
selected->ssid_len);
ieee80211_sta_set_bssid(sdata, selected->bssid);
ieee80211_sta_def_wmm_params(sdata, selected, 0);
+
+ /* Send out direct probe if no probe resp was received or
+ * the one we have is outdated
+ */
+ if (!selected->last_probe_resp ||
+ time_after(jiffies, selected->last_probe_resp
+ + IEEE80211_SCAN_RESULT_EXPIRE))
+ ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+ else
+ ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+
ieee80211_rx_bss_put(local, selected);
- ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
ieee80211_sta_reset_auth(sdata, ifsta);
return 0;
} else {