aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-07-29 10:08:55 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-29 12:55:00 -0400
commite5b900d228b76d445a4240d9aeb3cd8f79205a91 (patch)
treedffa32e827e2d6e5388430ae5ec732f0ca023b11
parentd28232b461b8d54b09e59325dbac8b0913ce2049 (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.h9
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/mlme.c32
-rw-r--r--net/mac80211/scan.c4
-rw-r--r--net/mac80211/work.c43
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 */
1031enum ieee80211_hw_flags { 1036enum 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
563static enum work_action __must_check
564ieee80211_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}
578
563static void ieee80211_auth_challenge(struct ieee80211_work *wk, 579static void ieee80211_auth_challenge(struct ieee80211_work *wk,
564 struct ieee80211_mgmt *mgmt, 580 struct ieee80211_mgmt *mgmt,
565 size_t len) 581 size_t len)
@@ -709,6 +725,25 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
709 return WORK_ACT_DONE; 725 return WORK_ACT_DONE;
710} 726}
711 727
728static enum work_action __must_check
729ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk,
730 struct ieee80211_mgmt *mgmt, size_t len)
731{
732 struct ieee80211_sub_if_data *sdata = wk->sdata;
733 struct ieee80211_local *local = sdata->local;
734
735 ASSERT_WORK_MTX(local);
736
737 if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
738 return WORK_ACT_MISMATCH;
739
740 if (len < 24 + 12)
741 return WORK_ACT_NONE;
742
743 printk(KERN_DEBUG "%s: beacon received\n", sdata->name);
744 return WORK_ACT_DONE;
745}
746
712static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, 747static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
713 struct sk_buff *skb) 748 struct sk_buff *skb)
714{ 749{
@@ -731,6 +766,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
731 case IEEE80211_WORK_DIRECT_PROBE: 766 case IEEE80211_WORK_DIRECT_PROBE:
732 case IEEE80211_WORK_AUTH: 767 case IEEE80211_WORK_AUTH:
733 case IEEE80211_WORK_ASSOC: 768 case IEEE80211_WORK_ASSOC:
769 case IEEE80211_WORK_ASSOC_BEACON_WAIT:
734 bssid = wk->filter_ta; 770 bssid = wk->filter_ta;
735 break; 771 break;
736 default: 772 default:
@@ -745,6 +781,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
745 continue; 781 continue;
746 782
747 switch (fc & IEEE80211_FCTL_STYPE) { 783 switch (fc & IEEE80211_FCTL_STYPE) {
784 case IEEE80211_STYPE_BEACON:
785 rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len);
786 break;
748 case IEEE80211_STYPE_PROBE_RESP: 787 case IEEE80211_STYPE_PROBE_RESP:
749 rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len, 788 rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
750 rx_status); 789 rx_status);
@@ -916,6 +955,9 @@ static void ieee80211_work_work(struct work_struct *work)
916 case IEEE80211_WORK_REMAIN_ON_CHANNEL: 955 case IEEE80211_WORK_REMAIN_ON_CHANNEL:
917 rma = ieee80211_remain_on_channel_timeout(wk); 956 rma = ieee80211_remain_on_channel_timeout(wk);
918 break; 957 break;
958 case IEEE80211_WORK_ASSOC_BEACON_WAIT:
959 rma = ieee80211_assoc_beacon_wait(wk);
960 break;
919 } 961 }
920 962
921 wk->started = started; 963 wk->started = started;
@@ -1065,6 +1107,7 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
1065 case IEEE80211_STYPE_PROBE_RESP: 1107 case IEEE80211_STYPE_PROBE_RESP:
1066 case IEEE80211_STYPE_ASSOC_RESP: 1108 case IEEE80211_STYPE_ASSOC_RESP:
1067 case IEEE80211_STYPE_REASSOC_RESP: 1109 case IEEE80211_STYPE_REASSOC_RESP:
1110 case IEEE80211_STYPE_BEACON:
1068 skb_queue_tail(&local->work_skb_queue, skb); 1111 skb_queue_tail(&local->work_skb_queue, skb);
1069 ieee80211_queue_work(&local->hw, &local->work_work); 1112 ieee80211_queue_work(&local->hw, &local->work_work);
1070 return RX_QUEUED; 1113 return RX_QUEUED;