xref: /OK3568_Linux_fs/kernel/net/wireless/wext-sme.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * cfg80211 wext compat for managed mode.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
6*4882a593Smuzhiyun  * Copyright (C) 2009   Intel Corporation. All rights reserved.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/export.h>
10*4882a593Smuzhiyun #include <linux/etherdevice.h>
11*4882a593Smuzhiyun #include <linux/if_arp.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <net/cfg80211.h>
14*4882a593Smuzhiyun #include <net/cfg80211-wext.h>
15*4882a593Smuzhiyun #include "wext-compat.h"
16*4882a593Smuzhiyun #include "nl80211.h"
17*4882a593Smuzhiyun 
cfg80211_mgd_wext_connect(struct cfg80211_registered_device * rdev,struct wireless_dev * wdev)18*4882a593Smuzhiyun int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
19*4882a593Smuzhiyun 			      struct wireless_dev *wdev)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	struct cfg80211_cached_keys *ck = NULL;
22*4882a593Smuzhiyun 	const u8 *prev_bssid = NULL;
23*4882a593Smuzhiyun 	int err, i;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	ASSERT_RTNL();
26*4882a593Smuzhiyun 	ASSERT_WDEV_LOCK(wdev);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	if (!netif_running(wdev->netdev))
29*4882a593Smuzhiyun 		return 0;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	wdev->wext.connect.ie = wdev->wext.ie;
32*4882a593Smuzhiyun 	wdev->wext.connect.ie_len = wdev->wext.ie_len;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	/* Use default background scan period */
35*4882a593Smuzhiyun 	wdev->wext.connect.bg_scan_period = -1;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (wdev->wext.keys) {
38*4882a593Smuzhiyun 		wdev->wext.keys->def = wdev->wext.default_key;
39*4882a593Smuzhiyun 		if (wdev->wext.default_key != -1)
40*4882a593Smuzhiyun 			wdev->wext.connect.privacy = true;
41*4882a593Smuzhiyun 	}
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	if (!wdev->wext.connect.ssid_len)
44*4882a593Smuzhiyun 		return 0;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	if (wdev->wext.keys && wdev->wext.keys->def != -1) {
47*4882a593Smuzhiyun 		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
48*4882a593Smuzhiyun 		if (!ck)
49*4882a593Smuzhiyun 			return -ENOMEM;
50*4882a593Smuzhiyun 		for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
51*4882a593Smuzhiyun 			ck->params[i].key = ck->data[i];
52*4882a593Smuzhiyun 	}
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	if (wdev->wext.prev_bssid_valid)
55*4882a593Smuzhiyun 		prev_bssid = wdev->wext.prev_bssid;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	err = cfg80211_connect(rdev, wdev->netdev,
58*4882a593Smuzhiyun 			       &wdev->wext.connect, ck, prev_bssid);
59*4882a593Smuzhiyun 	if (err)
60*4882a593Smuzhiyun 		kfree_sensitive(ck);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return err;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
cfg80211_mgd_wext_siwfreq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * wextfreq,char * extra)65*4882a593Smuzhiyun int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
66*4882a593Smuzhiyun 			      struct iw_request_info *info,
67*4882a593Smuzhiyun 			      struct iw_freq *wextfreq, char *extra)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
70*4882a593Smuzhiyun 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
71*4882a593Smuzhiyun 	struct ieee80211_channel *chan = NULL;
72*4882a593Smuzhiyun 	int err, freq;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	/* call only for station! */
75*4882a593Smuzhiyun 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
76*4882a593Smuzhiyun 		return -EINVAL;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	freq = cfg80211_wext_freq(wextfreq);
79*4882a593Smuzhiyun 	if (freq < 0)
80*4882a593Smuzhiyun 		return freq;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if (freq) {
83*4882a593Smuzhiyun 		chan = ieee80211_get_channel(wdev->wiphy, freq);
84*4882a593Smuzhiyun 		if (!chan)
85*4882a593Smuzhiyun 			return -EINVAL;
86*4882a593Smuzhiyun 		if (chan->flags & IEEE80211_CHAN_DISABLED)
87*4882a593Smuzhiyun 			return -EINVAL;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	wdev_lock(wdev);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (wdev->conn) {
93*4882a593Smuzhiyun 		bool event = true;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 		if (wdev->wext.connect.channel == chan) {
96*4882a593Smuzhiyun 			err = 0;
97*4882a593Smuzhiyun 			goto out;
98*4882a593Smuzhiyun 		}
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 		/* if SSID set, we'll try right again, avoid event */
101*4882a593Smuzhiyun 		if (wdev->wext.connect.ssid_len)
102*4882a593Smuzhiyun 			event = false;
103*4882a593Smuzhiyun 		err = cfg80211_disconnect(rdev, dev,
104*4882a593Smuzhiyun 					  WLAN_REASON_DEAUTH_LEAVING, event);
105*4882a593Smuzhiyun 		if (err)
106*4882a593Smuzhiyun 			goto out;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	wdev->wext.connect.channel = chan;
110*4882a593Smuzhiyun 	err = cfg80211_mgd_wext_connect(rdev, wdev);
111*4882a593Smuzhiyun  out:
112*4882a593Smuzhiyun 	wdev_unlock(wdev);
113*4882a593Smuzhiyun 	return err;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
cfg80211_mgd_wext_giwfreq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * freq,char * extra)116*4882a593Smuzhiyun int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
117*4882a593Smuzhiyun 			      struct iw_request_info *info,
118*4882a593Smuzhiyun 			      struct iw_freq *freq, char *extra)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
121*4882a593Smuzhiyun 	struct ieee80211_channel *chan = NULL;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	/* call only for station! */
124*4882a593Smuzhiyun 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
125*4882a593Smuzhiyun 		return -EINVAL;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	wdev_lock(wdev);
128*4882a593Smuzhiyun 	if (wdev->current_bss)
129*4882a593Smuzhiyun 		chan = wdev->current_bss->pub.channel;
130*4882a593Smuzhiyun 	else if (wdev->wext.connect.channel)
131*4882a593Smuzhiyun 		chan = wdev->wext.connect.channel;
132*4882a593Smuzhiyun 	wdev_unlock(wdev);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	if (chan) {
135*4882a593Smuzhiyun 		freq->m = chan->center_freq;
136*4882a593Smuzhiyun 		freq->e = 6;
137*4882a593Smuzhiyun 		return 0;
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* no channel if not joining */
141*4882a593Smuzhiyun 	return -EINVAL;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
cfg80211_mgd_wext_siwessid(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * ssid)144*4882a593Smuzhiyun int cfg80211_mgd_wext_siwessid(struct net_device *dev,
145*4882a593Smuzhiyun 			       struct iw_request_info *info,
146*4882a593Smuzhiyun 			       struct iw_point *data, char *ssid)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
149*4882a593Smuzhiyun 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
150*4882a593Smuzhiyun 	size_t len = data->length;
151*4882a593Smuzhiyun 	int err;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	/* call only for station! */
154*4882a593Smuzhiyun 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
155*4882a593Smuzhiyun 		return -EINVAL;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (!data->flags)
158*4882a593Smuzhiyun 		len = 0;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* iwconfig uses nul termination in SSID.. */
161*4882a593Smuzhiyun 	if (len > 0 && ssid[len - 1] == '\0')
162*4882a593Smuzhiyun 		len--;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	wdev_lock(wdev);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	err = 0;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	if (wdev->conn) {
169*4882a593Smuzhiyun 		bool event = true;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 		if (wdev->wext.connect.ssid && len &&
172*4882a593Smuzhiyun 		    len == wdev->wext.connect.ssid_len &&
173*4882a593Smuzhiyun 		    memcmp(wdev->wext.connect.ssid, ssid, len) == 0)
174*4882a593Smuzhiyun 			goto out;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		/* if SSID set now, we'll try to connect, avoid event */
177*4882a593Smuzhiyun 		if (len)
178*4882a593Smuzhiyun 			event = false;
179*4882a593Smuzhiyun 		err = cfg80211_disconnect(rdev, dev,
180*4882a593Smuzhiyun 					  WLAN_REASON_DEAUTH_LEAVING, event);
181*4882a593Smuzhiyun 		if (err)
182*4882a593Smuzhiyun 			goto out;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	wdev->wext.prev_bssid_valid = false;
186*4882a593Smuzhiyun 	wdev->wext.connect.ssid = wdev->wext.ssid;
187*4882a593Smuzhiyun 	memcpy(wdev->wext.ssid, ssid, len);
188*4882a593Smuzhiyun 	wdev->wext.connect.ssid_len = len;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	wdev->wext.connect.crypto.control_port = false;
191*4882a593Smuzhiyun 	wdev->wext.connect.crypto.control_port_ethertype =
192*4882a593Smuzhiyun 					cpu_to_be16(ETH_P_PAE);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	err = cfg80211_mgd_wext_connect(rdev, wdev);
195*4882a593Smuzhiyun  out:
196*4882a593Smuzhiyun 	wdev_unlock(wdev);
197*4882a593Smuzhiyun 	return err;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
cfg80211_mgd_wext_giwessid(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * ssid)200*4882a593Smuzhiyun int cfg80211_mgd_wext_giwessid(struct net_device *dev,
201*4882a593Smuzhiyun 			       struct iw_request_info *info,
202*4882a593Smuzhiyun 			       struct iw_point *data, char *ssid)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
205*4882a593Smuzhiyun 	int ret = 0;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	/* call only for station! */
208*4882a593Smuzhiyun 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
209*4882a593Smuzhiyun 		return -EINVAL;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	data->flags = 0;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	wdev_lock(wdev);
214*4882a593Smuzhiyun 	if (wdev->current_bss) {
215*4882a593Smuzhiyun 		const u8 *ie;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 		rcu_read_lock();
218*4882a593Smuzhiyun 		ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
219*4882a593Smuzhiyun 					  WLAN_EID_SSID);
220*4882a593Smuzhiyun 		if (ie) {
221*4882a593Smuzhiyun 			data->flags = 1;
222*4882a593Smuzhiyun 			data->length = ie[1];
223*4882a593Smuzhiyun 			if (data->length > IW_ESSID_MAX_SIZE)
224*4882a593Smuzhiyun 				ret = -EINVAL;
225*4882a593Smuzhiyun 			else
226*4882a593Smuzhiyun 				memcpy(ssid, ie + 2, data->length);
227*4882a593Smuzhiyun 		}
228*4882a593Smuzhiyun 		rcu_read_unlock();
229*4882a593Smuzhiyun 	} else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
230*4882a593Smuzhiyun 		data->flags = 1;
231*4882a593Smuzhiyun 		data->length = wdev->wext.connect.ssid_len;
232*4882a593Smuzhiyun 		memcpy(ssid, wdev->wext.connect.ssid, data->length);
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 	wdev_unlock(wdev);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	return ret;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
cfg80211_mgd_wext_siwap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * ap_addr,char * extra)239*4882a593Smuzhiyun int cfg80211_mgd_wext_siwap(struct net_device *dev,
240*4882a593Smuzhiyun 			    struct iw_request_info *info,
241*4882a593Smuzhiyun 			    struct sockaddr *ap_addr, char *extra)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
244*4882a593Smuzhiyun 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
245*4882a593Smuzhiyun 	u8 *bssid = ap_addr->sa_data;
246*4882a593Smuzhiyun 	int err;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	/* call only for station! */
249*4882a593Smuzhiyun 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
250*4882a593Smuzhiyun 		return -EINVAL;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if (ap_addr->sa_family != ARPHRD_ETHER)
253*4882a593Smuzhiyun 		return -EINVAL;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	/* automatic mode */
256*4882a593Smuzhiyun 	if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
257*4882a593Smuzhiyun 		bssid = NULL;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	wdev_lock(wdev);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (wdev->conn) {
262*4882a593Smuzhiyun 		err = 0;
263*4882a593Smuzhiyun 		/* both automatic */
264*4882a593Smuzhiyun 		if (!bssid && !wdev->wext.connect.bssid)
265*4882a593Smuzhiyun 			goto out;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 		/* fixed already - and no change */
268*4882a593Smuzhiyun 		if (wdev->wext.connect.bssid && bssid &&
269*4882a593Smuzhiyun 		    ether_addr_equal(bssid, wdev->wext.connect.bssid))
270*4882a593Smuzhiyun 			goto out;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 		err = cfg80211_disconnect(rdev, dev,
273*4882a593Smuzhiyun 					  WLAN_REASON_DEAUTH_LEAVING, false);
274*4882a593Smuzhiyun 		if (err)
275*4882a593Smuzhiyun 			goto out;
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	if (bssid) {
279*4882a593Smuzhiyun 		memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
280*4882a593Smuzhiyun 		wdev->wext.connect.bssid = wdev->wext.bssid;
281*4882a593Smuzhiyun 	} else
282*4882a593Smuzhiyun 		wdev->wext.connect.bssid = NULL;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	err = cfg80211_mgd_wext_connect(rdev, wdev);
285*4882a593Smuzhiyun  out:
286*4882a593Smuzhiyun 	wdev_unlock(wdev);
287*4882a593Smuzhiyun 	return err;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
cfg80211_mgd_wext_giwap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * ap_addr,char * extra)290*4882a593Smuzhiyun int cfg80211_mgd_wext_giwap(struct net_device *dev,
291*4882a593Smuzhiyun 			    struct iw_request_info *info,
292*4882a593Smuzhiyun 			    struct sockaddr *ap_addr, char *extra)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	/* call only for station! */
297*4882a593Smuzhiyun 	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
298*4882a593Smuzhiyun 		return -EINVAL;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	ap_addr->sa_family = ARPHRD_ETHER;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	wdev_lock(wdev);
303*4882a593Smuzhiyun 	if (wdev->current_bss)
304*4882a593Smuzhiyun 		memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
305*4882a593Smuzhiyun 	else
306*4882a593Smuzhiyun 		eth_zero_addr(ap_addr->sa_data);
307*4882a593Smuzhiyun 	wdev_unlock(wdev);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	return 0;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
cfg80211_wext_siwgenie(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)312*4882a593Smuzhiyun int cfg80211_wext_siwgenie(struct net_device *dev,
313*4882a593Smuzhiyun 			   struct iw_request_info *info,
314*4882a593Smuzhiyun 			   struct iw_point *data, char *extra)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
317*4882a593Smuzhiyun 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
318*4882a593Smuzhiyun 	u8 *ie = extra;
319*4882a593Smuzhiyun 	int ie_len = data->length, err;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	if (wdev->iftype != NL80211_IFTYPE_STATION)
322*4882a593Smuzhiyun 		return -EOPNOTSUPP;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if (!ie_len)
325*4882a593Smuzhiyun 		ie = NULL;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	wdev_lock(wdev);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	/* no change */
330*4882a593Smuzhiyun 	err = 0;
331*4882a593Smuzhiyun 	if (wdev->wext.ie_len == ie_len &&
332*4882a593Smuzhiyun 	    memcmp(wdev->wext.ie, ie, ie_len) == 0)
333*4882a593Smuzhiyun 		goto out;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (ie_len) {
336*4882a593Smuzhiyun 		ie = kmemdup(extra, ie_len, GFP_KERNEL);
337*4882a593Smuzhiyun 		if (!ie) {
338*4882a593Smuzhiyun 			err = -ENOMEM;
339*4882a593Smuzhiyun 			goto out;
340*4882a593Smuzhiyun 		}
341*4882a593Smuzhiyun 	} else
342*4882a593Smuzhiyun 		ie = NULL;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	kfree(wdev->wext.ie);
345*4882a593Smuzhiyun 	wdev->wext.ie = ie;
346*4882a593Smuzhiyun 	wdev->wext.ie_len = ie_len;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (wdev->conn) {
349*4882a593Smuzhiyun 		err = cfg80211_disconnect(rdev, dev,
350*4882a593Smuzhiyun 					  WLAN_REASON_DEAUTH_LEAVING, false);
351*4882a593Smuzhiyun 		if (err)
352*4882a593Smuzhiyun 			goto out;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	/* userspace better not think we'll reconnect */
356*4882a593Smuzhiyun 	err = 0;
357*4882a593Smuzhiyun  out:
358*4882a593Smuzhiyun 	wdev_unlock(wdev);
359*4882a593Smuzhiyun 	return err;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
cfg80211_wext_siwmlme(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)362*4882a593Smuzhiyun int cfg80211_wext_siwmlme(struct net_device *dev,
363*4882a593Smuzhiyun 			  struct iw_request_info *info,
364*4882a593Smuzhiyun 			  struct iw_point *data, char *extra)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	struct wireless_dev *wdev = dev->ieee80211_ptr;
367*4882a593Smuzhiyun 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
368*4882a593Smuzhiyun 	struct cfg80211_registered_device *rdev;
369*4882a593Smuzhiyun 	int err;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	if (!wdev)
372*4882a593Smuzhiyun 		return -EOPNOTSUPP;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	rdev = wiphy_to_rdev(wdev->wiphy);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	if (wdev->iftype != NL80211_IFTYPE_STATION)
377*4882a593Smuzhiyun 		return -EINVAL;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	if (mlme->addr.sa_family != ARPHRD_ETHER)
380*4882a593Smuzhiyun 		return -EINVAL;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	wdev_lock(wdev);
383*4882a593Smuzhiyun 	switch (mlme->cmd) {
384*4882a593Smuzhiyun 	case IW_MLME_DEAUTH:
385*4882a593Smuzhiyun 	case IW_MLME_DISASSOC:
386*4882a593Smuzhiyun 		err = cfg80211_disconnect(rdev, dev, mlme->reason_code, true);
387*4882a593Smuzhiyun 		break;
388*4882a593Smuzhiyun 	default:
389*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
390*4882a593Smuzhiyun 		break;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 	wdev_unlock(wdev);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	return err;
395*4882a593Smuzhiyun }
396