diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 54 | ||||
-rw-r--r-- | net/wireless/core.h | 4 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 16 | ||||
-rw-r--r-- | net/wireless/util.c | 108 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 16 |
5 files changed, 117 insertions, 81 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 9b157caa74fd..45b2be3274db 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -294,69 +294,17 @@ static void cfg80211_rfkill_sync_work(struct work_struct *work) | |||
294 | cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); | 294 | cfg80211_rfkill_set_block(rdev, rfkill_blocked(rdev->rfkill)); |
295 | } | 295 | } |
296 | 296 | ||
297 | static void cfg80211_process_events(struct wireless_dev *wdev) | ||
298 | { | ||
299 | struct cfg80211_event *ev; | ||
300 | unsigned long flags; | ||
301 | |||
302 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
303 | while (!list_empty(&wdev->event_list)) { | ||
304 | ev = list_first_entry(&wdev->event_list, | ||
305 | struct cfg80211_event, list); | ||
306 | list_del(&ev->list); | ||
307 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
308 | |||
309 | wdev_lock(wdev); | ||
310 | switch (ev->type) { | ||
311 | case EVENT_CONNECT_RESULT: | ||
312 | __cfg80211_connect_result( | ||
313 | wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ? | ||
314 | NULL : ev->cr.bssid, | ||
315 | ev->cr.req_ie, ev->cr.req_ie_len, | ||
316 | ev->cr.resp_ie, ev->cr.resp_ie_len, | ||
317 | ev->cr.status, | ||
318 | ev->cr.status == WLAN_STATUS_SUCCESS, | ||
319 | NULL); | ||
320 | break; | ||
321 | case EVENT_ROAMED: | ||
322 | __cfg80211_roamed(wdev, ev->rm.bssid, | ||
323 | ev->rm.req_ie, ev->rm.req_ie_len, | ||
324 | ev->rm.resp_ie, ev->rm.resp_ie_len); | ||
325 | break; | ||
326 | case EVENT_DISCONNECTED: | ||
327 | __cfg80211_disconnected(wdev->netdev, | ||
328 | ev->dc.ie, ev->dc.ie_len, | ||
329 | ev->dc.reason, true); | ||
330 | break; | ||
331 | case EVENT_IBSS_JOINED: | ||
332 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); | ||
333 | break; | ||
334 | } | ||
335 | wdev_unlock(wdev); | ||
336 | |||
337 | kfree(ev); | ||
338 | |||
339 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
340 | } | ||
341 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
342 | } | ||
343 | |||
344 | static void cfg80211_event_work(struct work_struct *work) | 297 | static void cfg80211_event_work(struct work_struct *work) |
345 | { | 298 | { |
346 | struct cfg80211_registered_device *rdev; | 299 | struct cfg80211_registered_device *rdev; |
347 | struct wireless_dev *wdev; | ||
348 | 300 | ||
349 | rdev = container_of(work, struct cfg80211_registered_device, | 301 | rdev = container_of(work, struct cfg80211_registered_device, |
350 | event_work); | 302 | event_work); |
351 | 303 | ||
352 | rtnl_lock(); | 304 | rtnl_lock(); |
353 | cfg80211_lock_rdev(rdev); | 305 | cfg80211_lock_rdev(rdev); |
354 | mutex_lock(&rdev->devlist_mtx); | ||
355 | 306 | ||
356 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 307 | cfg80211_process_rdev_events(rdev); |
357 | cfg80211_process_events(wdev); | ||
358 | |||
359 | mutex_unlock(&rdev->devlist_mtx); | ||
360 | cfg80211_unlock_rdev(rdev); | 308 | cfg80211_unlock_rdev(rdev); |
361 | rtnl_unlock(); | 309 | rtnl_unlock(); |
362 | } | 310 | } |
diff --git a/net/wireless/core.h b/net/wireless/core.h index d262d42cbd5e..2a33d8bc886b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -372,6 +372,10 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx); | |||
372 | void __cfg80211_scan_done(struct work_struct *wk); | 372 | void __cfg80211_scan_done(struct work_struct *wk); |
373 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); | 373 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); |
374 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 374 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
375 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | ||
376 | struct net_device *dev, enum nl80211_iftype ntype, | ||
377 | u32 *flags, struct vif_params *params); | ||
378 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | ||
375 | 379 | ||
376 | struct ieee80211_channel * | 380 | struct ieee80211_channel * |
377 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | 381 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a8aaadeb6773..71bfc044a939 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -977,12 +977,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
977 | } | 977 | } |
978 | } | 978 | } |
979 | 979 | ||
980 | if (!rdev->ops->change_virtual_intf || | ||
981 | !(rdev->wiphy.interface_modes & (1 << ntype))) { | ||
982 | err = -EOPNOTSUPP; | ||
983 | goto unlock; | ||
984 | } | ||
985 | |||
986 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 980 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
987 | if (ntype != NL80211_IFTYPE_MESH_POINT) { | 981 | if (ntype != NL80211_IFTYPE_MESH_POINT) { |
988 | err = -EINVAL; | 982 | err = -EINVAL; |
@@ -1008,18 +1002,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1008 | } | 1002 | } |
1009 | 1003 | ||
1010 | if (change) | 1004 | if (change) |
1011 | err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, | 1005 | err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); |
1012 | ntype, flags, ¶ms); | ||
1013 | else | 1006 | else |
1014 | err = 0; | 1007 | err = 0; |
1015 | 1008 | ||
1016 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); | ||
1017 | |||
1018 | if (!err && (ntype != otype)) { | ||
1019 | if (otype == NL80211_IFTYPE_ADHOC) | ||
1020 | cfg80211_clear_ibss(dev, false); | ||
1021 | } | ||
1022 | |||
1023 | unlock: | 1009 | unlock: |
1024 | dev_put(dev); | 1010 | dev_put(dev); |
1025 | cfg80211_unlock_rdev(rdev); | 1011 | cfg80211_unlock_rdev(rdev); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 693275a16a26..3fc2df86278f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -574,3 +574,111 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
574 | kfree(wdev->connect_keys); | 574 | kfree(wdev->connect_keys); |
575 | wdev->connect_keys = NULL; | 575 | wdev->connect_keys = NULL; |
576 | } | 576 | } |
577 | |||
578 | static void cfg80211_process_wdev_events(struct wireless_dev *wdev) | ||
579 | { | ||
580 | struct cfg80211_event *ev; | ||
581 | unsigned long flags; | ||
582 | const u8 *bssid = NULL; | ||
583 | |||
584 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
585 | while (!list_empty(&wdev->event_list)) { | ||
586 | ev = list_first_entry(&wdev->event_list, | ||
587 | struct cfg80211_event, list); | ||
588 | list_del(&ev->list); | ||
589 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
590 | |||
591 | wdev_lock(wdev); | ||
592 | switch (ev->type) { | ||
593 | case EVENT_CONNECT_RESULT: | ||
594 | if (!is_zero_ether_addr(ev->cr.bssid)) | ||
595 | bssid = ev->cr.bssid; | ||
596 | __cfg80211_connect_result( | ||
597 | wdev->netdev, bssid, | ||
598 | ev->cr.req_ie, ev->cr.req_ie_len, | ||
599 | ev->cr.resp_ie, ev->cr.resp_ie_len, | ||
600 | ev->cr.status, | ||
601 | ev->cr.status == WLAN_STATUS_SUCCESS, | ||
602 | NULL); | ||
603 | break; | ||
604 | case EVENT_ROAMED: | ||
605 | __cfg80211_roamed(wdev, ev->rm.bssid, | ||
606 | ev->rm.req_ie, ev->rm.req_ie_len, | ||
607 | ev->rm.resp_ie, ev->rm.resp_ie_len); | ||
608 | break; | ||
609 | case EVENT_DISCONNECTED: | ||
610 | __cfg80211_disconnected(wdev->netdev, | ||
611 | ev->dc.ie, ev->dc.ie_len, | ||
612 | ev->dc.reason, true); | ||
613 | break; | ||
614 | case EVENT_IBSS_JOINED: | ||
615 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); | ||
616 | break; | ||
617 | } | ||
618 | wdev_unlock(wdev); | ||
619 | |||
620 | kfree(ev); | ||
621 | |||
622 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
623 | } | ||
624 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
625 | } | ||
626 | |||
627 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | ||
628 | { | ||
629 | struct wireless_dev *wdev; | ||
630 | |||
631 | ASSERT_RTNL(); | ||
632 | ASSERT_RDEV_LOCK(rdev); | ||
633 | |||
634 | mutex_lock(&rdev->devlist_mtx); | ||
635 | |||
636 | list_for_each_entry(wdev, &rdev->netdev_list, list) | ||
637 | cfg80211_process_wdev_events(wdev); | ||
638 | |||
639 | mutex_unlock(&rdev->devlist_mtx); | ||
640 | } | ||
641 | |||
642 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | ||
643 | struct net_device *dev, enum nl80211_iftype ntype, | ||
644 | u32 *flags, struct vif_params *params) | ||
645 | { | ||
646 | int err; | ||
647 | enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; | ||
648 | |||
649 | ASSERT_RDEV_LOCK(rdev); | ||
650 | |||
651 | /* don't support changing VLANs, you just re-create them */ | ||
652 | if (otype == NL80211_IFTYPE_AP_VLAN) | ||
653 | return -EOPNOTSUPP; | ||
654 | |||
655 | if (!rdev->ops->change_virtual_intf || | ||
656 | !(rdev->wiphy.interface_modes & (1 << ntype))) | ||
657 | return -EOPNOTSUPP; | ||
658 | |||
659 | if (ntype != otype) { | ||
660 | switch (otype) { | ||
661 | case NL80211_IFTYPE_ADHOC: | ||
662 | cfg80211_leave_ibss(rdev, dev, false); | ||
663 | break; | ||
664 | case NL80211_IFTYPE_STATION: | ||
665 | cfg80211_disconnect(rdev, dev, | ||
666 | WLAN_REASON_DEAUTH_LEAVING, true); | ||
667 | break; | ||
668 | case NL80211_IFTYPE_MESH_POINT: | ||
669 | /* mesh should be handled? */ | ||
670 | break; | ||
671 | default: | ||
672 | break; | ||
673 | } | ||
674 | |||
675 | cfg80211_process_rdev_events(rdev); | ||
676 | } | ||
677 | |||
678 | err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, | ||
679 | ntype, flags, params); | ||
680 | |||
681 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); | ||
682 | |||
683 | return err; | ||
684 | } | ||
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c12029b1def0..429dd06a4ecc 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -70,18 +70,8 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | |||
70 | enum nl80211_iftype type; | 70 | enum nl80211_iftype type; |
71 | int ret; | 71 | int ret; |
72 | 72 | ||
73 | if (!wdev) | ||
74 | return -EOPNOTSUPP; | ||
75 | |||
76 | rdev = wiphy_to_dev(wdev->wiphy); | 73 | rdev = wiphy_to_dev(wdev->wiphy); |
77 | 74 | ||
78 | if (!rdev->ops->change_virtual_intf) | ||
79 | return -EOPNOTSUPP; | ||
80 | |||
81 | /* don't support changing VLANs, you just re-create them */ | ||
82 | if (wdev->iftype == NL80211_IFTYPE_AP_VLAN) | ||
83 | return -EOPNOTSUPP; | ||
84 | |||
85 | switch (*mode) { | 75 | switch (*mode) { |
86 | case IW_MODE_INFRA: | 76 | case IW_MODE_INFRA: |
87 | type = NL80211_IFTYPE_STATION; | 77 | type = NL80211_IFTYPE_STATION; |
@@ -104,9 +94,9 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | |||
104 | 94 | ||
105 | memset(&vifparams, 0, sizeof(vifparams)); | 95 | memset(&vifparams, 0, sizeof(vifparams)); |
106 | 96 | ||
107 | ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type, | 97 | cfg80211_lock_rdev(rdev); |
108 | NULL, &vifparams); | 98 | ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); |
109 | WARN_ON(!ret && wdev->iftype != type); | 99 | cfg80211_unlock_rdev(rdev); |
110 | 100 | ||
111 | return ret; | 101 | return ret; |
112 | } | 102 | } |