diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 105 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 38 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 86 | ||||
-rw-r--r-- | net/mac80211/iface.c | 28 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 1332 | ||||
-rw-r--r-- | net/mac80211/rx.c | 29 | ||||
-rw-r--r-- | net/mac80211/scan.c | 23 |
7 files changed, 750 insertions, 891 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e6d8860f26f2..7cfc14e4ca07 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1172,122 +1172,25 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1172 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | 1172 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, |
1173 | struct cfg80211_auth_request *req) | 1173 | struct cfg80211_auth_request *req) |
1174 | { | 1174 | { |
1175 | struct ieee80211_sub_if_data *sdata; | 1175 | return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req); |
1176 | const u8 *ssid; | ||
1177 | |||
1178 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1179 | |||
1180 | switch (req->auth_type) { | ||
1181 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
1182 | sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN; | ||
1183 | break; | ||
1184 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
1185 | sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY; | ||
1186 | break; | ||
1187 | case NL80211_AUTHTYPE_FT: | ||
1188 | sdata->u.mgd.auth_alg = WLAN_AUTH_FT; | ||
1189 | break; | ||
1190 | case NL80211_AUTHTYPE_NETWORK_EAP: | ||
1191 | sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP; | ||
1192 | break; | ||
1193 | default: | ||
1194 | return -EOPNOTSUPP; | ||
1195 | } | ||
1196 | |||
1197 | memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); | ||
1198 | |||
1199 | sdata->local->oper_channel = req->bss->channel; | ||
1200 | ieee80211_hw_config(sdata->local, 0); | ||
1201 | |||
1202 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | ||
1203 | if (!ssid) | ||
1204 | return -EINVAL; | ||
1205 | sdata->u.mgd.ssid_len = *(ssid + 1); | ||
1206 | memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); | ||
1207 | |||
1208 | kfree(sdata->u.mgd.sme_auth_ie); | ||
1209 | sdata->u.mgd.sme_auth_ie = NULL; | ||
1210 | sdata->u.mgd.sme_auth_ie_len = 0; | ||
1211 | if (req->ie) { | ||
1212 | sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL); | ||
1213 | if (sdata->u.mgd.sme_auth_ie == NULL) | ||
1214 | return -ENOMEM; | ||
1215 | memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len); | ||
1216 | sdata->u.mgd.sme_auth_ie_len = req->ie_len; | ||
1217 | } | ||
1218 | |||
1219 | sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
1220 | ieee80211_sta_req_auth(sdata); | ||
1221 | return 0; | ||
1222 | } | 1176 | } |
1223 | 1177 | ||
1224 | static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | 1178 | static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, |
1225 | struct cfg80211_assoc_request *req) | 1179 | struct cfg80211_assoc_request *req) |
1226 | { | 1180 | { |
1227 | struct ieee80211_sub_if_data *sdata; | 1181 | return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); |
1228 | int ret, i; | ||
1229 | |||
1230 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1231 | |||
1232 | if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || | ||
1233 | !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) | ||
1234 | return -ENOLINK; /* not authenticated */ | ||
1235 | |||
1236 | sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N; | ||
1237 | |||
1238 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | ||
1239 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | ||
1240 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | ||
1241 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) | ||
1242 | sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; | ||
1243 | |||
1244 | sdata->local->oper_channel = req->bss->channel; | ||
1245 | ieee80211_hw_config(sdata->local, 0); | ||
1246 | |||
1247 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); | ||
1248 | if (ret && ret != -EALREADY) | ||
1249 | return ret; | ||
1250 | |||
1251 | if (req->use_mfp) { | ||
1252 | sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; | ||
1253 | sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; | ||
1254 | } else { | ||
1255 | sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; | ||
1256 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; | ||
1257 | } | ||
1258 | |||
1259 | if (req->prev_bssid) { | ||
1260 | sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET; | ||
1261 | memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN); | ||
1262 | } else | ||
1263 | sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
1264 | |||
1265 | if (req->crypto.control_port) | ||
1266 | sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; | ||
1267 | else | ||
1268 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; | ||
1269 | |||
1270 | sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; | ||
1271 | ieee80211_sta_req_auth(sdata); | ||
1272 | return 0; | ||
1273 | } | 1182 | } |
1274 | 1183 | ||
1275 | static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, | 1184 | static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, |
1276 | struct cfg80211_deauth_request *req) | 1185 | struct cfg80211_deauth_request *req) |
1277 | { | 1186 | { |
1278 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1187 | return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); |
1279 | |||
1280 | /* TODO: req->ie, req->peer_addr */ | ||
1281 | return ieee80211_sta_deauthenticate(sdata, req->reason_code); | ||
1282 | } | 1188 | } |
1283 | 1189 | ||
1284 | static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, | 1190 | static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, |
1285 | struct cfg80211_disassoc_request *req) | 1191 | struct cfg80211_disassoc_request *req) |
1286 | { | 1192 | { |
1287 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1193 | return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); |
1288 | |||
1289 | /* TODO: req->ie, req->peer_addr */ | ||
1290 | return ieee80211_sta_disassociate(sdata, req->reason_code); | ||
1291 | } | 1194 | } |
1292 | 1195 | ||
1293 | static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | 1196 | static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 4c541f0f325f..e9ec6cae2d39 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -95,29 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); | |||
95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | 95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); |
96 | 96 | ||
97 | /* STA attributes */ | 97 | /* STA attributes */ |
98 | IEEE80211_IF_FILE(state, u.mgd.state, DEC); | ||
99 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 98 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
100 | IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); | ||
101 | IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); | ||
102 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); | 99 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); |
103 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); | 100 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); |
104 | IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); | ||
105 | IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); | ||
106 | IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); | ||
107 | IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); | ||
108 | IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); | ||
109 | |||
110 | static ssize_t ieee80211_if_fmt_flags( | ||
111 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
112 | { | ||
113 | return scnprintf(buf, buflen, "%s%s%s%s%s\n", | ||
114 | sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", | ||
115 | sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", | ||
116 | sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", | ||
117 | sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", | ||
118 | sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); | ||
119 | } | ||
120 | __IEEE80211_IF_FILE(flags); | ||
121 | 101 | ||
122 | /* AP attributes */ | 102 | /* AP attributes */ |
123 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | 103 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); |
@@ -180,18 +160,9 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) | |||
180 | DEBUGFS_ADD(force_unicast_rateidx, sta); | 160 | DEBUGFS_ADD(force_unicast_rateidx, sta); |
181 | DEBUGFS_ADD(max_ratectrl_rateidx, sta); | 161 | DEBUGFS_ADD(max_ratectrl_rateidx, sta); |
182 | 162 | ||
183 | DEBUGFS_ADD(state, sta); | ||
184 | DEBUGFS_ADD(bssid, sta); | 163 | DEBUGFS_ADD(bssid, sta); |
185 | DEBUGFS_ADD(prev_bssid, sta); | ||
186 | DEBUGFS_ADD(ssid_len, sta); | ||
187 | DEBUGFS_ADD(aid, sta); | 164 | DEBUGFS_ADD(aid, sta); |
188 | DEBUGFS_ADD(capab, sta); | 165 | DEBUGFS_ADD(capab, sta); |
189 | DEBUGFS_ADD(extra_ie_len, sta); | ||
190 | DEBUGFS_ADD(auth_tries, sta); | ||
191 | DEBUGFS_ADD(assoc_tries, sta); | ||
192 | DEBUGFS_ADD(auth_alg, sta); | ||
193 | DEBUGFS_ADD(auth_transaction, sta); | ||
194 | DEBUGFS_ADD(flags, sta); | ||
195 | } | 166 | } |
196 | 167 | ||
197 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 168 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
@@ -311,18 +282,9 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) | |||
311 | DEBUGFS_DEL(force_unicast_rateidx, sta); | 282 | DEBUGFS_DEL(force_unicast_rateidx, sta); |
312 | DEBUGFS_DEL(max_ratectrl_rateidx, sta); | 283 | DEBUGFS_DEL(max_ratectrl_rateidx, sta); |
313 | 284 | ||
314 | DEBUGFS_DEL(state, sta); | ||
315 | DEBUGFS_DEL(bssid, sta); | 285 | DEBUGFS_DEL(bssid, sta); |
316 | DEBUGFS_DEL(prev_bssid, sta); | ||
317 | DEBUGFS_DEL(ssid_len, sta); | ||
318 | DEBUGFS_DEL(aid, sta); | 286 | DEBUGFS_DEL(aid, sta); |
319 | DEBUGFS_DEL(capab, sta); | 287 | DEBUGFS_DEL(capab, sta); |
320 | DEBUGFS_DEL(extra_ie_len, sta); | ||
321 | DEBUGFS_DEL(auth_tries, sta); | ||
322 | DEBUGFS_DEL(assoc_tries, sta); | ||
323 | DEBUGFS_DEL(auth_alg, sta); | ||
324 | DEBUGFS_DEL(auth_transaction, sta); | ||
325 | DEBUGFS_DEL(flags, sta); | ||
326 | } | 288 | } |
327 | 289 | ||
328 | static void del_ap_files(struct ieee80211_sub_if_data *sdata) | 290 | static void del_ap_files(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d0354b16d24f..2e92bbd9b2d0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -227,11 +227,32 @@ struct mesh_preq_queue { | |||
227 | u8 flags; | 227 | u8 flags; |
228 | }; | 228 | }; |
229 | 229 | ||
230 | enum ieee80211_mgd_state { | ||
231 | IEEE80211_MGD_STATE_IDLE, | ||
232 | IEEE80211_MGD_STATE_PROBE, | ||
233 | IEEE80211_MGD_STATE_AUTH, | ||
234 | IEEE80211_MGD_STATE_ASSOC, | ||
235 | }; | ||
236 | |||
237 | struct ieee80211_mgd_work { | ||
238 | struct list_head list; | ||
239 | struct ieee80211_bss *bss; | ||
240 | int ie_len; | ||
241 | u8 prev_bssid[ETH_ALEN]; | ||
242 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
243 | u8 ssid_len; | ||
244 | unsigned long timeout; | ||
245 | enum ieee80211_mgd_state state; | ||
246 | u16 auth_alg, auth_transaction; | ||
247 | |||
248 | int tries; | ||
249 | |||
250 | /* must be last */ | ||
251 | u8 ie[0]; /* for auth or assoc frame, not probe */ | ||
252 | }; | ||
253 | |||
230 | /* flags used in struct ieee80211_if_managed.flags */ | 254 | /* flags used in struct ieee80211_if_managed.flags */ |
231 | enum ieee80211_sta_flags { | 255 | enum ieee80211_sta_flags { |
232 | IEEE80211_STA_PREV_BSSID_SET = BIT(0), | ||
233 | IEEE80211_STA_AUTHENTICATED = BIT(1), | ||
234 | IEEE80211_STA_ASSOCIATED = BIT(2), | ||
235 | IEEE80211_STA_PROBEREQ_POLL = BIT(3), | 256 | IEEE80211_STA_PROBEREQ_POLL = BIT(3), |
236 | IEEE80211_STA_CONTROL_PORT = BIT(4), | 257 | IEEE80211_STA_CONTROL_PORT = BIT(4), |
237 | IEEE80211_STA_WMM_ENABLED = BIT(5), | 258 | IEEE80211_STA_WMM_ENABLED = BIT(5), |
@@ -243,8 +264,6 @@ enum ieee80211_sta_flags { | |||
243 | /* flags for MLME request */ | 264 | /* flags for MLME request */ |
244 | enum ieee80211_sta_request { | 265 | enum ieee80211_sta_request { |
245 | IEEE80211_STA_REQ_SCAN, | 266 | IEEE80211_STA_REQ_SCAN, |
246 | IEEE80211_STA_REQ_AUTH, | ||
247 | IEEE80211_STA_REQ_RUN, | ||
248 | }; | 267 | }; |
249 | 268 | ||
250 | struct ieee80211_if_managed { | 269 | struct ieee80211_if_managed { |
@@ -254,35 +273,17 @@ struct ieee80211_if_managed { | |||
254 | struct work_struct chswitch_work; | 273 | struct work_struct chswitch_work; |
255 | struct work_struct beacon_loss_work; | 274 | struct work_struct beacon_loss_work; |
256 | 275 | ||
257 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 276 | struct mutex mtx; |
277 | struct ieee80211_bss *associated; | ||
278 | struct list_head work_list; | ||
258 | 279 | ||
259 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 280 | u8 bssid[ETH_ALEN]; |
260 | size_t ssid_len; | ||
261 | |||
262 | enum { | ||
263 | IEEE80211_STA_MLME_DISABLED, | ||
264 | IEEE80211_STA_MLME_DIRECT_PROBE, | ||
265 | IEEE80211_STA_MLME_AUTHENTICATE, | ||
266 | IEEE80211_STA_MLME_ASSOCIATE, | ||
267 | IEEE80211_STA_MLME_ASSOCIATED, | ||
268 | } state; | ||
269 | 281 | ||
270 | u16 aid; | 282 | u16 aid; |
271 | u16 capab; | 283 | u16 capab; |
272 | u8 *extra_ie; /* to be added to the end of AssocReq */ | ||
273 | size_t extra_ie_len; | ||
274 | |||
275 | /* The last AssocReq/Resp IEs */ | ||
276 | u8 *assocreq_ies, *assocresp_ies; | ||
277 | size_t assocreq_ies_len, assocresp_ies_len; | ||
278 | 284 | ||
279 | struct sk_buff_head skb_queue; | 285 | struct sk_buff_head skb_queue; |
280 | 286 | ||
281 | int assoc_scan_tries; /* number of scans done pre-association */ | ||
282 | int direct_probe_tries; /* retries for direct probes */ | ||
283 | int auth_tries; /* retries for auth req */ | ||
284 | int assoc_tries; /* retries for assoc req */ | ||
285 | |||
286 | unsigned long timers_running; /* used for quiesce/restart */ | 287 | unsigned long timers_running; /* used for quiesce/restart */ |
287 | bool powersave; /* powersave requested for this iface */ | 288 | bool powersave; /* powersave requested for this iface */ |
288 | 289 | ||
@@ -292,9 +293,6 @@ struct ieee80211_if_managed { | |||
292 | 293 | ||
293 | unsigned int flags; | 294 | unsigned int flags; |
294 | 295 | ||
295 | int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ | ||
296 | int auth_transaction; | ||
297 | |||
298 | u32 beacon_crc; | 296 | u32 beacon_crc; |
299 | 297 | ||
300 | enum { | 298 | enum { |
@@ -304,10 +302,6 @@ struct ieee80211_if_managed { | |||
304 | } mfp; /* management frame protection */ | 302 | } mfp; /* management frame protection */ |
305 | 303 | ||
306 | int wmm_last_param_set; | 304 | int wmm_last_param_set; |
307 | |||
308 | /* Extra IE data for management frames */ | ||
309 | u8 *sme_auth_ie; | ||
310 | size_t sme_auth_ie_len; | ||
311 | }; | 305 | }; |
312 | 306 | ||
313 | enum ieee80211_ibss_request { | 307 | enum ieee80211_ibss_request { |
@@ -466,18 +460,9 @@ struct ieee80211_sub_if_data { | |||
466 | union { | 460 | union { |
467 | struct { | 461 | struct { |
468 | struct dentry *drop_unencrypted; | 462 | struct dentry *drop_unencrypted; |
469 | struct dentry *state; | ||
470 | struct dentry *bssid; | 463 | struct dentry *bssid; |
471 | struct dentry *prev_bssid; | ||
472 | struct dentry *ssid_len; | ||
473 | struct dentry *aid; | 464 | struct dentry *aid; |
474 | struct dentry *capab; | 465 | struct dentry *capab; |
475 | struct dentry *extra_ie_len; | ||
476 | struct dentry *auth_tries; | ||
477 | struct dentry *assoc_tries; | ||
478 | struct dentry *auth_alg; | ||
479 | struct dentry *auth_transaction; | ||
480 | struct dentry *flags; | ||
481 | struct dentry *force_unicast_rateidx; | 466 | struct dentry *force_unicast_rateidx; |
482 | struct dentry *max_ratectrl_rateidx; | 467 | struct dentry *max_ratectrl_rateidx; |
483 | } sta; | 468 | } sta; |
@@ -928,11 +913,16 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; | |||
928 | 913 | ||
929 | /* STA code */ | 914 | /* STA code */ |
930 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); | 915 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); |
916 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | ||
917 | struct cfg80211_auth_request *req); | ||
918 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | ||
919 | struct cfg80211_assoc_request *req); | ||
920 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | ||
921 | struct cfg80211_deauth_request *req); | ||
922 | int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | ||
923 | struct cfg80211_disassoc_request *req); | ||
931 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | 924 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, |
932 | struct sk_buff *skb); | 925 | struct sk_buff *skb); |
933 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); | ||
934 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); | ||
935 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); | ||
936 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 926 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
937 | struct ieee80211_sub_if_data *sdata); | 927 | struct ieee80211_sub_if_data *sdata); |
938 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); | 928 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); |
@@ -966,8 +956,6 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
966 | void ieee80211_scan_cancel(struct ieee80211_local *local); | 956 | void ieee80211_scan_cancel(struct ieee80211_local *local); |
967 | ieee80211_rx_result | 957 | ieee80211_rx_result |
968 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 958 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
969 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | ||
970 | const char *ie, size_t len); | ||
971 | 959 | ||
972 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 960 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
973 | struct ieee80211_bss * | 961 | struct ieee80211_bss * |
@@ -983,8 +971,6 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | |||
983 | u8 *ssid, u8 ssid_len); | 971 | u8 *ssid, u8 ssid_len); |
984 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 972 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
985 | struct ieee80211_bss *bss); | 973 | struct ieee80211_bss *bss); |
986 | void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, | ||
987 | int freq, u8 *ssid, u8 ssid_len); | ||
988 | 974 | ||
989 | /* interface handling */ | 975 | /* interface handling */ |
990 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 976 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b87bf425f857..4839a2d97a3b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -233,9 +233,6 @@ static int ieee80211_open(struct net_device *dev) | |||
233 | ieee80211_configure_filter(local); | 233 | ieee80211_configure_filter(local); |
234 | netif_addr_unlock_bh(local->mdev); | 234 | netif_addr_unlock_bh(local->mdev); |
235 | break; | 235 | break; |
236 | case NL80211_IFTYPE_STATION: | ||
237 | sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
238 | /* fall through */ | ||
239 | default: | 236 | default: |
240 | conf.vif = &sdata->vif; | 237 | conf.vif = &sdata->vif; |
241 | conf.type = sdata->vif.type; | 238 | conf.type = sdata->vif.type; |
@@ -366,18 +363,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
366 | rcu_read_unlock(); | 363 | rcu_read_unlock(); |
367 | 364 | ||
368 | /* | 365 | /* |
369 | * Announce that we are leaving the network, in case we are a | ||
370 | * station interface type. This must be done before removing | ||
371 | * all stations associated with sta_info_flush, otherwise STA | ||
372 | * information will be gone and no announce being done. | ||
373 | */ | ||
374 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
375 | if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED) | ||
376 | ieee80211_sta_deauthenticate(sdata, | ||
377 | WLAN_REASON_DEAUTH_LEAVING); | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Remove all stations associated with this interface. | 366 | * Remove all stations associated with this interface. |
382 | * | 367 | * |
383 | * This must be done before calling ops->remove_interface() | 368 | * This must be done before calling ops->remove_interface() |
@@ -462,7 +447,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
462 | netif_addr_unlock_bh(local->mdev); | 447 | netif_addr_unlock_bh(local->mdev); |
463 | break; | 448 | break; |
464 | case NL80211_IFTYPE_STATION: | 449 | case NL80211_IFTYPE_STATION: |
465 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | ||
466 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 450 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
467 | del_timer_sync(&sdata->u.mgd.timer); | 451 | del_timer_sync(&sdata->u.mgd.timer); |
468 | /* | 452 | /* |
@@ -485,10 +469,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
485 | */ | 469 | */ |
486 | synchronize_rcu(); | 470 | synchronize_rcu(); |
487 | skb_queue_purge(&sdata->u.mgd.skb_queue); | 471 | skb_queue_purge(&sdata->u.mgd.skb_queue); |
488 | |||
489 | kfree(sdata->u.mgd.extra_ie); | ||
490 | sdata->u.mgd.extra_ie = NULL; | ||
491 | sdata->u.mgd.extra_ie_len = 0; | ||
492 | /* fall through */ | 472 | /* fall through */ |
493 | case NL80211_IFTYPE_ADHOC: | 473 | case NL80211_IFTYPE_ADHOC: |
494 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 474 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
@@ -650,11 +630,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
650 | kfree_skb(sdata->u.ibss.presp); | 630 | kfree_skb(sdata->u.ibss.presp); |
651 | break; | 631 | break; |
652 | case NL80211_IFTYPE_STATION: | 632 | case NL80211_IFTYPE_STATION: |
653 | kfree(sdata->u.mgd.extra_ie); | ||
654 | kfree(sdata->u.mgd.assocreq_ies); | ||
655 | kfree(sdata->u.mgd.assocresp_ies); | ||
656 | kfree(sdata->u.mgd.sme_auth_ie); | ||
657 | break; | ||
658 | case NL80211_IFTYPE_WDS: | 633 | case NL80211_IFTYPE_WDS: |
659 | case NL80211_IFTYPE_AP_VLAN: | 634 | case NL80211_IFTYPE_AP_VLAN: |
660 | case NL80211_IFTYPE_MONITOR: | 635 | case NL80211_IFTYPE_MONITOR: |
@@ -937,7 +912,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
937 | continue; | 912 | continue; |
938 | /* do not count disabled managed interfaces */ | 913 | /* do not count disabled managed interfaces */ |
939 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 914 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
940 | sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED) | 915 | !sdata->u.mgd.associated && |
916 | list_empty(&sdata->u.mgd.work_list)) | ||
941 | continue; | 917 | continue; |
942 | /* do not count unused IBSS interfaces */ | 918 | /* do not count unused IBSS interfaces */ |
943 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 919 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29575eea3ed1..108e8c9c60fd 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -27,20 +27,51 @@ | |||
27 | #include "rate.h" | 27 | #include "rate.h" |
28 | #include "led.h" | 28 | #include "led.h" |
29 | 29 | ||
30 | #define IEEE80211_ASSOC_SCANS_MAX_TRIES 2 | ||
31 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | 30 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) |
32 | #define IEEE80211_AUTH_MAX_TRIES 3 | 31 | #define IEEE80211_AUTH_MAX_TRIES 3 |
33 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
34 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 33 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 34 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
36 | #define IEEE80211_PROBE_WAIT (HZ / 5) | 35 | #define IEEE80211_PROBE_WAIT (HZ / 5) |
37 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) | ||
38 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | ||
39 | 36 | ||
40 | #define TMR_RUNNING_TIMER 0 | 37 | #define TMR_RUNNING_TIMER 0 |
41 | #define TMR_RUNNING_CHANSW 1 | 38 | #define TMR_RUNNING_CHANSW 1 |
42 | 39 | ||
40 | /* | ||
41 | * All cfg80211 functions have to be called outside a locked | ||
42 | * section so that they can acquire a lock themselves... This | ||
43 | * is much simpler than queuing up things in cfg80211, but we | ||
44 | * do need some indirection for that here. | ||
45 | */ | ||
46 | enum rx_mgmt_action { | ||
47 | /* no action required */ | ||
48 | RX_MGMT_NONE, | ||
49 | |||
50 | /* caller must call cfg80211_send_rx_auth() */ | ||
51 | RX_MGMT_CFG80211_AUTH, | ||
52 | |||
53 | /* caller must call cfg80211_send_rx_assoc() */ | ||
54 | RX_MGMT_CFG80211_ASSOC, | ||
55 | |||
56 | /* caller must call cfg80211_send_deauth() */ | ||
57 | RX_MGMT_CFG80211_DEAUTH, | ||
58 | |||
59 | /* caller must call cfg80211_send_disassoc() */ | ||
60 | RX_MGMT_CFG80211_DISASSOC, | ||
61 | |||
62 | /* caller must call cfg80211_auth_timeout() & free work */ | ||
63 | RX_MGMT_CFG80211_AUTH_TO, | ||
64 | |||
65 | /* caller must call cfg80211_assoc_timeout() & free work */ | ||
66 | RX_MGMT_CFG80211_ASSOC_TO, | ||
67 | }; | ||
68 | |||
43 | /* utils */ | 69 | /* utils */ |
70 | static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) | ||
71 | { | ||
72 | WARN_ON(!mutex_is_locked(&ifmgd->mtx)); | ||
73 | } | ||
74 | |||
44 | static int ecw2cw(int ecw) | 75 | static int ecw2cw(int ecw) |
45 | { | 76 | { |
46 | return (1 << ecw) - 1; | 77 | return (1 << ecw) - 1; |
@@ -74,11 +105,10 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
74 | */ | 105 | */ |
75 | static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | 106 | static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, |
76 | struct ieee80211_ht_info *hti, | 107 | struct ieee80211_ht_info *hti, |
77 | u16 ap_ht_cap_flags) | 108 | const u8 *bssid, u16 ap_ht_cap_flags) |
78 | { | 109 | { |
79 | struct ieee80211_local *local = sdata->local; | 110 | struct ieee80211_local *local = sdata->local; |
80 | struct ieee80211_supported_band *sband; | 111 | struct ieee80211_supported_band *sband; |
81 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
82 | struct sta_info *sta; | 112 | struct sta_info *sta; |
83 | u32 changed = 0; | 113 | u32 changed = 0; |
84 | u16 ht_opmode; | 114 | u16 ht_opmode; |
@@ -127,12 +157,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
127 | ieee80211_hw_config(local, 0); | 157 | ieee80211_hw_config(local, 0); |
128 | 158 | ||
129 | rcu_read_lock(); | 159 | rcu_read_lock(); |
130 | 160 | sta = sta_info_get(local, bssid); | |
131 | sta = sta_info_get(local, ifmgd->bssid); | ||
132 | if (sta) | 161 | if (sta) |
133 | rate_control_rate_update(local, sband, sta, | 162 | rate_control_rate_update(local, sband, sta, |
134 | IEEE80211_RC_HT_CHANGED); | 163 | IEEE80211_RC_HT_CHANGED); |
135 | |||
136 | rcu_read_unlock(); | 164 | rcu_read_unlock(); |
137 | } | 165 | } |
138 | 166 | ||
@@ -155,7 +183,8 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
155 | 183 | ||
156 | /* frame sending functions */ | 184 | /* frame sending functions */ |
157 | 185 | ||
158 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | 186 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, |
187 | struct ieee80211_mgd_work *wk) | ||
159 | { | 188 | { |
160 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 189 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
161 | struct ieee80211_local *local = sdata->local; | 190 | struct ieee80211_local *local = sdata->local; |
@@ -165,14 +194,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
165 | const u8 *ies, *ht_ie; | 194 | const u8 *ies, *ht_ie; |
166 | int i, len, count, rates_len, supp_rates_len; | 195 | int i, len, count, rates_len, supp_rates_len; |
167 | u16 capab; | 196 | u16 capab; |
168 | struct ieee80211_bss *bss; | ||
169 | int wmm = 0; | 197 | int wmm = 0; |
170 | struct ieee80211_supported_band *sband; | 198 | struct ieee80211_supported_band *sband; |
171 | u32 rates = 0; | 199 | u32 rates = 0; |
172 | 200 | ||
173 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 201 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
174 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + | 202 | sizeof(*mgmt) + 200 + wk->ie_len + |
175 | ifmgd->ssid_len); | 203 | wk->ssid_len); |
176 | if (!skb) { | 204 | if (!skb) { |
177 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 205 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
178 | "frame\n", sdata->dev->name); | 206 | "frame\n", sdata->dev->name); |
@@ -191,45 +219,35 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
191 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | 219 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; |
192 | } | 220 | } |
193 | 221 | ||
194 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | 222 | if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) |
195 | local->hw.conf.channel->center_freq, | 223 | capab |= WLAN_CAPABILITY_PRIVACY; |
196 | ifmgd->ssid, ifmgd->ssid_len); | 224 | if (wk->bss->wmm_used) |
197 | if (bss) { | 225 | wmm = 1; |
198 | if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) | ||
199 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
200 | if (bss->wmm_used) | ||
201 | wmm = 1; | ||
202 | 226 | ||
203 | /* get all rates supported by the device and the AP as | 227 | /* get all rates supported by the device and the AP as |
204 | * some APs don't like getting a superset of their rates | 228 | * some APs don't like getting a superset of their rates |
205 | * in the association request (e.g. D-Link DAP 1353 in | 229 | * in the association request (e.g. D-Link DAP 1353 in |
206 | * b-only mode) */ | 230 | * b-only mode) */ |
207 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | 231 | rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); |
208 | 232 | ||
209 | if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | 233 | if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && |
210 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | 234 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) |
211 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | 235 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; |
212 | |||
213 | ieee80211_rx_bss_put(local, bss); | ||
214 | } else { | ||
215 | rates = ~0; | ||
216 | rates_len = sband->n_bitrates; | ||
217 | } | ||
218 | 236 | ||
219 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 237 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
220 | memset(mgmt, 0, 24); | 238 | memset(mgmt, 0, 24); |
221 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); | 239 | memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); |
222 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 240 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
223 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); | 241 | memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); |
224 | 242 | ||
225 | if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) { | 243 | if (!is_zero_ether_addr(wk->prev_bssid)) { |
226 | skb_put(skb, 10); | 244 | skb_put(skb, 10); |
227 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 245 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
228 | IEEE80211_STYPE_REASSOC_REQ); | 246 | IEEE80211_STYPE_REASSOC_REQ); |
229 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | 247 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); |
230 | mgmt->u.reassoc_req.listen_interval = | 248 | mgmt->u.reassoc_req.listen_interval = |
231 | cpu_to_le16(local->hw.conf.listen_interval); | 249 | cpu_to_le16(local->hw.conf.listen_interval); |
232 | memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid, | 250 | memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, |
233 | ETH_ALEN); | 251 | ETH_ALEN); |
234 | } else { | 252 | } else { |
235 | skb_put(skb, 4); | 253 | skb_put(skb, 4); |
@@ -241,10 +259,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
241 | } | 259 | } |
242 | 260 | ||
243 | /* SSID */ | 261 | /* SSID */ |
244 | ies = pos = skb_put(skb, 2 + ifmgd->ssid_len); | 262 | ies = pos = skb_put(skb, 2 + wk->ssid_len); |
245 | *pos++ = WLAN_EID_SSID; | 263 | *pos++ = WLAN_EID_SSID; |
246 | *pos++ = ifmgd->ssid_len; | 264 | *pos++ = wk->ssid_len; |
247 | memcpy(pos, ifmgd->ssid, ifmgd->ssid_len); | 265 | memcpy(pos, wk->ssid, wk->ssid_len); |
248 | 266 | ||
249 | /* add all rates which were marked to be used above */ | 267 | /* add all rates which were marked to be used above */ |
250 | supp_rates_len = rates_len; | 268 | supp_rates_len = rates_len; |
@@ -299,9 +317,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
299 | } | 317 | } |
300 | } | 318 | } |
301 | 319 | ||
302 | if (ifmgd->extra_ie) { | 320 | if (wk->ie_len && wk->ie) { |
303 | pos = skb_put(skb, ifmgd->extra_ie_len); | 321 | pos = skb_put(skb, wk->ie_len); |
304 | memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len); | 322 | memcpy(pos, wk->ie, wk->ie_len); |
305 | } | 323 | } |
306 | 324 | ||
307 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { | 325 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { |
@@ -326,7 +344,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
326 | */ | 344 | */ |
327 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | 345 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
328 | sband->ht_cap.ht_supported && | 346 | sband->ht_cap.ht_supported && |
329 | (ht_ie = ieee80211_bss_get_ie(&bss->cbss, WLAN_EID_HT_INFORMATION)) && | 347 | (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && |
330 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && | 348 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && |
331 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { | 349 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { |
332 | struct ieee80211_ht_info *ht_info = | 350 | struct ieee80211_ht_info *ht_info = |
@@ -363,18 +381,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
363 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 381 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
364 | } | 382 | } |
365 | 383 | ||
366 | kfree(ifmgd->assocreq_ies); | ||
367 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; | ||
368 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); | ||
369 | if (ifmgd->assocreq_ies) | ||
370 | memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len); | ||
371 | |||
372 | ieee80211_tx_skb(sdata, skb, 0); | 384 | ieee80211_tx_skb(sdata, skb, 0); |
373 | } | 385 | } |
374 | 386 | ||
375 | 387 | ||
376 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 388 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
377 | u16 stype, u16 reason) | 389 | const u8 *bssid, u16 stype, u16 reason) |
378 | { | 390 | { |
379 | struct ieee80211_local *local = sdata->local; | 391 | struct ieee80211_local *local = sdata->local; |
380 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 392 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -391,9 +403,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
391 | 403 | ||
392 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 404 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
393 | memset(mgmt, 0, 24); | 405 | memset(mgmt, 0, 24); |
394 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); | 406 | memcpy(mgmt->da, bssid, ETH_ALEN); |
395 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 407 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
396 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); | 408 | memcpy(mgmt->bssid, bssid, ETH_ALEN); |
397 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | 409 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); |
398 | skb_put(skb, 2); | 410 | skb_put(skb, 2); |
399 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 411 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
@@ -477,28 +489,26 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
477 | { | 489 | { |
478 | struct ieee80211_sub_if_data *sdata = | 490 | struct ieee80211_sub_if_data *sdata = |
479 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 491 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
480 | struct ieee80211_bss *bss; | ||
481 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 492 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
482 | 493 | ||
483 | if (!netif_running(sdata->dev)) | 494 | if (!netif_running(sdata->dev)) |
484 | return; | 495 | return; |
485 | 496 | ||
486 | bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, | 497 | mutex_lock(&ifmgd->mtx); |
487 | sdata->local->hw.conf.channel->center_freq, | 498 | if (!ifmgd->associated) |
488 | ifmgd->ssid, ifmgd->ssid_len); | 499 | goto out; |
489 | if (!bss) | ||
490 | goto exit; | ||
491 | 500 | ||
492 | sdata->local->oper_channel = sdata->local->csa_channel; | 501 | sdata->local->oper_channel = sdata->local->csa_channel; |
502 | ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
503 | |||
493 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 504 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
494 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) | 505 | ifmgd->associated->cbss.channel = sdata->local->oper_channel; |
495 | bss->cbss.channel = sdata->local->oper_channel; | ||
496 | 506 | ||
497 | ieee80211_rx_bss_put(sdata->local, bss); | ||
498 | exit: | ||
499 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
500 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 507 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
501 | IEEE80211_QUEUE_STOP_REASON_CSA); | 508 | IEEE80211_QUEUE_STOP_REASON_CSA); |
509 | out: | ||
510 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
511 | mutex_unlock(&ifmgd->mtx); | ||
502 | } | 512 | } |
503 | 513 | ||
504 | static void ieee80211_chswitch_timer(unsigned long data) | 514 | static void ieee80211_chswitch_timer(unsigned long data) |
@@ -523,7 +533,9 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
523 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 533 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
524 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | 534 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); |
525 | 535 | ||
526 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) | 536 | ASSERT_MGD_MTX(ifmgd); |
537 | |||
538 | if (!ifmgd->associated) | ||
527 | return; | 539 | return; |
528 | 540 | ||
529 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | 541 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) |
@@ -634,7 +646,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
634 | } | 646 | } |
635 | 647 | ||
636 | if (count == 1 && found->u.mgd.powersave && | 648 | if (count == 1 && found->u.mgd.powersave && |
637 | (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && | 649 | found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && |
638 | !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { | 650 | !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { |
639 | s32 beaconint_us; | 651 | s32 beaconint_us; |
640 | 652 | ||
@@ -789,9 +801,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
789 | u16 capab, bool erp_valid, u8 erp) | 801 | u16 capab, bool erp_valid, u8 erp) |
790 | { | 802 | { |
791 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 803 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
792 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
793 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
794 | #endif | ||
795 | u32 changed = 0; | 804 | u32 changed = 0; |
796 | bool use_protection; | 805 | bool use_protection; |
797 | bool use_short_preamble; | 806 | bool use_short_preamble; |
@@ -808,42 +817,16 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
808 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 817 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
809 | 818 | ||
810 | if (use_protection != bss_conf->use_cts_prot) { | 819 | if (use_protection != bss_conf->use_cts_prot) { |
811 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
812 | if (net_ratelimit()) { | ||
813 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", | ||
814 | sdata->dev->name, | ||
815 | use_protection ? "enabled" : "disabled", | ||
816 | ifmgd->bssid); | ||
817 | } | ||
818 | #endif | ||
819 | bss_conf->use_cts_prot = use_protection; | 820 | bss_conf->use_cts_prot = use_protection; |
820 | changed |= BSS_CHANGED_ERP_CTS_PROT; | 821 | changed |= BSS_CHANGED_ERP_CTS_PROT; |
821 | } | 822 | } |
822 | 823 | ||
823 | if (use_short_preamble != bss_conf->use_short_preamble) { | 824 | if (use_short_preamble != bss_conf->use_short_preamble) { |
824 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
825 | if (net_ratelimit()) { | ||
826 | printk(KERN_DEBUG "%s: switched to %s barker preamble" | ||
827 | " (BSSID=%pM)\n", | ||
828 | sdata->dev->name, | ||
829 | use_short_preamble ? "short" : "long", | ||
830 | ifmgd->bssid); | ||
831 | } | ||
832 | #endif | ||
833 | bss_conf->use_short_preamble = use_short_preamble; | 825 | bss_conf->use_short_preamble = use_short_preamble; |
834 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 826 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
835 | } | 827 | } |
836 | 828 | ||
837 | if (use_short_slot != bss_conf->use_short_slot) { | 829 | if (use_short_slot != bss_conf->use_short_slot) { |
838 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
839 | if (net_ratelimit()) { | ||
840 | printk(KERN_DEBUG "%s: switched to %s slot time" | ||
841 | " (BSSID=%pM)\n", | ||
842 | sdata->dev->name, | ||
843 | use_short_slot ? "short" : "long", | ||
844 | ifmgd->bssid); | ||
845 | } | ||
846 | #endif | ||
847 | bss_conf->use_short_slot = use_short_slot; | 830 | bss_conf->use_short_slot = use_short_slot; |
848 | changed |= BSS_CHANGED_ERP_SLOT; | 831 | changed |= BSS_CHANGED_ERP_SLOT; |
849 | } | 832 | } |
@@ -852,32 +835,23 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
852 | } | 835 | } |
853 | 836 | ||
854 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 837 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
838 | struct ieee80211_bss *bss, | ||
855 | u32 bss_info_changed) | 839 | u32 bss_info_changed) |
856 | { | 840 | { |
857 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
858 | struct ieee80211_local *local = sdata->local; | 841 | struct ieee80211_local *local = sdata->local; |
859 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | ||
860 | |||
861 | struct ieee80211_bss *bss; | ||
862 | 842 | ||
863 | bss_info_changed |= BSS_CHANGED_ASSOC; | 843 | bss_info_changed |= BSS_CHANGED_ASSOC; |
864 | ifmgd->flags |= IEEE80211_STA_ASSOCIATED; | 844 | /* set timing information */ |
845 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; | ||
846 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; | ||
847 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | ||
865 | 848 | ||
866 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | 849 | bss_info_changed |= BSS_CHANGED_BEACON_INT; |
867 | conf->channel->center_freq, | 850 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
868 | ifmgd->ssid, ifmgd->ssid_len); | 851 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
869 | if (bss) { | ||
870 | /* set timing information */ | ||
871 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; | ||
872 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; | ||
873 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | ||
874 | 852 | ||
875 | bss_info_changed |= BSS_CHANGED_BEACON_INT; | 853 | sdata->u.mgd.associated = bss; |
876 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 854 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); |
877 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | ||
878 | |||
879 | ieee80211_rx_bss_put(local, bss); | ||
880 | } | ||
881 | 855 | ||
882 | ieee80211_led_assoc(local, 1); | 856 | ieee80211_led_assoc(local, 1); |
883 | 857 | ||
@@ -905,152 +879,133 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
905 | netif_carrier_on(sdata->dev); | 879 | netif_carrier_on(sdata->dev); |
906 | } | 880 | } |
907 | 881 | ||
908 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | 882 | static enum rx_mgmt_action __must_check |
883 | ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | ||
884 | struct ieee80211_mgd_work *wk) | ||
909 | { | 885 | { |
910 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 886 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
911 | struct ieee80211_local *local = sdata->local; | 887 | struct ieee80211_local *local = sdata->local; |
912 | 888 | ||
913 | ifmgd->direct_probe_tries++; | 889 | wk->tries++; |
914 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | 890 | if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { |
915 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | 891 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", |
916 | sdata->dev->name, ifmgd->bssid); | 892 | sdata->dev->name, wk->bss->cbss.bssid); |
917 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
918 | ieee80211_recalc_idle(local); | ||
919 | cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, | ||
920 | GFP_KERNEL); | ||
921 | 893 | ||
922 | /* | 894 | /* |
923 | * Most likely AP is not in the range so remove the | 895 | * Most likely AP is not in the range so remove the |
924 | * bss information associated to the AP | 896 | * bss struct for that AP. |
925 | */ | 897 | */ |
926 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 898 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); |
927 | sdata->local->hw.conf.channel->center_freq, | ||
928 | ifmgd->ssid, ifmgd->ssid_len); | ||
929 | 899 | ||
930 | /* | 900 | /* |
931 | * We might have a pending scan which had no chance to run yet | 901 | * We might have a pending scan which had no chance to run yet |
932 | * due to state == IEEE80211_STA_MLME_DIRECT_PROBE. | 902 | * due to work needing to be done. Hence, queue the STAs work |
933 | * Hence, queue the STAs work again | 903 | * again for that. |
934 | */ | 904 | */ |
935 | queue_work(local->hw.workqueue, &ifmgd->work); | 905 | queue_work(local->hw.workqueue, &ifmgd->work); |
936 | return; | 906 | return RX_MGMT_CFG80211_AUTH_TO; |
937 | } | 907 | } |
938 | 908 | ||
939 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", | 909 | printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", |
940 | sdata->dev->name, ifmgd->bssid, | 910 | sdata->dev->name, wk->bss->cbss.bssid, |
941 | ifmgd->direct_probe_tries); | 911 | wk->tries); |
942 | 912 | ||
943 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 913 | /* |
944 | 914 | * Direct probe is sent to broadcast address as some APs | |
945 | /* Direct probe is sent to broadcast address as some APs | ||
946 | * will not answer to direct packet in unassociated state. | 915 | * will not answer to direct packet in unassociated state. |
947 | */ | 916 | */ |
948 | ieee80211_send_probe_req(sdata, NULL, | 917 | ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); |
949 | ifmgd->ssid, ifmgd->ssid_len, NULL, 0); | 918 | |
919 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
920 | mod_timer(&ifmgd->timer, wk->timeout); | ||
950 | 921 | ||
951 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 922 | return RX_MGMT_NONE; |
952 | } | 923 | } |
953 | 924 | ||
954 | 925 | ||
955 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | 926 | static enum rx_mgmt_action __must_check |
927 | ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | ||
928 | struct ieee80211_mgd_work *wk) | ||
956 | { | 929 | { |
957 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 930 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
958 | struct ieee80211_local *local = sdata->local; | 931 | struct ieee80211_local *local = sdata->local; |
959 | 932 | ||
960 | ifmgd->auth_tries++; | 933 | wk->tries++; |
961 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | 934 | if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { |
962 | printk(KERN_DEBUG "%s: authentication with AP %pM" | 935 | printk(KERN_DEBUG "%s: authentication with AP %pM" |
963 | " timed out\n", | 936 | " timed out\n", |
964 | sdata->dev->name, ifmgd->bssid); | 937 | sdata->dev->name, wk->bss->cbss.bssid); |
965 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 938 | |
966 | ieee80211_recalc_idle(local); | 939 | /* |
967 | cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, | 940 | * Most likely AP is not in the range so remove the |
968 | GFP_KERNEL); | 941 | * bss struct for that AP. |
969 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 942 | */ |
970 | sdata->local->hw.conf.channel->center_freq, | 943 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); |
971 | ifmgd->ssid, ifmgd->ssid_len); | ||
972 | 944 | ||
973 | /* | 945 | /* |
974 | * We might have a pending scan which had no chance to run yet | 946 | * We might have a pending scan which had no chance to run yet |
975 | * due to state == IEEE80211_STA_MLME_AUTHENTICATE. | 947 | * due to work needing to be done. Hence, queue the STAs work |
976 | * Hence, queue the STAs work again | 948 | * again for that. |
977 | */ | 949 | */ |
978 | queue_work(local->hw.workqueue, &ifmgd->work); | 950 | queue_work(local->hw.workqueue, &ifmgd->work); |
979 | return; | 951 | return RX_MGMT_CFG80211_AUTH_TO; |
980 | } | 952 | } |
981 | 953 | ||
982 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; | 954 | printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", |
983 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", | 955 | sdata->dev->name, wk->bss->cbss.bssid, wk->tries); |
984 | sdata->dev->name, ifmgd->bssid); | 956 | |
957 | ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, | ||
958 | wk->bss->cbss.bssid, 0); | ||
959 | wk->auth_transaction = 2; | ||
985 | 960 | ||
986 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ifmgd->sme_auth_ie, | 961 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
987 | ifmgd->sme_auth_ie_len, ifmgd->bssid, 0); | 962 | mod_timer(&ifmgd->timer, wk->timeout); |
988 | ifmgd->auth_transaction = 2; | ||
989 | 963 | ||
990 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 964 | return RX_MGMT_NONE; |
991 | } | 965 | } |
992 | 966 | ||
993 | /* | ||
994 | * The disassoc 'reason' argument can be either our own reason | ||
995 | * if self disconnected or a reason code from the AP. | ||
996 | */ | ||
997 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 967 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
998 | bool deauth, bool self_disconnected, | 968 | const u8 *bssid, bool deauth) |
999 | u16 reason) | ||
1000 | { | 969 | { |
1001 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 970 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1002 | struct ieee80211_local *local = sdata->local; | 971 | struct ieee80211_local *local = sdata->local; |
1003 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | ||
1004 | struct ieee80211_bss *bss; | ||
1005 | struct sta_info *sta; | 972 | struct sta_info *sta; |
1006 | u32 changed = 0, config_changed = 0; | 973 | u32 changed = 0, config_changed = 0; |
1007 | 974 | ||
1008 | if (deauth) { | 975 | ASSERT_MGD_MTX(ifmgd); |
1009 | ifmgd->direct_probe_tries = 0; | 976 | |
1010 | ifmgd->auth_tries = 0; | 977 | ifmgd->associated = NULL; |
1011 | } | 978 | memset(ifmgd->bssid, 0, ETH_ALEN); |
1012 | ifmgd->assoc_scan_tries = 0; | 979 | |
1013 | ifmgd->assoc_tries = 0; | 980 | /* |
981 | * we need to commit the associated = NULL change because the | ||
982 | * scan code uses that to determine whether this iface should | ||
983 | * go to/wake up from powersave or not -- and could otherwise | ||
984 | * wake the queues erroneously. | ||
985 | */ | ||
986 | smp_mb(); | ||
987 | |||
988 | /* | ||
989 | * Thus, we can only afterwards stop the queues -- to account | ||
990 | * for the case where another CPU is finishing a scan at this | ||
991 | * time -- we don't want the scan code to enable queues. | ||
992 | */ | ||
1014 | 993 | ||
1015 | netif_tx_stop_all_queues(sdata->dev); | 994 | netif_tx_stop_all_queues(sdata->dev); |
1016 | netif_carrier_off(sdata->dev); | 995 | netif_carrier_off(sdata->dev); |
1017 | 996 | ||
1018 | rcu_read_lock(); | 997 | rcu_read_lock(); |
1019 | sta = sta_info_get(local, ifmgd->bssid); | 998 | sta = sta_info_get(local, bssid); |
1020 | if (sta) | 999 | if (sta) |
1021 | ieee80211_sta_tear_down_BA_sessions(sta); | 1000 | ieee80211_sta_tear_down_BA_sessions(sta); |
1022 | rcu_read_unlock(); | 1001 | rcu_read_unlock(); |
1023 | 1002 | ||
1024 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | ||
1025 | conf->channel->center_freq, | ||
1026 | ifmgd->ssid, ifmgd->ssid_len); | ||
1027 | |||
1028 | if (bss) | ||
1029 | ieee80211_rx_bss_put(local, bss); | ||
1030 | |||
1031 | if (self_disconnected) { | ||
1032 | if (deauth) | ||
1033 | ieee80211_send_deauth_disassoc(sdata, | ||
1034 | IEEE80211_STYPE_DEAUTH, reason); | ||
1035 | else | ||
1036 | ieee80211_send_deauth_disassoc(sdata, | ||
1037 | IEEE80211_STYPE_DISASSOC, reason); | ||
1038 | } | ||
1039 | |||
1040 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; | ||
1041 | changed |= ieee80211_reset_erp_info(sdata); | 1003 | changed |= ieee80211_reset_erp_info(sdata); |
1042 | 1004 | ||
1043 | ieee80211_led_assoc(local, 0); | 1005 | ieee80211_led_assoc(local, 0); |
1044 | changed |= BSS_CHANGED_ASSOC; | 1006 | changed |= BSS_CHANGED_ASSOC; |
1045 | sdata->vif.bss_conf.assoc = false; | 1007 | sdata->vif.bss_conf.assoc = false; |
1046 | 1008 | ||
1047 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { | ||
1048 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1049 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | ||
1050 | sdata->local->hw.conf.channel->center_freq, | ||
1051 | ifmgd->ssid, ifmgd->ssid_len); | ||
1052 | } | ||
1053 | |||
1054 | ieee80211_set_wmm_default(sdata); | 1009 | ieee80211_set_wmm_default(sdata); |
1055 | 1010 | ||
1056 | ieee80211_recalc_idle(local); | 1011 | ieee80211_recalc_idle(local); |
@@ -1079,7 +1034,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1079 | 1034 | ||
1080 | rcu_read_lock(); | 1035 | rcu_read_lock(); |
1081 | 1036 | ||
1082 | sta = sta_info_get(local, ifmgd->bssid); | 1037 | sta = sta_info_get(local, bssid); |
1083 | if (!sta) { | 1038 | if (!sta) { |
1084 | rcu_read_unlock(); | 1039 | rcu_read_unlock(); |
1085 | return; | 1040 | return; |
@@ -1092,38 +1047,42 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1092 | sta_info_destroy(sta); | 1047 | sta_info_destroy(sta); |
1093 | } | 1048 | } |
1094 | 1049 | ||
1095 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | 1050 | static enum rx_mgmt_action __must_check |
1051 | ieee80211_associate(struct ieee80211_sub_if_data *sdata, | ||
1052 | struct ieee80211_mgd_work *wk) | ||
1096 | { | 1053 | { |
1097 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1054 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1098 | struct ieee80211_local *local = sdata->local; | 1055 | struct ieee80211_local *local = sdata->local; |
1099 | 1056 | ||
1100 | ifmgd->assoc_tries++; | 1057 | wk->tries++; |
1101 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | 1058 | if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { |
1102 | printk(KERN_DEBUG "%s: association with AP %pM" | 1059 | printk(KERN_DEBUG "%s: association with AP %pM" |
1103 | " timed out\n", | 1060 | " timed out\n", |
1104 | sdata->dev->name, ifmgd->bssid); | 1061 | sdata->dev->name, wk->bss->cbss.bssid); |
1105 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 1062 | |
1106 | ieee80211_recalc_idle(local); | 1063 | /* |
1107 | cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid, | 1064 | * Most likely AP is not in the range so remove the |
1108 | GFP_KERNEL); | 1065 | * bss struct for that AP. |
1109 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 1066 | */ |
1110 | sdata->local->hw.conf.channel->center_freq, | 1067 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); |
1111 | ifmgd->ssid, ifmgd->ssid_len); | 1068 | |
1112 | /* | 1069 | /* |
1113 | * We might have a pending scan which had no chance to run yet | 1070 | * We might have a pending scan which had no chance to run yet |
1114 | * due to state == IEEE80211_STA_MLME_ASSOCIATE. | 1071 | * due to work needing to be done. Hence, queue the STAs work |
1115 | * Hence, queue the STAs work again | 1072 | * again for that. |
1116 | */ | 1073 | */ |
1117 | queue_work(local->hw.workqueue, &ifmgd->work); | 1074 | queue_work(local->hw.workqueue, &ifmgd->work); |
1118 | return; | 1075 | return RX_MGMT_CFG80211_ASSOC_TO; |
1119 | } | 1076 | } |
1120 | 1077 | ||
1121 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; | 1078 | printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", |
1122 | printk(KERN_DEBUG "%s: associate with AP %pM\n", | 1079 | sdata->dev->name, wk->bss->cbss.bssid, wk->tries); |
1123 | sdata->dev->name, ifmgd->bssid); | 1080 | ieee80211_send_assoc(sdata, wk); |
1124 | ieee80211_send_assoc(sdata); | 1081 | |
1082 | wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
1083 | mod_timer(&ifmgd->timer, wk->timeout); | ||
1125 | 1084 | ||
1126 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); | 1085 | return RX_MGMT_NONE; |
1127 | } | 1086 | } |
1128 | 1087 | ||
1129 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1088 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -1148,6 +1107,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work) | |||
1148 | container_of(work, struct ieee80211_sub_if_data, | 1107 | container_of(work, struct ieee80211_sub_if_data, |
1149 | u.mgd.beacon_loss_work); | 1108 | u.mgd.beacon_loss_work); |
1150 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1109 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1110 | const u8 *ssid; | ||
1151 | 1111 | ||
1152 | /* | 1112 | /* |
1153 | * The driver has already reported this event and we have | 1113 | * The driver has already reported this event and we have |
@@ -1160,12 +1120,15 @@ void ieee80211_beacon_loss_work(struct work_struct *work) | |||
1160 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) | 1120 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) |
1161 | return; | 1121 | return; |
1162 | 1122 | ||
1123 | mutex_lock(&ifmgd->mtx); | ||
1124 | |||
1125 | if (!ifmgd->associated) | ||
1126 | goto out; | ||
1127 | |||
1163 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1128 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1164 | if (net_ratelimit()) { | 1129 | if (net_ratelimit()) |
1165 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " | 1130 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP " |
1166 | "- sending probe request\n", sdata->dev->name, | 1131 | "- sending probe request\n", sdata->dev->name); |
1167 | sdata->u.mgd.bssid); | ||
1168 | } | ||
1169 | #endif | 1132 | #endif |
1170 | 1133 | ||
1171 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | 1134 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; |
@@ -1174,10 +1137,13 @@ void ieee80211_beacon_loss_work(struct work_struct *work) | |||
1174 | ieee80211_recalc_ps(sdata->local, -1); | 1137 | ieee80211_recalc_ps(sdata->local, -1); |
1175 | mutex_unlock(&sdata->local->iflist_mtx); | 1138 | mutex_unlock(&sdata->local->iflist_mtx); |
1176 | 1139 | ||
1177 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | 1140 | ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); |
1178 | ifmgd->ssid_len, NULL, 0); | 1141 | ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, |
1142 | ssid + 2, ssid[1], NULL, 0); | ||
1179 | 1143 | ||
1180 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); | 1144 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); |
1145 | out: | ||
1146 | mutex_unlock(&ifmgd->mtx); | ||
1181 | } | 1147 | } |
1182 | 1148 | ||
1183 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 1149 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
@@ -1189,102 +1155,16 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |||
1189 | } | 1155 | } |
1190 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 1156 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
1191 | 1157 | ||
1192 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | 1158 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, |
1159 | struct ieee80211_mgd_work *wk) | ||
1193 | { | 1160 | { |
1194 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1161 | wk->state = IEEE80211_MGD_STATE_IDLE; |
1195 | struct ieee80211_local *local = sdata->local; | ||
1196 | struct sta_info *sta; | ||
1197 | unsigned long last_rx; | ||
1198 | bool disassoc = false; | ||
1199 | |||
1200 | /* TODO: start monitoring current AP signal quality and number of | ||
1201 | * missed beacons. Scan other channels every now and then and search | ||
1202 | * for better APs. */ | ||
1203 | /* TODO: remove expired BSSes */ | ||
1204 | |||
1205 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED; | ||
1206 | |||
1207 | rcu_read_lock(); | ||
1208 | |||
1209 | sta = sta_info_get(local, ifmgd->bssid); | ||
1210 | if (!sta) { | ||
1211 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | ||
1212 | sdata->dev->name, ifmgd->bssid); | ||
1213 | disassoc = true; | ||
1214 | rcu_read_unlock(); | ||
1215 | goto out; | ||
1216 | } | ||
1217 | |||
1218 | last_rx = sta->last_rx; | ||
1219 | rcu_read_unlock(); | ||
1220 | |||
1221 | if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && | ||
1222 | time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) { | ||
1223 | printk(KERN_DEBUG "%s: no probe response from AP %pM " | ||
1224 | "- disassociating\n", | ||
1225 | sdata->dev->name, ifmgd->bssid); | ||
1226 | disassoc = true; | ||
1227 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
1228 | goto out; | ||
1229 | } | ||
1230 | |||
1231 | /* | ||
1232 | * Beacon filtering is only enabled with power save and then the | ||
1233 | * stack should not check for beacon loss. | ||
1234 | */ | ||
1235 | if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) && | ||
1236 | (local->hw.conf.flags & IEEE80211_CONF_PS)) && | ||
1237 | time_after(jiffies, | ||
1238 | ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { | ||
1239 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1240 | if (net_ratelimit()) { | ||
1241 | printk(KERN_DEBUG "%s: beacon loss from AP %pM " | ||
1242 | "- sending probe request\n", | ||
1243 | sdata->dev->name, ifmgd->bssid); | ||
1244 | } | ||
1245 | #endif | ||
1246 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1247 | mutex_lock(&local->iflist_mtx); | ||
1248 | ieee80211_recalc_ps(local, -1); | ||
1249 | mutex_unlock(&local->iflist_mtx); | ||
1250 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1251 | ifmgd->ssid_len, NULL, 0); | ||
1252 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); | ||
1253 | goto out; | ||
1254 | } | ||
1255 | |||
1256 | if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) { | ||
1257 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1258 | mutex_lock(&local->iflist_mtx); | ||
1259 | ieee80211_recalc_ps(local, -1); | ||
1260 | mutex_unlock(&local->iflist_mtx); | ||
1261 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1262 | ifmgd->ssid_len, NULL, 0); | ||
1263 | } | ||
1264 | |||
1265 | out: | ||
1266 | if (!disassoc) | ||
1267 | mod_timer(&ifmgd->timer, | ||
1268 | jiffies + IEEE80211_MONITORING_INTERVAL); | ||
1269 | else | ||
1270 | ieee80211_set_disassoc(sdata, true, true, | ||
1271 | WLAN_REASON_PREV_AUTH_NOT_VALID); | ||
1272 | } | ||
1273 | |||
1274 | |||
1275 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) | ||
1276 | { | ||
1277 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1278 | |||
1279 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | 1162 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); |
1280 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; | ||
1281 | /* Wait for SME to request association */ | ||
1282 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1283 | ieee80211_recalc_idle(sdata->local); | ||
1284 | } | 1163 | } |
1285 | 1164 | ||
1286 | 1165 | ||
1287 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | 1166 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, |
1167 | struct ieee80211_mgd_work *wk, | ||
1288 | struct ieee80211_mgmt *mgmt, | 1168 | struct ieee80211_mgmt *mgmt, |
1289 | size_t len) | 1169 | size_t len) |
1290 | { | 1170 | { |
@@ -1295,120 +1175,132 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1295 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 1175 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
1296 | if (!elems.challenge) | 1176 | if (!elems.challenge) |
1297 | return; | 1177 | return; |
1298 | ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg, | 1178 | ieee80211_send_auth(sdata, 3, wk->auth_alg, |
1299 | elems.challenge - 2, elems.challenge_len + 2, | 1179 | elems.challenge - 2, elems.challenge_len + 2, |
1300 | sdata->u.mgd.bssid, 1); | 1180 | wk->bss->cbss.bssid, 1); |
1301 | sdata->u.mgd.auth_transaction = 4; | 1181 | wk->auth_transaction = 4; |
1302 | } | 1182 | } |
1303 | 1183 | ||
1304 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 1184 | static enum rx_mgmt_action __must_check |
1305 | struct ieee80211_mgmt *mgmt, | 1185 | ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1306 | size_t len) | 1186 | struct ieee80211_mgd_work *wk, |
1187 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1307 | { | 1188 | { |
1308 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1309 | u16 auth_alg, auth_transaction, status_code; | 1189 | u16 auth_alg, auth_transaction, status_code; |
1310 | 1190 | ||
1311 | if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE) | 1191 | if (wk->state != IEEE80211_MGD_STATE_AUTH) |
1312 | return; | 1192 | return RX_MGMT_NONE; |
1313 | 1193 | ||
1314 | if (len < 24 + 6) | 1194 | if (len < 24 + 6) |
1315 | return; | 1195 | return RX_MGMT_NONE; |
1316 | 1196 | ||
1317 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) | 1197 | if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) |
1318 | return; | 1198 | return RX_MGMT_NONE; |
1319 | 1199 | ||
1320 | if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1200 | if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) |
1321 | return; | 1201 | return RX_MGMT_NONE; |
1322 | 1202 | ||
1323 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 1203 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
1324 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 1204 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
1325 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1205 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
1326 | 1206 | ||
1327 | if (auth_alg != ifmgd->auth_alg || | 1207 | if (auth_alg != wk->auth_alg || |
1328 | auth_transaction != ifmgd->auth_transaction) | 1208 | auth_transaction != wk->auth_transaction) |
1329 | return; | 1209 | return RX_MGMT_NONE; |
1330 | 1210 | ||
1331 | if (status_code != WLAN_STATUS_SUCCESS) { | 1211 | if (status_code != WLAN_STATUS_SUCCESS) { |
1332 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, | 1212 | list_del(&wk->list); |
1333 | GFP_KERNEL); | 1213 | kfree(wk); |
1334 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | 1214 | return RX_MGMT_CFG80211_AUTH; |
1335 | ieee80211_recalc_idle(sdata->local); | ||
1336 | return; | ||
1337 | } | 1215 | } |
1338 | 1216 | ||
1339 | switch (ifmgd->auth_alg) { | 1217 | switch (wk->auth_alg) { |
1340 | case WLAN_AUTH_OPEN: | 1218 | case WLAN_AUTH_OPEN: |
1341 | case WLAN_AUTH_LEAP: | 1219 | case WLAN_AUTH_LEAP: |
1342 | case WLAN_AUTH_FT: | 1220 | case WLAN_AUTH_FT: |
1343 | ieee80211_auth_completed(sdata); | 1221 | ieee80211_auth_completed(sdata, wk); |
1344 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, | 1222 | return RX_MGMT_CFG80211_AUTH; |
1345 | GFP_KERNEL); | ||
1346 | break; | ||
1347 | case WLAN_AUTH_SHARED_KEY: | 1223 | case WLAN_AUTH_SHARED_KEY: |
1348 | if (ifmgd->auth_transaction == 4) { | 1224 | if (wk->auth_transaction == 4) { |
1349 | ieee80211_auth_completed(sdata); | 1225 | ieee80211_auth_completed(sdata, wk); |
1350 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, | 1226 | return RX_MGMT_CFG80211_AUTH; |
1351 | GFP_KERNEL); | ||
1352 | } else | 1227 | } else |
1353 | ieee80211_auth_challenge(sdata, mgmt, len); | 1228 | ieee80211_auth_challenge(sdata, wk, mgmt, len); |
1354 | break; | 1229 | break; |
1355 | } | 1230 | } |
1231 | |||
1232 | return RX_MGMT_NONE; | ||
1356 | } | 1233 | } |
1357 | 1234 | ||
1358 | 1235 | ||
1359 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1236 | static enum rx_mgmt_action __must_check |
1360 | struct ieee80211_mgmt *mgmt, | 1237 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1361 | size_t len) | 1238 | struct ieee80211_mgd_work *wk, |
1239 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1362 | { | 1240 | { |
1363 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1241 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1242 | const u8 *bssid = NULL; | ||
1364 | u16 reason_code; | 1243 | u16 reason_code; |
1365 | 1244 | ||
1366 | if (len < 24 + 2) | 1245 | if (len < 24 + 2) |
1367 | return; | 1246 | return RX_MGMT_NONE; |
1368 | 1247 | ||
1369 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) | 1248 | ASSERT_MGD_MTX(ifmgd); |
1370 | return; | 1249 | |
1250 | if (wk) | ||
1251 | bssid = wk->bss->cbss.bssid; | ||
1252 | else | ||
1253 | bssid = ifmgd->associated->cbss.bssid; | ||
1371 | 1254 | ||
1372 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 1255 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
1373 | 1256 | ||
1374 | if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED) | 1257 | printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", |
1375 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", | 1258 | sdata->dev->name, bssid, reason_code); |
1376 | sdata->dev->name, reason_code); | 1259 | |
1260 | if (!wk) { | ||
1261 | ieee80211_set_disassoc(sdata, bssid, true); | ||
1262 | } else { | ||
1263 | list_del(&wk->list); | ||
1264 | kfree(wk); | ||
1265 | } | ||
1377 | 1266 | ||
1378 | ieee80211_set_disassoc(sdata, true, false, 0); | 1267 | return RX_MGMT_CFG80211_DEAUTH; |
1379 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; | ||
1380 | cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); | ||
1381 | } | 1268 | } |
1382 | 1269 | ||
1383 | 1270 | ||
1384 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | 1271 | static enum rx_mgmt_action __must_check |
1385 | struct ieee80211_mgmt *mgmt, | 1272 | ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, |
1386 | size_t len) | 1273 | struct ieee80211_mgmt *mgmt, size_t len) |
1387 | { | 1274 | { |
1388 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1275 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1389 | u16 reason_code; | 1276 | u16 reason_code; |
1390 | 1277 | ||
1391 | if (len < 24 + 2) | 1278 | if (len < 24 + 2) |
1392 | return; | 1279 | return RX_MGMT_NONE; |
1393 | 1280 | ||
1394 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) | 1281 | ASSERT_MGD_MTX(ifmgd); |
1395 | return; | 1282 | |
1283 | if (WARN_ON(!ifmgd->associated)) | ||
1284 | return RX_MGMT_NONE; | ||
1285 | |||
1286 | if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN))) | ||
1287 | return RX_MGMT_NONE; | ||
1396 | 1288 | ||
1397 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1289 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
1398 | 1290 | ||
1399 | if (ifmgd->flags & IEEE80211_STA_ASSOCIATED) | 1291 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1400 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1292 | sdata->dev->name, reason_code); |
1401 | sdata->dev->name, reason_code); | ||
1402 | 1293 | ||
1403 | ieee80211_set_disassoc(sdata, false, false, reason_code); | 1294 | ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false); |
1404 | cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); | 1295 | return RX_MGMT_CFG80211_DISASSOC; |
1405 | } | 1296 | } |
1406 | 1297 | ||
1407 | 1298 | ||
1408 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 1299 | static enum rx_mgmt_action __must_check |
1409 | struct ieee80211_mgmt *mgmt, | 1300 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, |
1410 | size_t len, | 1301 | struct ieee80211_mgd_work *wk, |
1411 | int reassoc) | 1302 | struct ieee80211_mgmt *mgmt, size_t len, |
1303 | bool reassoc) | ||
1412 | { | 1304 | { |
1413 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1305 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1414 | struct ieee80211_local *local = sdata->local; | 1306 | struct ieee80211_local *local = sdata->local; |
@@ -1424,17 +1316,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1424 | bool have_higher_than_11mbit = false, newsta = false; | 1316 | bool have_higher_than_11mbit = false, newsta = false; |
1425 | u16 ap_ht_cap_flags; | 1317 | u16 ap_ht_cap_flags; |
1426 | 1318 | ||
1427 | /* AssocResp and ReassocResp have identical structure, so process both | 1319 | /* |
1428 | * of them in this function. */ | 1320 | * AssocResp and ReassocResp have identical structure, so process both |
1429 | 1321 | * of them in this function. | |
1430 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) | 1322 | */ |
1431 | return; | ||
1432 | 1323 | ||
1433 | if (len < 24 + 6) | 1324 | if (len < 24 + 6) |
1434 | return; | 1325 | return RX_MGMT_NONE; |
1435 | 1326 | ||
1436 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) | 1327 | if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) |
1437 | return; | 1328 | return RX_MGMT_NONE; |
1438 | 1329 | ||
1439 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 1330 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
1440 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 1331 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
@@ -1457,21 +1348,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1457 | printk(KERN_DEBUG "%s: AP rejected association temporarily; " | 1348 | printk(KERN_DEBUG "%s: AP rejected association temporarily; " |
1458 | "comeback duration %u TU (%u ms)\n", | 1349 | "comeback duration %u TU (%u ms)\n", |
1459 | sdata->dev->name, tu, ms); | 1350 | sdata->dev->name, tu, ms); |
1351 | wk->timeout = jiffies + msecs_to_jiffies(ms); | ||
1460 | if (ms > IEEE80211_ASSOC_TIMEOUT) | 1352 | if (ms > IEEE80211_ASSOC_TIMEOUT) |
1461 | mod_timer(&ifmgd->timer, | 1353 | mod_timer(&ifmgd->timer, |
1462 | jiffies + msecs_to_jiffies(ms)); | 1354 | jiffies + msecs_to_jiffies(ms)); |
1463 | return; | 1355 | return RX_MGMT_NONE; |
1464 | } | 1356 | } |
1465 | 1357 | ||
1466 | if (status_code != WLAN_STATUS_SUCCESS) { | 1358 | if (status_code != WLAN_STATUS_SUCCESS) { |
1467 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | 1359 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", |
1468 | sdata->dev->name, status_code); | 1360 | sdata->dev->name, status_code); |
1469 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, | 1361 | list_del(&wk->list); |
1470 | GFP_KERNEL); | 1362 | kfree(wk); |
1471 | /* Wait for SME to decide what to do next */ | 1363 | return RX_MGMT_CFG80211_ASSOC; |
1472 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1473 | ieee80211_recalc_idle(local); | ||
1474 | return; | ||
1475 | } | 1364 | } |
1476 | 1365 | ||
1477 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | 1366 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) |
@@ -1482,50 +1371,38 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1482 | if (!elems.supp_rates) { | 1371 | if (!elems.supp_rates) { |
1483 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", | 1372 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", |
1484 | sdata->dev->name); | 1373 | sdata->dev->name); |
1485 | return; | 1374 | return RX_MGMT_NONE; |
1486 | } | 1375 | } |
1487 | 1376 | ||
1488 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); | 1377 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); |
1489 | ifmgd->aid = aid; | 1378 | ifmgd->aid = aid; |
1490 | 1379 | ||
1491 | kfree(ifmgd->assocresp_ies); | ||
1492 | ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); | ||
1493 | ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL); | ||
1494 | if (ifmgd->assocresp_ies) | ||
1495 | memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len); | ||
1496 | |||
1497 | rcu_read_lock(); | 1380 | rcu_read_lock(); |
1498 | 1381 | ||
1499 | /* Add STA entry for the AP */ | 1382 | /* Add STA entry for the AP */ |
1500 | sta = sta_info_get(local, ifmgd->bssid); | 1383 | sta = sta_info_get(local, wk->bss->cbss.bssid); |
1501 | if (!sta) { | 1384 | if (!sta) { |
1502 | newsta = true; | 1385 | newsta = true; |
1503 | 1386 | ||
1504 | sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC); | 1387 | rcu_read_unlock(); |
1388 | |||
1389 | sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); | ||
1505 | if (!sta) { | 1390 | if (!sta) { |
1506 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1391 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
1507 | " the AP\n", sdata->dev->name); | 1392 | " the AP\n", sdata->dev->name); |
1508 | rcu_read_unlock(); | 1393 | return RX_MGMT_NONE; |
1509 | return; | ||
1510 | } | 1394 | } |
1511 | 1395 | ||
1512 | /* update new sta with its last rx activity */ | 1396 | /* update new sta with its last rx activity */ |
1513 | sta->last_rx = jiffies; | 1397 | sta->last_rx = jiffies; |
1514 | } | ||
1515 | 1398 | ||
1516 | /* | 1399 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | |
1517 | * FIXME: Do we really need to update the sta_info's information here? | 1400 | WLAN_STA_ASSOC_AP); |
1518 | * We already know about the AP (we found it in our list) so it | 1401 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
1519 | * should already be filled with the right info, no? | 1402 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); |
1520 | * As is stands, all this is racy because typically we assume | ||
1521 | * the information that is filled in here (except flags) doesn't | ||
1522 | * change while a STA structure is alive. As such, it should move | ||
1523 | * to between the sta_info_alloc() and sta_info_insert() above. | ||
1524 | */ | ||
1525 | 1403 | ||
1526 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); | 1404 | rcu_read_lock(); |
1527 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 1405 | } |
1528 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
1529 | 1406 | ||
1530 | rates = 0; | 1407 | rates = 0; |
1531 | basic_rates = 0; | 1408 | basic_rates = 0; |
@@ -1595,7 +1472,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1595 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 1472 | printk(KERN_DEBUG "%s: failed to insert STA entry for" |
1596 | " the AP (error %d)\n", sdata->dev->name, err); | 1473 | " the AP (error %d)\n", sdata->dev->name, err); |
1597 | rcu_read_unlock(); | 1474 | rcu_read_unlock(); |
1598 | return; | 1475 | return RX_MGMT_NONE; |
1599 | } | 1476 | } |
1600 | } | 1477 | } |
1601 | 1478 | ||
@@ -1611,13 +1488,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1611 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | 1488 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
1612 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 1489 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
1613 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1490 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1491 | wk->bss->cbss.bssid, | ||
1614 | ap_ht_cap_flags); | 1492 | ap_ht_cap_flags); |
1615 | 1493 | ||
1616 | /* set AID and assoc capability, | 1494 | /* set AID and assoc capability, |
1617 | * ieee80211_set_associated() will tell the driver */ | 1495 | * ieee80211_set_associated() will tell the driver */ |
1618 | bss_conf->aid = aid; | 1496 | bss_conf->aid = aid; |
1619 | bss_conf->assoc_capability = capab_info; | 1497 | bss_conf->assoc_capability = capab_info; |
1620 | ieee80211_set_associated(sdata, changed); | 1498 | ieee80211_set_associated(sdata, wk->bss, changed); |
1621 | 1499 | ||
1622 | /* | 1500 | /* |
1623 | * initialise the time of last beacon to be the association time, | 1501 | * initialise the time of last beacon to be the association time, |
@@ -1625,8 +1503,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1625 | */ | 1503 | */ |
1626 | ifmgd->last_beacon = jiffies; | 1504 | ifmgd->last_beacon = jiffies; |
1627 | 1505 | ||
1628 | ieee80211_associated(sdata); | 1506 | list_del(&wk->list); |
1629 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); | 1507 | kfree(wk); |
1508 | return RX_MGMT_CFG80211_ASSOC; | ||
1630 | } | 1509 | } |
1631 | 1510 | ||
1632 | 1511 | ||
@@ -1654,23 +1533,25 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1654 | 1533 | ||
1655 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 1534 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
1656 | channel, beacon); | 1535 | channel, beacon); |
1657 | if (!bss) | 1536 | if (bss) |
1537 | ieee80211_rx_bss_put(local, bss); | ||
1538 | |||
1539 | if (!sdata->u.mgd.associated) | ||
1658 | return; | 1540 | return; |
1659 | 1541 | ||
1660 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 1542 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && |
1661 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { | 1543 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid, |
1544 | ETH_ALEN) == 0)) { | ||
1662 | struct ieee80211_channel_sw_ie *sw_elem = | 1545 | struct ieee80211_channel_sw_ie *sw_elem = |
1663 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1546 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
1664 | ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); | 1547 | ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); |
1665 | } | 1548 | } |
1666 | |||
1667 | ieee80211_rx_bss_put(local, bss); | ||
1668 | } | 1549 | } |
1669 | 1550 | ||
1670 | 1551 | ||
1671 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | 1552 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, |
1672 | struct ieee80211_mgmt *mgmt, | 1553 | struct ieee80211_mgd_work *wk, |
1673 | size_t len, | 1554 | struct ieee80211_mgmt *mgmt, size_t len, |
1674 | struct ieee80211_rx_status *rx_status) | 1555 | struct ieee80211_rx_status *rx_status) |
1675 | { | 1556 | { |
1676 | struct ieee80211_if_managed *ifmgd; | 1557 | struct ieee80211_if_managed *ifmgd; |
@@ -1679,6 +1560,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1679 | 1560 | ||
1680 | ifmgd = &sdata->u.mgd; | 1561 | ifmgd = &sdata->u.mgd; |
1681 | 1562 | ||
1563 | ASSERT_MGD_MTX(ifmgd); | ||
1564 | |||
1682 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1565 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) |
1683 | return; /* ignore ProbeResp to foreign address */ | 1566 | return; /* ignore ProbeResp to foreign address */ |
1684 | 1567 | ||
@@ -1692,13 +1575,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1692 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1575 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1693 | 1576 | ||
1694 | /* direct probe may be part of the association flow */ | 1577 | /* direct probe may be part of the association flow */ |
1695 | if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) { | 1578 | if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { |
1696 | printk(KERN_DEBUG "%s direct probe responded\n", | 1579 | printk(KERN_DEBUG "%s direct probe responded\n", |
1697 | sdata->dev->name); | 1580 | sdata->dev->name); |
1698 | ieee80211_authenticate(sdata); | 1581 | wk->tries = 0; |
1582 | wk->state = IEEE80211_MGD_STATE_AUTH; | ||
1583 | WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); | ||
1699 | } | 1584 | } |
1700 | 1585 | ||
1701 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | 1586 | if (ifmgd->associated && |
1587 | memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && | ||
1588 | ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | ||
1702 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 1589 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; |
1703 | mutex_lock(&sdata->local->iflist_mtx); | 1590 | mutex_lock(&sdata->local->iflist_mtx); |
1704 | ieee80211_recalc_ps(sdata->local, -1); | 1591 | ieee80211_recalc_ps(sdata->local, -1); |
@@ -1740,6 +1627,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1740 | bool erp_valid, directed_tim = false; | 1627 | bool erp_valid, directed_tim = false; |
1741 | u8 erp_value = 0; | 1628 | u8 erp_value = 0; |
1742 | u32 ncrc; | 1629 | u32 ncrc; |
1630 | u8 *bssid; | ||
1631 | |||
1632 | ASSERT_MGD_MTX(ifmgd); | ||
1743 | 1633 | ||
1744 | /* Process beacon from the current BSS */ | 1634 | /* Process beacon from the current BSS */ |
1745 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 1635 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
@@ -1749,8 +1639,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1749 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 1639 | if (rx_status->freq != local->hw.conf.channel->center_freq) |
1750 | return; | 1640 | return; |
1751 | 1641 | ||
1752 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || | 1642 | if (WARN_ON(!ifmgd->associated)) |
1753 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1643 | return; |
1644 | |||
1645 | bssid = ifmgd->associated->cbss.bssid; | ||
1646 | |||
1647 | if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)) | ||
1754 | return; | 1648 | return; |
1755 | 1649 | ||
1756 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | 1650 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { |
@@ -1829,8 +1723,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1829 | 1723 | ||
1830 | rcu_read_lock(); | 1724 | rcu_read_lock(); |
1831 | 1725 | ||
1832 | sta = sta_info_get(local, ifmgd->bssid); | 1726 | sta = sta_info_get(local, bssid); |
1833 | if (!sta) { | 1727 | if (WARN_ON(!sta)) { |
1834 | rcu_read_unlock(); | 1728 | rcu_read_unlock(); |
1835 | return; | 1729 | return; |
1836 | } | 1730 | } |
@@ -1845,7 +1739,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1845 | rcu_read_unlock(); | 1739 | rcu_read_unlock(); |
1846 | 1740 | ||
1847 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1741 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1848 | ap_ht_cap_flags); | 1742 | bssid, ap_ht_cap_flags); |
1849 | } | 1743 | } |
1850 | 1744 | ||
1851 | if (elems.country_elem) { | 1745 | if (elems.country_elem) { |
@@ -1887,6 +1781,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1887 | case IEEE80211_STYPE_REASSOC_RESP: | 1781 | case IEEE80211_STYPE_REASSOC_RESP: |
1888 | case IEEE80211_STYPE_DEAUTH: | 1782 | case IEEE80211_STYPE_DEAUTH: |
1889 | case IEEE80211_STYPE_DISASSOC: | 1783 | case IEEE80211_STYPE_DISASSOC: |
1784 | case IEEE80211_STYPE_ACTION: | ||
1890 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); | 1785 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); |
1891 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); | 1786 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); |
1892 | return RX_QUEUED; | 1787 | return RX_QUEUED; |
@@ -1898,40 +1793,118 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1898 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1793 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1899 | struct sk_buff *skb) | 1794 | struct sk_buff *skb) |
1900 | { | 1795 | { |
1796 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1901 | struct ieee80211_rx_status *rx_status; | 1797 | struct ieee80211_rx_status *rx_status; |
1902 | struct ieee80211_mgmt *mgmt; | 1798 | struct ieee80211_mgmt *mgmt; |
1799 | struct ieee80211_mgd_work *wk; | ||
1800 | enum rx_mgmt_action rma = RX_MGMT_NONE; | ||
1903 | u16 fc; | 1801 | u16 fc; |
1904 | 1802 | ||
1905 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 1803 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
1906 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1804 | mgmt = (struct ieee80211_mgmt *) skb->data; |
1907 | fc = le16_to_cpu(mgmt->frame_control); | 1805 | fc = le16_to_cpu(mgmt->frame_control); |
1908 | 1806 | ||
1909 | switch (fc & IEEE80211_FCTL_STYPE) { | 1807 | mutex_lock(&ifmgd->mtx); |
1910 | case IEEE80211_STYPE_PROBE_RESP: | 1808 | |
1911 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | 1809 | if (ifmgd->associated && |
1912 | rx_status); | 1810 | memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid, |
1913 | break; | 1811 | ETH_ALEN) == 0) { |
1914 | case IEEE80211_STYPE_BEACON: | 1812 | switch (fc & IEEE80211_FCTL_STYPE) { |
1915 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 1813 | case IEEE80211_STYPE_BEACON: |
1916 | rx_status); | 1814 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
1917 | break; | 1815 | rx_status); |
1918 | case IEEE80211_STYPE_AUTH: | 1816 | break; |
1919 | ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); | 1817 | case IEEE80211_STYPE_PROBE_RESP: |
1920 | break; | 1818 | ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, |
1921 | case IEEE80211_STYPE_ASSOC_RESP: | 1819 | skb->len, rx_status); |
1922 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0); | 1820 | break; |
1821 | case IEEE80211_STYPE_DEAUTH: | ||
1822 | rma = ieee80211_rx_mgmt_deauth(sdata, NULL, | ||
1823 | mgmt, skb->len); | ||
1824 | break; | ||
1825 | case IEEE80211_STYPE_DISASSOC: | ||
1826 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | ||
1827 | break; | ||
1828 | case IEEE80211_STYPE_ACTION: | ||
1829 | /* XXX: differentiate, can only happen for CSA now! */ | ||
1830 | ieee80211_sta_process_chanswitch(sdata, | ||
1831 | &mgmt->u.action.u.chan_switch.sw_elem, | ||
1832 | ifmgd->associated); | ||
1833 | break; | ||
1834 | } | ||
1835 | mutex_unlock(&ifmgd->mtx); | ||
1836 | |||
1837 | switch (rma) { | ||
1838 | case RX_MGMT_NONE: | ||
1839 | /* no action */ | ||
1840 | break; | ||
1841 | case RX_MGMT_CFG80211_DEAUTH: | ||
1842 | cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, | ||
1843 | skb->len, GFP_KERNEL); | ||
1844 | break; | ||
1845 | case RX_MGMT_CFG80211_DISASSOC: | ||
1846 | cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, | ||
1847 | skb->len, GFP_KERNEL); | ||
1848 | break; | ||
1849 | default: | ||
1850 | WARN(1, "unexpected: %d", rma); | ||
1851 | } | ||
1852 | goto out; | ||
1853 | } | ||
1854 | |||
1855 | list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
1856 | if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1857 | continue; | ||
1858 | |||
1859 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
1860 | case IEEE80211_STYPE_PROBE_RESP: | ||
1861 | ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, | ||
1862 | rx_status); | ||
1863 | break; | ||
1864 | case IEEE80211_STYPE_AUTH: | ||
1865 | rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); | ||
1866 | break; | ||
1867 | case IEEE80211_STYPE_ASSOC_RESP: | ||
1868 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
1869 | skb->len, false); | ||
1870 | break; | ||
1871 | case IEEE80211_STYPE_REASSOC_RESP: | ||
1872 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
1873 | skb->len, true); | ||
1874 | break; | ||
1875 | case IEEE80211_STYPE_DEAUTH: | ||
1876 | rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, | ||
1877 | skb->len); | ||
1878 | break; | ||
1879 | } | ||
1880 | /* | ||
1881 | * We've processed this frame for that work, so it can't | ||
1882 | * belong to another work struct. | ||
1883 | * NB: this is also required for correctness because the | ||
1884 | * called functions can free 'wk', and for 'rma'! | ||
1885 | */ | ||
1923 | break; | 1886 | break; |
1924 | case IEEE80211_STYPE_REASSOC_RESP: | 1887 | } |
1925 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1); | 1888 | |
1889 | mutex_unlock(&ifmgd->mtx); | ||
1890 | |||
1891 | switch (rma) { | ||
1892 | case RX_MGMT_NONE: | ||
1893 | /* no action */ | ||
1926 | break; | 1894 | break; |
1927 | case IEEE80211_STYPE_DEAUTH: | 1895 | case RX_MGMT_CFG80211_AUTH: |
1928 | ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); | 1896 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len, |
1897 | GFP_KERNEL); | ||
1929 | break; | 1898 | break; |
1930 | case IEEE80211_STYPE_DISASSOC: | 1899 | case RX_MGMT_CFG80211_ASSOC: |
1931 | ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | 1900 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len, |
1901 | GFP_KERNEL); | ||
1932 | break; | 1902 | break; |
1903 | default: | ||
1904 | WARN(1, "unexpected: %d", rma); | ||
1933 | } | 1905 | } |
1934 | 1906 | ||
1907 | out: | ||
1935 | kfree_skb(skb); | 1908 | kfree_skb(skb); |
1936 | } | 1909 | } |
1937 | 1910 | ||
@@ -1947,89 +1920,9 @@ static void ieee80211_sta_timer(unsigned long data) | |||
1947 | return; | 1920 | return; |
1948 | } | 1921 | } |
1949 | 1922 | ||
1950 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | ||
1951 | queue_work(local->hw.workqueue, &ifmgd->work); | 1923 | queue_work(local->hw.workqueue, &ifmgd->work); |
1952 | } | 1924 | } |
1953 | 1925 | ||
1954 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) | ||
1955 | { | ||
1956 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1957 | struct ieee80211_local *local = sdata->local; | ||
1958 | |||
1959 | /* Reset own TSF to allow time synchronization work. */ | ||
1960 | drv_reset_tsf(local); | ||
1961 | |||
1962 | ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ | ||
1963 | ifmgd->auth_transaction = -1; | ||
1964 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; | ||
1965 | ifmgd->assoc_scan_tries = 0; | ||
1966 | ifmgd->direct_probe_tries = 0; | ||
1967 | ifmgd->auth_tries = 0; | ||
1968 | ifmgd->assoc_tries = 0; | ||
1969 | netif_tx_stop_all_queues(sdata->dev); | ||
1970 | netif_carrier_off(sdata->dev); | ||
1971 | } | ||
1972 | |||
1973 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) | ||
1974 | { | ||
1975 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1976 | struct ieee80211_local *local = sdata->local; | ||
1977 | struct ieee80211_bss *bss; | ||
1978 | u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid; | ||
1979 | u8 ssid_len = ifmgd->ssid_len; | ||
1980 | u16 capa_mask = WLAN_CAPABILITY_ESS; | ||
1981 | u16 capa_val = WLAN_CAPABILITY_ESS; | ||
1982 | struct ieee80211_channel *chan = local->oper_channel; | ||
1983 | |||
1984 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, | ||
1985 | bssid, ssid, ssid_len, | ||
1986 | capa_mask, capa_val); | ||
1987 | |||
1988 | if (bss) { | ||
1989 | local->oper_channel = bss->cbss.channel; | ||
1990 | local->oper_channel_type = NL80211_CHAN_NO_HT; | ||
1991 | ieee80211_hw_config(local, 0); | ||
1992 | |||
1993 | ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, | ||
1994 | bss->supp_rates); | ||
1995 | if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) | ||
1996 | sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; | ||
1997 | else | ||
1998 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; | ||
1999 | |||
2000 | /* Send out direct probe if no probe resp was received or | ||
2001 | * the one we have is outdated | ||
2002 | */ | ||
2003 | if (!bss->last_probe_resp || | ||
2004 | time_after(jiffies, bss->last_probe_resp | ||
2005 | + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
2006 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
2007 | else | ||
2008 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
2009 | |||
2010 | ieee80211_rx_bss_put(local, bss); | ||
2011 | ieee80211_sta_reset_auth(sdata); | ||
2012 | return 0; | ||
2013 | } else { | ||
2014 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | ||
2015 | |||
2016 | ifmgd->assoc_scan_tries++; | ||
2017 | |||
2018 | ieee80211_request_internal_scan(sdata, ifmgd->ssid, | ||
2019 | ssid_len); | ||
2020 | |||
2021 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; | ||
2022 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | ||
2023 | } else { | ||
2024 | ifmgd->assoc_scan_tries = 0; | ||
2025 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
2026 | ieee80211_recalc_idle(local); | ||
2027 | } | ||
2028 | } | ||
2029 | return -1; | ||
2030 | } | ||
2031 | |||
2032 | |||
2033 | static void ieee80211_sta_work(struct work_struct *work) | 1926 | static void ieee80211_sta_work(struct work_struct *work) |
2034 | { | 1927 | { |
2035 | struct ieee80211_sub_if_data *sdata = | 1928 | struct ieee80211_sub_if_data *sdata = |
@@ -2037,6 +1930,10 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2037 | struct ieee80211_local *local = sdata->local; | 1930 | struct ieee80211_local *local = sdata->local; |
2038 | struct ieee80211_if_managed *ifmgd; | 1931 | struct ieee80211_if_managed *ifmgd; |
2039 | struct sk_buff *skb; | 1932 | struct sk_buff *skb; |
1933 | struct ieee80211_mgd_work *wk, *tmp; | ||
1934 | LIST_HEAD(free_work); | ||
1935 | enum rx_mgmt_action rma; | ||
1936 | bool anybusy = false; | ||
2040 | 1937 | ||
2041 | if (!netif_running(sdata->dev)) | 1938 | if (!netif_running(sdata->dev)) |
2042 | return; | 1939 | return; |
@@ -2059,46 +1956,93 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2059 | 1956 | ||
2060 | ifmgd = &sdata->u.mgd; | 1957 | ifmgd = &sdata->u.mgd; |
2061 | 1958 | ||
1959 | /* first process frames to avoid timing out while a frame is pending */ | ||
2062 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) | 1960 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) |
2063 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | 1961 | ieee80211_sta_rx_queued_mgmt(sdata, skb); |
2064 | 1962 | ||
2065 | if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE && | 1963 | /* then process the rest of the work */ |
2066 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1964 | mutex_lock(&ifmgd->mtx); |
2067 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && | 1965 | |
2068 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { | 1966 | list_for_each_entry(wk, &ifmgd->work_list, list) { |
2069 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | 1967 | if (wk->state != IEEE80211_MGD_STATE_IDLE) { |
2070 | round_jiffies_relative(0)); | 1968 | anybusy = true; |
2071 | return; | 1969 | break; |
1970 | } | ||
2072 | } | 1971 | } |
2073 | 1972 | ||
2074 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) { | 1973 | ieee80211_recalc_idle(local); |
2075 | if (ieee80211_sta_config_auth(sdata)) | 1974 | |
2076 | return; | 1975 | if (!anybusy) { |
2077 | clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | 1976 | mutex_unlock(&ifmgd->mtx); |
2078 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) | 1977 | |
1978 | if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) | ||
1979 | queue_delayed_work(local->hw.workqueue, | ||
1980 | &local->scan_work, | ||
1981 | round_jiffies_relative(0)); | ||
2079 | return; | 1982 | return; |
1983 | } | ||
2080 | 1984 | ||
2081 | ieee80211_recalc_idle(local); | 1985 | list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { |
1986 | if (time_before(jiffies, wk->timeout)) | ||
1987 | continue; | ||
2082 | 1988 | ||
2083 | switch (ifmgd->state) { | 1989 | switch (wk->state) { |
2084 | case IEEE80211_STA_MLME_DISABLED: | 1990 | default: |
2085 | break; | 1991 | WARN_ON(1); |
2086 | case IEEE80211_STA_MLME_DIRECT_PROBE: | 1992 | /* fall through */ |
2087 | ieee80211_direct_probe(sdata); | 1993 | case IEEE80211_MGD_STATE_IDLE: |
2088 | break; | 1994 | /* nothing */ |
2089 | case IEEE80211_STA_MLME_AUTHENTICATE: | 1995 | rma = RX_MGMT_NONE; |
2090 | ieee80211_authenticate(sdata); | 1996 | break; |
2091 | break; | 1997 | case IEEE80211_MGD_STATE_PROBE: |
2092 | case IEEE80211_STA_MLME_ASSOCIATE: | 1998 | rma = ieee80211_direct_probe(sdata, wk); |
2093 | ieee80211_associate(sdata); | 1999 | break; |
2094 | break; | 2000 | case IEEE80211_MGD_STATE_AUTH: |
2095 | case IEEE80211_STA_MLME_ASSOCIATED: | 2001 | rma = ieee80211_authenticate(sdata, wk); |
2096 | ieee80211_associated(sdata); | 2002 | break; |
2097 | break; | 2003 | case IEEE80211_MGD_STATE_ASSOC: |
2098 | default: | 2004 | rma = ieee80211_associate(sdata, wk); |
2099 | WARN_ON(1); | 2005 | break; |
2100 | break; | 2006 | } |
2007 | |||
2008 | switch (rma) { | ||
2009 | case RX_MGMT_NONE: | ||
2010 | /* no action required */ | ||
2011 | break; | ||
2012 | case RX_MGMT_CFG80211_AUTH_TO: | ||
2013 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
2014 | list_del(&wk->list); | ||
2015 | list_add(&wk->list, &free_work); | ||
2016 | wk->tries = rma; /* small abuse but only local */ | ||
2017 | break; | ||
2018 | default: | ||
2019 | WARN(1, "unexpected: %d", rma); | ||
2020 | } | ||
2021 | } | ||
2022 | |||
2023 | mutex_unlock(&ifmgd->mtx); | ||
2024 | |||
2025 | list_for_each_entry_safe(wk, tmp, &free_work, list) { | ||
2026 | switch (wk->tries) { | ||
2027 | case RX_MGMT_CFG80211_AUTH_TO: | ||
2028 | cfg80211_send_auth_timeout(sdata->dev, | ||
2029 | wk->bss->cbss.bssid, | ||
2030 | GFP_KERNEL); | ||
2031 | break; | ||
2032 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
2033 | cfg80211_send_auth_timeout(sdata->dev, | ||
2034 | wk->bss->cbss.bssid, | ||
2035 | GFP_KERNEL); | ||
2036 | break; | ||
2037 | default: | ||
2038 | WARN(1, "unexpected: %d", wk->tries); | ||
2039 | } | ||
2040 | |||
2041 | list_del(&wk->list); | ||
2042 | kfree(wk); | ||
2101 | } | 2043 | } |
2044 | |||
2045 | ieee80211_recalc_idle(local); | ||
2102 | } | 2046 | } |
2103 | 2047 | ||
2104 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | 2048 | static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) |
@@ -2110,7 +2054,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2110 | */ | 2054 | */ |
2111 | sdata->u.mgd.last_beacon = jiffies; | 2055 | sdata->u.mgd.last_beacon = jiffies; |
2112 | 2056 | ||
2113 | |||
2114 | queue_work(sdata->local->hw.workqueue, | 2057 | queue_work(sdata->local->hw.workqueue, |
2115 | &sdata->u.mgd.work); | 2058 | &sdata->u.mgd.work); |
2116 | } | 2059 | } |
@@ -2152,7 +2095,6 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
2152 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 2095 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
2153 | { | 2096 | { |
2154 | struct ieee80211_if_managed *ifmgd; | 2097 | struct ieee80211_if_managed *ifmgd; |
2155 | u32 hw_flags; | ||
2156 | 2098 | ||
2157 | ifmgd = &sdata->u.mgd; | 2099 | ifmgd = &sdata->u.mgd; |
2158 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 2100 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
@@ -2164,113 +2106,239 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2164 | (unsigned long) sdata); | 2106 | (unsigned long) sdata); |
2165 | skb_queue_head_init(&ifmgd->skb_queue); | 2107 | skb_queue_head_init(&ifmgd->skb_queue); |
2166 | 2108 | ||
2109 | INIT_LIST_HEAD(&ifmgd->work_list); | ||
2110 | |||
2167 | ifmgd->capab = WLAN_CAPABILITY_ESS; | 2111 | ifmgd->capab = WLAN_CAPABILITY_ESS; |
2168 | ifmgd->flags = 0; | 2112 | ifmgd->flags = 0; |
2169 | if (sdata->local->hw.queues >= 4) | 2113 | if (sdata->local->hw.queues >= 4) |
2170 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; | 2114 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; |
2171 | 2115 | ||
2172 | hw_flags = sdata->local->hw.flags; | 2116 | mutex_init(&ifmgd->mtx); |
2173 | } | 2117 | } |
2174 | 2118 | ||
2175 | /* configuration hooks */ | 2119 | /* scan finished notification */ |
2176 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) | 2120 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) |
2177 | { | 2121 | { |
2178 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2122 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
2179 | struct ieee80211_local *local = sdata->local; | ||
2180 | 2123 | ||
2181 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 2124 | /* Restart STA timers */ |
2182 | return; | 2125 | rcu_read_lock(); |
2126 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
2127 | ieee80211_restart_sta_timer(sdata); | ||
2128 | rcu_read_unlock(); | ||
2129 | } | ||
2183 | 2130 | ||
2184 | if (WARN_ON(ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) | 2131 | int ieee80211_max_network_latency(struct notifier_block *nb, |
2185 | ieee80211_set_disassoc(sdata, true, true, | 2132 | unsigned long data, void *dummy) |
2186 | WLAN_REASON_DEAUTH_LEAVING); | 2133 | { |
2134 | s32 latency_usec = (s32) data; | ||
2135 | struct ieee80211_local *local = | ||
2136 | container_of(nb, struct ieee80211_local, | ||
2137 | network_latency_notifier); | ||
2187 | 2138 | ||
2188 | if (WARN_ON(ifmgd->ssid_len == 0)) { | 2139 | mutex_lock(&local->iflist_mtx); |
2189 | /* | 2140 | ieee80211_recalc_ps(local, latency_usec); |
2190 | * Only allow association to be started if a valid SSID | 2141 | mutex_unlock(&local->iflist_mtx); |
2191 | * is configured. | ||
2192 | */ | ||
2193 | return; | ||
2194 | } | ||
2195 | 2142 | ||
2196 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | 2143 | return 0; |
2197 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
2198 | } | 2144 | } |
2199 | 2145 | ||
2200 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | 2146 | /* config hooks */ |
2201 | const char *ie, size_t len) | 2147 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
2148 | struct cfg80211_auth_request *req) | ||
2202 | { | 2149 | { |
2203 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2150 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2151 | const u8 *ssid; | ||
2152 | struct ieee80211_mgd_work *wk; | ||
2153 | u16 auth_alg; | ||
2204 | 2154 | ||
2205 | if (len == 0 && ifmgd->extra_ie_len == 0) | 2155 | switch (req->auth_type) { |
2206 | return -EALREADY; | 2156 | case NL80211_AUTHTYPE_OPEN_SYSTEM: |
2207 | 2157 | auth_alg = WLAN_AUTH_OPEN; | |
2208 | if (len == ifmgd->extra_ie_len && ifmgd->extra_ie && | 2158 | break; |
2209 | memcmp(ifmgd->extra_ie, ie, len) == 0) | 2159 | case NL80211_AUTHTYPE_SHARED_KEY: |
2210 | return -EALREADY; | 2160 | auth_alg = WLAN_AUTH_SHARED_KEY; |
2211 | 2161 | break; | |
2212 | kfree(ifmgd->extra_ie); | 2162 | case NL80211_AUTHTYPE_FT: |
2213 | if (len == 0) { | 2163 | auth_alg = WLAN_AUTH_FT; |
2214 | ifmgd->extra_ie = NULL; | 2164 | break; |
2215 | ifmgd->extra_ie_len = 0; | 2165 | case NL80211_AUTHTYPE_NETWORK_EAP: |
2216 | return 0; | 2166 | auth_alg = WLAN_AUTH_LEAP; |
2167 | break; | ||
2168 | default: | ||
2169 | return -EOPNOTSUPP; | ||
2217 | } | 2170 | } |
2218 | ifmgd->extra_ie = kmalloc(len, GFP_KERNEL); | 2171 | |
2219 | if (!ifmgd->extra_ie) { | 2172 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); |
2220 | ifmgd->extra_ie_len = 0; | 2173 | if (!wk) |
2221 | return -ENOMEM; | 2174 | return -ENOMEM; |
2175 | |||
2176 | wk->bss = (void *)req->bss; | ||
2177 | |||
2178 | if (req->ie && req->ie_len) { | ||
2179 | memcpy(wk->ie, req->ie, req->ie_len); | ||
2180 | wk->ie_len = req->ie_len; | ||
2222 | } | 2181 | } |
2223 | memcpy(ifmgd->extra_ie, ie, len); | 2182 | |
2224 | ifmgd->extra_ie_len = len; | 2183 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
2184 | memcpy(wk->ssid, ssid + 2, ssid[1]); | ||
2185 | wk->ssid_len = ssid[1]; | ||
2186 | |||
2187 | wk->state = IEEE80211_MGD_STATE_PROBE; | ||
2188 | wk->auth_alg = auth_alg; | ||
2189 | |||
2190 | /* | ||
2191 | * XXX: if still associated need to tell AP that we're going | ||
2192 | * to sleep and then change channel etc. | ||
2193 | */ | ||
2194 | sdata->local->oper_channel = req->bss->channel; | ||
2195 | ieee80211_hw_config(sdata->local, 0); | ||
2196 | |||
2197 | mutex_lock(&ifmgd->mtx); | ||
2198 | list_add(&wk->list, &sdata->u.mgd.work_list); | ||
2199 | mutex_unlock(&ifmgd->mtx); | ||
2200 | |||
2201 | queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); | ||
2225 | return 0; | 2202 | return 0; |
2226 | } | 2203 | } |
2227 | 2204 | ||
2228 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2205 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
2206 | struct cfg80211_assoc_request *req) | ||
2229 | { | 2207 | { |
2230 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | 2208 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2231 | sdata->dev->name, reason); | 2209 | struct ieee80211_mgd_work *wk, *found = NULL; |
2210 | int i, err; | ||
2232 | 2211 | ||
2233 | ieee80211_set_disassoc(sdata, true, true, reason); | 2212 | mutex_lock(&ifmgd->mtx); |
2234 | return 0; | 2213 | |
2214 | list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
2215 | if (&wk->bss->cbss == req->bss && | ||
2216 | wk->state == IEEE80211_MGD_STATE_IDLE) { | ||
2217 | found = wk; | ||
2218 | break; | ||
2219 | } | ||
2220 | } | ||
2221 | |||
2222 | if (!found) { | ||
2223 | err = -ENOLINK; | ||
2224 | goto out; | ||
2225 | } | ||
2226 | |||
2227 | list_del(&found->list); | ||
2228 | |||
2229 | wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL); | ||
2230 | if (!wk) { | ||
2231 | list_add(&found->list, &ifmgd->work_list); | ||
2232 | err = -ENOMEM; | ||
2233 | goto out; | ||
2234 | } | ||
2235 | |||
2236 | list_add(&wk->list, &ifmgd->work_list); | ||
2237 | |||
2238 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | ||
2239 | |||
2240 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | ||
2241 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | ||
2242 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | ||
2243 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) | ||
2244 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||
2245 | |||
2246 | sdata->local->oper_channel = req->bss->channel; | ||
2247 | ieee80211_hw_config(sdata->local, 0); | ||
2248 | |||
2249 | if (req->ie && req->ie_len) { | ||
2250 | memcpy(wk->ie, req->ie, req->ie_len); | ||
2251 | wk->ie_len = req->ie_len; | ||
2252 | } else | ||
2253 | wk->ie_len = 0; | ||
2254 | |||
2255 | if (req->prev_bssid) | ||
2256 | memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); | ||
2257 | |||
2258 | wk->state = IEEE80211_MGD_STATE_ASSOC; | ||
2259 | wk->tries = 0; | ||
2260 | |||
2261 | if (req->use_mfp) { | ||
2262 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | ||
2263 | ifmgd->flags |= IEEE80211_STA_MFP_ENABLED; | ||
2264 | } else { | ||
2265 | ifmgd->mfp = IEEE80211_MFP_DISABLED; | ||
2266 | ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED; | ||
2267 | } | ||
2268 | |||
2269 | if (req->crypto.control_port) | ||
2270 | ifmgd->flags |= IEEE80211_STA_CONTROL_PORT; | ||
2271 | else | ||
2272 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; | ||
2273 | |||
2274 | queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); | ||
2275 | |||
2276 | err = 0; | ||
2277 | |||
2278 | out: | ||
2279 | mutex_unlock(&ifmgd->mtx); | ||
2280 | return err; | ||
2235 | } | 2281 | } |
2236 | 2282 | ||
2237 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2283 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, |
2284 | struct cfg80211_deauth_request *req) | ||
2238 | { | 2285 | { |
2239 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2286 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2287 | struct ieee80211_mgd_work *wk; | ||
2288 | const u8 *bssid = NULL; | ||
2240 | 2289 | ||
2241 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | 2290 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", |
2242 | sdata->dev->name, reason); | 2291 | sdata->dev->name, req->reason_code); |
2292 | |||
2293 | mutex_lock(&ifmgd->mtx); | ||
2294 | |||
2295 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { | ||
2296 | bssid = req->bss->bssid; | ||
2297 | ieee80211_set_disassoc(sdata, bssid, true); | ||
2298 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
2299 | if (&wk->bss->cbss == req->bss) { | ||
2300 | bssid = req->bss->bssid; | ||
2301 | list_del(&wk->list); | ||
2302 | kfree(wk); | ||
2303 | break; | ||
2304 | } | ||
2305 | } | ||
2243 | 2306 | ||
2244 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) | 2307 | /* cfg80211 should catch this... */ |
2308 | if (WARN_ON(!bssid)) { | ||
2309 | mutex_unlock(&ifmgd->mtx); | ||
2245 | return -ENOLINK; | 2310 | return -ENOLINK; |
2311 | } | ||
2312 | |||
2313 | mutex_unlock(&ifmgd->mtx); | ||
2314 | |||
2315 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
2316 | IEEE80211_STYPE_DEAUTH, req->reason_code); | ||
2246 | 2317 | ||
2247 | ieee80211_set_disassoc(sdata, false, true, reason); | ||
2248 | return 0; | 2318 | return 0; |
2249 | } | 2319 | } |
2250 | 2320 | ||
2251 | /* scan finished notification */ | 2321 | int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, |
2252 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | 2322 | struct cfg80211_disassoc_request *req) |
2253 | { | 2323 | { |
2254 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 2324 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2255 | 2325 | ||
2256 | /* Restart STA timers */ | 2326 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", |
2257 | rcu_read_lock(); | 2327 | sdata->dev->name, req->reason_code); |
2258 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
2259 | ieee80211_restart_sta_timer(sdata); | ||
2260 | rcu_read_unlock(); | ||
2261 | } | ||
2262 | 2328 | ||
2263 | int ieee80211_max_network_latency(struct notifier_block *nb, | 2329 | mutex_lock(&ifmgd->mtx); |
2264 | unsigned long data, void *dummy) | ||
2265 | { | ||
2266 | s32 latency_usec = (s32) data; | ||
2267 | struct ieee80211_local *local = | ||
2268 | container_of(nb, struct ieee80211_local, | ||
2269 | network_latency_notifier); | ||
2270 | 2330 | ||
2271 | mutex_lock(&local->iflist_mtx); | 2331 | /* cfg80211 should catch that */ |
2272 | ieee80211_recalc_ps(local, latency_usec); | 2332 | if (WARN_ON(&ifmgd->associated->cbss != req->bss)) { |
2273 | mutex_unlock(&local->iflist_mtx); | 2333 | mutex_unlock(&ifmgd->mtx); |
2334 | return -ENOLINK; | ||
2335 | } | ||
2336 | |||
2337 | ieee80211_set_disassoc(sdata, req->bss->bssid, false); | ||
2338 | |||
2339 | mutex_unlock(&ifmgd->mtx); | ||
2274 | 2340 | ||
2341 | ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, | ||
2342 | IEEE80211_STYPE_DISASSOC, req->reason_code); | ||
2275 | return 0; | 2343 | return 0; |
2276 | } | 2344 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ec5acc6dc021..fe6b99059531 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1641,12 +1641,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
1641 | 1641 | ||
1642 | if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 || | 1642 | if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 || |
1643 | compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) { | 1643 | compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) { |
1644 | /* Not from the current AP. */ | 1644 | /* Not from the current AP or not associated yet. */ |
1645 | return; | ||
1646 | } | ||
1647 | |||
1648 | if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) { | ||
1649 | /* Association in progress; ignore SA Query */ | ||
1650 | return; | 1645 | return; |
1651 | } | 1646 | } |
1652 | 1647 | ||
@@ -1683,7 +1678,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1683 | struct ieee80211_local *local = rx->local; | 1678 | struct ieee80211_local *local = rx->local; |
1684 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1679 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
1685 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 1680 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
1686 | struct ieee80211_bss *bss; | ||
1687 | int len = rx->skb->len; | 1681 | int len = rx->skb->len; |
1688 | 1682 | ||
1689 | if (!ieee80211_is_action(mgmt->frame_control)) | 1683 | if (!ieee80211_is_action(mgmt->frame_control)) |
@@ -1761,17 +1755,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1761 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) | 1755 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) |
1762 | return RX_DROP_MONITOR; | 1756 | return RX_DROP_MONITOR; |
1763 | 1757 | ||
1764 | bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid, | 1758 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); |
1765 | local->hw.conf.channel->center_freq, | ||
1766 | sdata->u.mgd.ssid, | ||
1767 | sdata->u.mgd.ssid_len); | ||
1768 | if (!bss) | ||
1769 | return RX_DROP_MONITOR; | ||
1770 | |||
1771 | ieee80211_sta_process_chanswitch(sdata, | ||
1772 | &mgmt->u.action.u.chan_switch.sw_elem, bss); | ||
1773 | ieee80211_rx_bss_put(local, bss); | ||
1774 | break; | ||
1775 | } | 1759 | } |
1776 | break; | 1760 | break; |
1777 | case WLAN_CATEGORY_SA_QUERY: | 1761 | case WLAN_CATEGORY_SA_QUERY: |
@@ -2026,13 +2010,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2026 | case NL80211_IFTYPE_STATION: | 2010 | case NL80211_IFTYPE_STATION: |
2027 | if (!bssid) | 2011 | if (!bssid) |
2028 | return 0; | 2012 | return 0; |
2029 | if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) { | 2013 | if (!multicast && |
2030 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2014 | compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { |
2031 | return 0; | ||
2032 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | ||
2033 | } else if (!multicast && | ||
2034 | compare_ether_addr(sdata->dev->dev_addr, | ||
2035 | hdr->addr1) != 0) { | ||
2036 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2015 | if (!(sdata->dev->flags & IFF_PROMISC)) |
2037 | return 0; | 2016 | return 0; |
2038 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2017 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 569a464f60d8..5f4f7869d050 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -121,19 +121,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
121 | return bss; | 121 | return bss; |
122 | } | 122 | } |
123 | 123 | ||
124 | void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, | ||
125 | int freq, u8 *ssid, u8 ssid_len) | ||
126 | { | ||
127 | struct ieee80211_bss *bss; | ||
128 | struct ieee80211_local *local = sdata->local; | ||
129 | |||
130 | bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len); | ||
131 | if (bss) { | ||
132 | cfg80211_unlink_bss(local->hw.wiphy, (void *)bss); | ||
133 | ieee80211_rx_bss_put(local, bss); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | ieee80211_rx_result | 124 | ieee80211_rx_result |
138 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | 125 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
139 | { | 126 | { |
@@ -327,7 +314,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
327 | 314 | ||
328 | /* Tell AP we're back */ | 315 | /* Tell AP we're back */ |
329 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 316 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
330 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { | 317 | if (sdata->u.mgd.associated) { |
331 | ieee80211_scan_ps_disable(sdata); | 318 | ieee80211_scan_ps_disable(sdata); |
332 | netif_tx_wake_all_queues(sdata->dev); | 319 | netif_tx_wake_all_queues(sdata->dev); |
333 | } | 320 | } |
@@ -383,7 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
383 | sdata, BSS_CHANGED_BEACON_ENABLED); | 370 | sdata, BSS_CHANGED_BEACON_ENABLED); |
384 | 371 | ||
385 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 372 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
386 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { | 373 | if (sdata->u.mgd.associated) { |
387 | netif_tx_stop_all_queues(sdata->dev); | 374 | netif_tx_stop_all_queues(sdata->dev); |
388 | ieee80211_scan_ps_enable(sdata); | 375 | ieee80211_scan_ps_enable(sdata); |
389 | } | 376 | } |
@@ -443,10 +430,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
443 | 430 | ||
444 | if (req != &local->int_scan_req && | 431 | if (req != &local->int_scan_req && |
445 | sdata->vif.type == NL80211_IFTYPE_STATION && | 432 | sdata->vif.type == NL80211_IFTYPE_STATION && |
446 | (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE || | 433 | !list_empty(&ifmgd->work_list)) { |
447 | ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || | 434 | /* actually wait for the work it's doing to finish/time out */ |
448 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) { | ||
449 | /* actually wait for the assoc to finish/time out */ | ||
450 | set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); | 435 | set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); |
451 | return 0; | 436 | return 0; |
452 | } | 437 | } |