aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-04-04 02:37:19 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-07 14:37:56 -0400
commitd5cdfacb35ed886271d1ccfffbded98d3447da17 (patch)
tree8233a713949c4c8da8c98e75868efc74d5613c3d /net
parent7590a550b88b8c3cb025f0a8ed58e279ad62e4c1 (diff)
cfg80211: Add local-state-change-only auth/deauth/disassoc
cfg80211 is quite strict on allowing authentication and association commands only in certain states. In order to meet these requirements, user space applications may need to clear authentication or association state in some cases. Currently, this can be done with deauth/disassoc command, but that ends up sending out Deauthentication or Disassociation frame unnecessarily. Add a new nl80211 attribute to allow this sending of the frame be skipped, but with all other deauth/disassoc operations being completed. Similar state change is also needed for IEEE 802.11r FT protocol in the FT-over-DS case which does not use Authentication frame exchange in a transition to another BSS. For this to work with cfg80211, an authentication entry needs to be created for the target BSS without sending out an Authentication frame. The nl80211 authentication command can be used for this purpose, too, with the new attribute to indicate that the command is only for changing local state. This enables wpa_supplicant to complete FT-over-DS transition successfully. Signed-off-by: Jouni Malinen <j@w1.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/mlme.c23
-rw-r--r--net/wireless/core.h15
-rw-r--r--net/wireless/mlme.c39
-rw-r--r--net/wireless/nl80211.c19
-rw-r--r--net/wireless/sme.c15
5 files changed, 78 insertions, 33 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 57a3c62139e2..4c189d0be4a3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -210,7 +210,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
210 210
211static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, 211static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
212 const u8 *bssid, u16 stype, u16 reason, 212 const u8 *bssid, u16 stype, u16 reason,
213 void *cookie) 213 void *cookie, bool send_frame)
214{ 214{
215 struct ieee80211_local *local = sdata->local; 215 struct ieee80211_local *local = sdata->local;
216 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 216 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -247,7 +247,11 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
247 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); 247 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
248 if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) 248 if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
249 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 249 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
250 ieee80211_tx_skb(sdata, skb); 250
251 if (send_frame)
252 ieee80211_tx_skb(sdata, skb);
253 else
254 kfree_skb(skb);
251} 255}
252 256
253void ieee80211_send_pspoll(struct ieee80211_local *local, 257void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -980,7 +984,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
980 ieee80211_send_deauth_disassoc(sdata, bssid, 984 ieee80211_send_deauth_disassoc(sdata, bssid,
981 IEEE80211_STYPE_DEAUTH, 985 IEEE80211_STYPE_DEAUTH,
982 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, 986 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
983 NULL); 987 NULL, true);
984} 988}
985 989
986void ieee80211_beacon_connection_loss_work(struct work_struct *work) 990void ieee80211_beacon_connection_loss_work(struct work_struct *work)
@@ -1724,7 +1728,7 @@ static void ieee80211_sta_work(struct work_struct *work)
1724 ieee80211_send_deauth_disassoc(sdata, bssid, 1728 ieee80211_send_deauth_disassoc(sdata, bssid,
1725 IEEE80211_STYPE_DEAUTH, 1729 IEEE80211_STYPE_DEAUTH,
1726 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, 1730 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
1727 NULL); 1731 NULL, true);
1728 mutex_lock(&ifmgd->mtx); 1732 mutex_lock(&ifmgd->mtx);
1729 } 1733 }
1730 } 1734 }
@@ -1908,6 +1912,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
1908 struct ieee80211_work *wk; 1912 struct ieee80211_work *wk;
1909 u16 auth_alg; 1913 u16 auth_alg;
1910 1914
1915 if (req->local_state_change)
1916 return 0; /* no need to update mac80211 state */
1917
1911 switch (req->auth_type) { 1918 switch (req->auth_type) {
1912 case NL80211_AUTHTYPE_OPEN_SYSTEM: 1919 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1913 auth_alg = WLAN_AUTH_OPEN; 1920 auth_alg = WLAN_AUTH_OPEN;
@@ -2163,9 +2170,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2163 printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", 2170 printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
2164 sdata->name, bssid, req->reason_code); 2171 sdata->name, bssid, req->reason_code);
2165 2172
2166 ieee80211_send_deauth_disassoc(sdata, bssid, 2173 ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
2167 IEEE80211_STYPE_DEAUTH, req->reason_code, 2174 req->reason_code, cookie,
2168 cookie); 2175 !req->local_state_change);
2169 2176
2170 ieee80211_recalc_idle(sdata->local); 2177 ieee80211_recalc_idle(sdata->local);
2171 2178
@@ -2202,7 +2209,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
2202 2209
2203 ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, 2210 ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
2204 IEEE80211_STYPE_DISASSOC, req->reason_code, 2211 IEEE80211_STYPE_DISASSOC, req->reason_code,
2205 cookie); 2212 cookie, !req->local_state_change);
2206 sta_info_destroy_addr(sdata, bssid); 2213 sta_info_destroy_addr(sdata, bssid);
2207 2214
2208 ieee80211_recalc_idle(sdata->local); 2215 ieee80211_recalc_idle(sdata->local);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index d52da913145a..b2234b436ead 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -293,13 +293,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
293 const u8 *bssid, 293 const u8 *bssid,
294 const u8 *ssid, int ssid_len, 294 const u8 *ssid, int ssid_len,
295 const u8 *ie, int ie_len, 295 const u8 *ie, int ie_len,
296 const u8 *key, int key_len, int key_idx); 296 const u8 *key, int key_len, int key_idx,
297 bool local_state_change);
297int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 298int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
298 struct net_device *dev, struct ieee80211_channel *chan, 299 struct net_device *dev, struct ieee80211_channel *chan,
299 enum nl80211_auth_type auth_type, const u8 *bssid, 300 enum nl80211_auth_type auth_type, const u8 *bssid,
300 const u8 *ssid, int ssid_len, 301 const u8 *ssid, int ssid_len,
301 const u8 *ie, int ie_len, 302 const u8 *ie, int ie_len,
302 const u8 *key, int key_len, int key_idx); 303 const u8 *key, int key_len, int key_idx,
304 bool local_state_change);
303int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 305int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
304 struct net_device *dev, 306 struct net_device *dev,
305 struct ieee80211_channel *chan, 307 struct ieee80211_channel *chan,
@@ -315,13 +317,16 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
315 struct cfg80211_crypto_settings *crypt); 317 struct cfg80211_crypto_settings *crypt);
316int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 318int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
317 struct net_device *dev, const u8 *bssid, 319 struct net_device *dev, const u8 *bssid,
318 const u8 *ie, int ie_len, u16 reason); 320 const u8 *ie, int ie_len, u16 reason,
321 bool local_state_change);
319int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 322int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
320 struct net_device *dev, const u8 *bssid, 323 struct net_device *dev, const u8 *bssid,
321 const u8 *ie, int ie_len, u16 reason); 324 const u8 *ie, int ie_len, u16 reason,
325 bool local_state_change);
322int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 326int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
323 struct net_device *dev, const u8 *bssid, 327 struct net_device *dev, const u8 *bssid,
324 const u8 *ie, int ie_len, u16 reason); 328 const u8 *ie, int ie_len, u16 reason,
329 bool local_state_change);
325void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 330void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
326 struct net_device *dev); 331 struct net_device *dev);
327void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 332void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 0855f0d32349..387dd2a27d2f 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -377,7 +377,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
377 const u8 *bssid, 377 const u8 *bssid,
378 const u8 *ssid, int ssid_len, 378 const u8 *ssid, int ssid_len,
379 const u8 *ie, int ie_len, 379 const u8 *ie, int ie_len,
380 const u8 *key, int key_len, int key_idx) 380 const u8 *key, int key_len, int key_idx,
381 bool local_state_change)
381{ 382{
382 struct wireless_dev *wdev = dev->ieee80211_ptr; 383 struct wireless_dev *wdev = dev->ieee80211_ptr;
383 struct cfg80211_auth_request req; 384 struct cfg80211_auth_request req;
@@ -407,6 +408,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
407 408
408 memset(&req, 0, sizeof(req)); 409 memset(&req, 0, sizeof(req));
409 410
411 req.local_state_change = local_state_change;
410 req.ie = ie; 412 req.ie = ie;
411 req.ie_len = ie_len; 413 req.ie_len = ie_len;
412 req.auth_type = auth_type; 414 req.auth_type = auth_type;
@@ -433,12 +435,18 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
433 goto out; 435 goto out;
434 } 436 }
435 437
436 wdev->authtry_bsses[slot] = bss; 438 if (local_state_change)
439 wdev->auth_bsses[slot] = bss;
440 else
441 wdev->authtry_bsses[slot] = bss;
437 cfg80211_hold_bss(bss); 442 cfg80211_hold_bss(bss);
438 443
439 err = rdev->ops->auth(&rdev->wiphy, dev, &req); 444 err = rdev->ops->auth(&rdev->wiphy, dev, &req);
440 if (err) { 445 if (err) {
441 wdev->authtry_bsses[slot] = NULL; 446 if (local_state_change)
447 wdev->auth_bsses[slot] = NULL;
448 else
449 wdev->authtry_bsses[slot] = NULL;
442 cfg80211_unhold_bss(bss); 450 cfg80211_unhold_bss(bss);
443 } 451 }
444 452
@@ -453,14 +461,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
453 enum nl80211_auth_type auth_type, const u8 *bssid, 461 enum nl80211_auth_type auth_type, const u8 *bssid,
454 const u8 *ssid, int ssid_len, 462 const u8 *ssid, int ssid_len,
455 const u8 *ie, int ie_len, 463 const u8 *ie, int ie_len,
456 const u8 *key, int key_len, int key_idx) 464 const u8 *key, int key_len, int key_idx,
465 bool local_state_change)
457{ 466{
458 int err; 467 int err;
459 468
460 wdev_lock(dev->ieee80211_ptr); 469 wdev_lock(dev->ieee80211_ptr);
461 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 470 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
462 ssid, ssid_len, ie, ie_len, 471 ssid, ssid_len, ie, ie_len,
463 key, key_len, key_idx); 472 key, key_len, key_idx, local_state_change);
464 wdev_unlock(dev->ieee80211_ptr); 473 wdev_unlock(dev->ieee80211_ptr);
465 474
466 return err; 475 return err;
@@ -554,7 +563,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
554 563
555int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 564int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
556 struct net_device *dev, const u8 *bssid, 565 struct net_device *dev, const u8 *bssid,
557 const u8 *ie, int ie_len, u16 reason) 566 const u8 *ie, int ie_len, u16 reason,
567 bool local_state_change)
558{ 568{
559 struct wireless_dev *wdev = dev->ieee80211_ptr; 569 struct wireless_dev *wdev = dev->ieee80211_ptr;
560 struct cfg80211_deauth_request req; 570 struct cfg80211_deauth_request req;
@@ -564,6 +574,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
564 574
565 memset(&req, 0, sizeof(req)); 575 memset(&req, 0, sizeof(req));
566 req.reason_code = reason; 576 req.reason_code = reason;
577 req.local_state_change = local_state_change;
567 req.ie = ie; 578 req.ie = ie;
568 req.ie_len = ie_len; 579 req.ie_len = ie_len;
569 if (wdev->current_bss && 580 if (wdev->current_bss &&
@@ -590,13 +601,15 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
590 601
591int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 602int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
592 struct net_device *dev, const u8 *bssid, 603 struct net_device *dev, const u8 *bssid,
593 const u8 *ie, int ie_len, u16 reason) 604 const u8 *ie, int ie_len, u16 reason,
605 bool local_state_change)
594{ 606{
595 struct wireless_dev *wdev = dev->ieee80211_ptr; 607 struct wireless_dev *wdev = dev->ieee80211_ptr;
596 int err; 608 int err;
597 609
598 wdev_lock(wdev); 610 wdev_lock(wdev);
599 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason); 611 err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
612 local_state_change);
600 wdev_unlock(wdev); 613 wdev_unlock(wdev);
601 614
602 return err; 615 return err;
@@ -604,7 +617,8 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
604 617
605static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 618static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
606 struct net_device *dev, const u8 *bssid, 619 struct net_device *dev, const u8 *bssid,
607 const u8 *ie, int ie_len, u16 reason) 620 const u8 *ie, int ie_len, u16 reason,
621 bool local_state_change)
608{ 622{
609 struct wireless_dev *wdev = dev->ieee80211_ptr; 623 struct wireless_dev *wdev = dev->ieee80211_ptr;
610 struct cfg80211_disassoc_request req; 624 struct cfg80211_disassoc_request req;
@@ -619,6 +633,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
619 633
620 memset(&req, 0, sizeof(req)); 634 memset(&req, 0, sizeof(req));
621 req.reason_code = reason; 635 req.reason_code = reason;
636 req.local_state_change = local_state_change;
622 req.ie = ie; 637 req.ie = ie;
623 req.ie_len = ie_len; 638 req.ie_len = ie_len;
624 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) 639 if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
@@ -631,13 +646,15 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
631 646
632int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 647int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
633 struct net_device *dev, const u8 *bssid, 648 struct net_device *dev, const u8 *bssid,
634 const u8 *ie, int ie_len, u16 reason) 649 const u8 *ie, int ie_len, u16 reason,
650 bool local_state_change)
635{ 651{
636 struct wireless_dev *wdev = dev->ieee80211_ptr; 652 struct wireless_dev *wdev = dev->ieee80211_ptr;
637 int err; 653 int err;
638 654
639 wdev_lock(wdev); 655 wdev_lock(wdev);
640 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason); 656 err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
657 local_state_change);
641 wdev_unlock(wdev); 658 wdev_unlock(wdev);
642 659
643 return err; 660 return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 95149f303409..df5505b3930c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -150,6 +150,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
150 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, }, 150 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
151 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 }, 151 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
152 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, 152 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
153 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
153}; 154};
154 155
155/* policy for the attributes */ 156/* policy for the attributes */
@@ -3393,6 +3394,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3393 int err, ssid_len, ie_len = 0; 3394 int err, ssid_len, ie_len = 0;
3394 enum nl80211_auth_type auth_type; 3395 enum nl80211_auth_type auth_type;
3395 struct key_parse key; 3396 struct key_parse key;
3397 bool local_state_change;
3396 3398
3397 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3399 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3398 return -EINVAL; 3400 return -EINVAL;
@@ -3471,9 +3473,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3471 goto out; 3473 goto out;
3472 } 3474 }
3473 3475
3476 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
3477
3474 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 3478 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
3475 ssid, ssid_len, ie, ie_len, 3479 ssid, ssid_len, ie, ie_len,
3476 key.p.key, key.p.key_len, key.idx); 3480 key.p.key, key.p.key_len, key.idx,
3481 local_state_change);
3477 3482
3478out: 3483out:
3479 cfg80211_unlock_rdev(rdev); 3484 cfg80211_unlock_rdev(rdev);
@@ -3650,6 +3655,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
3650 const u8 *ie = NULL, *bssid; 3655 const u8 *ie = NULL, *bssid;
3651 int err, ie_len = 0; 3656 int err, ie_len = 0;
3652 u16 reason_code; 3657 u16 reason_code;
3658 bool local_state_change;
3653 3659
3654 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3660 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3655 return -EINVAL; 3661 return -EINVAL;
@@ -3695,7 +3701,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
3695 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3701 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3696 } 3702 }
3697 3703
3698 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code); 3704 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
3705
3706 err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
3707 local_state_change);
3699 3708
3700out: 3709out:
3701 cfg80211_unlock_rdev(rdev); 3710 cfg80211_unlock_rdev(rdev);
@@ -3712,6 +3721,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
3712 const u8 *ie = NULL, *bssid; 3721 const u8 *ie = NULL, *bssid;
3713 int err, ie_len = 0; 3722 int err, ie_len = 0;
3714 u16 reason_code; 3723 u16 reason_code;
3724 bool local_state_change;
3715 3725
3716 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3726 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3717 return -EINVAL; 3727 return -EINVAL;
@@ -3757,7 +3767,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
3757 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3767 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3758 } 3768 }
3759 3769
3760 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code); 3770 local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
3771
3772 err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
3773 local_state_change);
3761 3774
3762out: 3775out:
3763 cfg80211_unlock_rdev(rdev); 3776 cfg80211_unlock_rdev(rdev);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 17fde0da1b08..17465777eb47 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -170,7 +170,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
170 params->ssid, params->ssid_len, 170 params->ssid, params->ssid_len,
171 NULL, 0, 171 NULL, 0,
172 params->key, params->key_len, 172 params->key, params->key_len,
173 params->key_idx); 173 params->key_idx, false);
174 case CFG80211_CONN_ASSOCIATE_NEXT: 174 case CFG80211_CONN_ASSOCIATE_NEXT:
175 BUG_ON(!rdev->ops->assoc); 175 BUG_ON(!rdev->ops->assoc);
176 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 176 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -185,12 +185,13 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
185 if (err) 185 if (err)
186 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, 186 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
187 NULL, 0, 187 NULL, 0,
188 WLAN_REASON_DEAUTH_LEAVING); 188 WLAN_REASON_DEAUTH_LEAVING,
189 false);
189 return err; 190 return err;
190 case CFG80211_CONN_DEAUTH_ASSOC_FAIL: 191 case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
191 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, 192 __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
192 NULL, 0, 193 NULL, 0,
193 WLAN_REASON_DEAUTH_LEAVING); 194 WLAN_REASON_DEAUTH_LEAVING, false);
194 /* return an error so that we call __cfg80211_connect_result() */ 195 /* return an error so that we call __cfg80211_connect_result() */
195 return -EINVAL; 196 return -EINVAL;
196 default: 197 default:
@@ -675,7 +676,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
675 continue; 676 continue;
676 bssid = wdev->auth_bsses[i]->pub.bssid; 677 bssid = wdev->auth_bsses[i]->pub.bssid;
677 ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, 678 ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
678 WLAN_REASON_DEAUTH_LEAVING); 679 WLAN_REASON_DEAUTH_LEAVING,
680 false);
679 WARN(ret, "deauth failed: %d\n", ret); 681 WARN(ret, "deauth failed: %d\n", ret);
680 } 682 }
681 } 683 }
@@ -934,7 +936,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
934 /* wdev->conn->params.bssid must be set if > SCANNING */ 936 /* wdev->conn->params.bssid must be set if > SCANNING */
935 err = __cfg80211_mlme_deauth(rdev, dev, 937 err = __cfg80211_mlme_deauth(rdev, dev,
936 wdev->conn->params.bssid, 938 wdev->conn->params.bssid,
937 NULL, 0, reason); 939 NULL, 0, reason, false);
938 if (err) 940 if (err)
939 return err; 941 return err;
940 } else { 942 } else {
@@ -990,7 +992,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx)
990 992
991 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); 993 memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
992 if (__cfg80211_mlme_deauth(rdev, dev, bssid, 994 if (__cfg80211_mlme_deauth(rdev, dev, bssid,
993 NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { 995 NULL, 0, WLAN_REASON_DEAUTH_LEAVING,
996 false)) {
994 /* whatever -- assume gone anyway */ 997 /* whatever -- assume gone anyway */
995 cfg80211_unhold_bss(wdev->auth_bsses[idx]); 998 cfg80211_unhold_bss(wdev->auth_bsses[idx]);
996 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); 999 cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);