aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/work.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/mac80211/work.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'net/mac80211/work.c')
-rw-r--r--net/mac80211/work.c209
1 files changed, 152 insertions, 57 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 81d4ad64184a..d2e7f0e86677 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -30,7 +30,6 @@
30#define IEEE80211_AUTH_MAX_TRIES 3 30#define IEEE80211_AUTH_MAX_TRIES 3
31#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) 31#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
32#define IEEE80211_ASSOC_MAX_TRIES 3 32#define IEEE80211_ASSOC_MAX_TRIES 3
33#define IEEE80211_MAX_PROBE_TRIES 5
34 33
35enum work_action { 34enum work_action {
36 WORK_ACT_MISMATCH, 35 WORK_ACT_MISMATCH,
@@ -43,7 +42,7 @@ enum work_action {
43/* utils */ 42/* utils */
44static inline void ASSERT_WORK_MTX(struct ieee80211_local *local) 43static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
45{ 44{
46 WARN_ON(!mutex_is_locked(&local->work_mtx)); 45 lockdep_assert_held(&local->mtx);
47} 46}
48 47
49/* 48/*
@@ -66,17 +65,9 @@ static void run_again(struct ieee80211_local *local,
66 mod_timer(&local->work_timer, timeout); 65 mod_timer(&local->work_timer, timeout);
67} 66}
68 67
69static void work_free_rcu(struct rcu_head *head)
70{
71 struct ieee80211_work *wk =
72 container_of(head, struct ieee80211_work, rcu_head);
73
74 kfree(wk);
75}
76
77void free_work(struct ieee80211_work *wk) 68void free_work(struct ieee80211_work *wk)
78{ 69{
79 call_rcu(&wk->rcu_head, work_free_rcu); 70 kfree_rcu(wk, rcu_head);
80} 71}
81 72
82static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, 73static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
@@ -126,12 +117,6 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
126 117
127 /* determine capability flags */ 118 /* determine capability flags */
128 119
129 if (ieee80211_disable_40mhz_24ghz &&
130 sband->band == IEEE80211_BAND_2GHZ) {
131 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
132 cap &= ~IEEE80211_HT_CAP_SGI_40;
133 }
134
135 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 120 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
136 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 121 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
137 if (flags & IEEE80211_CHAN_NO_HT40PLUS) { 122 if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
@@ -205,9 +190,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
205 struct sk_buff *skb; 190 struct sk_buff *skb;
206 struct ieee80211_mgmt *mgmt; 191 struct ieee80211_mgmt *mgmt;
207 u8 *pos, qos_info; 192 u8 *pos, qos_info;
208 const u8 *ies;
209 size_t offset = 0, noffset; 193 size_t offset = 0, noffset;
210 int i, len, count, rates_len, supp_rates_len; 194 int i, count, rates_len, supp_rates_len;
211 u16 capab; 195 u16 capab;
212 struct ieee80211_supported_band *sband; 196 struct ieee80211_supported_band *sband;
213 u32 rates = 0; 197 u32 rates = 0;
@@ -292,7 +276,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
292 } 276 }
293 277
294 /* SSID */ 278 /* SSID */
295 ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); 279 pos = skb_put(skb, 2 + wk->assoc.ssid_len);
296 *pos++ = WLAN_EID_SSID; 280 *pos++ = WLAN_EID_SSID;
297 *pos++ = wk->assoc.ssid_len; 281 *pos++ = wk->assoc.ssid_len;
298 memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); 282 memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
@@ -302,7 +286,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
302 if (supp_rates_len > 8) 286 if (supp_rates_len > 8)
303 supp_rates_len = 8; 287 supp_rates_len = 8;
304 288
305 len = sband->n_bitrates;
306 pos = skb_put(skb, supp_rates_len + 2); 289 pos = skb_put(skb, supp_rates_len + 2);
307 *pos++ = WLAN_EID_SUPP_RATES; 290 *pos++ = WLAN_EID_SUPP_RATES;
308 *pos++ = supp_rates_len; 291 *pos++ = supp_rates_len;
@@ -458,8 +441,9 @@ ieee80211_direct_probe(struct ieee80211_work *wk)
458 return WORK_ACT_TIMEOUT; 441 return WORK_ACT_TIMEOUT;
459 } 442 }
460 443
461 printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n", 444 printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n",
462 sdata->name, wk->filter_ta, wk->probe_auth.tries); 445 sdata->name, wk->filter_ta, wk->probe_auth.tries,
446 IEEE80211_AUTH_MAX_TRIES);
463 447
464 /* 448 /*
465 * Direct probe is sent to broadcast address as some APs 449 * Direct probe is sent to broadcast address as some APs
@@ -561,6 +545,25 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
561} 545}
562 546
563static enum work_action __must_check 547static enum work_action __must_check
548ieee80211_offchannel_tx(struct ieee80211_work *wk)
549{
550 if (!wk->started) {
551 wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
552
553 /*
554 * After this, offchan_tx.frame remains but now is no
555 * longer a valid pointer -- we still need it as the
556 * cookie for canceling this work.
557 */
558 ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
559
560 return WORK_ACT_NONE;
561 }
562
563 return WORK_ACT_TIMEOUT;
564}
565
566static enum work_action __must_check
564ieee80211_assoc_beacon_wait(struct ieee80211_work *wk) 567ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
565{ 568{
566 if (wk->started) 569 if (wk->started)
@@ -757,7 +760,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
757 mgmt = (struct ieee80211_mgmt *) skb->data; 760 mgmt = (struct ieee80211_mgmt *) skb->data;
758 fc = le16_to_cpu(mgmt->frame_control); 761 fc = le16_to_cpu(mgmt->frame_control);
759 762
760 mutex_lock(&local->work_mtx); 763 mutex_lock(&local->mtx);
761 764
762 list_for_each_entry(wk, &local->work_list, list) { 765 list_for_each_entry(wk, &local->work_list, list) {
763 const u8 *bssid = NULL; 766 const u8 *bssid = NULL;
@@ -833,7 +836,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
833 WARN(1, "unexpected: %d", rma); 836 WARN(1, "unexpected: %d", rma);
834 } 837 }
835 838
836 mutex_unlock(&local->work_mtx); 839 mutex_unlock(&local->mtx);
837 840
838 if (rma != WORK_ACT_DONE) 841 if (rma != WORK_ACT_DONE)
839 goto out; 842 goto out;
@@ -845,15 +848,53 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
845 case WORK_DONE_REQUEUE: 848 case WORK_DONE_REQUEUE:
846 synchronize_rcu(); 849 synchronize_rcu();
847 wk->started = false; /* restart */ 850 wk->started = false; /* restart */
848 mutex_lock(&local->work_mtx); 851 mutex_lock(&local->mtx);
849 list_add_tail(&wk->list, &local->work_list); 852 list_add_tail(&wk->list, &local->work_list);
850 mutex_unlock(&local->work_mtx); 853 mutex_unlock(&local->mtx);
851 } 854 }
852 855
853 out: 856 out:
854 kfree_skb(skb); 857 kfree_skb(skb);
855} 858}
856 859
860static bool ieee80211_work_ct_coexists(enum nl80211_channel_type wk_ct,
861 enum nl80211_channel_type oper_ct)
862{
863 switch (wk_ct) {
864 case NL80211_CHAN_NO_HT:
865 return true;
866 case NL80211_CHAN_HT20:
867 if (oper_ct != NL80211_CHAN_NO_HT)
868 return true;
869 return false;
870 case NL80211_CHAN_HT40MINUS:
871 case NL80211_CHAN_HT40PLUS:
872 return (wk_ct == oper_ct);
873 }
874 WARN_ON(1); /* shouldn't get here */
875 return false;
876}
877
878static enum nl80211_channel_type
879ieee80211_calc_ct(enum nl80211_channel_type wk_ct,
880 enum nl80211_channel_type oper_ct)
881{
882 switch (wk_ct) {
883 case NL80211_CHAN_NO_HT:
884 return oper_ct;
885 case NL80211_CHAN_HT20:
886 if (oper_ct != NL80211_CHAN_NO_HT)
887 return oper_ct;
888 return wk_ct;
889 case NL80211_CHAN_HT40MINUS:
890 case NL80211_CHAN_HT40PLUS:
891 return wk_ct;
892 }
893 WARN_ON(1); /* shouldn't get here */
894 return wk_ct;
895}
896
897
857static void ieee80211_work_timer(unsigned long data) 898static void ieee80211_work_timer(unsigned long data)
858{ 899{
859 struct ieee80211_local *local = (void *) data; 900 struct ieee80211_local *local = (void *) data;
@@ -888,9 +929,9 @@ static void ieee80211_work_work(struct work_struct *work)
888 while ((skb = skb_dequeue(&local->work_skb_queue))) 929 while ((skb = skb_dequeue(&local->work_skb_queue)))
889 ieee80211_work_rx_queued_mgmt(local, skb); 930 ieee80211_work_rx_queued_mgmt(local, skb);
890 931
891 ieee80211_recalc_idle(local); 932 mutex_lock(&local->mtx);
892 933
893 mutex_lock(&local->work_mtx); 934 ieee80211_recalc_idle(local);
894 935
895 list_for_each_entry_safe(wk, tmp, &local->work_list, list) { 936 list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
896 bool started = wk->started; 937 bool started = wk->started;
@@ -904,18 +945,52 @@ static void ieee80211_work_work(struct work_struct *work)
904 } 945 }
905 946
906 if (!started && !local->tmp_channel) { 947 if (!started && !local->tmp_channel) {
948 bool on_oper_chan;
949 bool tmp_chan_changed = false;
950 bool on_oper_chan2;
951 enum nl80211_channel_type wk_ct;
952 on_oper_chan = ieee80211_cfg_on_oper_channel(local);
953
954 /* Work with existing channel type if possible. */
955 wk_ct = wk->chan_type;
956 if (wk->chan == local->hw.conf.channel)
957 wk_ct = ieee80211_calc_ct(wk->chan_type,
958 local->hw.conf.channel_type);
959
960 if (local->tmp_channel)
961 if ((local->tmp_channel != wk->chan) ||
962 (local->tmp_channel_type != wk_ct))
963 tmp_chan_changed = true;
964
965 local->tmp_channel = wk->chan;
966 local->tmp_channel_type = wk_ct;
907 /* 967 /*
908 * TODO: could optimize this by leaving the 968 * Leave the station vifs in awake mode if they
909 * station vifs in awake mode if they 969 * happen to be on the same channel as
910 * happen to be on the same channel as 970 * the requested channel.
911 * the requested channel
912 */ 971 */
913 ieee80211_offchannel_stop_beaconing(local); 972 on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
914 ieee80211_offchannel_stop_station(local); 973 if (on_oper_chan != on_oper_chan2) {
974 if (on_oper_chan2) {
975 /* going off oper channel, PS too */
976 ieee80211_offchannel_stop_vifs(local,
977 true);
978 ieee80211_hw_config(local, 0);
979 } else {
980 /* going on channel, but leave PS
981 * off-channel. */
982 ieee80211_hw_config(local, 0);
983 ieee80211_offchannel_return(local,
984 true,
985 false);
986 }
987 } else if (tmp_chan_changed)
988 /* Still off-channel, but on some other
989 * channel, so update hardware.
990 * PS should already be off-channel.
991 */
992 ieee80211_hw_config(local, 0);
915 993
916 local->tmp_channel = wk->chan;
917 local->tmp_channel_type = wk->chan_type;
918 ieee80211_hw_config(local, 0);
919 started = true; 994 started = true;
920 wk->timeout = jiffies; 995 wk->timeout = jiffies;
921 } 996 }
@@ -955,6 +1030,9 @@ static void ieee80211_work_work(struct work_struct *work)
955 case IEEE80211_WORK_REMAIN_ON_CHANNEL: 1030 case IEEE80211_WORK_REMAIN_ON_CHANNEL:
956 rma = ieee80211_remain_on_channel_timeout(wk); 1031 rma = ieee80211_remain_on_channel_timeout(wk);
957 break; 1032 break;
1033 case IEEE80211_WORK_OFFCHANNEL_TX:
1034 rma = ieee80211_offchannel_tx(wk);
1035 break;
958 case IEEE80211_WORK_ASSOC_BEACON_WAIT: 1036 case IEEE80211_WORK_ASSOC_BEACON_WAIT:
959 rma = ieee80211_assoc_beacon_wait(wk); 1037 rma = ieee80211_assoc_beacon_wait(wk);
960 break; 1038 break;
@@ -982,33 +1060,48 @@ static void ieee80211_work_work(struct work_struct *work)
982 continue; 1060 continue;
983 if (wk->chan != local->tmp_channel) 1061 if (wk->chan != local->tmp_channel)
984 continue; 1062 continue;
985 if (wk->chan_type != local->tmp_channel_type) 1063 if (ieee80211_work_ct_coexists(wk->chan_type,
1064 local->tmp_channel_type))
986 continue; 1065 continue;
987 remain_off_channel = true; 1066 remain_off_channel = true;
988 } 1067 }
989 1068
990 if (!remain_off_channel && local->tmp_channel) { 1069 if (!remain_off_channel && local->tmp_channel) {
1070 bool on_oper_chan = ieee80211_cfg_on_oper_channel(local);
991 local->tmp_channel = NULL; 1071 local->tmp_channel = NULL;
992 ieee80211_hw_config(local, 0); 1072 /* If tmp_channel wasn't operating channel, then
993 ieee80211_offchannel_return(local, true); 1073 * we need to go back on-channel.
1074 * NOTE: If we can ever be here while scannning,
1075 * or if the hw_config() channel config logic changes,
1076 * then we may need to do a more thorough check to see if
1077 * we still need to do a hardware config. Currently,
1078 * we cannot be here while scanning, however.
1079 */
1080 if (ieee80211_cfg_on_oper_channel(local) && !on_oper_chan)
1081 ieee80211_hw_config(local, 0);
1082
1083 /* At the least, we need to disable offchannel_ps,
1084 * so just go ahead and run the entire offchannel
1085 * return logic here. We *could* skip enabling
1086 * beaconing if we were already on-oper-channel
1087 * as a future optimization.
1088 */
1089 ieee80211_offchannel_return(local, true, true);
1090
994 /* give connection some time to breathe */ 1091 /* give connection some time to breathe */
995 run_again(local, jiffies + HZ/2); 1092 run_again(local, jiffies + HZ/2);
996 } 1093 }
997 1094
998 mutex_lock(&local->scan_mtx);
999
1000 if (list_empty(&local->work_list) && local->scan_req && 1095 if (list_empty(&local->work_list) && local->scan_req &&
1001 !local->scanning) 1096 !local->scanning)
1002 ieee80211_queue_delayed_work(&local->hw, 1097 ieee80211_queue_delayed_work(&local->hw,
1003 &local->scan_work, 1098 &local->scan_work,
1004 round_jiffies_relative(0)); 1099 round_jiffies_relative(0));
1005 1100
1006 mutex_unlock(&local->scan_mtx);
1007
1008 mutex_unlock(&local->work_mtx);
1009
1010 ieee80211_recalc_idle(local); 1101 ieee80211_recalc_idle(local);
1011 1102
1103 mutex_unlock(&local->mtx);
1104
1012 list_for_each_entry_safe(wk, tmp, &free_work, list) { 1105 list_for_each_entry_safe(wk, tmp, &free_work, list) {
1013 wk->done(wk, NULL); 1106 wk->done(wk, NULL);
1014 list_del(&wk->list); 1107 list_del(&wk->list);
@@ -1035,16 +1128,15 @@ void ieee80211_add_work(struct ieee80211_work *wk)
1035 wk->started = false; 1128 wk->started = false;
1036 1129
1037 local = wk->sdata->local; 1130 local = wk->sdata->local;
1038 mutex_lock(&local->work_mtx); 1131 mutex_lock(&local->mtx);
1039 list_add_tail(&wk->list, &local->work_list); 1132 list_add_tail(&wk->list, &local->work_list);
1040 mutex_unlock(&local->work_mtx); 1133 mutex_unlock(&local->mtx);
1041 1134
1042 ieee80211_queue_work(&local->hw, &local->work_work); 1135 ieee80211_queue_work(&local->hw, &local->work_work);
1043} 1136}
1044 1137
1045void ieee80211_work_init(struct ieee80211_local *local) 1138void ieee80211_work_init(struct ieee80211_local *local)
1046{ 1139{
1047 mutex_init(&local->work_mtx);
1048 INIT_LIST_HEAD(&local->work_list); 1140 INIT_LIST_HEAD(&local->work_list);
1049 setup_timer(&local->work_timer, ieee80211_work_timer, 1141 setup_timer(&local->work_timer, ieee80211_work_timer,
1050 (unsigned long)local); 1142 (unsigned long)local);
@@ -1056,28 +1148,31 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
1056{ 1148{
1057 struct ieee80211_local *local = sdata->local; 1149 struct ieee80211_local *local = sdata->local;
1058 struct ieee80211_work *wk; 1150 struct ieee80211_work *wk;
1151 bool cleanup = false;
1059 1152
1060 mutex_lock(&local->work_mtx); 1153 mutex_lock(&local->mtx);
1061 list_for_each_entry(wk, &local->work_list, list) { 1154 list_for_each_entry(wk, &local->work_list, list) {
1062 if (wk->sdata != sdata) 1155 if (wk->sdata != sdata)
1063 continue; 1156 continue;
1157 cleanup = true;
1064 wk->type = IEEE80211_WORK_ABORT; 1158 wk->type = IEEE80211_WORK_ABORT;
1065 wk->started = true; 1159 wk->started = true;
1066 wk->timeout = jiffies; 1160 wk->timeout = jiffies;
1067 } 1161 }
1068 mutex_unlock(&local->work_mtx); 1162 mutex_unlock(&local->mtx);
1069 1163
1070 /* run cleanups etc. */ 1164 /* run cleanups etc. */
1071 ieee80211_work_work(&local->work_work); 1165 if (cleanup)
1166 ieee80211_work_work(&local->work_work);
1072 1167
1073 mutex_lock(&local->work_mtx); 1168 mutex_lock(&local->mtx);
1074 list_for_each_entry(wk, &local->work_list, list) { 1169 list_for_each_entry(wk, &local->work_list, list) {
1075 if (wk->sdata != sdata) 1170 if (wk->sdata != sdata)
1076 continue; 1171 continue;
1077 WARN_ON(1); 1172 WARN_ON(1);
1078 break; 1173 break;
1079 } 1174 }
1080 mutex_unlock(&local->work_mtx); 1175 mutex_unlock(&local->mtx);
1081} 1176}
1082 1177
1083ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, 1178ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -1163,7 +1258,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
1163 struct ieee80211_work *wk, *tmp; 1258 struct ieee80211_work *wk, *tmp;
1164 bool found = false; 1259 bool found = false;
1165 1260
1166 mutex_lock(&local->work_mtx); 1261 mutex_lock(&local->mtx);
1167 list_for_each_entry_safe(wk, tmp, &local->work_list, list) { 1262 list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
1168 if ((unsigned long) wk == cookie) { 1263 if ((unsigned long) wk == cookie) {
1169 wk->timeout = jiffies; 1264 wk->timeout = jiffies;
@@ -1171,7 +1266,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
1171 break; 1266 break;
1172 } 1267 }
1173 } 1268 }
1174 mutex_unlock(&local->work_mtx); 1269 mutex_unlock(&local->mtx);
1175 1270
1176 if (!found) 1271 if (!found)
1177 return -ENOENT; 1272 return -ENOENT;