2 * cfg80211 wext compat for managed mode.
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
8 #include <linux/etherdevice.h>
9 #include <linux/if_arp.h>
10 #include <net/cfg80211.h>
11 #include "wext-compat.h"
14 int cfg80211_mgd_wext_connect(struct cfg80211_registered_device
*rdev
,
15 struct wireless_dev
*wdev
)
17 struct cfg80211_cached_keys
*ck
= NULL
;
18 const u8
*prev_bssid
= NULL
;
21 ASSERT_RDEV_LOCK(rdev
);
22 ASSERT_WDEV_LOCK(wdev
);
24 if (!netif_running(wdev
->netdev
))
27 wdev
->wext
.connect
.ie
= wdev
->wext
.ie
;
28 wdev
->wext
.connect
.ie_len
= wdev
->wext
.ie_len
;
30 if (wdev
->wext
.keys
) {
31 wdev
->wext
.keys
->def
= wdev
->wext
.default_key
;
32 wdev
->wext
.keys
->defmgmt
= wdev
->wext
.default_mgmt_key
;
33 if (wdev
->wext
.default_key
!= -1)
34 wdev
->wext
.connect
.privacy
= true;
37 if (!wdev
->wext
.connect
.ssid_len
)
40 if (wdev
->wext
.keys
) {
41 ck
= kmemdup(wdev
->wext
.keys
, sizeof(*ck
), GFP_KERNEL
);
44 for (i
= 0; i
< 6; i
++)
45 ck
->params
[i
].key
= ck
->data
[i
];
48 if (wdev
->wext
.prev_bssid_valid
)
49 prev_bssid
= wdev
->wext
.prev_bssid
;
51 err
= __cfg80211_connect(rdev
, wdev
->netdev
,
52 &wdev
->wext
.connect
, ck
, prev_bssid
);
59 int cfg80211_mgd_wext_siwfreq(struct net_device
*dev
,
60 struct iw_request_info
*info
,
61 struct iw_freq
*wextfreq
, char *extra
)
63 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
64 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wdev
->wiphy
);
65 struct ieee80211_channel
*chan
= NULL
;
68 /* call only for station! */
69 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
72 freq
= cfg80211_wext_freq(wdev
->wiphy
, wextfreq
);
77 chan
= ieee80211_get_channel(wdev
->wiphy
, freq
);
80 if (chan
->flags
& IEEE80211_CHAN_DISABLED
)
84 cfg80211_lock_rdev(rdev
);
85 mutex_lock(&rdev
->devlist_mtx
);
88 if (wdev
->sme_state
!= CFG80211_SME_IDLE
) {
91 if (wdev
->wext
.connect
.channel
== chan
) {
96 /* if SSID set, we'll try right again, avoid event */
97 if (wdev
->wext
.connect
.ssid_len
)
99 err
= __cfg80211_disconnect(rdev
, dev
,
100 WLAN_REASON_DEAUTH_LEAVING
, event
);
106 wdev
->wext
.connect
.channel
= chan
;
108 /* SSID is not set, we just want to switch channel */
109 if (chan
&& !wdev
->wext
.connect
.ssid_len
) {
110 err
= rdev_set_freq(rdev
, wdev
, freq
, NL80211_CHAN_NO_HT
);
114 err
= cfg80211_mgd_wext_connect(rdev
, wdev
);
117 mutex_unlock(&rdev
->devlist_mtx
);
118 cfg80211_unlock_rdev(rdev
);
122 int cfg80211_mgd_wext_giwfreq(struct net_device
*dev
,
123 struct iw_request_info
*info
,
124 struct iw_freq
*freq
, char *extra
)
126 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
127 struct ieee80211_channel
*chan
= NULL
;
129 /* call only for station! */
130 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
134 if (wdev
->current_bss
)
135 chan
= wdev
->current_bss
->pub
.channel
;
136 else if (wdev
->wext
.connect
.channel
)
137 chan
= wdev
->wext
.connect
.channel
;
141 freq
->m
= chan
->center_freq
;
146 /* no channel if not joining */
150 int cfg80211_mgd_wext_siwessid(struct net_device
*dev
,
151 struct iw_request_info
*info
,
152 struct iw_point
*data
, char *ssid
)
154 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
155 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wdev
->wiphy
);
156 size_t len
= data
->length
;
159 /* call only for station! */
160 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
166 /* iwconfig uses nul termination in SSID.. */
167 if (len
> 0 && ssid
[len
- 1] == '\0')
170 cfg80211_lock_rdev(rdev
);
171 mutex_lock(&rdev
->devlist_mtx
);
176 if (wdev
->sme_state
!= CFG80211_SME_IDLE
) {
179 if (wdev
->wext
.connect
.ssid
&& len
&&
180 len
== wdev
->wext
.connect
.ssid_len
&&
181 memcmp(wdev
->wext
.connect
.ssid
, ssid
, len
) == 0)
184 /* if SSID set now, we'll try to connect, avoid event */
187 err
= __cfg80211_disconnect(rdev
, dev
,
188 WLAN_REASON_DEAUTH_LEAVING
, event
);
193 wdev
->wext
.prev_bssid_valid
= false;
194 wdev
->wext
.connect
.ssid
= wdev
->wext
.ssid
;
195 memcpy(wdev
->wext
.ssid
, ssid
, len
);
196 wdev
->wext
.connect
.ssid_len
= len
;
198 wdev
->wext
.connect
.crypto
.control_port
= false;
200 err
= cfg80211_mgd_wext_connect(rdev
, wdev
);
203 mutex_unlock(&rdev
->devlist_mtx
);
204 cfg80211_unlock_rdev(rdev
);
208 int cfg80211_mgd_wext_giwessid(struct net_device
*dev
,
209 struct iw_request_info
*info
,
210 struct iw_point
*data
, char *ssid
)
212 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
214 /* call only for station! */
215 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
221 if (wdev
->current_bss
) {
222 const u8
*ie
= ieee80211_bss_get_ie(&wdev
->current_bss
->pub
,
226 data
->length
= ie
[1];
227 memcpy(ssid
, ie
+ 2, data
->length
);
229 } else if (wdev
->wext
.connect
.ssid
&& wdev
->wext
.connect
.ssid_len
) {
231 data
->length
= wdev
->wext
.connect
.ssid_len
;
232 memcpy(ssid
, wdev
->wext
.connect
.ssid
, data
->length
);
239 int cfg80211_mgd_wext_siwap(struct net_device
*dev
,
240 struct iw_request_info
*info
,
241 struct sockaddr
*ap_addr
, char *extra
)
243 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
244 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wdev
->wiphy
);
245 u8
*bssid
= ap_addr
->sa_data
;
248 /* call only for station! */
249 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
252 if (ap_addr
->sa_family
!= ARPHRD_ETHER
)
256 if (is_zero_ether_addr(bssid
) || is_broadcast_ether_addr(bssid
))
259 cfg80211_lock_rdev(rdev
);
260 mutex_lock(&rdev
->devlist_mtx
);
263 if (wdev
->sme_state
!= CFG80211_SME_IDLE
) {
266 if (!bssid
&& !wdev
->wext
.connect
.bssid
)
269 /* fixed already - and no change */
270 if (wdev
->wext
.connect
.bssid
&& bssid
&&
271 compare_ether_addr(bssid
, wdev
->wext
.connect
.bssid
) == 0)
274 err
= __cfg80211_disconnect(rdev
, dev
,
275 WLAN_REASON_DEAUTH_LEAVING
, false);
281 memcpy(wdev
->wext
.bssid
, bssid
, ETH_ALEN
);
282 wdev
->wext
.connect
.bssid
= wdev
->wext
.bssid
;
284 wdev
->wext
.connect
.bssid
= NULL
;
286 err
= cfg80211_mgd_wext_connect(rdev
, wdev
);
289 mutex_unlock(&rdev
->devlist_mtx
);
290 cfg80211_unlock_rdev(rdev
);
294 int cfg80211_mgd_wext_giwap(struct net_device
*dev
,
295 struct iw_request_info
*info
,
296 struct sockaddr
*ap_addr
, char *extra
)
298 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
300 /* call only for station! */
301 if (WARN_ON(wdev
->iftype
!= NL80211_IFTYPE_STATION
))
304 ap_addr
->sa_family
= ARPHRD_ETHER
;
307 if (wdev
->current_bss
)
308 memcpy(ap_addr
->sa_data
, wdev
->current_bss
->pub
.bssid
, ETH_ALEN
);
310 memset(ap_addr
->sa_data
, 0, ETH_ALEN
);
316 int cfg80211_wext_siwgenie(struct net_device
*dev
,
317 struct iw_request_info
*info
,
318 struct iw_point
*data
, char *extra
)
320 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
321 struct cfg80211_registered_device
*rdev
= wiphy_to_dev(wdev
->wiphy
);
323 int ie_len
= data
->length
, err
;
325 if (wdev
->iftype
!= NL80211_IFTYPE_STATION
)
335 if (wdev
->wext
.ie_len
== ie_len
&&
336 memcmp(wdev
->wext
.ie
, ie
, ie_len
) == 0)
340 ie
= kmemdup(extra
, ie_len
, GFP_KERNEL
);
348 kfree(wdev
->wext
.ie
);
350 wdev
->wext
.ie_len
= ie_len
;
352 if (wdev
->sme_state
!= CFG80211_SME_IDLE
) {
353 err
= __cfg80211_disconnect(rdev
, dev
,
354 WLAN_REASON_DEAUTH_LEAVING
, false);
359 /* userspace better not think we'll reconnect */
365 EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie
);
367 int cfg80211_wext_siwmlme(struct net_device
*dev
,
368 struct iw_request_info
*info
,
369 struct iw_point
*data
, char *extra
)
371 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
372 struct iw_mlme
*mlme
= (struct iw_mlme
*)extra
;
373 struct cfg80211_registered_device
*rdev
;
379 rdev
= wiphy_to_dev(wdev
->wiphy
);
381 if (wdev
->iftype
!= NL80211_IFTYPE_STATION
)
384 if (mlme
->addr
.sa_family
!= ARPHRD_ETHER
)
390 case IW_MLME_DISASSOC
:
391 err
= __cfg80211_disconnect(rdev
, dev
, mlme
->reason_code
,
402 EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme
);