Blame view

net/wireless/wext-sme.c 8.71 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
f21293549   Johannes Berg   cfg80211: managed...
2
3
4
5
6
7
  /*
   * cfg80211 wext compat for managed mode.
   *
   * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
   * Copyright (C) 2009   Intel Corporation. All rights reserved.
   */
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
8
  #include <linux/export.h>
f21293549   Johannes Berg   cfg80211: managed...
9
10
  #include <linux/etherdevice.h>
  #include <linux/if_arp.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
f21293549   Johannes Berg   cfg80211: managed...
12
  #include <net/cfg80211.h>
262eb9b22   Johannes Berg   cfg80211: split w...
13
  #include <net/cfg80211-wext.h>
0e82ffe3b   Johannes Berg   cfg80211: combine...
14
  #include "wext-compat.h"
f21293549   Johannes Berg   cfg80211: managed...
15
  #include "nl80211.h"
fffd0934b   Johannes Berg   cfg80211: rework ...
16
17
  int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
  			      struct wireless_dev *wdev)
f21293549   Johannes Berg   cfg80211: managed...
18
  {
fffd0934b   Johannes Berg   cfg80211: rework ...
19
  	struct cfg80211_cached_keys *ck = NULL;
f401a6f7e   Johannes Berg   cfg80211: use rea...
20
  	const u8 *prev_bssid = NULL;
fffd0934b   Johannes Berg   cfg80211: rework ...
21
  	int err, i;
f21293549   Johannes Berg   cfg80211: managed...
22

73fb08e24   Zhao, Gang   cfg80211: remove ...
23
  	ASSERT_RTNL();
667503ddc   Johannes Berg   cfg80211: fix loc...
24
  	ASSERT_WDEV_LOCK(wdev);
f21293549   Johannes Berg   cfg80211: managed...
25
26
27
28
29
  	if (!netif_running(wdev->netdev))
  		return 0;
  
  	wdev->wext.connect.ie = wdev->wext.ie;
  	wdev->wext.connect.ie_len = wdev->wext.ie_len;
f21293549   Johannes Berg   cfg80211: managed...
30

4486ea987   Bala Shanmugam   cfg80211: Add bac...
31
32
  	/* Use default background scan period */
  	wdev->wext.connect.bg_scan_period = -1;
fffd0934b   Johannes Berg   cfg80211: rework ...
33
34
  	if (wdev->wext.keys) {
  		wdev->wext.keys->def = wdev->wext.default_key;
4be3bd8cc   Johannes Berg   cfg80211: don't s...
35
36
  		if (wdev->wext.default_key != -1)
  			wdev->wext.connect.privacy = true;
fffd0934b   Johannes Berg   cfg80211: rework ...
37
38
39
40
  	}
  
  	if (!wdev->wext.connect.ssid_len)
  		return 0;
f1c1f17ac   Johannes Berg   cfg80211: allow c...
41
  	if (wdev->wext.keys && wdev->wext.keys->def != -1) {
fffd0934b   Johannes Berg   cfg80211: rework ...
42
43
44
  		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
  		if (!ck)
  			return -ENOMEM;
b8676221f   David Spinadel   cfg80211: Add sup...
45
  		for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
fffd0934b   Johannes Berg   cfg80211: rework ...
46
47
  			ck->params[i].key = ck->data[i];
  	}
f401a6f7e   Johannes Berg   cfg80211: use rea...
48
49
50
  
  	if (wdev->wext.prev_bssid_valid)
  		prev_bssid = wdev->wext.prev_bssid;
83739b03d   Johannes Berg   cfg80211: remove ...
51
52
  	err = cfg80211_connect(rdev, wdev->netdev,
  			       &wdev->wext.connect, ck, prev_bssid);
fffd0934b   Johannes Berg   cfg80211: rework ...
53
  	if (err)
453431a54   Waiman Long   mm, treewide: ren...
54
  		kfree_sensitive(ck);
f21293549   Johannes Berg   cfg80211: managed...
55
56
57
58
59
60
  
  	return err;
  }
  
  int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
  			      struct iw_request_info *info,
59bbb6f75   Johannes Berg   cfg80211: validat...
61
  			      struct iw_freq *wextfreq, char *extra)
f21293549   Johannes Berg   cfg80211: managed...
62
63
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
64
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
59bbb6f75   Johannes Berg   cfg80211: validat...
65
66
  	struct ieee80211_channel *chan = NULL;
  	int err, freq;
f21293549   Johannes Berg   cfg80211: managed...
67
68
69
70
  
  	/* call only for station! */
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
  		return -EINVAL;
96998e3a2   Zhao, Gang   cfg80211: remove ...
71
  	freq = cfg80211_wext_freq(wextfreq);
59bbb6f75   Johannes Berg   cfg80211: validat...
72
73
  	if (freq < 0)
  		return freq;
f21293549   Johannes Berg   cfg80211: managed...
74

59bbb6f75   Johannes Berg   cfg80211: validat...
75
76
77
78
79
80
81
  	if (freq) {
  		chan = ieee80211_get_channel(wdev->wiphy, freq);
  		if (!chan)
  			return -EINVAL;
  		if (chan->flags & IEEE80211_CHAN_DISABLED)
  			return -EINVAL;
  	}
f21293549   Johannes Berg   cfg80211: managed...
82

667503ddc   Johannes Berg   cfg80211: fix loc...
83
  	wdev_lock(wdev);
ceca7b712   Johannes Berg   cfg80211: separat...
84
  	if (wdev->conn) {
f21293549   Johannes Berg   cfg80211: managed...
85
  		bool event = true;
25e83c490   Johannes Berg   cfg80211: don't o...
86
87
88
89
90
  
  		if (wdev->wext.connect.channel == chan) {
  			err = 0;
  			goto out;
  		}
f21293549   Johannes Berg   cfg80211: managed...
91
92
93
  		/* if SSID set, we'll try right again, avoid event */
  		if (wdev->wext.connect.ssid_len)
  			event = false;
83739b03d   Johannes Berg   cfg80211: remove ...
94
95
  		err = cfg80211_disconnect(rdev, dev,
  					  WLAN_REASON_DEAUTH_LEAVING, event);
f21293549   Johannes Berg   cfg80211: managed...
96
  		if (err)
667503ddc   Johannes Berg   cfg80211: fix loc...
97
  			goto out;
f21293549   Johannes Berg   cfg80211: managed...
98
99
100
  	}
  
  	wdev->wext.connect.channel = chan;
59bbb6f75   Johannes Berg   cfg80211: validat...
101
  	err = cfg80211_mgd_wext_connect(rdev, wdev);
667503ddc   Johannes Berg   cfg80211: fix loc...
102
103
   out:
  	wdev_unlock(wdev);
667503ddc   Johannes Berg   cfg80211: fix loc...
104
  	return err;
f21293549   Johannes Berg   cfg80211: managed...
105
  }
f21293549   Johannes Berg   cfg80211: managed...
106
107
108
109
110
111
112
113
114
115
116
  
  int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
  			      struct iw_request_info *info,
  			      struct iw_freq *freq, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  	struct ieee80211_channel *chan = NULL;
  
  	/* call only for station! */
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
  		return -EINVAL;
667503ddc   Johannes Berg   cfg80211: fix loc...
117
  	wdev_lock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
118
  	if (wdev->current_bss)
19957bb39   Johannes Berg   cfg80211: keep tr...
119
  		chan = wdev->current_bss->pub.channel;
f21293549   Johannes Berg   cfg80211: managed...
120
121
  	else if (wdev->wext.connect.channel)
  		chan = wdev->wext.connect.channel;
667503ddc   Johannes Berg   cfg80211: fix loc...
122
  	wdev_unlock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
123
124
125
126
127
128
129
130
131
132
  
  	if (chan) {
  		freq->m = chan->center_freq;
  		freq->e = 6;
  		return 0;
  	}
  
  	/* no channel if not joining */
  	return -EINVAL;
  }
f21293549   Johannes Berg   cfg80211: managed...
133
134
135
136
137
138
  
  int cfg80211_mgd_wext_siwessid(struct net_device *dev,
  			       struct iw_request_info *info,
  			       struct iw_point *data, char *ssid)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
139
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
f21293549   Johannes Berg   cfg80211: managed...
140
141
142
143
144
145
146
147
148
149
150
151
152
  	size_t len = data->length;
  	int err;
  
  	/* call only for station! */
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
  		return -EINVAL;
  
  	if (!data->flags)
  		len = 0;
  
  	/* iwconfig uses nul termination in SSID.. */
  	if (len > 0 && ssid[len - 1] == '\0')
  		len--;
667503ddc   Johannes Berg   cfg80211: fix loc...
153
154
155
  	wdev_lock(wdev);
  
  	err = 0;
ceca7b712   Johannes Berg   cfg80211: separat...
156
  	if (wdev->conn) {
f21293549   Johannes Berg   cfg80211: managed...
157
  		bool event = true;
25e83c490   Johannes Berg   cfg80211: don't o...
158
159
160
161
162
  
  		if (wdev->wext.connect.ssid && len &&
  		    len == wdev->wext.connect.ssid_len &&
  		    memcmp(wdev->wext.connect.ssid, ssid, len) == 0)
  			goto out;
f21293549   Johannes Berg   cfg80211: managed...
163
164
165
  		/* if SSID set now, we'll try to connect, avoid event */
  		if (len)
  			event = false;
83739b03d   Johannes Berg   cfg80211: remove ...
166
167
  		err = cfg80211_disconnect(rdev, dev,
  					  WLAN_REASON_DEAUTH_LEAVING, event);
f21293549   Johannes Berg   cfg80211: managed...
168
  		if (err)
667503ddc   Johannes Berg   cfg80211: fix loc...
169
  			goto out;
f21293549   Johannes Berg   cfg80211: managed...
170
  	}
f401a6f7e   Johannes Berg   cfg80211: use rea...
171
  	wdev->wext.prev_bssid_valid = false;
f21293549   Johannes Berg   cfg80211: managed...
172
173
174
175
176
  	wdev->wext.connect.ssid = wdev->wext.ssid;
  	memcpy(wdev->wext.ssid, ssid, len);
  	wdev->wext.connect.ssid_len = len;
  
  	wdev->wext.connect.crypto.control_port = false;
c0692b8fe   Johannes Berg   cfg80211: allow c...
177
178
  	wdev->wext.connect.crypto.control_port_ethertype =
  					cpu_to_be16(ETH_P_PAE);
f21293549   Johannes Berg   cfg80211: managed...
179

59bbb6f75   Johannes Berg   cfg80211: validat...
180
  	err = cfg80211_mgd_wext_connect(rdev, wdev);
667503ddc   Johannes Berg   cfg80211: fix loc...
181
182
   out:
  	wdev_unlock(wdev);
667503ddc   Johannes Berg   cfg80211: fix loc...
183
  	return err;
f21293549   Johannes Berg   cfg80211: managed...
184
  }
f21293549   Johannes Berg   cfg80211: managed...
185
186
187
188
189
190
  
  int cfg80211_mgd_wext_giwessid(struct net_device *dev,
  			       struct iw_request_info *info,
  			       struct iw_point *data, char *ssid)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
4ac2813cc   Will Deacon   cfg80211: wext: a...
191
  	int ret = 0;
f21293549   Johannes Berg   cfg80211: managed...
192
193
194
195
196
197
  
  	/* call only for station! */
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
  		return -EINVAL;
  
  	data->flags = 0;
667503ddc   Johannes Berg   cfg80211: fix loc...
198
  	wdev_lock(wdev);
a42dd7efd   Zhu Yi   wireless: display...
199
  	if (wdev->current_bss) {
9caf03640   Johannes Berg   cfg80211: fix BSS...
200
201
202
203
204
  		const u8 *ie;
  
  		rcu_read_lock();
  		ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
  					  WLAN_EID_SSID);
a42dd7efd   Zhu Yi   wireless: display...
205
206
207
  		if (ie) {
  			data->flags = 1;
  			data->length = ie[1];
4ac2813cc   Will Deacon   cfg80211: wext: a...
208
209
210
211
  			if (data->length > IW_ESSID_MAX_SIZE)
  				ret = -EINVAL;
  			else
  				memcpy(ssid, ie + 2, data->length);
a42dd7efd   Zhu Yi   wireless: display...
212
  		}
9caf03640   Johannes Berg   cfg80211: fix BSS...
213
  		rcu_read_unlock();
a42dd7efd   Zhu Yi   wireless: display...
214
  	} else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
f21293549   Johannes Berg   cfg80211: managed...
215
216
217
  		data->flags = 1;
  		data->length = wdev->wext.connect.ssid_len;
  		memcpy(ssid, wdev->wext.connect.ssid, data->length);
33de4f9d7   Johannes Berg   cfg80211: wext: d...
218
  	}
667503ddc   Johannes Berg   cfg80211: fix loc...
219
  	wdev_unlock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
220

4ac2813cc   Will Deacon   cfg80211: wext: a...
221
  	return ret;
f21293549   Johannes Berg   cfg80211: managed...
222
  }
f21293549   Johannes Berg   cfg80211: managed...
223
224
225
226
227
228
  
  int cfg80211_mgd_wext_siwap(struct net_device *dev,
  			    struct iw_request_info *info,
  			    struct sockaddr *ap_addr, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
229
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
f21293549   Johannes Berg   cfg80211: managed...
230
231
232
233
234
235
236
237
238
239
240
241
242
  	u8 *bssid = ap_addr->sa_data;
  	int err;
  
  	/* call only for station! */
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
  		return -EINVAL;
  
  	if (ap_addr->sa_family != ARPHRD_ETHER)
  		return -EINVAL;
  
  	/* automatic mode */
  	if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
  		bssid = NULL;
667503ddc   Johannes Berg   cfg80211: fix loc...
243
  	wdev_lock(wdev);
ceca7b712   Johannes Berg   cfg80211: separat...
244
  	if (wdev->conn) {
25e83c490   Johannes Berg   cfg80211: don't o...
245
246
247
248
  		err = 0;
  		/* both automatic */
  		if (!bssid && !wdev->wext.connect.bssid)
  			goto out;
f21293549   Johannes Berg   cfg80211: managed...
249

25e83c490   Johannes Berg   cfg80211: don't o...
250
251
  		/* fixed already - and no change */
  		if (wdev->wext.connect.bssid && bssid &&
ac422d3cc   Joe Perches   wireless: Convert...
252
  		    ether_addr_equal(bssid, wdev->wext.connect.bssid))
25e83c490   Johannes Berg   cfg80211: don't o...
253
  			goto out;
f21293549   Johannes Berg   cfg80211: managed...
254

83739b03d   Johannes Berg   cfg80211: remove ...
255
256
  		err = cfg80211_disconnect(rdev, dev,
  					  WLAN_REASON_DEAUTH_LEAVING, false);
f21293549   Johannes Berg   cfg80211: managed...
257
  		if (err)
667503ddc   Johannes Berg   cfg80211: fix loc...
258
  			goto out;
f21293549   Johannes Berg   cfg80211: managed...
259
260
261
262
263
264
265
  	}
  
  	if (bssid) {
  		memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
  		wdev->wext.connect.bssid = wdev->wext.bssid;
  	} else
  		wdev->wext.connect.bssid = NULL;
59bbb6f75   Johannes Berg   cfg80211: validat...
266
  	err = cfg80211_mgd_wext_connect(rdev, wdev);
667503ddc   Johannes Berg   cfg80211: fix loc...
267
268
   out:
  	wdev_unlock(wdev);
667503ddc   Johannes Berg   cfg80211: fix loc...
269
  	return err;
f21293549   Johannes Berg   cfg80211: managed...
270
  }
f21293549   Johannes Berg   cfg80211: managed...
271
272
273
274
275
276
277
278
279
280
281
282
  
  int cfg80211_mgd_wext_giwap(struct net_device *dev,
  			    struct iw_request_info *info,
  			    struct sockaddr *ap_addr, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	/* call only for station! */
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
  		return -EINVAL;
  
  	ap_addr->sa_family = ARPHRD_ETHER;
667503ddc   Johannes Berg   cfg80211: fix loc...
283
  	wdev_lock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
284
  	if (wdev->current_bss)
19957bb39   Johannes Berg   cfg80211: keep tr...
285
  		memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
f21293549   Johannes Berg   cfg80211: managed...
286
  	else
d2beae107   Joe Perches   wireless: Use eth...
287
  		eth_zero_addr(ap_addr->sa_data);
667503ddc   Johannes Berg   cfg80211: fix loc...
288
  	wdev_unlock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
289
290
291
  
  	return 0;
  }
f21293549   Johannes Berg   cfg80211: managed...
292
293
294
295
296
297
  
  int cfg80211_wext_siwgenie(struct net_device *dev,
  			   struct iw_request_info *info,
  			   struct iw_point *data, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
298
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
f21293549   Johannes Berg   cfg80211: managed...
299
300
301
302
303
304
305
306
  	u8 *ie = extra;
  	int ie_len = data->length, err;
  
  	if (wdev->iftype != NL80211_IFTYPE_STATION)
  		return -EOPNOTSUPP;
  
  	if (!ie_len)
  		ie = NULL;
667503ddc   Johannes Berg   cfg80211: fix loc...
307
  	wdev_lock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
308
  	/* no change */
667503ddc   Johannes Berg   cfg80211: fix loc...
309
  	err = 0;
f21293549   Johannes Berg   cfg80211: managed...
310
311
  	if (wdev->wext.ie_len == ie_len &&
  	    memcmp(wdev->wext.ie, ie, ie_len) == 0)
667503ddc   Johannes Berg   cfg80211: fix loc...
312
  		goto out;
f21293549   Johannes Berg   cfg80211: managed...
313
314
315
  
  	if (ie_len) {
  		ie = kmemdup(extra, ie_len, GFP_KERNEL);
667503ddc   Johannes Berg   cfg80211: fix loc...
316
317
318
319
  		if (!ie) {
  			err = -ENOMEM;
  			goto out;
  		}
f21293549   Johannes Berg   cfg80211: managed...
320
321
322
323
324
325
  	} else
  		ie = NULL;
  
  	kfree(wdev->wext.ie);
  	wdev->wext.ie = ie;
  	wdev->wext.ie_len = ie_len;
ceca7b712   Johannes Berg   cfg80211: separat...
326
  	if (wdev->conn) {
83739b03d   Johannes Berg   cfg80211: remove ...
327
328
  		err = cfg80211_disconnect(rdev, dev,
  					  WLAN_REASON_DEAUTH_LEAVING, false);
f21293549   Johannes Berg   cfg80211: managed...
329
  		if (err)
667503ddc   Johannes Berg   cfg80211: fix loc...
330
  			goto out;
f21293549   Johannes Berg   cfg80211: managed...
331
332
333
  	}
  
  	/* userspace better not think we'll reconnect */
667503ddc   Johannes Berg   cfg80211: fix loc...
334
335
336
337
  	err = 0;
   out:
  	wdev_unlock(wdev);
  	return err;
f21293549   Johannes Berg   cfg80211: managed...
338
  }
f21293549   Johannes Berg   cfg80211: managed...
339
340
341
342
343
344
345
346
  
  int cfg80211_wext_siwmlme(struct net_device *dev,
  			  struct iw_request_info *info,
  			  struct iw_point *data, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  	struct iw_mlme *mlme = (struct iw_mlme *)extra;
  	struct cfg80211_registered_device *rdev;
667503ddc   Johannes Berg   cfg80211: fix loc...
347
  	int err;
f21293549   Johannes Berg   cfg80211: managed...
348
349
350
  
  	if (!wdev)
  		return -EOPNOTSUPP;
f26cbf401   Zhao, Gang   cfg80211: change ...
351
  	rdev = wiphy_to_rdev(wdev->wiphy);
f21293549   Johannes Berg   cfg80211: managed...
352
353
354
355
356
357
  
  	if (wdev->iftype != NL80211_IFTYPE_STATION)
  		return -EINVAL;
  
  	if (mlme->addr.sa_family != ARPHRD_ETHER)
  		return -EINVAL;
667503ddc   Johannes Berg   cfg80211: fix loc...
358
  	wdev_lock(wdev);
f21293549   Johannes Berg   cfg80211: managed...
359
360
361
  	switch (mlme->cmd) {
  	case IW_MLME_DEAUTH:
  	case IW_MLME_DISASSOC:
83739b03d   Johannes Berg   cfg80211: remove ...
362
  		err = cfg80211_disconnect(rdev, dev, mlme->reason_code, true);
667503ddc   Johannes Berg   cfg80211: fix loc...
363
  		break;
f21293549   Johannes Berg   cfg80211: managed...
364
  	default:
667503ddc   Johannes Berg   cfg80211: fix loc...
365
366
  		err = -EOPNOTSUPP;
  		break;
f21293549   Johannes Berg   cfg80211: managed...
367
  	}
667503ddc   Johannes Berg   cfg80211: fix loc...
368
369
370
  	wdev_unlock(wdev);
  
  	return err;
f21293549   Johannes Berg   cfg80211: managed...
371
  }