blob: 3f2dfaf879c57ab2de5d7384c4df44c0701211cd [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/* Copyright (C) 2006, Red Hat, Inc. */
2
3#include <linux/bitops.h>
4#include <net/ieee80211.h>
5
6#include "assoc.h"
7#include "join.h"
8#include "decl.h"
9#include "hostcmd.h"
10#include "host.h"
11
12
13static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
14static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
15
16static int assoc_helper_essid(wlan_private *priv,
17 struct assoc_request * assoc_req)
18{
19 wlan_adapter *adapter = priv->adapter;
20 int ret = 0;
Dan Williamsfcdb53d2007-05-25 16:15:56 -040021 struct bss_descriptor * bss;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020022
Holger Schurig9012b282007-05-25 11:27:16 -040023 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020024
Dan Williamsef9a2642007-05-25 16:46:33 -040025 /* FIXME: take channel into account when picking SSIDs if a channel
26 * is set.
27 */
28
Holger Schurig9012b282007-05-25 11:27:16 -040029 lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
Dan Williams0dc5a292007-05-10 22:58:02 -040030 if (assoc_req->mode == IW_MODE_INFRA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020031 if (adapter->prescan) {
Dan Williamseb8f7332007-05-25 16:25:21 -040032 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020033 }
34
Dan Williamsfcdb53d2007-05-25 16:15:56 -040035 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
Dan Williams0dc5a292007-05-10 22:58:02 -040036 NULL, IW_MODE_INFRA);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040037 if (bss != NULL) {
38 lbs_deb_assoc("SSID found in scan list, associating\n");
39 ret = wlan_associate(priv, bss);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020040 if (ret == 0) {
Dan Williamsfcdb53d2007-05-25 16:15:56 -040041 memcpy(&assoc_req->bssid, bss->bssid, ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020042 }
43 } else {
Holger Schurig9012b282007-05-25 11:27:16 -040044 lbs_deb_assoc("SSID '%s' not found; cannot associate\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020045 assoc_req->ssid.ssid);
46 }
Dan Williams0dc5a292007-05-10 22:58:02 -040047 } else if (assoc_req->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020048 /* Scan for the network, do not save previous results. Stale
49 * scan data will cause us to join a non-existant adhoc network
50 */
Dan Williamseb8f7332007-05-25 16:25:21 -040051 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020052
53 /* Search for the requested SSID in the scan table */
Dan Williamsfcdb53d2007-05-25 16:15:56 -040054 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
Dan Williams0dc5a292007-05-10 22:58:02 -040055 IW_MODE_ADHOC);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040056 if (bss != NULL) {
57 lbs_deb_assoc("SSID found joining\n");
58 libertas_join_adhoc_network(priv, bss);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020059 } else {
60 /* else send START command */
Holger Schurig9012b282007-05-25 11:27:16 -040061 lbs_deb_assoc("SSID not found in list, so creating adhoc"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020062 " with SSID '%s'\n", assoc_req->ssid.ssid);
63 libertas_start_adhoc_network(priv, &assoc_req->ssid);
64 }
65 memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN);
66 }
67
Holger Schurig9012b282007-05-25 11:27:16 -040068 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020069 return ret;
70}
71
72
73static int assoc_helper_bssid(wlan_private *priv,
74 struct assoc_request * assoc_req)
75{
76 wlan_adapter *adapter = priv->adapter;
Dan Williamsfcdb53d2007-05-25 16:15:56 -040077 int ret = 0;
78 struct bss_descriptor * bss;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020079
Holger Schurig9012b282007-05-25 11:27:16 -040080 lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID" MAC_FMT "\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020081 MAC_ARG(assoc_req->bssid));
82
83 /* Search for index position in list for requested MAC */
Dan Williamsfcdb53d2007-05-25 16:15:56 -040084 bss = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020085 assoc_req->mode);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040086 if (bss == NULL) {
Holger Schurig9012b282007-05-25 11:27:16 -040087 lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020088 "cannot associate.\n", MAC_ARG(assoc_req->bssid));
89 goto out;
90 }
91
Dan Williams0dc5a292007-05-10 22:58:02 -040092 if (assoc_req->mode == IW_MODE_INFRA) {
Dan Williamsfcdb53d2007-05-25 16:15:56 -040093 ret = wlan_associate(priv, bss);
94 lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
Dan Williams0dc5a292007-05-10 22:58:02 -040095 } else if (assoc_req->mode == IW_MODE_ADHOC) {
Dan Williamsfcdb53d2007-05-25 16:15:56 -040096 libertas_join_adhoc_network(priv, bss);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020097 }
Dan Williamsfcdb53d2007-05-25 16:15:56 -040098 memcpy(&assoc_req->ssid, &bss->ssid, sizeof(struct WLAN_802_11_SSID));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020099
100out:
Holger Schurig9012b282007-05-25 11:27:16 -0400101 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200102 return ret;
103}
104
105
106static int assoc_helper_associate(wlan_private *priv,
107 struct assoc_request * assoc_req)
108{
109 int ret = 0, done = 0;
110
111 /* If we're given and 'any' BSSID, try associating based on SSID */
112
113 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
114 if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
115 && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
116 ret = assoc_helper_bssid(priv, assoc_req);
117 done = 1;
118 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400119 lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200120 }
121 }
122 }
123
124 if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
125 ret = assoc_helper_essid(priv, assoc_req);
126 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400127 lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200128 }
129 }
130
131 return ret;
132}
133
134
135static int assoc_helper_mode(wlan_private *priv,
136 struct assoc_request * assoc_req)
137{
138 wlan_adapter *adapter = priv->adapter;
139 int ret = 0;
140
Holger Schurig9012b282007-05-25 11:27:16 -0400141 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200142
Holger Schurig9012b282007-05-25 11:27:16 -0400143 if (assoc_req->mode == adapter->mode)
144 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200145
Dan Williams0dc5a292007-05-10 22:58:02 -0400146 if (assoc_req->mode == IW_MODE_INFRA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200147 if (adapter->psstate != PS_STATE_FULL_POWER)
148 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
149 adapter->psmode = wlan802_11powermodecam;
150 }
151
Dan Williams0dc5a292007-05-10 22:58:02 -0400152 adapter->mode = assoc_req->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200153 ret = libertas_prepare_and_send_command(priv,
154 cmd_802_11_snmp_mib,
155 0, cmd_option_waitforrsp,
156 OID_802_11_INFRASTRUCTURE_MODE,
Dan Williams0dc5a292007-05-10 22:58:02 -0400157 (void *) (size_t) assoc_req->mode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200158
Holger Schurig9012b282007-05-25 11:27:16 -0400159done:
160 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200161 return ret;
162}
163
164
Dan Williamsef9a2642007-05-25 16:46:33 -0400165static int update_channel(wlan_private * priv)
166{
167 /* the channel in f/w could be out of sync, get the current channel */
168 return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
169 cmd_opt_802_11_rf_channel_get,
170 cmd_option_waitforrsp, 0, NULL);
171}
172
173static int assoc_helper_channel(wlan_private *priv,
174 struct assoc_request * assoc_req)
175{
176 wlan_adapter *adapter = priv->adapter;
177 int ret = 0;
178
179 lbs_deb_enter(LBS_DEB_ASSOC);
180
181 ret = update_channel(priv);
182 if (ret < 0) {
183 lbs_deb_assoc("ASSOC: channel: error getting channel.");
184 }
185
186 if (assoc_req->channel == adapter->curbssparams.channel)
187 goto done;
188
189 lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
190 adapter->curbssparams.channel, assoc_req->channel);
191
192 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
193 cmd_opt_802_11_rf_channel_set,
194 cmd_option_waitforrsp, 0, &assoc_req->channel);
195 if (ret < 0) {
196 lbs_deb_assoc("ASSOC: channel: error setting channel.");
197 }
198
199 ret = update_channel(priv);
200 if (ret < 0) {
201 lbs_deb_assoc("ASSOC: channel: error getting channel.");
202 }
203
204 if (assoc_req->channel != adapter->curbssparams.channel) {
205 lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
206 assoc_req->channel);
207 goto done;
208 }
209
210 if ( assoc_req->secinfo.wep_enabled
211 && (assoc_req->wep_keys[0].len
212 || assoc_req->wep_keys[1].len
213 || assoc_req->wep_keys[2].len
214 || assoc_req->wep_keys[3].len)) {
215 /* Make sure WEP keys are re-sent to firmware */
216 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
217 }
218
219 /* Must restart/rejoin adhoc networks after channel change */
220 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
221
222done:
223 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
224 return ret;
225}
226
227
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200228static int assoc_helper_wep_keys(wlan_private *priv,
229 struct assoc_request * assoc_req)
230{
231 wlan_adapter *adapter = priv->adapter;
232 int i;
233 int ret = 0;
234
Holger Schurig9012b282007-05-25 11:27:16 -0400235 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200236
237 /* Set or remove WEP keys */
238 if ( assoc_req->wep_keys[0].len
239 || assoc_req->wep_keys[1].len
240 || assoc_req->wep_keys[2].len
241 || assoc_req->wep_keys[3].len) {
242 ret = libertas_prepare_and_send_command(priv,
243 cmd_802_11_set_wep,
244 cmd_act_add,
245 cmd_option_waitforrsp,
246 0, assoc_req);
247 } else {
248 ret = libertas_prepare_and_send_command(priv,
249 cmd_802_11_set_wep,
250 cmd_act_remove,
251 cmd_option_waitforrsp,
252 0, NULL);
253 }
254
255 if (ret)
256 goto out;
257
258 /* enable/disable the MAC's WEP packet filter */
Dan Williams889c05b2007-05-10 22:57:23 -0400259 if (assoc_req->secinfo.wep_enabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200260 adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
261 else
262 adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
263 ret = libertas_set_mac_packet_filter(priv);
264 if (ret)
265 goto out;
266
267 mutex_lock(&adapter->lock);
268
269 /* Copy WEP keys into adapter wep key fields */
270 for (i = 0; i < 4; i++) {
271 memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
272 sizeof(struct WLAN_802_11_KEY));
273 }
274 adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
275
276 mutex_unlock(&adapter->lock);
277
278out:
Holger Schurig9012b282007-05-25 11:27:16 -0400279 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200280 return ret;
281}
282
283static int assoc_helper_secinfo(wlan_private *priv,
284 struct assoc_request * assoc_req)
285{
286 wlan_adapter *adapter = priv->adapter;
287 int ret = 0;
288
Holger Schurig9012b282007-05-25 11:27:16 -0400289 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200290
291 memcpy(&adapter->secinfo, &assoc_req->secinfo,
292 sizeof(struct wlan_802_11_security));
293
294 ret = libertas_set_mac_packet_filter(priv);
295
Holger Schurig9012b282007-05-25 11:27:16 -0400296 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200297 return ret;
298}
299
300
301static int assoc_helper_wpa_keys(wlan_private *priv,
302 struct assoc_request * assoc_req)
303{
304 int ret = 0;
305
Holger Schurig9012b282007-05-25 11:27:16 -0400306 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200307
308 /* enable/Disable RSN */
309 ret = libertas_prepare_and_send_command(priv,
310 cmd_802_11_enable_rsn,
311 cmd_act_set,
312 cmd_option_waitforrsp,
313 0, assoc_req);
314 if (ret)
315 goto out;
316
317 ret = libertas_prepare_and_send_command(priv,
318 cmd_802_11_key_material,
319 cmd_act_set,
320 cmd_option_waitforrsp,
321 0, assoc_req);
322
323out:
Holger Schurig9012b282007-05-25 11:27:16 -0400324 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200325 return ret;
326}
327
328
329static int assoc_helper_wpa_ie(wlan_private *priv,
330 struct assoc_request * assoc_req)
331{
332 wlan_adapter *adapter = priv->adapter;
333 int ret = 0;
334
Holger Schurig9012b282007-05-25 11:27:16 -0400335 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200336
337 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
338 memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
339 adapter->wpa_ie_len = assoc_req->wpa_ie_len;
340 } else {
341 memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
342 adapter->wpa_ie_len = 0;
343 }
344
Holger Schurig9012b282007-05-25 11:27:16 -0400345 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200346 return ret;
347}
348
349
350static int should_deauth_infrastructure(wlan_adapter *adapter,
351 struct assoc_request * assoc_req)
352{
353 if (adapter->connect_status != libertas_connected)
354 return 0;
355
356 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400357 lbs_deb_assoc("Deauthenticating due to new SSID in "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200358 " configuration request.\n");
359 return 1;
360 }
361
362 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
Dan Williams6affe782007-05-10 22:56:42 -0400363 if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
Holger Schurig9012b282007-05-25 11:27:16 -0400364 lbs_deb_assoc("Deauthenticating due to updated security "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200365 "info in configuration request.\n");
366 return 1;
367 }
368 }
369
370 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400371 lbs_deb_assoc("Deauthenticating due to new BSSID in "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200372 " configuration request.\n");
373 return 1;
374 }
375
376 /* FIXME: deal with 'auto' mode somehow */
377 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400378 if (assoc_req->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200379 return 1;
380 }
381
382 return 0;
383}
384
385
386static int should_stop_adhoc(wlan_adapter *adapter,
387 struct assoc_request * assoc_req)
388{
389 if (adapter->connect_status != libertas_connected)
390 return 0;
391
392 if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
393 return 1;
394 if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
Dan Williamsad1f3292007-05-10 22:52:37 -0400395 adapter->curbssparams.ssid.ssidlength))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200396 return 1;
397
398 /* FIXME: deal with 'auto' mode somehow */
399 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400400 if (assoc_req->mode != IW_MODE_ADHOC)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200401 return 1;
402 }
403
Dan Williamsef9a2642007-05-25 16:46:33 -0400404 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
405 if (assoc_req->channel != adapter->curbssparams.channel)
406 return 1;
407 }
408
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200409 return 0;
410}
411
412
Holger Schurigeb3ce632007-05-24 23:41:15 -0400413void libertas_association_worker(struct work_struct *work)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200414{
415 wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
416 wlan_adapter *adapter = priv->adapter;
417 struct assoc_request * assoc_req = NULL;
418 int ret = 0;
419 int find_any_ssid = 0;
420
Holger Schurig9012b282007-05-25 11:27:16 -0400421 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200422
423 mutex_lock(&adapter->lock);
424 assoc_req = adapter->assoc_req;
425 adapter->assoc_req = NULL;
426 mutex_unlock(&adapter->lock);
427
Holger Schurig9012b282007-05-25 11:27:16 -0400428 if (!assoc_req)
429 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200430
Holger Schurig9012b282007-05-25 11:27:16 -0400431 lbs_deb_assoc("ASSOC: starting new association request: flags = 0x%lX\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200432 assoc_req->flags);
433
434 /* If 'any' SSID was specified, find an SSID to associate with */
435 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
436 && !assoc_req->ssid.ssidlength)
437 find_any_ssid = 1;
438
439 /* But don't use 'any' SSID if there's a valid locked BSSID to use */
440 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
441 if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
442 && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
443 find_any_ssid = 0;
444 }
445
446 if (find_any_ssid) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400447 u8 new_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200448
449 ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
450 assoc_req->mode, &new_mode);
451 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400452 lbs_deb_assoc("Could not find best network\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200453 ret = -ENETUNREACH;
454 goto out;
455 }
456
457 /* Ensure we switch to the mode of the AP */
Dan Williams0dc5a292007-05-10 22:58:02 -0400458 if (assoc_req->mode == IW_MODE_AUTO) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200459 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
460 assoc_req->mode = new_mode;
461 }
462 }
463
464 /*
465 * Check if the attributes being changing require deauthentication
466 * from the currently associated infrastructure access point.
467 */
Dan Williams0dc5a292007-05-10 22:58:02 -0400468 if (adapter->mode == IW_MODE_INFRA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200469 if (should_deauth_infrastructure(adapter, assoc_req)) {
470 ret = libertas_send_deauthentication(priv);
471 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400472 lbs_deb_assoc("Deauthentication due to new "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200473 "configuration request failed: %d\n",
474 ret);
475 }
476 }
Dan Williams0dc5a292007-05-10 22:58:02 -0400477 } else if (adapter->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200478 if (should_stop_adhoc(adapter, assoc_req)) {
479 ret = libertas_stop_adhoc_network(priv);
480 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400481 lbs_deb_assoc("Teardown of AdHoc network due to "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482 "new configuration request failed: %d\n",
483 ret);
484 }
485
486 }
487 }
488
489 /* Send the various configuration bits to the firmware */
490 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
491 ret = assoc_helper_mode(priv, assoc_req);
492 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400493lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200494 goto out;
495 }
496 }
497
Dan Williamsef9a2642007-05-25 16:46:33 -0400498 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
499 ret = assoc_helper_channel(priv, assoc_req);
500 if (ret) {
501 lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n",
502 __LINE__, ret);
503 goto out;
504 }
505 }
506
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200507 if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
508 || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
509 ret = assoc_helper_wep_keys(priv, assoc_req);
510 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400511lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200512 goto out;
513 }
514 }
515
516 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
517 ret = assoc_helper_secinfo(priv, assoc_req);
518 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400519lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200520 goto out;
521 }
522 }
523
524 if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
525 ret = assoc_helper_wpa_ie(priv, assoc_req);
526 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400527lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200528 goto out;
529 }
530 }
531
532 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
533 || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
534 ret = assoc_helper_wpa_keys(priv, assoc_req);
535 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400536lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200537 goto out;
538 }
539 }
540
541 /* SSID/BSSID should be the _last_ config option set, because they
542 * trigger the association attempt.
543 */
544 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
545 || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
546 int success = 1;
547
548 ret = assoc_helper_associate(priv, assoc_req);
549 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400550 lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200551 ret);
552 success = 0;
553 }
554
555 if (adapter->connect_status != libertas_connected) {
Holger Schurig9012b282007-05-25 11:27:16 -0400556 lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200557 "not connected.\n");
558 success = 0;
559 }
560
561 if (success) {
Holger Schurig9012b282007-05-25 11:27:16 -0400562 lbs_deb_assoc("ASSOC: association attempt successful. "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200563 "Associated to '%s' (" MAC_FMT ")\n",
564 assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
565 libertas_prepare_and_send_command(priv,
566 cmd_802_11_rssi,
567 0, cmd_option_waitforrsp, 0, NULL);
568
569 libertas_prepare_and_send_command(priv,
570 cmd_802_11_get_log,
571 0, cmd_option_waitforrsp, 0, NULL);
572 } else {
573
574 ret = -1;
575 }
576 }
577
578out:
579 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400580 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200581 ret);
582 }
583 kfree(assoc_req);
Holger Schurig9012b282007-05-25 11:27:16 -0400584
585done:
586 lbs_deb_leave(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200587}
588
589
590/*
591 * Caller MUST hold any necessary locks
592 */
593struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
594{
595 struct assoc_request * assoc_req;
596
597 if (!adapter->assoc_req) {
598 adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
599 if (!adapter->assoc_req) {
600 lbs_pr_info("Not enough memory to allocate association"
601 " request!\n");
602 return NULL;
603 }
604 }
605
606 /* Copy current configuration attributes to the association request,
607 * but don't overwrite any that are already set.
608 */
609 assoc_req = adapter->assoc_req;
610 if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
611 memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
612 adapter->curbssparams.ssid.ssidlength);
613 }
614
615 if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
616 assoc_req->channel = adapter->curbssparams.channel;
617
618 if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
Dan Williams0dc5a292007-05-10 22:58:02 -0400619 assoc_req->mode = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200620
621 if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
622 memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
623 ETH_ALEN);
624 }
625
626 if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
627 int i;
628 for (i = 0; i < 4; i++) {
629 memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
630 sizeof(struct WLAN_802_11_KEY));
631 }
632 }
633
634 if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
635 assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
636
637 if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
638 memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
639 sizeof(struct WLAN_802_11_KEY));
640 }
641
642 if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
643 memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
644 sizeof(struct WLAN_802_11_KEY));
645 }
646
647 if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
648 memcpy(&assoc_req->secinfo, &adapter->secinfo,
649 sizeof(struct wlan_802_11_security));
650 }
651
652 if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
653 memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
654 MAX_WPA_IE_LEN);
655 assoc_req->wpa_ie_len = adapter->wpa_ie_len;
656 }
657
658 return assoc_req;
659}
660
661