diff options
Diffstat (limited to 'net/wireless/sme.c')
-rw-r--r-- | net/wireless/sme.c | 252 |
1 files changed, 196 insertions, 56 deletions
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 066a19ef9d73..472e2412c781 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -38,6 +38,8 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
38 | int n_channels, err; | 38 | int n_channels, err; |
39 | 39 | ||
40 | ASSERT_RTNL(); | 40 | ASSERT_RTNL(); |
41 | ASSERT_RDEV_LOCK(drv); | ||
42 | ASSERT_WDEV_LOCK(wdev); | ||
41 | 43 | ||
42 | if (drv->scan_req) | 44 | if (drv->scan_req) |
43 | return -EBUSY; | 45 | return -EBUSY; |
@@ -106,6 +108,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
106 | struct cfg80211_connect_params *params; | 108 | struct cfg80211_connect_params *params; |
107 | int err; | 109 | int err; |
108 | 110 | ||
111 | ASSERT_WDEV_LOCK(wdev); | ||
112 | |||
109 | if (!wdev->conn) | 113 | if (!wdev->conn) |
110 | return 0; | 114 | return 0; |
111 | 115 | ||
@@ -117,11 +121,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
117 | case CFG80211_CONN_AUTHENTICATE_NEXT: | 121 | case CFG80211_CONN_AUTHENTICATE_NEXT: |
118 | BUG_ON(!drv->ops->auth); | 122 | BUG_ON(!drv->ops->auth); |
119 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; | 123 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; |
120 | return cfg80211_mlme_auth(drv, wdev->netdev, | 124 | return __cfg80211_mlme_auth(drv, wdev->netdev, |
121 | params->channel, params->auth_type, | 125 | params->channel, params->auth_type, |
122 | params->bssid, | 126 | params->bssid, |
123 | params->ssid, params->ssid_len, | 127 | params->ssid, params->ssid_len, |
124 | NULL, 0); | 128 | NULL, 0); |
125 | case CFG80211_CONN_ASSOCIATE_NEXT: | 129 | case CFG80211_CONN_ASSOCIATE_NEXT: |
126 | BUG_ON(!drv->ops->assoc); | 130 | BUG_ON(!drv->ops->assoc); |
127 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 131 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
@@ -131,14 +135,16 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
131 | * that some APs don't like that -- so we'd need to retry | 135 | * that some APs don't like that -- so we'd need to retry |
132 | * the association. | 136 | * the association. |
133 | */ | 137 | */ |
134 | err = cfg80211_mlme_assoc(drv, wdev->netdev, | 138 | err = __cfg80211_mlme_assoc(drv, wdev->netdev, |
135 | params->channel, params->bssid, NULL, | 139 | params->channel, params->bssid, |
136 | params->ssid, params->ssid_len, | 140 | NULL, |
137 | params->ie, params->ie_len, | 141 | params->ssid, params->ssid_len, |
138 | false, ¶ms->crypto); | 142 | params->ie, params->ie_len, |
143 | false, ¶ms->crypto); | ||
139 | if (err) | 144 | if (err) |
140 | cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, | 145 | __cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, |
141 | NULL, 0, WLAN_REASON_DEAUTH_LEAVING); | 146 | NULL, 0, |
147 | WLAN_REASON_DEAUTH_LEAVING); | ||
142 | return err; | 148 | return err; |
143 | default: | 149 | default: |
144 | return 0; | 150 | return 0; |
@@ -152,22 +158,31 @@ void cfg80211_conn_work(struct work_struct *work) | |||
152 | struct wireless_dev *wdev; | 158 | struct wireless_dev *wdev; |
153 | 159 | ||
154 | rtnl_lock(); | 160 | rtnl_lock(); |
161 | cfg80211_lock_rdev(drv); | ||
155 | mutex_lock(&drv->devlist_mtx); | 162 | mutex_lock(&drv->devlist_mtx); |
156 | 163 | ||
157 | list_for_each_entry(wdev, &drv->netdev_list, list) { | 164 | list_for_each_entry(wdev, &drv->netdev_list, list) { |
158 | if (!netif_running(wdev->netdev)) | 165 | wdev_lock(wdev); |
166 | if (!netif_running(wdev->netdev)) { | ||
167 | wdev_unlock(wdev); | ||
159 | continue; | 168 | continue; |
160 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 169 | } |
170 | if (wdev->sme_state != CFG80211_SME_CONNECTING) { | ||
171 | wdev_unlock(wdev); | ||
161 | continue; | 172 | continue; |
173 | } | ||
162 | if (cfg80211_conn_do_work(wdev)) | 174 | if (cfg80211_conn_do_work(wdev)) |
163 | cfg80211_connect_result(wdev->netdev, | 175 | __cfg80211_connect_result( |
164 | wdev->conn->params.bssid, | 176 | wdev->netdev, |
165 | NULL, 0, NULL, 0, | 177 | wdev->conn->params.bssid, |
166 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 178 | NULL, 0, NULL, 0, |
167 | GFP_ATOMIC); | 179 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
180 | false); | ||
181 | wdev_unlock(wdev); | ||
168 | } | 182 | } |
169 | 183 | ||
170 | mutex_unlock(&drv->devlist_mtx); | 184 | mutex_unlock(&drv->devlist_mtx); |
185 | cfg80211_unlock_rdev(drv); | ||
171 | rtnl_unlock(); | 186 | rtnl_unlock(); |
172 | } | 187 | } |
173 | 188 | ||
@@ -177,6 +192,8 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
177 | struct cfg80211_bss *bss; | 192 | struct cfg80211_bss *bss; |
178 | u16 capa = WLAN_CAPABILITY_ESS; | 193 | u16 capa = WLAN_CAPABILITY_ESS; |
179 | 194 | ||
195 | ASSERT_WDEV_LOCK(wdev); | ||
196 | |||
180 | if (wdev->conn->params.privacy) | 197 | if (wdev->conn->params.privacy) |
181 | capa |= WLAN_CAPABILITY_PRIVACY; | 198 | capa |= WLAN_CAPABILITY_PRIVACY; |
182 | 199 | ||
@@ -198,11 +215,13 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
198 | return true; | 215 | return true; |
199 | } | 216 | } |
200 | 217 | ||
201 | void cfg80211_sme_scan_done(struct net_device *dev) | 218 | static void __cfg80211_sme_scan_done(struct net_device *dev) |
202 | { | 219 | { |
203 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 220 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
204 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); | 221 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); |
205 | 222 | ||
223 | ASSERT_WDEV_LOCK(wdev); | ||
224 | |||
206 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 225 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
207 | return; | 226 | return; |
208 | 227 | ||
@@ -218,15 +237,26 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
218 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) | 237 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) |
219 | schedule_work(&drv->conn_work); | 238 | schedule_work(&drv->conn_work); |
220 | else | 239 | else |
221 | cfg80211_connect_result(dev, wdev->conn->params.bssid, | 240 | __cfg80211_connect_result( |
222 | NULL, 0, NULL, 0, | 241 | wdev->netdev, |
223 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 242 | wdev->conn->params.bssid, |
224 | GFP_ATOMIC); | 243 | NULL, 0, NULL, 0, |
225 | return; | 244 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
245 | false); | ||
226 | } | 246 | } |
227 | } | 247 | } |
228 | 248 | ||
229 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | 249 | void cfg80211_sme_scan_done(struct net_device *dev) |
250 | { | ||
251 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
252 | |||
253 | wdev_lock(wdev); | ||
254 | __cfg80211_sme_scan_done(dev); | ||
255 | wdev_unlock(wdev); | ||
256 | } | ||
257 | |||
258 | void cfg80211_sme_rx_auth(struct net_device *dev, | ||
259 | const u8 *buf, size_t len) | ||
230 | { | 260 | { |
231 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 261 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
232 | struct wiphy *wiphy = wdev->wiphy; | 262 | struct wiphy *wiphy = wdev->wiphy; |
@@ -234,6 +264,8 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
234 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 264 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
235 | u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); | 265 | u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); |
236 | 266 | ||
267 | ASSERT_WDEV_LOCK(wdev); | ||
268 | |||
237 | /* should only RX auth frames when connecting */ | 269 | /* should only RX auth frames when connecting */ |
238 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 270 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
239 | return; | 271 | return; |
@@ -273,10 +305,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
273 | } | 305 | } |
274 | } | 306 | } |
275 | 307 | ||
276 | static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 308 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
277 | const u8 *req_ie, size_t req_ie_len, | 309 | const u8 *req_ie, size_t req_ie_len, |
278 | const u8 *resp_ie, size_t resp_ie_len, | 310 | const u8 *resp_ie, size_t resp_ie_len, |
279 | u16 status, bool wextev, gfp_t gfp) | 311 | u16 status, bool wextev) |
280 | { | 312 | { |
281 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 313 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
282 | struct cfg80211_bss *bss; | 314 | struct cfg80211_bss *bss; |
@@ -284,18 +316,20 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
284 | union iwreq_data wrqu; | 316 | union iwreq_data wrqu; |
285 | #endif | 317 | #endif |
286 | 318 | ||
319 | ASSERT_WDEV_LOCK(wdev); | ||
320 | |||
287 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 321 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
288 | return; | 322 | return; |
289 | 323 | ||
290 | if (wdev->sme_state == CFG80211_SME_CONNECTED) | 324 | if (wdev->sme_state == CFG80211_SME_CONNECTED) |
291 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, | 325 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, |
292 | bssid, req_ie, req_ie_len, | 326 | bssid, req_ie, req_ie_len, |
293 | resp_ie, resp_ie_len, gfp); | 327 | resp_ie, resp_ie_len, GFP_KERNEL); |
294 | else | 328 | else |
295 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, | 329 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, |
296 | bssid, req_ie, req_ie_len, | 330 | bssid, req_ie, req_ie_len, |
297 | resp_ie, resp_ie_len, | 331 | resp_ie, resp_ie_len, |
298 | status, gfp); | 332 | status, GFP_KERNEL); |
299 | 333 | ||
300 | #ifdef CONFIG_WIRELESS_EXT | 334 | #ifdef CONFIG_WIRELESS_EXT |
301 | if (wextev) { | 335 | if (wextev) { |
@@ -362,21 +396,43 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
362 | const u8 *resp_ie, size_t resp_ie_len, | 396 | const u8 *resp_ie, size_t resp_ie_len, |
363 | u16 status, gfp_t gfp) | 397 | u16 status, gfp_t gfp) |
364 | { | 398 | { |
365 | bool wextev = status == WLAN_STATUS_SUCCESS; | 399 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
366 | __cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, wextev, gfp); | 400 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
401 | struct cfg80211_event *ev; | ||
402 | unsigned long flags; | ||
403 | |||
404 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | ||
405 | if (!ev) | ||
406 | return; | ||
407 | |||
408 | ev->type = EVENT_CONNECT_RESULT; | ||
409 | memcpy(ev->cr.bssid, bssid, ETH_ALEN); | ||
410 | ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); | ||
411 | ev->cr.req_ie_len = req_ie_len; | ||
412 | memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); | ||
413 | ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; | ||
414 | ev->cr.resp_ie_len = resp_ie_len; | ||
415 | memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); | ||
416 | ev->cr.status = status; | ||
417 | |||
418 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
419 | list_add_tail(&ev->list, &wdev->event_list); | ||
420 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
421 | schedule_work(&rdev->event_work); | ||
367 | } | 422 | } |
368 | EXPORT_SYMBOL(cfg80211_connect_result); | 423 | EXPORT_SYMBOL(cfg80211_connect_result); |
369 | 424 | ||
370 | void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | 425 | void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, |
371 | const u8 *req_ie, size_t req_ie_len, | 426 | const u8 *req_ie, size_t req_ie_len, |
372 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) | 427 | const u8 *resp_ie, size_t resp_ie_len) |
373 | { | 428 | { |
374 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
375 | struct cfg80211_bss *bss; | 429 | struct cfg80211_bss *bss; |
376 | #ifdef CONFIG_WIRELESS_EXT | 430 | #ifdef CONFIG_WIRELESS_EXT |
377 | union iwreq_data wrqu; | 431 | union iwreq_data wrqu; |
378 | #endif | 432 | #endif |
379 | 433 | ||
434 | ASSERT_WDEV_LOCK(wdev); | ||
435 | |||
380 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 436 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
381 | return; | 437 | return; |
382 | 438 | ||
@@ -402,31 +458,62 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | |||
402 | cfg80211_hold_bss(bss_from_pub(bss)); | 458 | cfg80211_hold_bss(bss_from_pub(bss)); |
403 | wdev->current_bss = bss_from_pub(bss); | 459 | wdev->current_bss = bss_from_pub(bss); |
404 | 460 | ||
405 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, | 461 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid, |
406 | req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); | 462 | req_ie, req_ie_len, resp_ie, resp_ie_len, |
463 | GFP_KERNEL); | ||
407 | 464 | ||
408 | #ifdef CONFIG_WIRELESS_EXT | 465 | #ifdef CONFIG_WIRELESS_EXT |
409 | if (req_ie) { | 466 | if (req_ie) { |
410 | memset(&wrqu, 0, sizeof(wrqu)); | 467 | memset(&wrqu, 0, sizeof(wrqu)); |
411 | wrqu.data.length = req_ie_len; | 468 | wrqu.data.length = req_ie_len; |
412 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); | 469 | wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, |
470 | &wrqu, req_ie); | ||
413 | } | 471 | } |
414 | 472 | ||
415 | if (resp_ie) { | 473 | if (resp_ie) { |
416 | memset(&wrqu, 0, sizeof(wrqu)); | 474 | memset(&wrqu, 0, sizeof(wrqu)); |
417 | wrqu.data.length = resp_ie_len; | 475 | wrqu.data.length = resp_ie_len; |
418 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); | 476 | wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, |
477 | &wrqu, resp_ie); | ||
419 | } | 478 | } |
420 | 479 | ||
421 | memset(&wrqu, 0, sizeof(wrqu)); | 480 | memset(&wrqu, 0, sizeof(wrqu)); |
422 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 481 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
423 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 482 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
424 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 483 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); |
425 | #endif | 484 | #endif |
426 | } | 485 | } |
486 | |||
487 | void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | ||
488 | const u8 *req_ie, size_t req_ie_len, | ||
489 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) | ||
490 | { | ||
491 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
492 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
493 | struct cfg80211_event *ev; | ||
494 | unsigned long flags; | ||
495 | |||
496 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | ||
497 | if (!ev) | ||
498 | return; | ||
499 | |||
500 | ev->type = EVENT_ROAMED; | ||
501 | memcpy(ev->rm.bssid, bssid, ETH_ALEN); | ||
502 | ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev); | ||
503 | ev->rm.req_ie_len = req_ie_len; | ||
504 | memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len); | ||
505 | ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; | ||
506 | ev->rm.resp_ie_len = resp_ie_len; | ||
507 | memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len); | ||
508 | |||
509 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
510 | list_add_tail(&ev->list, &wdev->event_list); | ||
511 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
512 | schedule_work(&rdev->event_work); | ||
513 | } | ||
427 | EXPORT_SYMBOL(cfg80211_roamed); | 514 | EXPORT_SYMBOL(cfg80211_roamed); |
428 | 515 | ||
429 | void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | 516 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
430 | size_t ie_len, u16 reason, bool from_ap) | 517 | size_t ie_len, u16 reason, bool from_ap) |
431 | { | 518 | { |
432 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 519 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -434,6 +521,8 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
434 | union iwreq_data wrqu; | 521 | union iwreq_data wrqu; |
435 | #endif | 522 | #endif |
436 | 523 | ||
524 | ASSERT_WDEV_LOCK(wdev); | ||
525 | |||
437 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 526 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
438 | return; | 527 | return; |
439 | 528 | ||
@@ -456,7 +545,7 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
456 | } | 545 | } |
457 | 546 | ||
458 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, | 547 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, |
459 | reason, ie, ie_len, from_ap, gfp); | 548 | reason, ie, ie_len, from_ap); |
460 | 549 | ||
461 | #ifdef CONFIG_WIRELESS_EXT | 550 | #ifdef CONFIG_WIRELESS_EXT |
462 | memset(&wrqu, 0, sizeof(wrqu)); | 551 | memset(&wrqu, 0, sizeof(wrqu)); |
@@ -468,16 +557,36 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
468 | void cfg80211_disconnected(struct net_device *dev, u16 reason, | 557 | void cfg80211_disconnected(struct net_device *dev, u16 reason, |
469 | u8 *ie, size_t ie_len, gfp_t gfp) | 558 | u8 *ie, size_t ie_len, gfp_t gfp) |
470 | { | 559 | { |
471 | __cfg80211_disconnected(dev, gfp, ie, ie_len, reason, true); | 560 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
561 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
562 | struct cfg80211_event *ev; | ||
563 | unsigned long flags; | ||
564 | |||
565 | ev = kzalloc(sizeof(*ev) + ie_len, gfp); | ||
566 | if (!ev) | ||
567 | return; | ||
568 | |||
569 | ev->type = EVENT_DISCONNECTED; | ||
570 | ev->dc.ie = ((u8 *)ev) + sizeof(*ev); | ||
571 | ev->dc.ie_len = ie_len; | ||
572 | memcpy((void *)ev->dc.ie, ie, ie_len); | ||
573 | ev->dc.reason = reason; | ||
574 | |||
575 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
576 | list_add_tail(&ev->list, &wdev->event_list); | ||
577 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
578 | schedule_work(&rdev->event_work); | ||
472 | } | 579 | } |
473 | EXPORT_SYMBOL(cfg80211_disconnected); | 580 | EXPORT_SYMBOL(cfg80211_disconnected); |
474 | 581 | ||
475 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 582 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
476 | struct net_device *dev, | 583 | struct net_device *dev, |
477 | struct cfg80211_connect_params *connect) | 584 | struct cfg80211_connect_params *connect) |
478 | { | 585 | { |
479 | int err; | ||
480 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 586 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
587 | int err; | ||
588 | |||
589 | ASSERT_WDEV_LOCK(wdev); | ||
481 | 590 | ||
482 | if (wdev->sme_state != CFG80211_SME_IDLE) | 591 | if (wdev->sme_state != CFG80211_SME_IDLE) |
483 | return -EALREADY; | 592 | return -EALREADY; |
@@ -572,12 +681,27 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
572 | } | 681 | } |
573 | } | 682 | } |
574 | 683 | ||
575 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 684 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
576 | struct net_device *dev, u16 reason, bool wextev) | 685 | struct net_device *dev, |
686 | struct cfg80211_connect_params *connect) | ||
687 | { | ||
688 | int err; | ||
689 | |||
690 | wdev_lock(dev->ieee80211_ptr); | ||
691 | err = __cfg80211_connect(rdev, dev, connect); | ||
692 | wdev_unlock(dev->ieee80211_ptr); | ||
693 | |||
694 | return err; | ||
695 | } | ||
696 | |||
697 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
698 | struct net_device *dev, u16 reason, bool wextev) | ||
577 | { | 699 | { |
578 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 700 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
579 | int err; | 701 | int err; |
580 | 702 | ||
703 | ASSERT_WDEV_LOCK(wdev); | ||
704 | |||
581 | if (wdev->sme_state == CFG80211_SME_IDLE) | 705 | if (wdev->sme_state == CFG80211_SME_IDLE) |
582 | return -EINVAL; | 706 | return -EINVAL; |
583 | 707 | ||
@@ -601,8 +725,9 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
601 | } | 725 | } |
602 | 726 | ||
603 | /* wdev->conn->params.bssid must be set if > SCANNING */ | 727 | /* wdev->conn->params.bssid must be set if > SCANNING */ |
604 | err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, | 728 | err = __cfg80211_mlme_deauth(rdev, dev, |
605 | NULL, 0, reason); | 729 | wdev->conn->params.bssid, |
730 | NULL, 0, reason); | ||
606 | if (err) | 731 | if (err) |
607 | return err; | 732 | return err; |
608 | } else { | 733 | } else { |
@@ -612,21 +737,36 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
612 | } | 737 | } |
613 | 738 | ||
614 | if (wdev->sme_state == CFG80211_SME_CONNECTED) | 739 | if (wdev->sme_state == CFG80211_SME_CONNECTED) |
615 | __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false); | 740 | __cfg80211_disconnected(dev, NULL, 0, 0, false); |
616 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) | 741 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) |
617 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, | 742 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, |
618 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 743 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
619 | wextev, GFP_KERNEL); | 744 | wextev); |
620 | 745 | ||
621 | return 0; | 746 | return 0; |
622 | } | 747 | } |
623 | 748 | ||
749 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
750 | struct net_device *dev, | ||
751 | u16 reason, bool wextev) | ||
752 | { | ||
753 | int err; | ||
754 | |||
755 | wdev_lock(dev->ieee80211_ptr); | ||
756 | err = __cfg80211_disconnect(rdev, dev, reason, wextev); | ||
757 | wdev_unlock(dev->ieee80211_ptr); | ||
758 | |||
759 | return err; | ||
760 | } | ||
761 | |||
624 | void cfg80211_sme_disassoc(struct net_device *dev, int idx) | 762 | void cfg80211_sme_disassoc(struct net_device *dev, int idx) |
625 | { | 763 | { |
626 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 764 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
627 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 765 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
628 | u8 bssid[ETH_ALEN]; | 766 | u8 bssid[ETH_ALEN]; |
629 | 767 | ||
768 | ASSERT_WDEV_LOCK(wdev); | ||
769 | |||
630 | if (!wdev->conn) | 770 | if (!wdev->conn) |
631 | return; | 771 | return; |
632 | 772 | ||