diff options
| author | Johannes Berg <johannes.berg@intel.com> | 2010-07-29 10:08:55 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2010-07-29 12:55:00 -0400 |
| commit | e5b900d228b76d445a4240d9aeb3cd8f79205a91 (patch) | |
| tree | dffa32e827e2d6e5388430ae5ec732f0ca023b11 | |
| parent | d28232b461b8d54b09e59325dbac8b0913ce2049 (diff) | |
mac80211: allow drivers to request DTIM period
Some features require knowing the DTIM period
before associating. This implements the ability
to wait for a beacon in mac80211 before assoc
to provide this value. It is optional since
most likely not all drivers will need this.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | include/net/mac80211.h | 9 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
| -rw-r--r-- | net/mac80211/mlme.c | 32 | ||||
| -rw-r--r-- | net/mac80211/scan.c | 4 | ||||
| -rw-r--r-- | net/mac80211/work.c | 43 |
5 files changed, 84 insertions, 5 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c7027ef51c75..f85fc8a140dc 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -194,7 +194,9 @@ enum ieee80211_bss_change { | |||
| 194 | * if the hardware cannot handle this it must set the | 194 | * if the hardware cannot handle this it must set the |
| 195 | * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag | 195 | * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag |
| 196 | * @dtim_period: num of beacons before the next DTIM, for beaconing, | 196 | * @dtim_period: num of beacons before the next DTIM, for beaconing, |
| 197 | * not valid in station mode (cf. hw conf ps_dtim_period) | 197 | * valid in station mode only while @assoc is true and if also |
| 198 | * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf | ||
| 199 | * @ps_dtim_period) | ||
| 198 | * @timestamp: beacon timestamp | 200 | * @timestamp: beacon timestamp |
| 199 | * @beacon_int: beacon interval | 201 | * @beacon_int: beacon interval |
| 200 | * @assoc_capability: capabilities taken from assoc resp | 202 | * @assoc_capability: capabilities taken from assoc resp |
| @@ -1027,6 +1029,9 @@ enum ieee80211_tkip_key_type { | |||
| 1027 | * connection quality related parameters, such as the RSSI level and | 1029 | * connection quality related parameters, such as the RSSI level and |
| 1028 | * provide notifications if configured trigger levels are reached. | 1030 | * provide notifications if configured trigger levels are reached. |
| 1029 | * | 1031 | * |
| 1032 | * @IEEE80211_HW_NEED_DTIM_PERIOD: | ||
| 1033 | * This device needs to know the DTIM period for the BSS before | ||
| 1034 | * associating. | ||
| 1030 | */ | 1035 | */ |
| 1031 | enum ieee80211_hw_flags { | 1036 | enum ieee80211_hw_flags { |
| 1032 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, | 1037 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, |
| @@ -1036,7 +1041,7 @@ enum ieee80211_hw_flags { | |||
| 1036 | IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, | 1041 | IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, |
| 1037 | IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, | 1042 | IEEE80211_HW_SIGNAL_UNSPEC = 1<<5, |
| 1038 | IEEE80211_HW_SIGNAL_DBM = 1<<6, | 1043 | IEEE80211_HW_SIGNAL_DBM = 1<<6, |
| 1039 | /* use this hole */ | 1044 | IEEE80211_HW_NEED_DTIM_PERIOD = 1<<7, |
| 1040 | IEEE80211_HW_SPECTRUM_MGMT = 1<<8, | 1045 | IEEE80211_HW_SPECTRUM_MGMT = 1<<8, |
| 1041 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<9, | 1046 | IEEE80211_HW_AMPDU_AGGREGATION = 1<<9, |
| 1042 | IEEE80211_HW_SUPPORTS_PS = 1<<10, | 1047 | IEEE80211_HW_SUPPORTS_PS = 1<<10, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ef470064b154..65e0ed6c2975 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -238,6 +238,7 @@ enum ieee80211_work_type { | |||
| 238 | IEEE80211_WORK_ABORT, | 238 | IEEE80211_WORK_ABORT, |
| 239 | IEEE80211_WORK_DIRECT_PROBE, | 239 | IEEE80211_WORK_DIRECT_PROBE, |
| 240 | IEEE80211_WORK_AUTH, | 240 | IEEE80211_WORK_AUTH, |
| 241 | IEEE80211_WORK_ASSOC_BEACON_WAIT, | ||
| 241 | IEEE80211_WORK_ASSOC, | 242 | IEEE80211_WORK_ASSOC, |
| 242 | IEEE80211_WORK_REMAIN_ON_CHANNEL, | 243 | IEEE80211_WORK_REMAIN_ON_CHANNEL, |
| 243 | }; | 244 | }; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cf8d72196c65..b6c163ac22da 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -870,6 +870,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
| 870 | 870 | ||
| 871 | ieee80211_led_assoc(local, 1); | 871 | ieee80211_led_assoc(local, 1); |
| 872 | 872 | ||
| 873 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | ||
| 874 | bss_conf->dtim_period = bss->dtim_period; | ||
| 875 | else | ||
| 876 | bss_conf->dtim_period = 0; | ||
| 877 | |||
| 873 | bss_conf->assoc = 1; | 878 | bss_conf->assoc = 1; |
| 874 | /* | 879 | /* |
| 875 | * For now just always ask the driver to update the basic rateset | 880 | * For now just always ask the driver to update the basic rateset |
| @@ -1751,7 +1756,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1751 | if (wk->sdata != sdata) | 1756 | if (wk->sdata != sdata) |
| 1752 | continue; | 1757 | continue; |
| 1753 | 1758 | ||
| 1754 | if (wk->type != IEEE80211_WORK_ASSOC) | 1759 | if (wk->type != IEEE80211_WORK_ASSOC && |
| 1760 | wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
| 1755 | continue; | 1761 | continue; |
| 1756 | 1762 | ||
| 1757 | if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) | 1763 | if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) |
| @@ -2086,6 +2092,8 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
| 2086 | struct sk_buff *skb) | 2092 | struct sk_buff *skb) |
| 2087 | { | 2093 | { |
| 2088 | struct ieee80211_mgmt *mgmt; | 2094 | struct ieee80211_mgmt *mgmt; |
| 2095 | struct ieee80211_rx_status *rx_status; | ||
| 2096 | struct ieee802_11_elems elems; | ||
| 2089 | u16 status; | 2097 | u16 status; |
| 2090 | 2098 | ||
| 2091 | if (!skb) { | 2099 | if (!skb) { |
| @@ -2093,6 +2101,19 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
| 2093 | return WORK_DONE_DESTROY; | 2101 | return WORK_DONE_DESTROY; |
| 2094 | } | 2102 | } |
| 2095 | 2103 | ||
| 2104 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { | ||
| 2105 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
| 2106 | rx_status = (void *) skb->cb; | ||
| 2107 | ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems); | ||
| 2108 | ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status, | ||
| 2109 | &elems, true); | ||
| 2110 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
| 2111 | |||
| 2112 | wk->type = IEEE80211_WORK_ASSOC; | ||
| 2113 | /* not really done yet */ | ||
| 2114 | return WORK_DONE_REQUEUE; | ||
| 2115 | } | ||
| 2116 | |||
| 2096 | mgmt = (void *)skb->data; | 2117 | mgmt = (void *)skb->data; |
| 2097 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 2118 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
| 2098 | 2119 | ||
| @@ -2206,10 +2227,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 2206 | if (req->prev_bssid) | 2227 | if (req->prev_bssid) |
| 2207 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); | 2228 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); |
| 2208 | 2229 | ||
| 2209 | wk->type = IEEE80211_WORK_ASSOC; | ||
| 2210 | wk->chan = req->bss->channel; | 2230 | wk->chan = req->bss->channel; |
| 2211 | wk->sdata = sdata; | 2231 | wk->sdata = sdata; |
| 2212 | wk->done = ieee80211_assoc_done; | 2232 | wk->done = ieee80211_assoc_done; |
| 2233 | if (!bss->dtim_period && | ||
| 2234 | sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | ||
| 2235 | wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT; | ||
| 2236 | else | ||
| 2237 | wk->type = IEEE80211_WORK_ASSOC; | ||
| 2213 | 2238 | ||
| 2214 | if (req->use_mfp) { | 2239 | if (req->use_mfp) { |
| 2215 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | 2240 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; |
| @@ -2257,7 +2282,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 2257 | 2282 | ||
| 2258 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && | 2283 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && |
| 2259 | wk->type != IEEE80211_WORK_AUTH && | 2284 | wk->type != IEEE80211_WORK_AUTH && |
| 2260 | wk->type != IEEE80211_WORK_ASSOC) | 2285 | wk->type != IEEE80211_WORK_ASSOC && |
| 2286 | wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
| 2261 | continue; | 2287 | continue; |
| 2262 | 2288 | ||
| 2263 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | 2289 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 41635b2c91bf..41f20fb7e670 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -114,6 +114,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
| 114 | bss->dtim_period = tim_ie->dtim_period; | 114 | bss->dtim_period = tim_ie->dtim_period; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /* If the beacon had no TIM IE, or it was invalid, use 1 */ | ||
| 118 | if (beacon && !bss->dtim_period) | ||
| 119 | bss->dtim_period = 1; | ||
| 120 | |||
| 117 | /* replace old supported rates if we get new values */ | 121 | /* replace old supported rates if we get new values */ |
| 118 | srlen = 0; | 122 | srlen = 0; |
| 119 | if (elems->supp_rates) { | 123 | if (elems->supp_rates) { |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index c22a71c5cb45..81d4ad64184a 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
| @@ -560,6 +560,22 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) | |||
| 560 | return WORK_ACT_TIMEOUT; | 560 | return WORK_ACT_TIMEOUT; |
| 561 | } | 561 | } |
| 562 | 562 | ||
| 563 | static enum work_action __must_check | ||
| 564 | ieee80211_assoc_beacon_wait(struct ieee80211_work *wk) | ||
| 565 | { | ||
| 566 | if (wk->started) | ||
| 567 | return WORK_ACT_TIMEOUT; | ||
| 568 | |||
| 569 | /* | ||
| 570 | * Wait up to one beacon interval ... | ||
| 571 | * should this be more if we miss one? | ||
| 572 | */ | ||
| 573 | printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", | ||
| 574 | wk->sdata->name, wk->filter_ta); | ||
| 575 | wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval); | ||
| 576 | return WORK_ACT_NONE; | ||
| 577 | } | ||
