diff options
-rw-r--r-- | include/net/cfg80211.h | 86 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 22 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 6 | ||||
-rw-r--r-- | net/wireless/core.c | 5 | ||||
-rw-r--r-- | net/wireless/core.h | 41 | ||||
-rw-r--r-- | net/wireless/ibss.c | 12 | ||||
-rw-r--r-- | net/wireless/mlme.c | 357 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 144 | ||||
-rw-r--r-- | net/wireless/scan.c | 31 | ||||
-rw-r--r-- | net/wireless/sme.c | 156 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 4 |
11 files changed, 589 insertions, 275 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index eb026541f928..ca986cc91098 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -584,7 +584,6 @@ enum cfg80211_signal_type { | |||
584 | * is no guarantee that these are well-formed!) | 584 | * is no guarantee that these are well-formed!) |
585 | * @len_information_elements: total length of the information elements | 585 | * @len_information_elements: total length of the information elements |
586 | * @signal: signal strength value (type depends on the wiphy's signal_type) | 586 | * @signal: signal strength value (type depends on the wiphy's signal_type) |
587 | * @hold: BSS should not expire | ||
588 | * @free_priv: function pointer to free private data | 587 | * @free_priv: function pointer to free private data |
589 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes | 588 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes |
590 | */ | 589 | */ |
@@ -642,33 +641,17 @@ struct cfg80211_crypto_settings { | |||
642 | * | 641 | * |
643 | * This structure provides information needed to complete IEEE 802.11 | 642 | * This structure provides information needed to complete IEEE 802.11 |
644 | * authentication. | 643 | * authentication. |
645 | * NOTE: This structure will likely change when more code from mac80211 is | 644 | * |
646 | * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too. | 645 | * @bss: The BSS to authenticate with. |
647 | * Before using this in a driver that does not use mac80211, it would be better | ||
648 | * to check the status of that work and better yet, volunteer to work on it. | ||
649 | * | ||
650 | * @chan: The channel to use or %NULL if not specified (auto-select based on | ||
651 | * scan results) | ||
652 | * @peer_addr: The address of the peer STA (AP BSSID in infrastructure case); | ||
653 | * this field is required to be present; if the driver wants to help with | ||
654 | * BSS selection, it should use (yet to be added) MLME event to allow user | ||
655 | * space SME to be notified of roaming candidate, so that the SME can then | ||
656 | * use the authentication request with the recommended BSSID and whatever | ||
657 | * other data may be needed for authentication/association | ||
658 | * @ssid: SSID or %NULL if not yet available | ||
659 | * @ssid_len: Length of ssid in octets | ||
660 | * @auth_type: Authentication type (algorithm) | 646 | * @auth_type: Authentication type (algorithm) |
661 | * @ie: Extra IEs to add to Authentication frame or %NULL | 647 | * @ie: Extra IEs to add to Authentication frame or %NULL |
662 | * @ie_len: Length of ie buffer in octets | 648 | * @ie_len: Length of ie buffer in octets |
663 | */ | 649 | */ |
664 | struct cfg80211_auth_request { | 650 | struct cfg80211_auth_request { |
665 | struct ieee80211_channel *chan; | 651 | struct cfg80211_bss *bss; |
666 | u8 *peer_addr; | ||
667 | const u8 *ssid; | ||
668 | size_t ssid_len; | ||
669 | enum nl80211_auth_type auth_type; | ||
670 | const u8 *ie; | 652 | const u8 *ie; |
671 | size_t ie_len; | 653 | size_t ie_len; |
654 | enum nl80211_auth_type auth_type; | ||
672 | }; | 655 | }; |
673 | 656 | ||
674 | /** | 657 | /** |
@@ -676,32 +659,18 @@ struct cfg80211_auth_request { | |||
676 | * | 659 | * |
677 | * This structure provides information needed to complete IEEE 802.11 | 660 | * This structure provides information needed to complete IEEE 802.11 |
678 | * (re)association. | 661 | * (re)association. |
679 | * NOTE: This structure will likely change when more code from mac80211 is | 662 | * @bss: The BSS to associate with. |
680 | * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too. | ||
681 | * Before using this in a driver that does not use mac80211, it would be better | ||
682 | * to check the status of that work and better yet, volunteer to work on it. | ||
683 | * | ||
684 | * @chan: The channel to use or %NULL if not specified (auto-select based on | ||
685 | * scan results) | ||
686 | * @peer_addr: The address of the peer STA (AP BSSID); this field is required | ||
687 | * to be present and the STA must be in State 2 (authenticated) with the | ||
688 | * peer STA | ||
689 | * @ssid: SSID | ||
690 | * @ssid_len: Length of ssid in octets | ||
691 | * @ie: Extra IEs to add to (Re)Association Request frame or %NULL | 663 | * @ie: Extra IEs to add to (Re)Association Request frame or %NULL |
692 | * @ie_len: Length of ie buffer in octets | 664 | * @ie_len: Length of ie buffer in octets |
693 | * @use_mfp: Use management frame protection (IEEE 802.11w) in this association | 665 | * @use_mfp: Use management frame protection (IEEE 802.11w) in this association |
694 | * @crypto: crypto settings | 666 | * @crypto: crypto settings |
695 | */ | 667 | */ |
696 | struct cfg80211_assoc_request { | 668 | struct cfg80211_assoc_request { |
697 | struct ieee80211_channel *chan; | 669 | struct cfg80211_bss *bss; |
698 | u8 *peer_addr; | ||
699 | const u8 *ssid; | ||
700 | size_t ssid_len; | ||
701 | const u8 *ie; | 670 | const u8 *ie; |
702 | size_t ie_len; | 671 | size_t ie_len; |
703 | bool use_mfp; | ||
704 | struct cfg80211_crypto_settings crypto; | 672 | struct cfg80211_crypto_settings crypto; |
673 | bool use_mfp; | ||
705 | }; | 674 | }; |
706 | 675 | ||
707 | /** | 676 | /** |
@@ -710,16 +679,16 @@ struct cfg80211_assoc_request { | |||
710 | * This structure provides information needed to complete IEEE 802.11 | 679 | * This structure provides information needed to complete IEEE 802.11 |
711 | * deauthentication. | 680 | * deauthentication. |
712 | * | 681 | * |
713 | * @peer_addr: The address of the peer STA (AP BSSID); this field is required | 682 | * @bss: the BSS to deauthenticate from |
714 | * to be present and the STA must be authenticated with the peer STA | ||
715 | * @ie: Extra IEs to add to Deauthentication frame or %NULL | 683 | * @ie: Extra IEs to add to Deauthentication frame or %NULL |
716 | * @ie_len: Length of ie buffer in octets | 684 | * @ie_len: Length of ie buffer in octets |
685 | * @reason_code: The reason code for the deauthentication | ||
717 | */ | 686 | */ |
718 | struct cfg80211_deauth_request { | 687 | struct cfg80211_deauth_request { |
719 | u8 *peer_addr; | 688 | struct cfg80211_bss *bss; |
720 | u16 reason_code; | ||
721 | const u8 *ie; | 689 | const u8 *ie; |
722 | size_t ie_len; | 690 | size_t ie_len; |
691 | u16 reason_code; | ||
723 | }; | 692 | }; |
724 | 693 | ||
725 | /** | 694 | /** |
@@ -728,16 +697,16 @@ struct cfg80211_deauth_request { | |||
728 | * This structure provides information needed to complete IEEE 802.11 | 697 | * This structure provides information needed to complete IEEE 802.11 |
729 | * disassocation. | 698 | * disassocation. |
730 | * | 699 | * |
731 | * @peer_addr: The address of the peer STA (AP BSSID); this field is required | 700 | * @bss: the BSS to disassociate from |
732 | * to be present and the STA must be associated with the peer STA | ||
733 | * @ie: Extra IEs to add to Disassociation frame or %NULL | 701 | * @ie: Extra IEs to add to Disassociation frame or %NULL |
734 | * @ie_len: Length of ie buffer in octets | 702 | * @ie_len: Length of ie buffer in octets |
703 | * @reason_code: The reason code for the disassociation | ||
735 | */ | 704 | */ |
736 | struct cfg80211_disassoc_request { | 705 | struct cfg80211_disassoc_request { |
737 | u8 *peer_addr; | 706 | struct cfg80211_bss *bss; |
738 | u16 reason_code; | ||
739 | const u8 *ie; | 707 | const u8 *ie; |
740 | size_t ie_len; | 708 | size_t ie_len; |
709 | u16 reason_code; | ||
741 | }; | 710 | }; |
742 | 711 | ||
743 | /** | 712 | /** |
@@ -1252,6 +1221,9 @@ extern void wiphy_free(struct wiphy *wiphy); | |||
1252 | 1221 | ||
1253 | /* internal struct */ | 1222 | /* internal struct */ |
1254 | struct cfg80211_conn; | 1223 | struct cfg80211_conn; |
1224 | struct cfg80211_internal_bss; | ||
1225 | |||
1226 | #define MAX_AUTH_BSSES 4 | ||
1255 | 1227 | ||
1256 | /** | 1228 | /** |
1257 | * struct wireless_dev - wireless per-netdev state | 1229 | * struct wireless_dev - wireless per-netdev state |
@@ -1281,7 +1253,6 @@ struct wireless_dev { | |||
1281 | struct net_device *netdev; | 1253 | struct net_device *netdev; |
1282 | 1254 | ||
1283 | /* currently used for IBSS and SME - might be rearranged later */ | 1255 | /* currently used for IBSS and SME - might be rearranged later */ |
1284 | struct cfg80211_bss *current_bss; | ||
1285 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 1256 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
1286 | u8 ssid_len; | 1257 | u8 ssid_len; |
1287 | enum { | 1258 | enum { |
@@ -1291,6 +1262,10 @@ struct wireless_dev { | |||
1291 | } sme_state; | 1262 | } sme_state; |
1292 | struct cfg80211_conn *conn; | 1263 | struct cfg80211_conn *conn; |
1293 | 1264 | ||
1265 | struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; | ||
1266 | struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; | ||
1267 | struct cfg80211_internal_bss *current_bss; /* associated / joined */ | ||
1268 | |||
1294 | #ifdef CONFIG_WIRELESS_EXT | 1269 | #ifdef CONFIG_WIRELESS_EXT |
1295 | /* wext data */ | 1270 | /* wext data */ |
1296 | struct { | 1271 | struct { |
@@ -1813,23 +1788,6 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp | |||
1813 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); | 1788 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); |
1814 | 1789 | ||
1815 | /** | 1790 | /** |
1816 | * cfg80211_hold_bss - exclude bss from expiration | ||
1817 | * @bss: bss which should not expire | ||
1818 | * | ||
1819 | * In a case when the BSS is not updated but it shouldn't expire this | ||
1820 | * function can be used to mark the BSS to be excluded from expiration. | ||
1821 | */ | ||
1822 | void cfg80211_hold_bss(struct cfg80211_bss *bss); | ||
1823 | |||
1824 | /** | ||
1825 | * cfg80211_unhold_bss - remove expiration exception from the BSS | ||
1826 | * @bss: bss which can expire again | ||
1827 | * | ||
1828 | * This function marks the BSS to be expirable again. | ||
1829 | */ | ||
1830 | void cfg80211_unhold_bss(struct cfg80211_bss *bss); | ||
1831 | |||
1832 | /** | ||
1833 | * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) | 1791 | * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) |
1834 | * @dev: network device | 1792 | * @dev: network device |
1835 | * @addr: The source MAC address of the frame | 1793 | * @addr: The source MAC address of the frame |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7606571d4581..0f29cd0580c9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1173,6 +1173,7 @@ 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 | struct ieee80211_sub_if_data *sdata; |
1176 | const u8 *ssid; | ||
1176 | 1177 | ||
1177 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1178 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1178 | 1179 | ||
@@ -1193,15 +1194,16 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | |||
1193 | return -EOPNOTSUPP; | 1194 | return -EOPNOTSUPP; |
1194 | } | 1195 | } |
1195 | 1196 | ||
1196 | memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); | 1197 | memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); |
1197 | 1198 | ||
1198 | sdata->local->oper_channel = req->chan; | 1199 | sdata->local->oper_channel = req->bss->channel; |
1199 | ieee80211_hw_config(sdata->local, 0); | 1200 | ieee80211_hw_config(sdata->local, 0); |
1200 | 1201 | ||
1201 | if (!req->ssid) | 1202 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
1203 | if (!ssid) | ||
1202 | return -EINVAL; | 1204 | return -EINVAL; |
1203 | memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); | 1205 | sdata->u.mgd.ssid_len = *(ssid + 1); |
1204 | sdata->u.mgd.ssid_len = req->ssid_len; | 1206 | memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); |
1205 | 1207 | ||
1206 | kfree(sdata->u.mgd.sme_auth_ie); | 1208 | kfree(sdata->u.mgd.sme_auth_ie); |
1207 | sdata->u.mgd.sme_auth_ie = NULL; | 1209 | sdata->u.mgd.sme_auth_ie = NULL; |
@@ -1227,7 +1229,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | |||
1227 | 1229 | ||
1228 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1230 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1229 | 1231 | ||
1230 | if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 || | 1232 | if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || |
1231 | !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) | 1233 | !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) |
1232 | return -ENOLINK; /* not authenticated */ | 1234 | return -ENOLINK; /* not authenticated */ |
1233 | 1235 | ||
@@ -1239,15 +1241,9 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | |||
1239 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) | 1241 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) |
1240 | sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; | 1242 | sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; |
1241 | 1243 | ||
1242 | sdata->local->oper_channel = req->chan; | 1244 | sdata->local->oper_channel = req->bss->channel; |
1243 | ieee80211_hw_config(sdata->local, 0); | 1245 | ieee80211_hw_config(sdata->local, 0); |
1244 | 1246 | ||
1245 | if (!req->ssid) | ||
1246 | return -EINVAL; | ||
1247 | |||
1248 | memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); | ||
1249 | sdata->u.mgd.ssid_len = req->ssid_len; | ||
1250 | |||
1251 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); | 1247 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); |
1252 | if (ret && ret != -EALREADY) | 1248 | if (ret && ret != -EALREADY) |
1253 | return ret; | 1249 | return ret; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5748cda659c2..aa1829ae431d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -876,8 +876,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
876 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 876 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
877 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 877 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
878 | 878 | ||
879 | cfg80211_hold_bss(&bss->cbss); | ||
880 | |||
881 | ieee80211_rx_bss_put(local, bss); | 879 | ieee80211_rx_bss_put(local, bss); |
882 | } | 880 | } |
883 | 881 | ||
@@ -1031,10 +1029,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1031 | conf->channel->center_freq, | 1029 | conf->channel->center_freq, |
1032 | ifmgd->ssid, ifmgd->ssid_len); | 1030 | ifmgd->ssid, ifmgd->ssid_len); |
1033 | 1031 | ||
1034 | if (bss) { | 1032 | if (bss) |
1035 | cfg80211_unhold_bss(&bss->cbss); | ||
1036 | ieee80211_rx_bss_put(local, bss); | 1033 | ieee80211_rx_bss_put(local, bss); |
1037 | } | ||
1038 | 1034 | ||
1039 | if (self_disconnected) { | 1035 | if (self_disconnected) { |
1040 | if (deauth) | 1036 | if (deauth) |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 5f6a8322bcb3..7b66cf15349a 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -583,15 +583,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
583 | #endif | 583 | #endif |
584 | cfg80211_disconnect(rdev, dev, | 584 | cfg80211_disconnect(rdev, dev, |
585 | WLAN_REASON_DEAUTH_LEAVING, true); | 585 | WLAN_REASON_DEAUTH_LEAVING, true); |
586 | cfg80211_mlme_down(rdev, dev); | ||
586 | break; | 587 | break; |
587 | default: | 588 | default: |
588 | break; | 589 | break; |
589 | } | 590 | } |
590 | break; | 591 | break; |
591 | case NETDEV_DOWN: | ||
592 | kfree(wdev->conn); | ||
593 | wdev->conn = NULL; | ||
594 | break; | ||
595 | case NETDEV_UP: | 592 | case NETDEV_UP: |
596 | #ifdef CONFIG_WIRELESS_EXT | 593 | #ifdef CONFIG_WIRELESS_EXT |
597 | switch (wdev->iftype) { | 594 | switch (wdev->iftype) { |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 5209acb0ff7e..82918f5896a5 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -110,12 +110,30 @@ struct cfg80211_internal_bss { | |||
110 | struct rb_node rbn; | 110 | struct rb_node rbn; |
111 | unsigned long ts; | 111 | unsigned long ts; |
112 | struct kref ref; | 112 | struct kref ref; |
113 | bool hold, ies_allocated; | 113 | atomic_t hold; |
114 | bool ies_allocated; | ||
114 | 115 | ||
115 | /* must be last because of priv member */ | 116 | /* must be last because of priv member */ |
116 | struct cfg80211_bss pub; | 117 | struct cfg80211_bss pub; |
117 | }; | 118 | }; |
118 | 119 | ||
120 | static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub) | ||
121 | { | ||
122 | return container_of(pub, struct cfg80211_internal_bss, pub); | ||
123 | } | ||
124 | |||
125 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) | ||
126 | { | ||
127 | atomic_inc(&bss->hold); | ||
128 | } | ||
129 | |||
130 | static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) | ||
131 | { | ||
132 | int r = atomic_dec_return(&bss->hold); | ||
133 | WARN_ON(r < 0); | ||
134 | } | ||
135 | |||
136 | |||
119 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); | 137 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); |
120 | int get_wiphy_idx(struct wiphy *wiphy); | 138 | int get_wiphy_idx(struct wiphy *wiphy); |
121 | 139 | ||
@@ -176,6 +194,26 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | |||
176 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 194 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
177 | struct net_device *dev, bool nowext); | 195 | struct net_device *dev, bool nowext); |
178 | 196 | ||
197 | /* MLME */ | ||
198 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | ||
199 | struct net_device *dev, struct ieee80211_channel *chan, | ||
200 | enum nl80211_auth_type auth_type, const u8 *bssid, | ||
201 | const u8 *ssid, int ssid_len, | ||
202 | const u8 *ie, int ie_len); | ||
203 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | ||
204 | struct net_device *dev, struct ieee80211_channel *chan, | ||
205 | const u8 *bssid, const u8 *ssid, int ssid_len, | ||
206 | const u8 *ie, int ie_len, bool use_mfp, | ||
207 | struct cfg80211_crypto_settings *crypt); | ||
208 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | ||
209 | struct net_device *dev, const u8 *bssid, | ||
210 | const u8 *ie, int ie_len, u16 reason); | ||
211 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | ||
212 | struct net_device *dev, const u8 *bssid, | ||
213 | const u8 *ie, int ie_len, u16 reason); | ||
214 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | ||
215 | struct net_device *dev); | ||
216 | |||
179 | /* SME */ | 217 | /* SME */ |
180 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 218 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
181 | struct net_device *dev, | 219 | struct net_device *dev, |
@@ -193,5 +231,6 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
193 | size_t ie_len, u16 reason, bool from_ap); | 231 | size_t ie_len, u16 reason, bool from_ap); |
194 | void cfg80211_sme_scan_done(struct net_device *dev); | 232 | void cfg80211_sme_scan_done(struct net_device *dev); |
195 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 233 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
234 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | ||
196 | 235 | ||
197 | #endif /* __NET_WIRELESS_CORE_H */ | 236 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 34b11eae30c8..c92b542d54b0 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -33,11 +33,11 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | |||
33 | 33 | ||
34 | if (wdev->current_bss) { | 34 | if (wdev->current_bss) { |
35 | cfg80211_unhold_bss(wdev->current_bss); | 35 | cfg80211_unhold_bss(wdev->current_bss); |
36 | cfg80211_put_bss(wdev->current_bss); | 36 | cfg80211_put_bss(&wdev->current_bss->pub); |
37 | } | 37 | } |
38 | 38 | ||
39 | cfg80211_hold_bss(bss); | 39 | cfg80211_hold_bss(bss_from_pub(bss)); |
40 | wdev->current_bss = bss; | 40 | wdev->current_bss = bss_from_pub(bss); |
41 | 41 | ||
42 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); | 42 | nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); |
43 | #ifdef CONFIG_WIRELESS_EXT | 43 | #ifdef CONFIG_WIRELESS_EXT |
@@ -78,7 +78,7 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
78 | 78 | ||
79 | if (wdev->current_bss) { | 79 | if (wdev->current_bss) { |
80 | cfg80211_unhold_bss(wdev->current_bss); | 80 | cfg80211_unhold_bss(wdev->current_bss); |
81 | cfg80211_put_bss(wdev->current_bss); | 81 | cfg80211_put_bss(&wdev->current_bss->pub); |
82 | } | 82 | } |
83 | 83 | ||
84 | wdev->current_bss = NULL; | 84 | wdev->current_bss = NULL; |
@@ -212,7 +212,7 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, | |||
212 | return -EINVAL; | 212 | return -EINVAL; |
213 | 213 | ||
214 | if (wdev->current_bss) | 214 | if (wdev->current_bss) |
215 | chan = wdev->current_bss->channel; | 215 | chan = wdev->current_bss->pub.channel; |
216 | else if (wdev->wext.ibss.channel) | 216 | else if (wdev->wext.ibss.channel) |
217 | chan = wdev->wext.ibss.channel; | 217 | chan = wdev->wext.ibss.channel; |
218 | 218 | ||
@@ -352,7 +352,7 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, | |||
352 | ap_addr->sa_family = ARPHRD_ETHER; | 352 | ap_addr->sa_family = ARPHRD_ETHER; |
353 | 353 | ||
354 | if (wdev->current_bss) | 354 | if (wdev->current_bss) |
355 | memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); | 355 | memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); |
356 | else | 356 | else |
357 | memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); | 357 | memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); |
358 | return 0; | 358 | return 0; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 3427fe73d3c3..1a92bf7597bf 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -14,8 +14,32 @@ | |||
14 | 14 | ||
15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) | 15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
16 | { | 16 | { |
17 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 17 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
18 | struct wiphy *wiphy = wdev->wiphy; | ||
18 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 19 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
20 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | ||
21 | u8 *bssid = mgmt->bssid; | ||
22 | int i; | ||
23 | u16 status = le16_to_cpu(mgmt->u.auth.status_code); | ||
24 | bool done = false; | ||
25 | |||
26 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
27 | if (wdev->authtry_bsses[i] && | ||
28 | memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, | ||
29 | ETH_ALEN) == 0) { | ||
30 | if (status == WLAN_STATUS_SUCCESS) { | ||
31 | wdev->auth_bsses[i] = wdev->authtry_bsses[i]; | ||
32 | } else { | ||
33 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); | ||
34 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); | ||
35 | } | ||
36 | wdev->authtry_bsses[i] = NULL; | ||
37 | done = true; | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | WARN_ON(!done); | ||
19 | 43 | ||
20 | nl80211_send_rx_auth(rdev, dev, buf, len, gfp); | 44 | nl80211_send_rx_auth(rdev, dev, buf, len, gfp); |
21 | cfg80211_sme_rx_auth(dev, buf, len); | 45 | cfg80211_sme_rx_auth(dev, buf, len); |
@@ -30,7 +54,8 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g | |||
30 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 54 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
31 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 55 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
32 | u8 *ie = mgmt->u.assoc_resp.variable; | 56 | u8 *ie = mgmt->u.assoc_resp.variable; |
33 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | 57 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
58 | bool done; | ||
34 | 59 | ||
35 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 60 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
36 | 61 | ||
@@ -38,6 +63,20 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, g | |||
38 | 63 | ||
39 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | 64 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, |
40 | status_code, gfp); | 65 | status_code, gfp); |
66 | |||
67 | if (status_code == WLAN_STATUS_SUCCESS) { | ||
68 | for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { | ||
69 | if (wdev->auth_bsses[i] == wdev->current_bss) { | ||
70 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | ||
71 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | ||
72 | wdev->auth_bsses[i] = NULL; | ||
73 | done = true; | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | WARN_ON(!done); | ||
79 | } | ||
41 | } | 80 | } |
42 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 81 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
43 | 82 | ||
@@ -47,9 +86,45 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp | |||
47 | struct wiphy *wiphy = wdev->wiphy; | 86 | struct wiphy *wiphy = wdev->wiphy; |
48 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 87 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
49 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 88 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
89 | const u8 *bssid = mgmt->bssid; | ||
90 | int i; | ||
91 | bool done = false; | ||
50 | 92 | ||
51 | nl80211_send_deauth(rdev, dev, buf, len, gfp); | 93 | nl80211_send_deauth(rdev, dev, buf, len, gfp); |
52 | 94 | ||
95 | if (wdev->current_bss && | ||
96 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { | ||
97 | done = true; | ||
98 | cfg80211_unhold_bss(wdev->current_bss); | ||
99 | cfg80211_put_bss(&wdev->current_bss->pub); | ||
100 | wdev->current_bss = NULL; | ||
101 | } else for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
102 | if (wdev->auth_bsses[i] && | ||
103 | memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { | ||
104 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | ||
105 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | ||
106 | wdev->auth_bsses[i] = NULL; | ||
107 | done = true; | ||
108 | break; | ||
109 | } | ||
110 | if (wdev->authtry_bsses[i] && | ||
111 | memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { | ||
112 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); | ||
113 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); | ||
114 | wdev->authtry_bsses[i] = NULL; | ||
115 | done = true; | ||
116 | break; | ||
117 | } | ||
118 | } | ||
119 | /* | ||
120 | * mac80211 currently triggers this warning, | ||
121 | * so disable for now (it's harmless, just | ||
122 | * means that we got a spurious event) | ||
123 | |||
124 | WARN_ON(!done); | ||
125 | |||
126 | */ | ||
127 | |||
53 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | 128 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { |
54 | u16 reason_code; | 129 | u16 reason_code; |
55 | bool from_ap; | 130 | bool from_ap; |
@@ -59,8 +134,6 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp | |||
59 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 134 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; |
60 | __cfg80211_disconnected(dev, gfp, NULL, 0, | 135 | __cfg80211_disconnected(dev, gfp, NULL, 0, |
61 | reason_code, from_ap); | 136 | reason_code, from_ap); |
62 | |||
63 | wdev->sme_state = CFG80211_SME_IDLE; | ||
64 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | 137 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
65 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 138 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
66 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); | 139 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); |
@@ -74,21 +147,38 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, g | |||
74 | struct wiphy *wiphy = wdev->wiphy; | 147 | struct wiphy *wiphy = wdev->wiphy; |
75 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 148 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
76 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 149 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
150 | const u8 *bssid = mgmt->bssid; | ||
151 | int i; | ||
152 | u16 reason_code; | ||
153 | bool from_ap; | ||
154 | bool done = false; | ||
77 | 155 | ||
78 | nl80211_send_disassoc(rdev, dev, buf, len, gfp); | 156 | nl80211_send_disassoc(rdev, dev, buf, len, gfp); |
79 | 157 | ||
80 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { | 158 | if (!wdev->sme_state == CFG80211_SME_CONNECTED) |
81 | u16 reason_code; | 159 | return; |
82 | bool from_ap; | ||
83 | 160 | ||
84 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 161 | if (wdev->current_bss && |
162 | memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { | ||
163 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
164 | if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) | ||
165 | continue; | ||
166 | wdev->auth_bsses[i] = wdev->current_bss; | ||
167 | wdev->current_bss = NULL; | ||
168 | done = true; | ||
169 | cfg80211_sme_disassoc(dev, i); | ||
170 | break; | ||
171 | } | ||
172 | WARN_ON(!done); | ||
173 | } else | ||
174 | WARN_ON(1); | ||
85 | 175 | ||
86 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | ||
87 | __cfg80211_disconnected(dev, gfp, NULL, 0, | ||
88 | reason_code, from_ap); | ||
89 | 176 | ||
90 | wdev->sme_state = CFG80211_SME_IDLE; | 177 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
91 | } | 178 | |
179 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | ||
180 | __cfg80211_disconnected(dev, gfp, NULL, 0, | ||
181 | reason_code, from_ap); | ||
92 | } | 182 | } |
93 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 183 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
94 | 184 | ||
@@ -97,11 +187,27 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gf | |||
97 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 187 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
98 | struct wiphy *wiphy = wdev->wiphy; | 188 | struct wiphy *wiphy = wdev->wiphy; |
99 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 189 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
190 | int i; | ||
191 | bool done = false; | ||
192 | |||
100 | nl80211_send_auth_timeout(rdev, dev, addr, gfp); | 193 | nl80211_send_auth_timeout(rdev, dev, addr, gfp); |
101 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 194 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
102 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 195 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
103 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); | 196 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); |
104 | wdev->sme_state = CFG80211_SME_IDLE; | 197 | |
198 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | ||
199 | if (wdev->authtry_bsses[i] && | ||
200 | memcmp(wdev->authtry_bsses[i]->pub.bssid, | ||
201 | addr, ETH_ALEN) == 0) { | ||
202 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); | ||
203 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); | ||
204 | wdev->authtry_bsses[i] = NULL; | ||
205 | done = true; | ||
206 | break; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | WARN_ON(!done); | ||
105 | } | 211 | } |
106 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); | 212 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); |
107 | 213 | ||
@@ -110,11 +216,27 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t g | |||
110 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 216 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
111 | struct wiphy *wiphy = wdev->wiphy; | 217 | struct wiphy *wiphy = wdev->wiphy; |
112 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 218 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
219 | int i; | ||
220 | bool done = false; | ||
221 | |||
113 | nl80211_send_assoc_timeout(rdev, dev, addr, gfp); | 222 | nl80211_send_assoc_timeout(rdev, dev, addr, gfp); |
114 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 223 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
115 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 224 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
116 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); | 225 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); |
117 | wdev->sme_state = CFG80211_SME_IDLE; | 226 | |
227 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | ||
228 | if (wdev->auth_bsses[i] && | ||
229 | memcmp(wdev->auth_bsses[i]->pub.bssid, | ||
230 | addr, ETH_ALEN) == 0) { | ||
231 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | ||
232 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | ||
233 | wdev->auth_bsses[i] = NULL; | ||
234 | done = true; | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | WARN_ON(!done); | ||
118 | } | 240 | } |
119 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); | 241 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); |
120 | 242 | ||
@@ -143,3 +265,208 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, | |||
143 | nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); | 265 | nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); |
144 | } | 266 | } |
145 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); | 267 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); |
268 | |||
269 | /* some MLME handling for userspace SME */ | ||
270 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | ||
271 | struct net_device *dev, struct ieee80211_channel *chan, | ||
272 | enum nl80211_auth_type auth_type, const u8 *bssid, | ||
273 | const u8 *ssid, int ssid_len, | ||
274 | const u8 *ie, int ie_len) | ||
275 | { | ||
276 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
277 | struct cfg80211_auth_request req; | ||
278 | struct cfg80211_internal_bss *bss; | ||
279 | int i, err, slot = -1, nfree = 0; | ||
280 | |||
281 | memset(&req, 0, sizeof(req)); | ||
282 | |||
283 | req.ie = ie; | ||
284 | req.ie_len = ie_len; | ||
285 | req.auth_type = auth_type; | ||
286 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | ||
287 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | ||
288 | if (!req.bss) | ||
289 | return -ENOENT; | ||
290 | |||
291 | bss = bss_from_pub(req.bss); | ||
292 | |||
293 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
294 | if (bss == wdev->auth_bsses[i]) { | ||
295 | err = -EALREADY; | ||
296 | goto out; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
301 | if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) { | ||
302 | slot = i; | ||
303 | nfree++; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | /* we need one free slot for disassoc and one for this auth */ | ||
308 | if (nfree < 2) { | ||
309 | err = -ENOSPC; | ||
310 | goto out; | ||
311 | } | ||
312 | |||
313 | wdev->authtry_bsses[slot] = bss; | ||
314 | cfg80211_hold_bss(bss); | ||
315 | |||
316 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); | ||
317 | if (err) { | ||
318 | wdev->authtry_bsses[slot] = NULL; | ||
319 | cfg80211_unhold_bss(bss); | ||
320 | } | ||
321 | |||
322 | out: | ||
323 | if (err) | ||
324 | cfg80211_put_bss(req.bss); | ||
325 | return err; | ||
326 | } | ||
327 | |||
328 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | ||
329 | struct net_device *dev, struct ieee80211_channel *chan, | ||
330 | const u8 *bssid, const u8 *ssid, int ssid_len, | ||
331 | const u8 *ie, int ie_len, bool use_mfp, | ||
332 | struct cfg80211_crypto_settings *crypt) | ||
333 | { | ||
334 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
335 | struct cfg80211_assoc_request req; | ||
336 | struct cfg80211_internal_bss *bss; | ||
337 | int i, err, slot = -1; | ||
338 | |||
339 | memset(&req, 0, sizeof(req)); | ||
340 | |||
341 | if (wdev->current_bss) | ||
342 | return -EALREADY; | ||
343 | |||
344 | req.ie = ie; | ||
345 | req.ie_len = ie_len; | ||
346 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); | ||
347 | req.use_mfp = use_mfp; | ||
348 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | ||
349 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | ||
350 | if (!req.bss) | ||
351 | return -ENOENT; | ||
352 | |||
353 | bss = bss_from_pub(req.bss); | ||
354 | |||
355 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
356 | if (bss == wdev->auth_bsses[i]) { | ||
357 | slot = i; | ||
358 | break; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | if (slot < 0) { | ||
363 | err = -ENOTCONN; | ||
364 | goto out; | ||
365 | } | ||
366 | |||
367 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); | ||
368 | out: | ||
369 | /* still a reference in wdev->auth_bsses[slot] */ | ||
370 | cfg80211_put_bss(req.bss); | ||
371 | return err; | ||
372 | } | ||
373 | |||
374 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | ||
375 | struct net_device *dev, const u8 *bssid, | ||
376 | const u8 *ie, int ie_len, u16 reason) | ||
377 | { | ||
378 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
379 | struct cfg80211_deauth_request req; | ||
380 | int i; | ||
381 | |||
382 | memset(&req, 0, sizeof(req)); | ||
383 | req.reason_code = reason; | ||
384 | req.ie = ie; | ||
385 | req.ie_len = ie_len; | ||
386 | if (wdev->current_bss && | ||
387 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { | ||
388 | req.bss = &wdev->current_bss->pub; | ||
389 | } else for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
390 | if (wdev->auth_bsses[i] && | ||
391 | memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) { | ||
392 | req.bss = &wdev->auth_bsses[i]->pub; | ||
393 | break; | ||
394 | } | ||
395 | if (wdev->authtry_bsses[i] && | ||
396 | memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) { | ||
397 | req.bss = &wdev->authtry_bsses[i]->pub; | ||
398 | break; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | if (!req.bss) | ||
403 | return -ENOTCONN; | ||
404 | |||
405 | return rdev->ops->deauth(&rdev->wiphy, dev, &req); | ||
406 | } | ||
407 | |||
408 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | ||
409 | struct net_device *dev, const u8 *bssid, | ||
410 | const u8 *ie, int ie_len, u16 reason) | ||
411 | { | ||
412 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
413 | struct cfg80211_disassoc_request req; | ||
414 | |||
415 | memset(&req, 0, sizeof(req)); | ||
416 | req.reason_code = reason; | ||
417 | req.ie = ie; | ||
418 | req.ie_len = ie_len; | ||
419 | if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) | ||
420 | req.bss = &wdev->current_bss->pub; | ||
421 | else | ||
422 | return -ENOTCONN; | ||
423 | |||
424 | return rdev->ops->disassoc(&rdev->wiphy, dev, &req); | ||
425 | } | ||
426 | |||
427 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | ||
428 | struct net_device *dev) | ||
429 | { | ||
430 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
431 | struct cfg80211_deauth_request req; | ||
432 | int i; | ||
433 | |||
434 | if (!rdev->ops->deauth) | ||
435 | return; | ||
436 | |||
437 | memset(&req, 0, sizeof(req)); | ||
438 | req.reason_code = WLAN_REASON_DEAUTH_LEAVING; | ||
439 | req.ie = NULL; | ||
440 | req.ie_len = 0; | ||
441 | |||
442 | if (wdev->current_bss) { | ||
443 | req.bss = &wdev->current_bss->pub; | ||
444 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | ||
445 | if (wdev->current_bss) { | ||
446 | cfg80211_unhold_bss(wdev->current_bss); | ||
447 | cfg80211_put_bss(&wdev->current_bss->pub); | ||
448 | wdev->current_bss = NULL; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
453 | if (wdev->auth_bsses[i]) { | ||
454 | req.bss = &wdev->auth_bsses[i]->pub; | ||
455 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | ||
456 | if (wdev->auth_bsses[i]) { | ||
457 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | ||
458 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | ||
459 | wdev->auth_bsses[i] = NULL; | ||
460 | } | ||
461 | } | ||
462 | if (wdev->authtry_bsses[i]) { | ||
463 | req.bss = &wdev->authtry_bsses[i]->pub; | ||
464 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | ||
465 | if (wdev->authtry_bsses[i]) { | ||
466 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); | ||
467 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); | ||
468 | wdev->authtry_bsses[i] = NULL; | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | } | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0008144b354b..aa2b3f35cc48 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3044,9 +3044,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3044 | { | 3044 | { |
3045 | struct cfg80211_registered_device *drv; | 3045 | struct cfg80211_registered_device *drv; |
3046 | struct net_device *dev; | 3046 | struct net_device *dev; |
3047 | struct cfg80211_auth_request req; | 3047 | struct ieee80211_channel *chan; |
3048 | struct wiphy *wiphy; | 3048 | const u8 *bssid, *ssid, *ie = NULL; |
3049 | int err; | 3049 | int err, ssid_len, ie_len = 0; |
3050 | enum nl80211_auth_type auth_type; | ||
3050 | 3051 | ||
3051 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3052 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3052 | return -EINVAL; | 3053 | return -EINVAL; |
@@ -3057,6 +3058,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3057 | if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) | 3058 | if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) |
3058 | return -EINVAL; | 3059 | return -EINVAL; |
3059 | 3060 | ||
3061 | if (!info->attrs[NL80211_ATTR_SSID]) | ||
3062 | return -EINVAL; | ||
3063 | |||
3064 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | ||
3065 | return -EINVAL; | ||
3066 | |||
3060 | rtnl_lock(); | 3067 | rtnl_lock(); |
3061 | 3068 | ||
3062 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3069 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -3078,38 +3085,30 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3078 | goto out; | 3085 | goto out; |
3079 | } | 3086 | } |
3080 | 3087 | ||
3081 | wiphy = &drv->wiphy; | 3088 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3082 | memset(&req, 0, sizeof(req)); | 3089 | chan = ieee80211_get_channel(&drv->wiphy, |
3083 | 3090 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | |
3084 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3091 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { |
3085 | 3092 | err = -EINVAL; | |
3086 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 3093 | goto out; |
3087 | req.chan = ieee80211_get_channel( | ||
3088 | wiphy, | ||
3089 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
3090 | if (!req.chan) { | ||
3091 | err = -EINVAL; | ||
3092 | goto out; | ||
3093 | } | ||
3094 | } | 3094 | } |
3095 | 3095 | ||
3096 | if (info->attrs[NL80211_ATTR_SSID]) { | 3096 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3097 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3097 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3098 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
3099 | } | ||
3100 | 3098 | ||
3101 | if (info->attrs[NL80211_ATTR_IE]) { | 3099 | if (info->attrs[NL80211_ATTR_IE]) { |
3102 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3100 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3103 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3101 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3104 | } | 3102 | } |
3105 | 3103 | ||
3106 | req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 3104 | auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
3107 | if (!nl80211_valid_auth_type(req.auth_type)) { | 3105 | if (!nl80211_valid_auth_type(auth_type)) { |
3108 | err = -EINVAL; | 3106 | err = -EINVAL; |
3109 | goto out; | 3107 | goto out; |
3110 | } | 3108 | } |
3111 | 3109 | ||
3112 | err = drv->ops->auth(&drv->wiphy, dev, &req); | 3110 | err = cfg80211_mlme_auth(drv, dev, chan, auth_type, bssid, |
3111 | ssid, ssid_len, ie, ie_len); | ||
3113 | 3112 | ||
3114 | out: | 3113 | out: |
3115 | cfg80211_put_dev(drv); | 3114 | cfg80211_put_dev(drv); |
@@ -3183,26 +3182,29 @@ static int nl80211_crypto_settings(struct genl_info *info, | |||
3183 | 3182 | ||
3184 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3183 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) |
3185 | { | 3184 | { |
3186 | struct cfg80211_registered_device *drv; | 3185 | struct cfg80211_registered_device *rdev; |
3187 | struct net_device *dev; | 3186 | struct net_device *dev; |
3188 | struct cfg80211_assoc_request req; | 3187 | struct cfg80211_crypto_settings crypto; |
3189 | struct wiphy *wiphy; | 3188 | struct ieee80211_channel *chan; |
3190 | int err; | 3189 | const u8 *bssid, *ssid, *ie = NULL; |
3190 | int err, ssid_len, ie_len = 0; | ||
3191 | bool use_mfp = false; | ||
3191 | 3192 | ||
3192 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3193 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3193 | return -EINVAL; | 3194 | return -EINVAL; |
3194 | 3195 | ||
3195 | if (!info->attrs[NL80211_ATTR_MAC] || | 3196 | if (!info->attrs[NL80211_ATTR_MAC] || |
3196 | !info->attrs[NL80211_ATTR_SSID]) | 3197 | !info->attrs[NL80211_ATTR_SSID] || |
3198 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | ||
3197 | return -EINVAL; | 3199 | return -EINVAL; |
3198 | 3200 | ||
3199 | rtnl_lock(); | 3201 | rtnl_lock(); |
3200 | 3202 | ||
3201 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3203 | err = get_drv_dev_by_info_ifindex(info->attrs, &rdev, &dev); |
3202 | if (err) | 3204 | if (err) |
3203 | goto unlock_rtnl; | 3205 | goto unlock_rtnl; |
3204 | 3206 | ||
3205 | if (!drv->ops->assoc) { | 3207 | if (!rdev->ops->assoc) { |
3206 | err = -EOPNOTSUPP; | 3208 | err = -EOPNOTSUPP; |
3207 | goto out; | 3209 | goto out; |
3208 | } | 3210 | } |
@@ -3217,46 +3219,42 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3217 | goto out; | 3219 | goto out; |
3218 | } | 3220 | } |
3219 | 3221 | ||
3220 | wiphy = &drv->wiphy; | 3222 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3221 | memset(&req, 0, sizeof(req)); | ||
3222 | |||
3223 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3224 | 3223 | ||
3225 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 3224 | chan = ieee80211_get_channel(&rdev->wiphy, |
3226 | req.chan = ieee80211_get_channel( | 3225 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); |
3227 | wiphy, | 3226 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { |
3228 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 3227 | err = -EINVAL; |
3229 | if (!req.chan) { | 3228 | goto out; |
3230 | err = -EINVAL; | ||
3231 | goto out; | ||
3232 | } | ||
3233 | } | 3229 | } |
3234 | 3230 | ||
3235 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3231 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3236 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3232 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3237 | 3233 | ||
3238 | if (info->attrs[NL80211_ATTR_IE]) { | 3234 | if (info->attrs[NL80211_ATTR_IE]) { |
3239 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3235 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3240 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3236 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3241 | } | 3237 | } |
3242 | 3238 | ||
3243 | if (info->attrs[NL80211_ATTR_USE_MFP]) { | 3239 | if (info->attrs[NL80211_ATTR_USE_MFP]) { |
3244 | enum nl80211_mfp use_mfp = | 3240 | enum nl80211_mfp use_mfp = |
3245 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 3241 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
3246 | if (use_mfp == NL80211_MFP_REQUIRED) | 3242 | if (use_mfp == NL80211_MFP_REQUIRED) |
3247 | req.use_mfp = true; | 3243 | use_mfp = true; |
3248 | else if (use_mfp != NL80211_MFP_NO) { | 3244 | else if (use_mfp != NL80211_MFP_NO) { |
3249 | err = -EINVAL; | 3245 | err = -EINVAL; |
3250 | goto out; | 3246 | goto out; |
3251 | } | 3247 | } |
3252 | } | 3248 | } |
3253 | 3249 | ||
3254 | err = nl80211_crypto_settings(info, &req.crypto); | 3250 | err = nl80211_crypto_settings(info, &crypto); |
3255 | if (!err) | 3251 | if (!err) |
3256 | err = drv->ops->assoc(&drv->wiphy, dev, &req); | 3252 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid, |
3253 | ssid_len, ie, ie_len, use_mfp, | ||
3254 | &crypto); | ||
3257 | 3255 | ||
3258 | out: | 3256 | out: |
3259 | cfg80211_put_dev(drv); | 3257 | cfg80211_put_dev(rdev); |
3260 | dev_put(dev); | 3258 | dev_put(dev); |
3261 | unlock_rtnl: | 3259 | unlock_rtnl: |
3262 | rtnl_unlock(); | 3260 | rtnl_unlock(); |
@@ -3267,9 +3265,9 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3267 | { | 3265 | { |
3268 | struct cfg80211_registered_device *drv; | 3266 | struct cfg80211_registered_device *drv; |
3269 | struct net_device *dev; | 3267 | struct net_device *dev; |
3270 | struct cfg80211_deauth_request req; | 3268 | const u8 *ie = NULL, *bssid; |
3271 | struct wiphy *wiphy; | 3269 | int err, ie_len = 0; |
3272 | int err; | 3270 | u16 reason_code; |
3273 | 3271 | ||
3274 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3272 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3275 | return -EINVAL; | 3273 | return -EINVAL; |
@@ -3301,24 +3299,21 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
3301 | goto out; | 3299 | goto out; |
3302 | } | 3300 | } |
3303 | 3301 | ||
3304 | wiphy = &drv->wiphy; | 3302 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3305 | memset(&req, 0, sizeof(req)); | ||
3306 | |||
3307 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3308 | 3303 | ||
3309 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3304 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3310 | if (req.reason_code == 0) { | 3305 | if (reason_code == 0) { |
3311 | /* Reason Code 0 is reserved */ | 3306 | /* Reason Code 0 is reserved */ |
3312 | err = -EINVAL; | 3307 | err = -EINVAL; |
3313 | goto out; | 3308 | goto out; |
3314 | } | 3309 | } |
3315 | 3310 | ||
3316 | if (info->attrs[NL80211_ATTR_IE]) { | 3311 | if (info->attrs[NL80211_ATTR_IE]) { |
3317 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3312 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3318 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3313 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3319 | } | 3314 | } |
3320 | 3315 | ||
3321 | err = drv->ops->deauth(&drv->wiphy, dev, &req); | 3316 | err = cfg80211_mlme_deauth(drv, dev, bssid, ie, ie_len, reason_code); |
3322 | 3317 | ||
3323 | out: | 3318 | out: |
3324 | cfg80211_put_dev(drv); | 3319 | cfg80211_put_dev(drv); |
@@ -3332,9 +3327,9 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3332 | { | 3327 | { |
3333 | struct cfg80211_registered_device *drv; | 3328 | struct cfg80211_registered_device *drv; |
3334 | struct net_device *dev; | 3329 | struct net_device *dev; |
3335 | struct cfg80211_disassoc_request req; | 3330 | const u8 *ie = NULL, *bssid; |
3336 | struct wiphy *wiphy; | 3331 | int err, ie_len = 0; |
3337 | int err; | 3332 | u16 reason_code; |
3338 | 3333 | ||
3339 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3334 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3340 | return -EINVAL; | 3335 | return -EINVAL; |
@@ -3366,24 +3361,21 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3366 | goto out; | 3361 | goto out; |
3367 | } | 3362 | } |
3368 | 3363 | ||
3369 | wiphy = &drv->wiphy; | 3364 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
3370 | memset(&req, 0, sizeof(req)); | ||
3371 | |||
3372 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3373 | 3365 | ||
3374 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3366 | reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
3375 | if (req.reason_code == 0) { | 3367 | if (reason_code == 0) { |
3376 | /* Reason Code 0 is reserved */ | 3368 | /* Reason Code 0 is reserved */ |
3377 | err = -EINVAL; | 3369 | err = -EINVAL; |
3378 | goto out; | 3370 | goto out; |
3379 | } | 3371 | } |
3380 | 3372 | ||
3381 | if (info->attrs[NL80211_ATTR_IE]) { | 3373 | if (info->attrs[NL80211_ATTR_IE]) { |
3382 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 3374 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
3383 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3375 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
3384 | } | 3376 | } |
3385 | 3377 | ||
3386 | err = drv->ops->disassoc(&drv->wiphy, dev, &req); | 3378 | err = cfg80211_mlme_disassoc(drv, dev, bssid, ie, ie_len, reason_code); |
3387 | 3379 | ||
3388 | out: | 3380 | out: |
3389 | cfg80211_put_dev(drv); | 3381 | cfg80211_put_dev(drv); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 82b33e708488..925399462a79 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -70,6 +70,8 @@ static void bss_release(struct kref *ref) | |||
70 | if (bss->ies_allocated) | 70 | if (bss->ies_allocated) |
71 | kfree(bss->pub.information_elements); | 71 | kfree(bss->pub.information_elements); |
72 | 72 | ||
73 | BUG_ON(atomic_read(&bss->hold)); | ||
74 | |||
73 | kfree(bss); | 75 | kfree(bss); |
74 | } | 76 | } |
75 | 77 | ||
@@ -92,8 +94,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | |||
92 | bool expired = false; | 94 | bool expired = false; |
93 | 95 | ||
94 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { | 96 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { |
95 | if (bss->hold || | 97 | if (atomic_read(&bss->hold)) |
96 | !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) | 98 | continue; |
99 | if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
97 | continue; | 100 | continue; |
98 | list_del(&bss->list); | 101 | list_del(&bss->list); |
99 | rb_erase(&bss->rbn, &dev->bss_tree); | 102 | rb_erase(&bss->rbn, &dev->bss_tree); |
@@ -553,30 +556,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
553 | } | 556 | } |
554 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 557 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
555 | 558 | ||
556 | void cfg80211_hold_bss(struct cfg80211_bss *pub) | ||
557 | { | ||
558 | struct cfg80211_internal_bss *bss; | ||
559 | |||
560 | if (!pub) | ||
561 | return; | ||
562 | |||
563 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | ||
564 | bss->hold = true; | ||
565 | } | ||
566 | EXPORT_SYMBOL(cfg80211_hold_bss); | ||
567 | |||
568 | void cfg80211_unhold_bss(struct cfg80211_bss *pub) | ||
569 | { | ||
570 | struct cfg80211_internal_bss *bss; | ||
571 | |||
572 | if (!pub) | ||
573 | return; | ||
574 | |||
575 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | ||
576 | bss->hold = false; | ||
577 | } | ||
578 | EXPORT_SYMBOL(cfg80211_unhold_bss); | ||
579 | |||
580 | #ifdef CONFIG_WIRELESS_EXT | 559 | #ifdef CONFIG_WIRELESS_EXT |
581 | int cfg80211_wext_siwscan(struct net_device *dev, | 560 | int cfg80211_wext_siwscan(struct net_device *dev, |
582 | struct iw_request_info *info, | 561 | struct iw_request_info *info, |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index d4e0b4065cbc..412161f7b08e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -103,44 +103,37 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
103 | static int cfg80211_conn_do_work(struct wireless_dev *wdev) | 103 | static int cfg80211_conn_do_work(struct wireless_dev *wdev) |
104 | { | 104 | { |
105 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); | 105 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); |
106 | union { | 106 | struct cfg80211_connect_params *params; |
107 | struct cfg80211_auth_request auth_req; | 107 | int err; |
108 | struct cfg80211_assoc_request assoc_req; | ||
109 | } u; | ||
110 | |||
111 | memset(&u, 0, sizeof(u)); | ||
112 | 108 | ||
113 | if (!wdev->conn) | 109 | if (!wdev->conn) |
114 | return 0; | 110 | return 0; |
115 | 111 | ||
112 | params = &wdev->conn->params; | ||
113 | |||
116 | switch (wdev->conn->state) { | 114 | switch (wdev->conn->state) { |
117 | case CFG80211_CONN_SCAN_AGAIN: | 115 | case CFG80211_CONN_SCAN_AGAIN: |
118 | return cfg80211_conn_scan(wdev); | 116 | return cfg80211_conn_scan(wdev); |
119 | case CFG80211_CONN_AUTHENTICATE_NEXT: | 117 | case CFG80211_CONN_AUTHENTICATE_NEXT: |
120 | u.auth_req.chan = wdev->conn->params.channel; | ||
121 | u.auth_req.peer_addr = wdev->conn->params.bssid; | ||
122 | u.auth_req.ssid = wdev->conn->params.ssid; | ||
123 | u.auth_req.ssid_len = wdev->conn->params.ssid_len; | ||
124 | u.auth_req.auth_type = wdev->conn->params.auth_type; | ||
125 | u.auth_req.ie = NULL; | ||
126 | u.auth_req.ie_len = 0; | ||
127 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; | ||
128 | BUG_ON(!drv->ops->auth); | 118 | BUG_ON(!drv->ops->auth); |
129 | return drv->ops->auth(wdev->wiphy, wdev->netdev, &u.auth_req); | 119 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; |
120 | return cfg80211_mlme_auth(drv, wdev->netdev, | ||
121 | params->channel, params->auth_type, | ||
122 | params->bssid, | ||
123 | params->ssid, params->ssid_len, | ||
124 | NULL, 0); | ||
130 | case CFG80211_CONN_ASSOCIATE_NEXT: | 125 | case CFG80211_CONN_ASSOCIATE_NEXT: |
131 | u.assoc_req.chan = wdev->conn->params.channel; | ||
132 | u.assoc_req.peer_addr = wdev->conn->params.bssid; | ||
133 | u.assoc_req.ssid = wdev->conn->params.ssid; | ||
134 | u.assoc_req.ssid_len = wdev->conn->params.ssid_len; | ||
135 | u.assoc_req.ie = wdev->conn->params.ie; | ||
136 | u.assoc_req.ie_len = wdev->conn->params.ie_len; | ||
137 | u.assoc_req.use_mfp = false; | ||
138 | memcpy(&u.assoc_req.crypto, &wdev->conn->params.crypto, | ||
139 | sizeof(u.assoc_req.crypto)); | ||
140 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | ||
141 | BUG_ON(!drv->ops->assoc); | 126 | BUG_ON(!drv->ops->assoc); |
142 | return drv->ops->assoc(wdev->wiphy, wdev->netdev, | 127 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
143 | &u.assoc_req); | 128 | err = cfg80211_mlme_assoc(drv, wdev->netdev, |
129 | params->channel, params->bssid, | ||
130 | params->ssid, params->ssid_len, | ||
131 | params->ie, params->ie_len, | ||
132 | false, ¶ms->crypto); | ||
133 | if (err) | ||
134 | cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, | ||
135 | NULL, 0, WLAN_REASON_DEAUTH_LEAVING); | ||
136 | return err; | ||
144 | default: | 137 | default: |
145 | return 0; | 138 | return 0; |
146 | } | 139 | } |
@@ -186,7 +179,6 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
186 | wdev->conn->params.ssid_len, | 179 | wdev->conn->params.ssid_len, |
187 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, | 180 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, |
188 | capa); | 181 | capa); |
189 | |||
190 | if (!bss) | 182 | if (!bss) |
191 | return false; | 183 | return false; |
192 | 184 | ||
@@ -264,9 +256,11 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
264 | } | 256 | } |
265 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 257 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
266 | schedule_work(&rdev->conn_work); | 258 | schedule_work(&rdev->conn_work); |
267 | } else if (status_code != WLAN_STATUS_SUCCESS) | 259 | } else if (status_code != WLAN_STATUS_SUCCESS) { |
268 | wdev->sme_state = CFG80211_SME_IDLE; | 260 | wdev->sme_state = CFG80211_SME_IDLE; |
269 | else if (wdev->sme_state == CFG80211_SME_CONNECTING && | 261 | kfree(wdev->conn); |
262 | wdev->conn = NULL; | ||
263 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING && | ||
270 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { | 264 | wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { |
271 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | 265 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; |
272 | schedule_work(&rdev->conn_work); | 266 | schedule_work(&rdev->conn_work); |
@@ -330,10 +324,13 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
330 | 324 | ||
331 | if (wdev->current_bss) { | 325 | if (wdev->current_bss) { |
332 | cfg80211_unhold_bss(wdev->current_bss); | 326 | cfg80211_unhold_bss(wdev->current_bss); |
333 | cfg80211_put_bss(wdev->current_bss); | 327 | cfg80211_put_bss(&wdev->current_bss->pub); |
334 | wdev->current_bss = NULL; | 328 | wdev->current_bss = NULL; |
335 | } | 329 | } |
336 | 330 | ||
331 | if (wdev->conn) | ||
332 | wdev->conn->state = CFG80211_CONN_IDLE; | ||
333 | |||
337 | if (status == WLAN_STATUS_SUCCESS) { | 334 | if (status == WLAN_STATUS_SUCCESS) { |
338 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 335 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
339 | wdev->ssid, wdev->ssid_len, | 336 | wdev->ssid, wdev->ssid_len, |
@@ -343,16 +340,15 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
343 | if (WARN_ON(!bss)) | 340 | if (WARN_ON(!bss)) |
344 | return; | 341 | return; |
345 | 342 | ||
346 | cfg80211_hold_bss(bss); | 343 | cfg80211_hold_bss(bss_from_pub(bss)); |
347 | wdev->current_bss = bss; | 344 | wdev->current_bss = bss_from_pub(bss); |
348 | 345 | ||
349 | wdev->sme_state = CFG80211_SME_CONNECTED; | 346 | wdev->sme_state = CFG80211_SME_CONNECTED; |
350 | } else { | 347 | } else { |
351 | wdev->sme_state = CFG80211_SME_IDLE; | 348 | wdev->sme_state = CFG80211_SME_IDLE; |
349 | kfree(wdev->conn); | ||
350 | wdev->conn = NULL; | ||
352 | } | 351 | } |
353 | |||
354 | if (wdev->conn) | ||
355 | wdev->conn->state = CFG80211_CONN_IDLE; | ||
356 | } | 352 | } |
357 | 353 | ||
358 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 354 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
@@ -387,7 +383,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | |||
387 | } | 383 | } |
388 | 384 | ||
389 | cfg80211_unhold_bss(wdev->current_bss); | 385 | cfg80211_unhold_bss(wdev->current_bss); |
390 | cfg80211_put_bss(wdev->current_bss); | 386 | cfg80211_put_bss(&wdev->current_bss->pub); |
391 | wdev->current_bss = NULL; | 387 | wdev->current_bss = NULL; |
392 | 388 | ||
393 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 389 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
@@ -397,8 +393,8 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | |||
397 | if (WARN_ON(!bss)) | 393 | if (WARN_ON(!bss)) |
398 | return; | 394 | return; |
399 | 395 | ||
400 | cfg80211_hold_bss(bss); | 396 | cfg80211_hold_bss(bss_from_pub(bss)); |
401 | wdev->current_bss = bss; | 397 | wdev->current_bss = bss_from_pub(bss); |
402 | 398 | ||
403 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, | 399 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, |
404 | req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); | 400 | req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); |
@@ -440,7 +436,7 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
440 | 436 | ||
441 | if (wdev->current_bss) { | 437 | if (wdev->current_bss) { |
442 | cfg80211_unhold_bss(wdev->current_bss); | 438 | cfg80211_unhold_bss(wdev->current_bss); |
443 | cfg80211_put_bss(wdev->current_bss); | 439 | cfg80211_put_bss(&wdev->current_bss->pub); |
444 | } | 440 | } |
445 | 441 | ||
446 | wdev->current_bss = NULL; | 442 | wdev->current_bss = NULL; |
@@ -449,6 +445,8 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
449 | if (wdev->conn) { | 445 | if (wdev->conn) { |
450 | kfree(wdev->conn->ie); | 446 | kfree(wdev->conn->ie); |
451 | wdev->conn->ie = NULL; | 447 | wdev->conn->ie = NULL; |
448 | kfree(wdev->conn); | ||
449 | wdev->conn = NULL; | ||
452 | } | 450 | } |
453 | 451 | ||
454 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, | 452 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, |
@@ -482,12 +480,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
482 | if (!rdev->ops->auth || !rdev->ops->assoc) | 480 | if (!rdev->ops->auth || !rdev->ops->assoc) |
483 | return -EOPNOTSUPP; | 481 | return -EOPNOTSUPP; |
484 | 482 | ||
485 | if (!wdev->conn) { | 483 | if (WARN_ON(wdev->conn)) |
486 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); | 484 | return -EINPROGRESS; |
487 | if (!wdev->conn) | 485 | |
488 | return -ENOMEM; | 486 | wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); |
489 | } else | 487 | if (!wdev->conn) |
490 | memset(wdev->conn, 0, sizeof(*wdev->conn)); | 488 | return -ENOMEM; |
491 | 489 | ||
492 | /* | 490 | /* |
493 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. | 491 | * Copy all parameters, and treat explicitly IEs, BSSID, SSID. |
@@ -502,8 +500,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
502 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, | 500 | wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, |
503 | GFP_KERNEL); | 501 | GFP_KERNEL); |
504 | wdev->conn->params.ie = wdev->conn->ie; | 502 | wdev->conn->params.ie = wdev->conn->ie; |
505 | if (!wdev->conn->ie) | 503 | if (!wdev->conn->ie) { |
504 | kfree(wdev->conn); | ||
505 | wdev->conn = NULL; | ||
506 | return -ENOMEM; | 506 | return -ENOMEM; |
507 | } | ||
507 | } | 508 | } |
508 | 509 | ||
509 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { | 510 | if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { |
@@ -543,8 +544,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
543 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; | 544 | wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; |
544 | } | 545 | } |
545 | } | 546 | } |
546 | if (err) | 547 | if (err) { |
548 | kfree(wdev->conn); | ||
549 | wdev->conn = NULL; | ||
547 | wdev->sme_state = CFG80211_SME_IDLE; | 550 | wdev->sme_state = CFG80211_SME_IDLE; |
551 | } | ||
548 | 552 | ||
549 | return err; | 553 | return err; |
550 | } else { | 554 | } else { |
@@ -572,31 +576,27 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
572 | return -EINVAL; | 576 | return -EINVAL; |
573 | 577 | ||
574 | if (!rdev->ops->disconnect) { | 578 | if (!rdev->ops->disconnect) { |
575 | struct cfg80211_deauth_request deauth; | 579 | if (!rdev->ops->deauth) |
576 | u8 bssid[ETH_ALEN]; | 580 | return -EOPNOTSUPP; |
577 | 581 | ||
578 | /* internal bug. */ | 582 | /* was it connected by userspace SME? */ |
579 | if (WARN_ON(!wdev->conn)) | 583 | if (!wdev->conn) { |
580 | return -EINVAL; | 584 | cfg80211_mlme_down(rdev, dev); |
585 | return 0; | ||
586 | } | ||
581 | 587 | ||
582 | if (wdev->sme_state == CFG80211_SME_CONNECTING && | 588 | if (wdev->sme_state == CFG80211_SME_CONNECTING && |
583 | (wdev->conn->state == CFG80211_CONN_SCANNING || | 589 | (wdev->conn->state == CFG80211_CONN_SCANNING || |
584 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { | 590 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { |
585 | wdev->sme_state = CFG80211_SME_IDLE; | 591 | wdev->sme_state = CFG80211_SME_IDLE; |
592 | kfree(wdev->conn); | ||
593 | wdev->conn = NULL; | ||
586 | return 0; | 594 | return 0; |
587 | } | 595 | } |
588 | 596 | ||
589 | if (!rdev->ops->deauth) | ||
590 | return -EOPNOTSUPP; | ||
591 | |||
592 | memset(&deauth, 0, sizeof(deauth)); | ||
593 | |||
594 | /* wdev->conn->params.bssid must be set if > SCANNING */ | 597 | /* wdev->conn->params.bssid must be set if > SCANNING */ |
595 | memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); | 598 | err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, |
596 | deauth.peer_addr = bssid; | 599 | NULL, 0, reason); |
597 | deauth.reason_code = reason; | ||
598 | |||
599 | err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth); | ||
600 | if (err) | 600 | if (err) |
601 | return err; | 601 | return err; |
602 | } else { | 602 | } else { |
@@ -614,3 +614,33 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
614 | 614 | ||
615 | return 0; | 615 | return 0; |
616 | } | 616 | } |
617 | |||
618 | void cfg80211_sme_disassoc(struct net_device *dev, int idx) | ||
619 | { | ||
620 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
621 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
622 | u8 bssid[ETH_ALEN]; | ||
623 | |||
624 | if (!wdev->conn) | ||
625 | return; | ||
626 | |||
627 | if (wdev->conn->state == CFG80211_CONN_IDLE) | ||
628 | return; | ||
629 | |||
630 | /* | ||
631 | * Ok, so the association was made by this SME -- we don't | ||
632 | * want it any more so deauthenticate too. | ||
633 | */ | ||
634 | |||
635 | if (!wdev->auth_bsses[idx]) | ||
636 | return; | ||
637 | |||
638 | memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); | ||
639 | if (cfg80211_mlme_deauth(rdev, dev, bssid, | ||
640 | NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { | ||
641 | /* whatever -- assume gone anyway */ | ||
642 | cfg80211_unhold_bss(wdev->auth_bsses[idx]); | ||
643 | cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); | ||
644 | wdev->auth_bsses[idx] = NULL; | ||
645 | } | ||
646 | } | ||
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 3b531d572b69..fe1987acb891 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -93,7 +93,7 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev, | |||
93 | return -EINVAL; | 93 | return -EINVAL; |
94 | 94 | ||
95 | if (wdev->current_bss) | 95 | if (wdev->current_bss) |
96 | chan = wdev->current_bss->channel; | 96 | chan = wdev->current_bss->pub.channel; |
97 | else if (wdev->wext.connect.channel) | 97 | else if (wdev->wext.connect.channel) |
98 | chan = wdev->wext.connect.channel; | 98 | chan = wdev->wext.connect.channel; |
99 | 99 | ||
@@ -244,7 +244,7 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, | |||
244 | ap_addr->sa_family = ARPHRD_ETHER; | 244 | ap_addr->sa_family = ARPHRD_ETHER; |
245 | 245 | ||
246 | if (wdev->current_bss) | 246 | if (wdev->current_bss) |
247 | memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); | 247 | memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); |
248 | else if (wdev->wext.connect.bssid) | 248 | else if (wdev->wext.connect.bssid) |
249 | memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); | 249 | memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); |
250 | else | 250 | else |