aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/work.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/work.c')
-rw-r--r--net/mac80211/work.c153
1 files changed, 20 insertions, 133 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 6c53b6d1002b..c6dd01a05291 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -94,7 +94,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
94 94
95/* frame sending functions */ 95/* frame sending functions */
96 96
97static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, 97static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
98 struct sk_buff *skb, const u8 *ht_info_ie,
98 struct ieee80211_supported_band *sband, 99 struct ieee80211_supported_band *sband,
99 struct ieee80211_channel *channel, 100 struct ieee80211_channel *channel,
100 enum ieee80211_smps_mode smps) 101 enum ieee80211_smps_mode smps)
@@ -102,8 +103,10 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
102 struct ieee80211_ht_info *ht_info; 103 struct ieee80211_ht_info *ht_info;
103 u8 *pos; 104 u8 *pos;
104 u32 flags = channel->flags; 105 u32 flags = channel->flags;
105 u16 cap = sband->ht_cap.cap; 106 u16 cap;
106 __le16 tmp; 107 struct ieee80211_sta_ht_cap ht_cap;
108
109 BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
107 110
108 if (!sband->ht_cap.ht_supported) 111 if (!sband->ht_cap.ht_supported)
109 return; 112 return;
@@ -114,9 +117,13 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
114 if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) 117 if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
115 return; 118 return;
116 119
120 memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
121 ieee80211_apply_htcap_overrides(sdata, &ht_cap);
122
117 ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); 123 ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
118 124
119 /* determine capability flags */ 125 /* determine capability flags */
126 cap = ht_cap.cap;
120 127
121 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { 128 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
122 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 129 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
@@ -154,34 +161,8 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
154 } 161 }
155 162
156 /* reserve and fill IE */ 163 /* reserve and fill IE */
157
158 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); 164 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
159 *pos++ = WLAN_EID_HT_CAPABILITY; 165 ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
160 *pos++ = sizeof(struct ieee80211_ht_cap);
161 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
162
163 /* capability flags */
164 tmp = cpu_to_le16(cap);
165 memcpy(pos, &tmp, sizeof(u16));
166 pos += sizeof(u16);
167
168 /* AMPDU parameters */
169 *pos++ = sband->ht_cap.ampdu_factor |
170 (sband->ht_cap.ampdu_density <<
171 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
172
173 /* MCS set */
174 memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
175 pos += sizeof(sband->ht_cap.mcs);
176
177 /* extended capabilities */
178 pos += sizeof(__le16);
179
180 /* BF capabilities */
181 pos += sizeof(__le32);
182
183 /* antenna selection */
184 pos += sizeof(u8);
185} 166}
186 167
187static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, 168static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
@@ -356,7 +337,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
356 337
357 if (wk->assoc.use_11n && wk->assoc.wmm_used && 338 if (wk->assoc.use_11n && wk->assoc.wmm_used &&
358 local->hw.queues >= 4) 339 local->hw.queues >= 4)
359 ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, 340 ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie,
360 sband, wk->chan, wk->assoc.smps); 341 sband, wk->chan, wk->assoc.smps);
361 342
362 /* if present, add any custom non-vendor IEs that go after HT */ 343 /* if present, add any custom non-vendor IEs that go after HT */
@@ -881,44 +862,6 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
881 kfree_skb(skb); 862 kfree_skb(skb);
882} 863}
883 864
884static bool ieee80211_work_ct_coexists(enum nl80211_channel_type wk_ct,
885 enum nl80211_channel_type oper_ct)
886{
887 switch (wk_ct) {
888 case NL80211_CHAN_NO_HT:
889 return true;
890 case NL80211_CHAN_HT20:
891 if (oper_ct != NL80211_CHAN_NO_HT)
892 return true;
893 return false;
894 case NL80211_CHAN_HT40MINUS:
895 case NL80211_CHAN_HT40PLUS:
896 return (wk_ct == oper_ct);
897 }
898 WARN_ON(1); /* shouldn't get here */
899 return false;
900}
901
902static enum nl80211_channel_type
903ieee80211_calc_ct(enum nl80211_channel_type wk_ct,
904 enum nl80211_channel_type oper_ct)
905{
906 switch (wk_ct) {
907 case NL80211_CHAN_NO_HT:
908 return oper_ct;
909 case NL80211_CHAN_HT20:
910 if (oper_ct != NL80211_CHAN_NO_HT)
911 return oper_ct;
912 return wk_ct;
913 case NL80211_CHAN_HT40MINUS:
914 case NL80211_CHAN_HT40PLUS:
915 return wk_ct;
916 }
917 WARN_ON(1); /* shouldn't get here */
918 return wk_ct;
919}
920
921
922static void ieee80211_work_timer(unsigned long data) 865static void ieee80211_work_timer(unsigned long data)
923{ 866{
924 struct ieee80211_local *local = (void *) data; 867 struct ieee80211_local *local = (void *) data;
@@ -969,51 +912,12 @@ static void ieee80211_work_work(struct work_struct *work)
969 } 912 }
970 913
971 if (!started && !local->tmp_channel) { 914 if (!started && !local->tmp_channel) {
972 bool on_oper_chan; 915 ieee80211_offchannel_stop_vifs(local, true);
973 bool tmp_chan_changed = false;
974 bool on_oper_chan2;
975 enum nl80211_channel_type wk_ct;
976 on_oper_chan = ieee80211_cfg_on_oper_channel(local);
977
978 /* Work with existing channel type if possible. */
979 wk_ct = wk->chan_type;
980 if (wk->chan == local->hw.conf.channel)
981 wk_ct = ieee80211_calc_ct(wk->chan_type,
982 local->hw.conf.channel_type);
983
984 if (local->tmp_channel)
985 if ((local->tmp_channel != wk->chan) ||
986 (local->tmp_channel_type != wk_ct))
987 tmp_chan_changed = true;
988 916
989 local->tmp_channel = wk->chan; 917 local->tmp_channel = wk->chan;
990 local->tmp_channel_type = wk_ct; 918 local->tmp_channel_type = wk->chan_type;
991 /* 919
992 * Leave the station vifs in awake mode if they 920 ieee80211_hw_config(local, 0);
993 * happen to be on the same channel as
994 * the requested channel.
995 */
996 on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
997 if (on_oper_chan != on_oper_chan2) {
998 if (on_oper_chan2) {
999 /* going off oper channel, PS too */
1000 ieee80211_offchannel_stop_vifs(local,
1001 true);
1002 ieee80211_hw_config(local, 0);
1003 } else {
1004 /* going on channel, but leave PS
1005 * off-channel. */
1006 ieee80211_hw_config(local, 0);
1007 ieee80211_offchannel_return(local,
1008 true,
1009 false);
1010 }
1011 } else if (tmp_chan_changed)
1012 /* Still off-channel, but on some other
1013 * channel, so update hardware.
1014 * PS should already be off-channel.
1015 */
1016 ieee80211_hw_config(local, 0);
1017 921
1018 started = true; 922 started = true;
1019 wk->timeout = jiffies; 923 wk->timeout = jiffies;
@@ -1082,34 +986,17 @@ static void ieee80211_work_work(struct work_struct *work)
1082 list_for_each_entry(wk, &local->work_list, list) { 986 list_for_each_entry(wk, &local->work_list, list) {
1083 if (!wk->started) 987 if (!wk->started)
1084 continue; 988 continue;
1085 if (wk->chan != local->tmp_channel) 989 if (wk->chan != local->tmp_channel ||
1086 continue; 990 wk->chan_type != local->tmp_channel_type)
1087 if (!ieee80211_work_ct_coexists(wk->chan_type,
1088 local->tmp_channel_type))
1089 continue; 991 continue;
1090 remain_off_channel = true; 992 remain_off_channel = true;
1091 } 993 }
1092 994
1093 if (!remain_off_channel && local->tmp_channel) { 995 if (!remain_off_channel && local->tmp_channel) {
1094 local->tmp_channel = NULL; 996 local->tmp_channel = NULL;
1095 /* If tmp_channel wasn't operating channel, then 997 ieee80211_hw_config(local, 0);
1096 * we need to go back on-channel.
1097 * NOTE: If we can ever be here while scannning,
1098 * or if the hw_config() channel config logic changes,
1099 * then we may need to do a more thorough check to see if
1100 * we still need to do a hardware config. Currently,
1101 * we cannot be here while scanning, however.
1102 */
1103 if (!ieee80211_cfg_on_oper_channel(local))
1104 ieee80211_hw_config(local, 0);
1105 998
1106 /* At the least, we need to disable offchannel_ps, 999 ieee80211_offchannel_return(local, true);
1107 * so just go ahead and run the entire offchannel
1108 * return logic here. We *could* skip enabling
1109 * beaconing if we were already on-oper-channel
1110 * as a future optimization.
1111 */
1112 ieee80211_offchannel_return(local, true, true);
1113 1000
1114 /* give connection some time to breathe */ 1001 /* give connection some time to breathe */
1115 run_again(local, jiffies + HZ/2); 1002 run_again(local, jiffies + HZ/2);