Blame view

net/wireless/sme.c 31.6 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
b23aa676a   Samuel Ortiz   cfg80211: connect...
2
  /*
ceca7b712   Johannes Berg   cfg80211: separat...
3
4
5
   * SME code for cfg80211
   * both driver SME event handling and the SME implementation
   * (for nl80211's connect() and wext)
b23aa676a   Samuel Ortiz   cfg80211: connect...
6
7
8
   *
   * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
   * Copyright (C) 2009   Intel Corporation. All rights reserved.
29ce6ecbb   Avraham Stern   cfg80211: unify c...
9
   * Copyright 2017	Intel Deutschland GmbH
b23aa676a   Samuel Ortiz   cfg80211: connect...
10
11
12
13
   */
  
  #include <linux/etherdevice.h>
  #include <linux/if_arp.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
b23aa676a   Samuel Ortiz   cfg80211: connect...
15
  #include <linux/workqueue.h>
a9a11622c   Johannes Berg   cfg80211: self-co...
16
  #include <linux/wireless.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
17
  #include <linux/export.h>
a9a11622c   Johannes Berg   cfg80211: self-co...
18
  #include <net/iw_handler.h>
b23aa676a   Samuel Ortiz   cfg80211: connect...
19
20
21
  #include <net/cfg80211.h>
  #include <net/rtnetlink.h>
  #include "nl80211.h"
8b19e6ca3   Luis R. Rodriguez   cfg80211: enable ...
22
  #include "reg.h"
e35e4d28b   Hila Gonen   cfg80211: add wra...
23
  #include "rdev-ops.h"
b23aa676a   Samuel Ortiz   cfg80211: connect...
24

ceca7b712   Johannes Berg   cfg80211: separat...
25
26
27
28
29
  /*
   * Software SME in cfg80211, using auth/assoc/deauth calls to the
   * driver. This is is for implementing nl80211's connect/disconnect
   * and wireless extensions (if configured.)
   */
6829c878e   Johannes Berg   cfg80211: emulate...
30
31
32
33
  struct cfg80211_conn {
  	struct cfg80211_connect_params params;
  	/* these are sub-states of the _CONNECTING sme_state */
  	enum {
6829c878e   Johannes Berg   cfg80211: emulate...
34
35
36
37
  		CFG80211_CONN_SCANNING,
  		CFG80211_CONN_SCAN_AGAIN,
  		CFG80211_CONN_AUTHENTICATE_NEXT,
  		CFG80211_CONN_AUTHENTICATING,
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
38
  		CFG80211_CONN_AUTH_FAILED_TIMEOUT,
6829c878e   Johannes Berg   cfg80211: emulate...
39
40
  		CFG80211_CONN_ASSOCIATE_NEXT,
  		CFG80211_CONN_ASSOCIATING,
923a0e7de   Johannes Berg   cfg80211: fix bug...
41
  		CFG80211_CONN_ASSOC_FAILED,
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
42
  		CFG80211_CONN_ASSOC_FAILED_TIMEOUT,
ceca7b712   Johannes Berg   cfg80211: separat...
43
  		CFG80211_CONN_DEAUTH,
e6f462df9   Johannes Berg   cfg80211/mac80211...
44
  		CFG80211_CONN_ABANDON,
ceca7b712   Johannes Berg   cfg80211: separat...
45
  		CFG80211_CONN_CONNECTED,
6829c878e   Johannes Berg   cfg80211: emulate...
46
  	} state;
f401a6f7e   Johannes Berg   cfg80211: use rea...
47
  	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
46b9d1801   Johannes Berg   cfg80211: send ex...
48
  	const u8 *ie;
6829c878e   Johannes Berg   cfg80211: emulate...
49
  	size_t ie_len;
f401a6f7e   Johannes Berg   cfg80211: use rea...
50
  	bool auto_auth, prev_bssid_valid;
6829c878e   Johannes Berg   cfg80211: emulate...
51
  };
ceca7b712   Johannes Berg   cfg80211: separat...
52
  static void cfg80211_sme_free(struct wireless_dev *wdev)
09d989d17   Luis R. Rodriguez   cfg80211: add reg...
53
  {
ceca7b712   Johannes Berg   cfg80211: separat...
54
55
  	if (!wdev->conn)
  		return;
09d989d17   Luis R. Rodriguez   cfg80211: add reg...
56

ceca7b712   Johannes Berg   cfg80211: separat...
57
58
59
  	kfree(wdev->conn->ie);
  	kfree(wdev->conn);
  	wdev->conn = NULL;
09d989d17   Luis R. Rodriguez   cfg80211: add reg...
60
  }
6829c878e   Johannes Berg   cfg80211: emulate...
61
62
  static int cfg80211_conn_scan(struct wireless_dev *wdev)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
63
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
6829c878e   Johannes Berg   cfg80211: emulate...
64
65
66
67
  	struct cfg80211_scan_request *request;
  	int n_channels, err;
  
  	ASSERT_RTNL();
667503ddc   Johannes Berg   cfg80211: fix loc...
68
  	ASSERT_WDEV_LOCK(wdev);
6829c878e   Johannes Berg   cfg80211: emulate...
69

f9d15d162   Johannes Berg   cfg80211: send sc...
70
  	if (rdev->scan_req || rdev->scan_msg)
6829c878e   Johannes Berg   cfg80211: emulate...
71
  		return -EBUSY;
bdfbec2d2   Ilan Peer   cfg80211: Add a f...
72
  	if (wdev->conn->params.channel)
6829c878e   Johannes Berg   cfg80211: emulate...
73
  		n_channels = 1;
bdfbec2d2   Ilan Peer   cfg80211: Add a f...
74
75
  	else
  		n_channels = ieee80211_get_num_supported_channels(wdev->wiphy);
6829c878e   Johannes Berg   cfg80211: emulate...
76

6829c878e   Johannes Berg   cfg80211: emulate...
77
78
79
80
81
  	request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
  			  sizeof(request->channels[0]) * n_channels,
  			  GFP_KERNEL);
  	if (!request)
  		return -ENOMEM;
2a84ee862   Karl Beldan   cfg80211: set the...
82
  	if (wdev->conn->params.channel) {
57fbcce37   Johannes Berg   cfg80211: remove ...
83
  		enum nl80211_band band = wdev->conn->params.channel->band;
2a84ee862   Karl Beldan   cfg80211: set the...
84
85
86
87
88
89
90
  		struct ieee80211_supported_band *sband =
  			wdev->wiphy->bands[band];
  
  		if (!sband) {
  			kfree(request);
  			return -EINVAL;
  		}
6829c878e   Johannes Berg   cfg80211: emulate...
91
  		request->channels[0] = wdev->conn->params.channel;
2a84ee862   Karl Beldan   cfg80211: set the...
92
93
  		request->rates[band] = (1 << sband->n_bitrates) - 1;
  	} else {
6829c878e   Johannes Berg   cfg80211: emulate...
94
  		int i = 0, j;
57fbcce37   Johannes Berg   cfg80211: remove ...
95
  		enum nl80211_band band;
e30815016   Rajkumar Manoharan   wireless: Do not ...
96
97
  		struct ieee80211_supported_band *bands;
  		struct ieee80211_channel *channel;
6829c878e   Johannes Berg   cfg80211: emulate...
98

57fbcce37   Johannes Berg   cfg80211: remove ...
99
  		for (band = 0; band < NUM_NL80211_BANDS; band++) {
e30815016   Rajkumar Manoharan   wireless: Do not ...
100
101
  			bands = wdev->wiphy->bands[band];
  			if (!bands)
6829c878e   Johannes Berg   cfg80211: emulate...
102
  				continue;
e30815016   Rajkumar Manoharan   wireless: Do not ...
103
104
105
106
107
108
109
  			for (j = 0; j < bands->n_channels; j++) {
  				channel = &bands->channels[j];
  				if (channel->flags & IEEE80211_CHAN_DISABLED)
  					continue;
  				request->channels[i++] = channel;
  			}
  			request->rates[band] = (1 << bands->n_bitrates) - 1;
6829c878e   Johannes Berg   cfg80211: emulate...
110
  		}
e30815016   Rajkumar Manoharan   wireless: Do not ...
111
  		n_channels = i;
6829c878e   Johannes Berg   cfg80211: emulate...
112
113
  	}
  	request->n_channels = n_channels;
5ba63533b   Johannes Berg   cfg80211: fix ali...
114
  	request->ssids = (void *)&request->channels[n_channels];
6829c878e   Johannes Berg   cfg80211: emulate...
115
116
117
118
119
  	request->n_ssids = 1;
  
  	memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
  		wdev->conn->params.ssid_len);
  	request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
818965d39   Jouni Malinen   cfg80211: Allow a...
120
  	eth_broadcast_addr(request->bssid);
fd0142844   Johannes Berg   nl80211: move sca...
121
  	request->wdev = wdev;
79c97e97a   Johannes Berg   cfg80211: clean u...
122
  	request->wiphy = &rdev->wiphy;
15d6030b4   Sam Leffler   cfg80211: add sup...
123
  	request->scan_start = jiffies;
6829c878e   Johannes Berg   cfg80211: emulate...
124

79c97e97a   Johannes Berg   cfg80211: clean u...
125
  	rdev->scan_req = request;
6829c878e   Johannes Berg   cfg80211: emulate...
126

e35e4d28b   Hila Gonen   cfg80211: add wra...
127
  	err = rdev_scan(rdev, request);
6829c878e   Johannes Berg   cfg80211: emulate...
128
129
  	if (!err) {
  		wdev->conn->state = CFG80211_CONN_SCANNING;
fd0142844   Johannes Berg   nl80211: move sca...
130
  		nl80211_send_scan_start(rdev, wdev);
463d01832   Johannes Berg   cfg80211: make aw...
131
  		dev_hold(wdev->netdev);
6829c878e   Johannes Berg   cfg80211: emulate...
132
  	} else {
79c97e97a   Johannes Berg   cfg80211: clean u...
133
  		rdev->scan_req = NULL;
6829c878e   Johannes Berg   cfg80211: emulate...
134
135
136
137
  		kfree(request);
  	}
  	return err;
  }
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
138
139
  static int cfg80211_conn_do_work(struct wireless_dev *wdev,
  				 enum nl80211_timeout_reason *treason)
6829c878e   Johannes Berg   cfg80211: emulate...
140
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
141
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
19957bb39   Johannes Berg   cfg80211: keep tr...
142
  	struct cfg80211_connect_params *params;
f62fab735   Johannes Berg   cfg80211: refacto...
143
  	struct cfg80211_assoc_request req = {};
19957bb39   Johannes Berg   cfg80211: keep tr...
144
  	int err;
6829c878e   Johannes Berg   cfg80211: emulate...
145

667503ddc   Johannes Berg   cfg80211: fix loc...
146
  	ASSERT_WDEV_LOCK(wdev);
6829c878e   Johannes Berg   cfg80211: emulate...
147
148
  	if (!wdev->conn)
  		return 0;
19957bb39   Johannes Berg   cfg80211: keep tr...
149
  	params = &wdev->conn->params;
6829c878e   Johannes Berg   cfg80211: emulate...
150
  	switch (wdev->conn->state) {
ceca7b712   Johannes Berg   cfg80211: separat...
151
152
153
  	case CFG80211_CONN_SCANNING:
  		/* didn't find it during scan ... */
  		return -ENOENT;
6829c878e   Johannes Berg   cfg80211: emulate...
154
155
156
  	case CFG80211_CONN_SCAN_AGAIN:
  		return cfg80211_conn_scan(wdev);
  	case CFG80211_CONN_AUTHENTICATE_NEXT:
2fd051155   Johannes Berg   cfg80211: remove ...
157
158
  		if (WARN_ON(!rdev->ops->auth))
  			return -EOPNOTSUPP;
19957bb39   Johannes Berg   cfg80211: keep tr...
159
  		wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
91bf9b26f   Johannes Berg   cfg80211: remove ...
160
161
162
163
164
165
166
  		return cfg80211_mlme_auth(rdev, wdev->netdev,
  					  params->channel, params->auth_type,
  					  params->bssid,
  					  params->ssid, params->ssid_len,
  					  NULL, 0,
  					  params->key, params->key_len,
  					  params->key_idx, NULL, 0);
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
167
168
  	case CFG80211_CONN_AUTH_FAILED_TIMEOUT:
  		*treason = NL80211_TIMEOUT_AUTH;
923a0e7de   Johannes Berg   cfg80211: fix bug...
169
  		return -ENOTCONN;
6829c878e   Johannes Berg   cfg80211: emulate...
170
  	case CFG80211_CONN_ASSOCIATE_NEXT:
2fd051155   Johannes Berg   cfg80211: remove ...
171
172
  		if (WARN_ON(!rdev->ops->assoc))
  			return -EOPNOTSUPP;
19957bb39   Johannes Berg   cfg80211: keep tr...
173
  		wdev->conn->state = CFG80211_CONN_ASSOCIATING;
f401a6f7e   Johannes Berg   cfg80211: use rea...
174
  		if (wdev->conn->prev_bssid_valid)
f62fab735   Johannes Berg   cfg80211: refacto...
175
176
177
178
179
180
181
182
183
184
  			req.prev_bssid = wdev->conn->prev_bssid;
  		req.ie = params->ie;
  		req.ie_len = params->ie_len;
  		req.use_mfp = params->mfp != NL80211_MFP_NO;
  		req.crypto = params->crypto;
  		req.flags = params->flags;
  		req.ht_capa = params->ht_capa;
  		req.ht_capa_mask = params->ht_capa_mask;
  		req.vht_capa = params->vht_capa;
  		req.vht_capa_mask = params->vht_capa_mask;
91bf9b26f   Johannes Berg   cfg80211: remove ...
185
186
187
  		err = cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel,
  					  params->bssid, params->ssid,
  					  params->ssid_len, &req);
19957bb39   Johannes Berg   cfg80211: keep tr...
188
  		if (err)
91bf9b26f   Johannes Berg   cfg80211: remove ...
189
190
191
192
  			cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
  					     NULL, 0,
  					     WLAN_REASON_DEAUTH_LEAVING,
  					     false);
19957bb39   Johannes Berg   cfg80211: keep tr...
193
  		return err;
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
194
195
196
  	case CFG80211_CONN_ASSOC_FAILED_TIMEOUT:
  		*treason = NL80211_TIMEOUT_ASSOC;
  		/* fall through */
923a0e7de   Johannes Berg   cfg80211: fix bug...
197
198
199
200
201
  	case CFG80211_CONN_ASSOC_FAILED:
  		cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
  				     NULL, 0,
  				     WLAN_REASON_DEAUTH_LEAVING, false);
  		return -ENOTCONN;
ceca7b712   Johannes Berg   cfg80211: separat...
202
  	case CFG80211_CONN_DEAUTH:
91bf9b26f   Johannes Berg   cfg80211: remove ...
203
204
205
  		cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
  				     NULL, 0,
  				     WLAN_REASON_DEAUTH_LEAVING, false);
e6f462df9   Johannes Berg   cfg80211/mac80211...
206
207
  		/* fall through */
  	case CFG80211_CONN_ABANDON:
923a0e7de   Johannes Berg   cfg80211: fix bug...
208
209
  		/* free directly, disconnected event already sent */
  		cfg80211_sme_free(wdev);
ceca7b712   Johannes Berg   cfg80211: separat...
210
  		return 0;
6829c878e   Johannes Berg   cfg80211: emulate...
211
212
213
214
215
216
217
  	default:
  		return 0;
  	}
  }
  
  void cfg80211_conn_work(struct work_struct *work)
  {
79c97e97a   Johannes Berg   cfg80211: clean u...
218
  	struct cfg80211_registered_device *rdev =
6829c878e   Johannes Berg   cfg80211: emulate...
219
220
  		container_of(work, struct cfg80211_registered_device, conn_work);
  	struct wireless_dev *wdev;
7400f42e9   Johannes Berg   cfg80211: fix NUL...
221
  	u8 bssid_buf[ETH_ALEN], *bssid = NULL;
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
222
  	enum nl80211_timeout_reason treason;
6829c878e   Johannes Berg   cfg80211: emulate...
223
224
  
  	rtnl_lock();
6829c878e   Johannes Berg   cfg80211: emulate...
225

53873f134   Johannes Berg   cfg80211: make wd...
226
  	list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
c81579766   Johannes Berg   cfg80211: check w...
227
228
  		if (!wdev->netdev)
  			continue;
667503ddc   Johannes Berg   cfg80211: fix loc...
229
230
231
  		wdev_lock(wdev);
  		if (!netif_running(wdev->netdev)) {
  			wdev_unlock(wdev);
6829c878e   Johannes Berg   cfg80211: emulate...
232
  			continue;
667503ddc   Johannes Berg   cfg80211: fix loc...
233
  		}
ceca7b712   Johannes Berg   cfg80211: separat...
234
235
  		if (!wdev->conn ||
  		    wdev->conn->state == CFG80211_CONN_CONNECTED) {
667503ddc   Johannes Berg   cfg80211: fix loc...
236
  			wdev_unlock(wdev);
6829c878e   Johannes Berg   cfg80211: emulate...
237
  			continue;
667503ddc   Johannes Berg   cfg80211: fix loc...
238
  		}
7400f42e9   Johannes Berg   cfg80211: fix NUL...
239
240
241
242
  		if (wdev->conn->params.bssid) {
  			memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
  			bssid = bssid_buf;
  		}
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
243
244
  		treason = NL80211_TIMEOUT_UNSPECIFIED;
  		if (cfg80211_conn_do_work(wdev, &treason)) {
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
245
246
247
248
249
250
251
  			struct cfg80211_connect_resp_params cr;
  
  			memset(&cr, 0, sizeof(cr));
  			cr.status = -1;
  			cr.bssid = bssid;
  			cr.timeout_reason = treason;
  			__cfg80211_connect_result(wdev->netdev, &cr, false);
ceca7b712   Johannes Berg   cfg80211: separat...
252
  		}
667503ddc   Johannes Berg   cfg80211: fix loc...
253
  		wdev_unlock(wdev);
6829c878e   Johannes Berg   cfg80211: emulate...
254
  	}
6829c878e   Johannes Berg   cfg80211: emulate...
255
256
  	rtnl_unlock();
  }
0e3a39b56   Ben Greear   wireless: add com...
257
  /* Returned bss is reference counted and must be cleaned up appropriately. */
bbac31f4c   Johannes Berg   cfg80211: fix SME...
258
  static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
6829c878e   Johannes Berg   cfg80211: emulate...
259
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
260
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
6829c878e   Johannes Berg   cfg80211: emulate...
261
  	struct cfg80211_bss *bss;
6829c878e   Johannes Berg   cfg80211: emulate...
262

667503ddc   Johannes Berg   cfg80211: fix loc...
263
  	ASSERT_WDEV_LOCK(wdev);
ed9d01026   Jouni Malinen   cfg80211: Use con...
264
265
  	bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
  			       wdev->conn->params.bssid,
6829c878e   Johannes Berg   cfg80211: emulate...
266
267
  			       wdev->conn->params.ssid,
  			       wdev->conn->params.ssid_len,
34d505193   Lior David   cfg80211: basic s...
268
  			       wdev->conn_bss_type,
6eb181376   Dedy Lansky   cfg80211: add bss...
269
  			       IEEE80211_PRIVACY(wdev->conn->params.privacy));
6829c878e   Johannes Berg   cfg80211: emulate...
270
  	if (!bss)
bbac31f4c   Johannes Berg   cfg80211: fix SME...
271
  		return NULL;
6829c878e   Johannes Berg   cfg80211: emulate...
272
273
274
275
276
  
  	memcpy(wdev->conn->bssid, bss->bssid, ETH_ALEN);
  	wdev->conn->params.bssid = wdev->conn->bssid;
  	wdev->conn->params.channel = bss->channel;
  	wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
79c97e97a   Johannes Berg   cfg80211: clean u...
277
  	schedule_work(&rdev->conn_work);
6829c878e   Johannes Berg   cfg80211: emulate...
278

bbac31f4c   Johannes Berg   cfg80211: fix SME...
279
  	return bss;
6829c878e   Johannes Berg   cfg80211: emulate...
280
  }
667503ddc   Johannes Berg   cfg80211: fix loc...
281
  static void __cfg80211_sme_scan_done(struct net_device *dev)
6829c878e   Johannes Berg   cfg80211: emulate...
282
283
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
284
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
bbac31f4c   Johannes Berg   cfg80211: fix SME...
285
  	struct cfg80211_bss *bss;
6829c878e   Johannes Berg   cfg80211: emulate...
286

667503ddc   Johannes Berg   cfg80211: fix loc...
287
  	ASSERT_WDEV_LOCK(wdev);
d4b1a6876   Zhu Yi   cfg80211: remove ...
288
  	if (!wdev->conn)
6829c878e   Johannes Berg   cfg80211: emulate...
289
290
291
292
293
  		return;
  
  	if (wdev->conn->state != CFG80211_CONN_SCANNING &&
  	    wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
  		return;
bbac31f4c   Johannes Berg   cfg80211: fix SME...
294
  	bss = cfg80211_get_conn_bss(wdev);
ceca7b712   Johannes Berg   cfg80211: separat...
295
  	if (bss)
5b112d3d0   Johannes Berg   cfg80211: pass wi...
296
  		cfg80211_put_bss(&rdev->wiphy, bss);
ceca7b712   Johannes Berg   cfg80211: separat...
297
298
  	else
  		schedule_work(&rdev->conn_work);
6829c878e   Johannes Berg   cfg80211: emulate...
299
  }
667503ddc   Johannes Berg   cfg80211: fix loc...
300
301
302
303
304
305
306
307
  void cfg80211_sme_scan_done(struct net_device *dev)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	wdev_lock(wdev);
  	__cfg80211_sme_scan_done(dev);
  	wdev_unlock(wdev);
  }
ceca7b712   Johannes Berg   cfg80211: separat...
308
  void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
6829c878e   Johannes Berg   cfg80211: emulate...
309
  {
6829c878e   Johannes Berg   cfg80211: emulate...
310
  	struct wiphy *wiphy = wdev->wiphy;
f26cbf401   Zhao, Gang   cfg80211: change ...
311
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
6829c878e   Johannes Berg   cfg80211: emulate...
312
313
  	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
  	u16 status_code = le16_to_cpu(mgmt->u.auth.status_code);
667503ddc   Johannes Berg   cfg80211: fix loc...
314
  	ASSERT_WDEV_LOCK(wdev);
ceca7b712   Johannes Berg   cfg80211: separat...
315
  	if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED)
6829c878e   Johannes Berg   cfg80211: emulate...
316
317
318
319
320
321
322
323
  		return;
  
  	if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
  	    wdev->conn->auto_auth &&
  	    wdev->conn->params.auth_type != NL80211_AUTHTYPE_NETWORK_EAP) {
  		/* select automatically between only open, shared, leap */
  		switch (wdev->conn->params.auth_type) {
  		case NL80211_AUTHTYPE_OPEN_SYSTEM:
fffd0934b   Johannes Berg   cfg80211: rework ...
324
325
326
327
328
329
  			if (wdev->connect_keys)
  				wdev->conn->params.auth_type =
  					NL80211_AUTHTYPE_SHARED_KEY;
  			else
  				wdev->conn->params.auth_type =
  					NL80211_AUTHTYPE_NETWORK_EAP;
6829c878e   Johannes Berg   cfg80211: emulate...
330
331
332
333
334
335
336
337
338
339
340
341
342
  			break;
  		case NL80211_AUTHTYPE_SHARED_KEY:
  			wdev->conn->params.auth_type =
  				NL80211_AUTHTYPE_NETWORK_EAP;
  			break;
  		default:
  			/* huh? */
  			wdev->conn->params.auth_type =
  				NL80211_AUTHTYPE_OPEN_SYSTEM;
  			break;
  		}
  		wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
  		schedule_work(&rdev->conn_work);
19957bb39   Johannes Berg   cfg80211: keep tr...
343
  	} else if (status_code != WLAN_STATUS_SUCCESS) {
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
344
345
346
347
348
349
350
  		struct cfg80211_connect_resp_params cr;
  
  		memset(&cr, 0, sizeof(cr));
  		cr.status = status_code;
  		cr.bssid = mgmt->bssid;
  		cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
  		__cfg80211_connect_result(wdev->netdev, &cr, false);
ceca7b712   Johannes Berg   cfg80211: separat...
351
  	} else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
6829c878e   Johannes Berg   cfg80211: emulate...
352
353
354
355
  		wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
  		schedule_work(&rdev->conn_work);
  	}
  }
b23aa676a   Samuel Ortiz   cfg80211: connect...
356

ceca7b712   Johannes Berg   cfg80211: separat...
357
  bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
f401a6f7e   Johannes Berg   cfg80211: use rea...
358
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
359
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
f401a6f7e   Johannes Berg   cfg80211: use rea...
360

ceca7b712   Johannes Berg   cfg80211: separat...
361
  	if (!wdev->conn)
f401a6f7e   Johannes Berg   cfg80211: use rea...
362
  		return false;
ceca7b712   Johannes Berg   cfg80211: separat...
363
364
  	if (status == WLAN_STATUS_SUCCESS) {
  		wdev->conn->state = CFG80211_CONN_CONNECTED;
f401a6f7e   Johannes Berg   cfg80211: use rea...
365
  		return false;
ceca7b712   Johannes Berg   cfg80211: separat...
366
  	}
f401a6f7e   Johannes Berg   cfg80211: use rea...
367

ceca7b712   Johannes Berg   cfg80211: separat...
368
369
370
371
372
373
374
375
376
377
378
  	if (wdev->conn->prev_bssid_valid) {
  		/*
  		 * Some stupid APs don't accept reassoc, so we
  		 * need to fall back to trying regular assoc;
  		 * return true so no event is sent to userspace.
  		 */
  		wdev->conn->prev_bssid_valid = false;
  		wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
  		schedule_work(&rdev->conn_work);
  		return true;
  	}
923a0e7de   Johannes Berg   cfg80211: fix bug...
379
  	wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
f401a6f7e   Johannes Berg   cfg80211: use rea...
380
  	schedule_work(&rdev->conn_work);
ceca7b712   Johannes Berg   cfg80211: separat...
381
382
  	return false;
  }
f401a6f7e   Johannes Berg   cfg80211: use rea...
383

ceca7b712   Johannes Berg   cfg80211: separat...
384
385
386
  void cfg80211_sme_deauth(struct wireless_dev *wdev)
  {
  	cfg80211_sme_free(wdev);
f401a6f7e   Johannes Berg   cfg80211: use rea...
387
  }
ceca7b712   Johannes Berg   cfg80211: separat...
388
  void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
7d930bc33   Johannes Berg   cfg80211: sme: de...
389
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
390
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
923a0e7de   Johannes Berg   cfg80211: fix bug...
391
392
393
  
  	if (!wdev->conn)
  		return;
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
394
  	wdev->conn->state = CFG80211_CONN_AUTH_FAILED_TIMEOUT;
923a0e7de   Johannes Berg   cfg80211: fix bug...
395
  	schedule_work(&rdev->conn_work);
ceca7b712   Johannes Berg   cfg80211: separat...
396
  }
7d930bc33   Johannes Berg   cfg80211: sme: de...
397

ceca7b712   Johannes Berg   cfg80211: separat...
398
399
  void cfg80211_sme_disassoc(struct wireless_dev *wdev)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
400
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
ceca7b712   Johannes Berg   cfg80211: separat...
401
402
403
404
405
  
  	if (!wdev->conn)
  		return;
  
  	wdev->conn->state = CFG80211_CONN_DEAUTH;
7d930bc33   Johannes Berg   cfg80211: sme: de...
406
407
  	schedule_work(&rdev->conn_work);
  }
ceca7b712   Johannes Berg   cfg80211: separat...
408
409
  void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
410
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
923a0e7de   Johannes Berg   cfg80211: fix bug...
411
412
413
  
  	if (!wdev->conn)
  		return;
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
414
  	wdev->conn->state = CFG80211_CONN_ASSOC_FAILED_TIMEOUT;
923a0e7de   Johannes Berg   cfg80211: fix bug...
415
  	schedule_work(&rdev->conn_work);
ceca7b712   Johannes Berg   cfg80211: separat...
416
  }
e6f462df9   Johannes Berg   cfg80211/mac80211...
417
418
419
420
421
422
423
424
425
426
  void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev)
  {
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
  
  	if (!wdev->conn)
  		return;
  
  	wdev->conn->state = CFG80211_CONN_ABANDON;
  	schedule_work(&rdev->conn_work);
  }
46b9d1801   Johannes Berg   cfg80211: send ex...
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev,
  				     const u8 *ies, size_t ies_len,
  				     const u8 **out_ies, size_t *out_ies_len)
  {
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
  	u8 *buf;
  	size_t offs;
  
  	if (!rdev->wiphy.extended_capabilities_len ||
  	    (ies && cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, ies, ies_len))) {
  		*out_ies = kmemdup(ies, ies_len, GFP_KERNEL);
  		if (!*out_ies)
  			return -ENOMEM;
  		*out_ies_len = ies_len;
  		return 0;
  	}
  
  	buf = kmalloc(ies_len + rdev->wiphy.extended_capabilities_len + 2,
  		      GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  
  	if (ies_len) {
  		static const u8 before_extcapa[] = {
  			/* not listing IEs expected to be created by driver */
  			WLAN_EID_RSN,
  			WLAN_EID_QOS_CAPA,
  			WLAN_EID_RRM_ENABLED_CAPABILITIES,
  			WLAN_EID_MOBILITY_DOMAIN,
  			WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
  			WLAN_EID_BSS_COEX_2040,
  		};
  
  		offs = ieee80211_ie_split(ies, ies_len, before_extcapa,
  					  ARRAY_SIZE(before_extcapa), 0);
  		memcpy(buf, ies, offs);
  		/* leave a whole for extended capabilities IE */
  		memcpy(buf + offs + rdev->wiphy.extended_capabilities_len + 2,
  		       ies + offs, ies_len - offs);
  	} else {
  		offs = 0;
  	}
  
  	/* place extended capabilities IE (with only driver capabilities) */
  	buf[offs] = WLAN_EID_EXT_CAPABILITY;
  	buf[offs + 1] = rdev->wiphy.extended_capabilities_len;
  	memcpy(buf + offs + 2,
  	       rdev->wiphy.extended_capabilities,
  	       rdev->wiphy.extended_capabilities_len);
  
  	*out_ies = buf;
  	*out_ies_len = ies_len + rdev->wiphy.extended_capabilities_len + 2;
  
  	return 0;
  }
ceca7b712   Johannes Berg   cfg80211: separat...
482
483
484
485
  static int cfg80211_sme_connect(struct wireless_dev *wdev,
  				struct cfg80211_connect_params *connect,
  				const u8 *prev_bssid)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
486
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
ceca7b712   Johannes Berg   cfg80211: separat...
487
488
489
490
491
  	struct cfg80211_bss *bss;
  	int err;
  
  	if (!rdev->ops->auth || !rdev->ops->assoc)
  		return -EOPNOTSUPP;
4ce2bd9c4   Jouni Malinen   cfg80211: Allow r...
492
  	if (wdev->current_bss) {
4ce2bd9c4   Jouni Malinen   cfg80211: Allow r...
493
494
495
496
497
498
  		cfg80211_unhold_bss(wdev->current_bss);
  		cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
  		wdev->current_bss = NULL;
  
  		cfg80211_sme_free(wdev);
  	}
ceca7b712   Johannes Berg   cfg80211: separat...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  
  	if (WARN_ON(wdev->conn))
  		return -EINPROGRESS;
  
  	wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
  	if (!wdev->conn)
  		return -ENOMEM;
  
  	/*
  	 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
  	 */
  	memcpy(&wdev->conn->params, connect, sizeof(*connect));
  	if (connect->bssid) {
  		wdev->conn->params.bssid = wdev->conn->bssid;
  		memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
  	}
46b9d1801   Johannes Berg   cfg80211: send ex...
515
516
517
518
519
520
  	if (cfg80211_sme_get_conn_ies(wdev, connect->ie, connect->ie_len,
  				      &wdev->conn->ie,
  				      &wdev->conn->params.ie_len)) {
  		kfree(wdev->conn);
  		wdev->conn = NULL;
  		return -ENOMEM;
ceca7b712   Johannes Berg   cfg80211: separat...
521
  	}
46b9d1801   Johannes Berg   cfg80211: send ex...
522
  	wdev->conn->params.ie = wdev->conn->ie;
ceca7b712   Johannes Berg   cfg80211: separat...
523
524
525
526
527
528
529
530
531
532
533
  
  	if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
  		wdev->conn->auto_auth = true;
  		/* start with open system ... should mostly work */
  		wdev->conn->params.auth_type =
  			NL80211_AUTHTYPE_OPEN_SYSTEM;
  	} else {
  		wdev->conn->auto_auth = false;
  	}
  
  	wdev->conn->params.ssid = wdev->ssid;
babd3a272   Zhao, Gang   cfg80211: slightl...
534
  	wdev->conn->params.ssid_len = wdev->ssid_len;
ceca7b712   Johannes Berg   cfg80211: separat...
535
536
537
538
539
540
541
542
543
544
545
  
  	/* see if we have the bss already */
  	bss = cfg80211_get_conn_bss(wdev);
  
  	if (prev_bssid) {
  		memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
  		wdev->conn->prev_bssid_valid = true;
  	}
  
  	/* we're good if we have a matching bss struct */
  	if (bss) {
3093ebbea   Purushottam Kushwaha   cfg80211: Specify...
546
547
548
  		enum nl80211_timeout_reason treason;
  
  		err = cfg80211_conn_do_work(wdev, &treason);
ceca7b712   Johannes Berg   cfg80211: separat...
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  		cfg80211_put_bss(wdev->wiphy, bss);
  	} else {
  		/* otherwise we'll need to scan for the AP first */
  		err = cfg80211_conn_scan(wdev);
  
  		/*
  		 * If we can't scan right now, then we need to scan again
  		 * after the current scan finished, since the parameters
  		 * changed (unless we find a good AP anyway).
  		 */
  		if (err == -EBUSY) {
  			err = 0;
  			wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
  		}
  	}
  
  	if (err)
  		cfg80211_sme_free(wdev);
  
  	return err;
  }
  
  static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
573
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
ceca7b712   Johannes Berg   cfg80211: separat...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  	int err;
  
  	if (!wdev->conn)
  		return 0;
  
  	if (!rdev->ops->deauth)
  		return -EOPNOTSUPP;
  
  	if (wdev->conn->state == CFG80211_CONN_SCANNING ||
  	    wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) {
  		err = 0;
  		goto out;
  	}
  
  	/* wdev->conn->params.bssid must be set if > SCANNING */
  	err = cfg80211_mlme_deauth(rdev, wdev->netdev,
  				   wdev->conn->params.bssid,
  				   NULL, 0, reason, false);
   out:
  	cfg80211_sme_free(wdev);
  	return err;
  }
  
  /*
   * code shared for in-device and software SME
   */
  
  static bool cfg80211_is_all_idle(void)
  {
  	struct cfg80211_registered_device *rdev;
  	struct wireless_dev *wdev;
  	bool is_all_idle = true;
  
  	/*
  	 * All devices must be idle as otherwise if you are actively
  	 * scanning some new beacon hints could be learned and would
  	 * count as new regulatory hints.
  	 */
  	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
53873f134   Johannes Berg   cfg80211: make wd...
613
  		list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
ceca7b712   Johannes Berg   cfg80211: separat...
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  			wdev_lock(wdev);
  			if (wdev->conn || wdev->current_bss)
  				is_all_idle = false;
  			wdev_unlock(wdev);
  		}
  	}
  
  	return is_all_idle;
  }
  
  static void disconnect_work(struct work_struct *work)
  {
  	rtnl_lock();
  	if (cfg80211_is_all_idle())
  		regulatory_hint_disconnect();
  	rtnl_unlock();
  }
  
  static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
  
  
  /*
   * API calls for drivers implementing connect/disconnect and
   * SME event handling
   */
6f390908e   Ben Greear   wireless: Make su...
639
  /* This method must consume bss one way or another */
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
640
641
642
  void __cfg80211_connect_result(struct net_device *dev,
  			       struct cfg80211_connect_resp_params *cr,
  			       bool wextev)
b23aa676a   Samuel Ortiz   cfg80211: connect...
643
644
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
9caf03640   Johannes Berg   cfg80211: fix BSS...
645
  	const u8 *country_ie;
3d23e349d   Johannes Berg   wext: refactor
646
  #ifdef CONFIG_CFG80211_WEXT
b23aa676a   Samuel Ortiz   cfg80211: connect...
647
648
  	union iwreq_data wrqu;
  #endif
667503ddc   Johannes Berg   cfg80211: fix loc...
649
  	ASSERT_WDEV_LOCK(wdev);
074ac8df9   Johannes Berg   cfg80211/nl80211:...
650
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
6f390908e   Ben Greear   wireless: Make su...
651
  		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
652
  		cfg80211_put_bss(wdev->wiphy, cr->bss);
b23aa676a   Samuel Ortiz   cfg80211: connect...
653
  		return;
6f390908e   Ben Greear   wireless: Make su...
654
  	}
b23aa676a   Samuel Ortiz   cfg80211: connect...
655

5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
656
657
  	nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
  				    GFP_KERNEL);
e45cd82ac   Johannes Berg   cfg80211: send ev...
658

3d23e349d   Johannes Berg   wext: refactor
659
  #ifdef CONFIG_CFG80211_WEXT
e45cd82ac   Johannes Berg   cfg80211: send ev...
660
  	if (wextev) {
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
661
  		if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) {
e45cd82ac   Johannes Berg   cfg80211: send ev...
662
  			memset(&wrqu, 0, sizeof(wrqu));
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
663
664
665
  			wrqu.data.length = cr->req_ie_len;
  			wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
  					    cr->req_ie);
e45cd82ac   Johannes Berg   cfg80211: send ev...
666
  		}
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
667
  		if (cr->resp_ie && cr->status == WLAN_STATUS_SUCCESS) {
e45cd82ac   Johannes Berg   cfg80211: send ev...
668
  			memset(&wrqu, 0, sizeof(wrqu));
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
669
670
671
  			wrqu.data.length = cr->resp_ie_len;
  			wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
  					    cr->resp_ie);
e45cd82ac   Johannes Berg   cfg80211: send ev...
672
673
674
675
  		}
  
  		memset(&wrqu, 0, sizeof(wrqu));
  		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
676
677
678
  		if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) {
  			memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN);
  			memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN);
f401a6f7e   Johannes Berg   cfg80211: use rea...
679
680
  			wdev->wext.prev_bssid_valid = true;
  		}
e45cd82ac   Johannes Berg   cfg80211: send ev...
681
682
683
  		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
  	}
  #endif
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
684
  	if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) {
f26cbf401   Zhao, Gang   cfg80211: change ...
685
  		WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
686
687
688
689
690
691
  		cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid,
  					   wdev->ssid, wdev->ssid_len,
  					   wdev->conn_bss_type,
  					   IEEE80211_PRIVACY_ANY);
  		if (cr->bss)
  			cfg80211_hold_bss(bss_from_pub(cr->bss));
4c4d684a5   Ujjal Roy   cfg80211: fix WAR...
692
  	}
df7fc0f97   Johannes Berg   cfg80211: keep tr...
693
694
  	if (wdev->current_bss) {
  		cfg80211_unhold_bss(wdev->current_bss);
5b112d3d0   Johannes Berg   cfg80211: pass wi...
695
  		cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
df7fc0f97   Johannes Berg   cfg80211: keep tr...
696
697
  		wdev->current_bss = NULL;
  	}
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
698
  	if (cr->status != WLAN_STATUS_SUCCESS) {
b47f610bd   Johannes Berg   cfg80211: clear c...
699
  		kzfree(wdev->connect_keys);
fffd0934b   Johannes Berg   cfg80211: rework ...
700
  		wdev->connect_keys = NULL;
8dadadb7e   Johannes Berg   cfg80211: clear S...
701
  		wdev->ssid_len = 0;
bd2522b16   Andrzej Zaborowski   cfg80211: NL80211...
702
  		wdev->conn_owner_nlportid = 0;
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
703
704
705
  		if (cr->bss) {
  			cfg80211_unhold_bss(bss_from_pub(cr->bss));
  			cfg80211_put_bss(wdev->wiphy, cr->bss);
f1940c573   Johannes Berg   cfg80211: hold BS...
706
  		}
c1fbb2588   Eliad Peller   cfg80211: free sm...
707
  		cfg80211_sme_free(wdev);
fffd0934b   Johannes Berg   cfg80211: rework ...
708
  		return;
b23aa676a   Samuel Ortiz   cfg80211: connect...
709
  	}
fffd0934b   Johannes Berg   cfg80211: rework ...
710

5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
711
  	if (WARN_ON(!cr->bss))
4c4d684a5   Ujjal Roy   cfg80211: fix WAR...
712
  		return;
fffd0934b   Johannes Berg   cfg80211: rework ...
713

5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
714
  	wdev->current_bss = bss_from_pub(cr->bss);
fffd0934b   Johannes Berg   cfg80211: rework ...
715

b8676221f   David Spinadel   cfg80211: Add sup...
716
717
  	if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
  		cfg80211_upload_connect_keys(wdev);
8b19e6ca3   Luis R. Rodriguez   cfg80211: enable ...
718

9caf03640   Johannes Berg   cfg80211: fix BSS...
719
  	rcu_read_lock();
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
720
  	country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY);
9caf03640   Johannes Berg   cfg80211: fix BSS...
721
722
723
724
725
726
727
  	if (!country_ie) {
  		rcu_read_unlock();
  		return;
  	}
  
  	country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC);
  	rcu_read_unlock();
8b19e6ca3   Luis R. Rodriguez   cfg80211: enable ...
728
729
730
731
732
733
734
735
736
  
  	if (!country_ie)
  		return;
  
  	/*
  	 * ieee80211_bss_get_ie() ensures we can access:
  	 * - country_ie + 2, the start of the country ie data, and
  	 * - and country_ie[1] which is the IE length
  	 */
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
737
  	regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band,
789fd0333   Luis R. Rodriguez   cfg80211: rename ...
738
  				   country_ie + 2, country_ie[1]);
9caf03640   Johannes Berg   cfg80211: fix BSS...
739
  	kfree(country_ie);
b23aa676a   Samuel Ortiz   cfg80211: connect...
740
  }
f21293549   Johannes Berg   cfg80211: managed...
741

e70549894   Kanchanapally, Vidyullatha   cfg80211: Add opt...
742
  /* Consumes bss object one way or another */
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
743
744
745
  void cfg80211_connect_done(struct net_device *dev,
  			   struct cfg80211_connect_resp_params *params,
  			   gfp_t gfp)
f21293549   Johannes Berg   cfg80211: managed...
746
  {
667503ddc   Johannes Berg   cfg80211: fix loc...
747
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
748
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
667503ddc   Johannes Berg   cfg80211: fix loc...
749
750
  	struct cfg80211_event *ev;
  	unsigned long flags;
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
751
  	u8 *next;
667503ddc   Johannes Berg   cfg80211: fix loc...
752

5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
753
  	if (params->bss) {
e70549894   Kanchanapally, Vidyullatha   cfg80211: Add opt...
754
  		/* Make sure the bss entry provided by the driver is valid. */
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
755
  		struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss);
e70549894   Kanchanapally, Vidyullatha   cfg80211: Add opt...
756
757
  
  		if (WARN_ON(list_empty(&ibss->list))) {
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
758
  			cfg80211_put_bss(wdev->wiphy, params->bss);
e70549894   Kanchanapally, Vidyullatha   cfg80211: Add opt...
759
760
761
  			return;
  		}
  	}
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
762
  	ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) +
a3caf7440   Vidyullatha Kanchanapally   cfg80211: Add sup...
763
764
765
  		     params->req_ie_len + params->resp_ie_len +
  		     params->fils_kek_len + params->pmk_len +
  		     (params->pmkid ? WLAN_PMKID_LEN : 0), gfp);
e70549894   Kanchanapally, Vidyullatha   cfg80211: Add opt...
766
  	if (!ev) {
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
767
  		cfg80211_put_bss(wdev->wiphy, params->bss);
667503ddc   Johannes Berg   cfg80211: fix loc...
768
  		return;
e70549894   Kanchanapally, Vidyullatha   cfg80211: Add opt...
769
  	}
667503ddc   Johannes Berg   cfg80211: fix loc...
770
771
  
  	ev->type = EVENT_CONNECT_RESULT;
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
772
773
774
775
776
  	next = ((u8 *)ev) + sizeof(*ev);
  	if (params->bssid) {
  		ev->cr.bssid = next;
  		memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN);
  		next += ETH_ALEN;
7834704be   Nishant Sarmukadam   cfg80211: Avoid s...
777
  	}
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
778
779
780
781
782
783
  	if (params->req_ie_len) {
  		ev->cr.req_ie = next;
  		ev->cr.req_ie_len = params->req_ie_len;
  		memcpy((void *)ev->cr.req_ie, params->req_ie,
  		       params->req_ie_len);
  		next += params->req_ie_len;
7834704be   Nishant Sarmukadam   cfg80211: Avoid s...
784
  	}
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
785
786
787
788
789
790
791
  	if (params->resp_ie_len) {
  		ev->cr.resp_ie = next;
  		ev->cr.resp_ie_len = params->resp_ie_len;
  		memcpy((void *)ev->cr.resp_ie, params->resp_ie,
  		       params->resp_ie_len);
  		next += params->resp_ie_len;
  	}
a3caf7440   Vidyullatha Kanchanapally   cfg80211: Add sup...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
  	if (params->fils_kek_len) {
  		ev->cr.fils_kek = next;
  		ev->cr.fils_kek_len = params->fils_kek_len;
  		memcpy((void *)ev->cr.fils_kek, params->fils_kek,
  		       params->fils_kek_len);
  		next += params->fils_kek_len;
  	}
  	if (params->pmk_len) {
  		ev->cr.pmk = next;
  		ev->cr.pmk_len = params->pmk_len;
  		memcpy((void *)ev->cr.pmk, params->pmk, params->pmk_len);
  		next += params->pmk_len;
  	}
  	if (params->pmkid) {
  		ev->cr.pmkid = next;
  		memcpy((void *)ev->cr.pmkid, params->pmkid, WLAN_PMKID_LEN);
  		next += WLAN_PMKID_LEN;
  	}
  	ev->cr.update_erp_next_seq_num = params->update_erp_next_seq_num;
  	if (params->update_erp_next_seq_num)
  		ev->cr.fils_erp_next_seq_num = params->fils_erp_next_seq_num;
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
813
814
815
816
817
  	if (params->bss)
  		cfg80211_hold_bss(bss_from_pub(params->bss));
  	ev->cr.bss = params->bss;
  	ev->cr.status = params->status;
  	ev->cr.timeout_reason = params->timeout_reason;
667503ddc   Johannes Berg   cfg80211: fix loc...
818
819
820
821
  
  	spin_lock_irqsave(&wdev->event_lock, flags);
  	list_add_tail(&ev->list, &wdev->event_list);
  	spin_unlock_irqrestore(&wdev->event_lock, flags);
e60d7443e   Alban Browaeys   wireless : use a ...
822
  	queue_work(cfg80211_wq, &rdev->event_work);
f21293549   Johannes Berg   cfg80211: managed...
823
  }
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
824
  EXPORT_SYMBOL(cfg80211_connect_done);
b23aa676a   Samuel Ortiz   cfg80211: connect...
825

0e3a39b56   Ben Greear   wireless: add com...
826
  /* Consumes bss object one way or another */
ed9d01026   Jouni Malinen   cfg80211: Use con...
827
  void __cfg80211_roamed(struct wireless_dev *wdev,
29ce6ecbb   Avraham Stern   cfg80211: unify c...
828
  		       struct cfg80211_roam_info *info)
b23aa676a   Samuel Ortiz   cfg80211: connect...
829
  {
3d23e349d   Johannes Berg   wext: refactor
830
  #ifdef CONFIG_CFG80211_WEXT
b23aa676a   Samuel Ortiz   cfg80211: connect...
831
832
  	union iwreq_data wrqu;
  #endif
667503ddc   Johannes Berg   cfg80211: fix loc...
833
  	ASSERT_WDEV_LOCK(wdev);
074ac8df9   Johannes Berg   cfg80211/nl80211:...
834
835
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
  		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
836
  		goto out;
b23aa676a   Samuel Ortiz   cfg80211: connect...
837

ceca7b712   Johannes Berg   cfg80211: separat...
838
  	if (WARN_ON(!wdev->current_bss))
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
839
  		goto out;
b23aa676a   Samuel Ortiz   cfg80211: connect...
840
841
  
  	cfg80211_unhold_bss(wdev->current_bss);
5b112d3d0   Johannes Berg   cfg80211: pass wi...
842
  	cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
b23aa676a   Samuel Ortiz   cfg80211: connect...
843
  	wdev->current_bss = NULL;
29ce6ecbb   Avraham Stern   cfg80211: unify c...
844
845
846
847
848
  	if (WARN_ON(!info->bss))
  		return;
  
  	cfg80211_hold_bss(bss_from_pub(info->bss));
  	wdev->current_bss = bss_from_pub(info->bss);
b23aa676a   Samuel Ortiz   cfg80211: connect...
849

f26cbf401   Zhao, Gang   cfg80211: change ...
850
  	nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
29ce6ecbb   Avraham Stern   cfg80211: unify c...
851
  			    wdev->netdev, info, GFP_KERNEL);
b23aa676a   Samuel Ortiz   cfg80211: connect...
852

3d23e349d   Johannes Berg   wext: refactor
853
  #ifdef CONFIG_CFG80211_WEXT
29ce6ecbb   Avraham Stern   cfg80211: unify c...
854
  	if (info->req_ie) {
b23aa676a   Samuel Ortiz   cfg80211: connect...
855
  		memset(&wrqu, 0, sizeof(wrqu));
29ce6ecbb   Avraham Stern   cfg80211: unify c...
856
  		wrqu.data.length = info->req_ie_len;
3409ff771   Zhu Yi   cfg80211: fix typ...
857
  		wireless_send_event(wdev->netdev, IWEVASSOCREQIE,
29ce6ecbb   Avraham Stern   cfg80211: unify c...
858
  				    &wrqu, info->req_ie);
b23aa676a   Samuel Ortiz   cfg80211: connect...
859
  	}
29ce6ecbb   Avraham Stern   cfg80211: unify c...
860
  	if (info->resp_ie) {
b23aa676a   Samuel Ortiz   cfg80211: connect...
861
  		memset(&wrqu, 0, sizeof(wrqu));
29ce6ecbb   Avraham Stern   cfg80211: unify c...
862
  		wrqu.data.length = info->resp_ie_len;
667503ddc   Johannes Berg   cfg80211: fix loc...
863
  		wireless_send_event(wdev->netdev, IWEVASSOCRESPIE,
29ce6ecbb   Avraham Stern   cfg80211: unify c...
864
  				    &wrqu, info->resp_ie);
b23aa676a   Samuel Ortiz   cfg80211: connect...
865
866
867
868
  	}
  
  	memset(&wrqu, 0, sizeof(wrqu));
  	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
29ce6ecbb   Avraham Stern   cfg80211: unify c...
869
870
  	memcpy(wrqu.ap_addr.sa_data, info->bss->bssid, ETH_ALEN);
  	memcpy(wdev->wext.prev_bssid, info->bss->bssid, ETH_ALEN);
f401a6f7e   Johannes Berg   cfg80211: use rea...
871
  	wdev->wext.prev_bssid_valid = true;
667503ddc   Johannes Berg   cfg80211: fix loc...
872
  	wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL);
b23aa676a   Samuel Ortiz   cfg80211: connect...
873
  #endif
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
874
875
876
  
  	return;
  out:
29ce6ecbb   Avraham Stern   cfg80211: unify c...
877
  	cfg80211_put_bss(wdev->wiphy, info->bss);
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
878
  }
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
879

29ce6ecbb   Avraham Stern   cfg80211: unify c...
880
881
882
  /* Consumes info->bss object one way or another */
  void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
  		     gfp_t gfp)
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
883
884
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
885
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
667503ddc   Johannes Berg   cfg80211: fix loc...
886
887
  	struct cfg80211_event *ev;
  	unsigned long flags;
29ce6ecbb   Avraham Stern   cfg80211: unify c...
888
889
890
891
892
893
894
895
896
  	if (!info->bss) {
  		info->bss = cfg80211_get_bss(wdev->wiphy, info->channel,
  					     info->bssid, wdev->ssid,
  					     wdev->ssid_len,
  					     wdev->conn_bss_type,
  					     IEEE80211_PRIVACY_ANY);
  	}
  
  	if (WARN_ON(!info->bss))
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
897
  		return;
29ce6ecbb   Avraham Stern   cfg80211: unify c...
898
  	ev = kzalloc(sizeof(*ev) + info->req_ie_len + info->resp_ie_len, gfp);
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
899
  	if (!ev) {
29ce6ecbb   Avraham Stern   cfg80211: unify c...
900
  		cfg80211_put_bss(wdev->wiphy, info->bss);
667503ddc   Johannes Berg   cfg80211: fix loc...
901
  		return;
adbde344d   Vasanthakumar Thiagarajan   cfg80211: Fix rac...
902
  	}
667503ddc   Johannes Berg   cfg80211: fix loc...
903
904
  
  	ev->type = EVENT_ROAMED;
667503ddc   Johannes Berg   cfg80211: fix loc...
905
  	ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
29ce6ecbb   Avraham Stern   cfg80211: unify c...
906
907
908
909
910
911
  	ev->rm.req_ie_len = info->req_ie_len;
  	memcpy((void *)ev->rm.req_ie, info->req_ie, info->req_ie_len);
  	ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + info->req_ie_len;
  	ev->rm.resp_ie_len = info->resp_ie_len;
  	memcpy((void *)ev->rm.resp_ie, info->resp_ie, info->resp_ie_len);
  	ev->rm.bss = info->bss;
f45cbe6e6   Avraham Stern   nl80211: add auth...
912
  	ev->rm.authorized = info->authorized;
667503ddc   Johannes Berg   cfg80211: fix loc...
913
914
915
916
  
  	spin_lock_irqsave(&wdev->event_lock, flags);
  	list_add_tail(&ev->list, &wdev->event_list);
  	spin_unlock_irqrestore(&wdev->event_lock, flags);
e60d7443e   Alban Browaeys   wireless : use a ...
917
  	queue_work(cfg80211_wq, &rdev->event_work);
667503ddc   Johannes Berg   cfg80211: fix loc...
918
  }
29ce6ecbb   Avraham Stern   cfg80211: unify c...
919
  EXPORT_SYMBOL(cfg80211_roamed);
b23aa676a   Samuel Ortiz   cfg80211: connect...
920

667503ddc   Johannes Berg   cfg80211: fix loc...
921
  void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
6829c878e   Johannes Berg   cfg80211: emulate...
922
  			     size_t ie_len, u16 reason, bool from_ap)
b23aa676a   Samuel Ortiz   cfg80211: connect...
923
924
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
925
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
fffd0934b   Johannes Berg   cfg80211: rework ...
926
  	int i;
3d23e349d   Johannes Berg   wext: refactor
927
  #ifdef CONFIG_CFG80211_WEXT
b23aa676a   Samuel Ortiz   cfg80211: connect...
928
929
  	union iwreq_data wrqu;
  #endif
667503ddc   Johannes Berg   cfg80211: fix loc...
930
  	ASSERT_WDEV_LOCK(wdev);
074ac8df9   Johannes Berg   cfg80211/nl80211:...
931
932
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
  		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
b23aa676a   Samuel Ortiz   cfg80211: connect...
933
  		return;
b23aa676a   Samuel Ortiz   cfg80211: connect...
934
935
  	if (wdev->current_bss) {
  		cfg80211_unhold_bss(wdev->current_bss);
5b112d3d0   Johannes Berg   cfg80211: pass wi...
936
  		cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
b23aa676a   Samuel Ortiz   cfg80211: connect...
937
938
939
  	}
  
  	wdev->current_bss = NULL;
8dadadb7e   Johannes Berg   cfg80211: clear S...
940
  	wdev->ssid_len = 0;
bd2522b16   Andrzej Zaborowski   cfg80211: NL80211...
941
  	wdev->conn_owner_nlportid = 0;
f6bfc88f1   Avraham Stern   cfg80211: clear w...
942
943
  	kzfree(wdev->connect_keys);
  	wdev->connect_keys = NULL;
b23aa676a   Samuel Ortiz   cfg80211: connect...
944

fffd0934b   Johannes Berg   cfg80211: rework ...
945
  	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
b86071528   Arend van Spriel   cfg80211: stop cr...
946
947
948
949
950
  	/* stop critical protocol if supported */
  	if (rdev->ops->crit_proto_stop && rdev->crit_proto_nlportid) {
  		rdev->crit_proto_nlportid = 0;
  		rdev_crit_proto_stop(rdev, wdev);
  	}
fffd0934b   Johannes Berg   cfg80211: rework ...
951
952
953
954
955
956
  	/*
  	 * Delete all the keys ... pairwise keys can't really
  	 * exist any more anyway, but default keys might.
  	 */
  	if (rdev->ops->del_key)
  		for (i = 0; i < 6; i++)
e35e4d28b   Hila Gonen   cfg80211: add wra...
957
  			rdev_del_key(rdev, dev, i, false, NULL);
b23aa676a   Samuel Ortiz   cfg80211: connect...
958

fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
959
  	rdev_set_qos_map(rdev, dev, NULL);
3d23e349d   Johannes Berg   wext: refactor
960
  #ifdef CONFIG_CFG80211_WEXT
b23aa676a   Samuel Ortiz   cfg80211: connect...
961
962
963
  	memset(&wrqu, 0, sizeof(wrqu));
  	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
5f6120335   Abhijeet Kolekar   cfg80211: fix cha...
964
  	wdev->wext.connect.ssid_len = 0;
b23aa676a   Samuel Ortiz   cfg80211: connect...
965
  #endif
09d989d17   Luis R. Rodriguez   cfg80211: add reg...
966
967
  
  	schedule_work(&cfg80211_disconnect_work);
b23aa676a   Samuel Ortiz   cfg80211: connect...
968
969
970
  }
  
  void cfg80211_disconnected(struct net_device *dev, u16 reason,
80279fb7b   Johannes Berg   cfg80211: properl...
971
972
  			   const u8 *ie, size_t ie_len,
  			   bool locally_generated, gfp_t gfp)
b23aa676a   Samuel Ortiz   cfg80211: connect...
973
  {
667503ddc   Johannes Berg   cfg80211: fix loc...
974
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
975
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
667503ddc   Johannes Berg   cfg80211: fix loc...
976
977
978
979
980
981
982
983
984
985
986
987
  	struct cfg80211_event *ev;
  	unsigned long flags;
  
  	ev = kzalloc(sizeof(*ev) + ie_len, gfp);
  	if (!ev)
  		return;
  
  	ev->type = EVENT_DISCONNECTED;
  	ev->dc.ie = ((u8 *)ev) + sizeof(*ev);
  	ev->dc.ie_len = ie_len;
  	memcpy((void *)ev->dc.ie, ie, ie_len);
  	ev->dc.reason = reason;
80279fb7b   Johannes Berg   cfg80211: properl...
988
  	ev->dc.locally_generated = locally_generated;
667503ddc   Johannes Berg   cfg80211: fix loc...
989
990
991
992
  
  	spin_lock_irqsave(&wdev->event_lock, flags);
  	list_add_tail(&ev->list, &wdev->event_list);
  	spin_unlock_irqrestore(&wdev->event_lock, flags);
e60d7443e   Alban Browaeys   wireless : use a ...
993
  	queue_work(cfg80211_wq, &rdev->event_work);
b23aa676a   Samuel Ortiz   cfg80211: connect...
994
995
  }
  EXPORT_SYMBOL(cfg80211_disconnected);
ceca7b712   Johannes Berg   cfg80211: separat...
996
997
998
  /*
   * API calls for nl80211/wext compatibility code
   */
83739b03d   Johannes Berg   cfg80211: remove ...
999
1000
1001
1002
1003
  int cfg80211_connect(struct cfg80211_registered_device *rdev,
  		     struct net_device *dev,
  		     struct cfg80211_connect_params *connect,
  		     struct cfg80211_cached_keys *connkeys,
  		     const u8 *prev_bssid)
b23aa676a   Samuel Ortiz   cfg80211: connect...
1004
  {
b23aa676a   Samuel Ortiz   cfg80211: connect...
1005
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
667503ddc   Johannes Berg   cfg80211: fix loc...
1006
1007
1008
  	int err;
  
  	ASSERT_WDEV_LOCK(wdev);
b23aa676a   Samuel Ortiz   cfg80211: connect...
1009

51e13359c   Johannes Berg   cfg80211: fix con...
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  	/*
  	 * If we have an ssid_len, we're trying to connect or are
  	 * already connected, so reject a new SSID unless it's the
  	 * same (which is the case for re-association.)
  	 */
  	if (wdev->ssid_len &&
  	    (wdev->ssid_len != connect->ssid_len ||
  	     memcmp(wdev->ssid, connect->ssid, wdev->ssid_len)))
  		return -EALREADY;
  
  	/*
  	 * If connected, reject (re-)association unless prev_bssid
  	 * matches the current BSSID.
  	 */
  	if (wdev->current_bss) {
  		if (!prev_bssid)
  			return -EALREADY;
  		if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid))
  			return -ENOTCONN;
fffd0934b   Johannes Berg   cfg80211: rework ...
1029
  	}
51e13359c   Johannes Berg   cfg80211: fix con...
1030
1031
1032
1033
1034
1035
1036
  	/*
  	 * Reject if we're in the process of connecting with WEP,
  	 * this case isn't very interesting and trying to handle
  	 * it would make the code much more complex.
  	 */
  	if (wdev->connect_keys)
  		return -EINPROGRESS;
7e7c8926b   Ben Greear   wireless: Support...
1037
1038
  	cfg80211_oper_and_ht_capa(&connect->ht_capa_mask,
  				  rdev->wiphy.ht_capa_mod_mask);
fffd0934b   Johannes Berg   cfg80211: rework ...
1039
1040
  	if (connkeys && connkeys->def >= 0) {
  		int idx;
bcba8eae1   Samuel Ortiz   cfg80211: Set WEP...
1041
  		u32 cipher;
fffd0934b   Johannes Berg   cfg80211: rework ...
1042
1043
  
  		idx = connkeys->def;
bcba8eae1   Samuel Ortiz   cfg80211: Set WEP...
1044
  		cipher = connkeys->params[idx].cipher;
fffd0934b   Johannes Berg   cfg80211: rework ...
1045
  		/* If given a WEP key we may need it for shared key auth */
bcba8eae1   Samuel Ortiz   cfg80211: Set WEP...
1046
1047
  		if (cipher == WLAN_CIPHER_SUITE_WEP40 ||
  		    cipher == WLAN_CIPHER_SUITE_WEP104) {
fffd0934b   Johannes Berg   cfg80211: rework ...
1048
1049
1050
  			connect->key_idx = idx;
  			connect->key = connkeys->params[idx].key;
  			connect->key_len = connkeys->params[idx].key_len;
bcba8eae1   Samuel Ortiz   cfg80211: Set WEP...
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  
  			/*
  			 * If ciphers are not set (e.g. when going through
  			 * iwconfig), we have to set them appropriately here.
  			 */
  			if (connect->crypto.cipher_group == 0)
  				connect->crypto.cipher_group = cipher;
  
  			if (connect->crypto.n_ciphers_pairwise == 0) {
  				connect->crypto.n_ciphers_pairwise = 1;
  				connect->crypto.ciphers_pairwise[0] = cipher;
  			}
fffd0934b   Johannes Berg   cfg80211: rework ...
1063
  		}
b8676221f   David Spinadel   cfg80211: Add sup...
1064
1065
1066
  
  		connect->crypto.wep_keys = connkeys->params;
  		connect->crypto.wep_tx_key = connkeys->def;
f1c1f17ac   Johannes Berg   cfg80211: allow c...
1067
1068
1069
  	} else {
  		if (WARN_ON(connkeys))
  			return -EINVAL;
fffd0934b   Johannes Berg   cfg80211: rework ...
1070
  	}
ceca7b712   Johannes Berg   cfg80211: separat...
1071
1072
1073
  	wdev->connect_keys = connkeys;
  	memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
  	wdev->ssid_len = connect->ssid_len;
6829c878e   Johannes Berg   cfg80211: emulate...
1074

34d505193   Lior David   cfg80211: basic s...
1075
1076
  	wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS :
  					      IEEE80211_BSS_TYPE_ESS;
ceca7b712   Johannes Berg   cfg80211: separat...
1077
1078
1079
  	if (!rdev->ops->connect)
  		err = cfg80211_sme_connect(wdev, connect, prev_bssid);
  	else
e35e4d28b   Hila Gonen   cfg80211: add wra...
1080
  		err = rdev_connect(rdev, dev, connect);
b23aa676a   Samuel Ortiz   cfg80211: connect...
1081

ceca7b712   Johannes Berg   cfg80211: separat...
1082
1083
  	if (err) {
  		wdev->connect_keys = NULL;
51e13359c   Johannes Berg   cfg80211: fix con...
1084
1085
1086
1087
1088
1089
  		/*
  		 * This could be reassoc getting refused, don't clear
  		 * ssid_len in that case.
  		 */
  		if (!wdev->current_bss)
  			wdev->ssid_len = 0;
ceca7b712   Johannes Berg   cfg80211: separat...
1090
  		return err;
6829c878e   Johannes Berg   cfg80211: emulate...
1091
  	}
ceca7b712   Johannes Berg   cfg80211: separat...
1092
1093
  
  	return 0;
b23aa676a   Samuel Ortiz   cfg80211: connect...
1094
  }
83739b03d   Johannes Berg   cfg80211: remove ...
1095
1096
  int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
  			struct net_device *dev, u16 reason, bool wextev)
b23aa676a   Samuel Ortiz   cfg80211: connect...
1097
  {
6829c878e   Johannes Berg   cfg80211: emulate...
1098
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
dee8a9732   Johannes Berg   cfg80211: don't r...
1099
  	int err = 0;
b23aa676a   Samuel Ortiz   cfg80211: connect...
1100

667503ddc   Johannes Berg   cfg80211: fix loc...
1101
  	ASSERT_WDEV_LOCK(wdev);
b47f610bd   Johannes Berg   cfg80211: clear c...
1102
  	kzfree(wdev->connect_keys);
fffd0934b   Johannes Berg   cfg80211: rework ...
1103
  	wdev->connect_keys = NULL;
bd2522b16   Andrzej Zaborowski   cfg80211: NL80211...
1104
  	wdev->conn_owner_nlportid = 0;
dee8a9732   Johannes Berg   cfg80211: don't r...
1105
  	if (wdev->conn)
ceca7b712   Johannes Berg   cfg80211: separat...
1106
  		err = cfg80211_sme_disconnect(wdev, reason);
dee8a9732   Johannes Berg   cfg80211: don't r...
1107
  	else if (!rdev->ops->disconnect)
ceca7b712   Johannes Berg   cfg80211: separat...
1108
  		cfg80211_mlme_down(rdev, dev);
0711d6387   Ilan Peer   cfg80211: allow a...
1109
  	else if (wdev->ssid_len)
e35e4d28b   Hila Gonen   cfg80211: add wra...
1110
  		err = rdev_disconnect(rdev, dev, reason);
b23aa676a   Samuel Ortiz   cfg80211: connect...
1111

51e13359c   Johannes Berg   cfg80211: fix con...
1112
1113
1114
1115
1116
1117
1118
  	/*
  	 * Clear ssid_len unless we actually were fully connected,
  	 * in which case cfg80211_disconnected() will take care of
  	 * this later.
  	 */
  	if (!wdev->current_bss)
  		wdev->ssid_len = 0;
ceca7b712   Johannes Berg   cfg80211: separat...
1119
  	return err;
19957bb39   Johannes Berg   cfg80211: keep tr...
1120
  }
bd2522b16   Andrzej Zaborowski   cfg80211: NL80211...
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
  
  /*
   * Used to clean up after the connection / connection attempt owner socket
   * disconnects
   */
  void cfg80211_autodisconnect_wk(struct work_struct *work)
  {
  	struct wireless_dev *wdev =
  		container_of(work, struct wireless_dev, disconnect_wk);
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
  
  	wdev_lock(wdev);
  
  	if (wdev->conn_owner_nlportid) {
  		/*
  		 * Use disconnect_bssid if still connecting and ops->disconnect
  		 * not implemented.  Otherwise we can use cfg80211_disconnect.
  		 */
  		if (rdev->ops->disconnect || wdev->current_bss)
  			cfg80211_disconnect(rdev, wdev->netdev,
  					    WLAN_REASON_DEAUTH_LEAVING, true);
  		else
  			cfg80211_mlme_deauth(rdev, wdev->netdev,
  					     wdev->disconnect_bssid, NULL, 0,
  					     WLAN_REASON_DEAUTH_LEAVING, false);
  	}
  
  	wdev_unlock(wdev);
  }