blob: b18464224b952eeb55c82ea306f0042744748ddd [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
Dan Williamse76850d2007-05-25 17:09:41 -040016/* From ieee80211_module.c */
17static const char *libertas_escape_essid(const char *essid, u8 essid_len)
18{
19 static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
20 const char *s = essid;
21 char *d = escaped;
22
23 if (ieee80211_is_empty_essid(essid, essid_len))
24 return "";
25
26 essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
27 while (essid_len--) {
28 if (*s == '\0') {
29 *d++ = '\\';
30 *d++ = '0';
31 s++;
32 } else {
33 *d++ = *s++;
34 }
35 }
36 *d = '\0';
37 return escaped;
38}
39
40static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
41{
42 lbs_deb_assoc(
43 "#### Association Request: %s\n"
44 " flags: 0x%08lX\n"
45 " SSID: '%s'\n"
46 " channel: %d\n"
47 " band: %d\n"
48 " mode: %d\n"
49 " BSSID: " MAC_FMT "\n"
50 " WPA: %d\n"
51 " WPA2: %d\n"
52 " WEP status: %d\n"
53 " auth: %d\n"
54 " auth_alg: %d\n"
55 " encmode: %d\n",
56 extra, assoc_req->flags,
57 libertas_escape_essid(assoc_req->ssid.ssid, assoc_req->ssid.ssidlength),
58 assoc_req->channel, assoc_req->band, assoc_req->mode,
59 MAC_ARG(assoc_req->bssid), assoc_req->secinfo.WPAenabled,
60 assoc_req->secinfo.WPA2enabled, assoc_req->secinfo.WEPstatus,
61 assoc_req->secinfo.authmode, assoc_req->secinfo.auth1xalg,
62 assoc_req->secinfo.Encryptionmode);
63}
64
65
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020066static int assoc_helper_essid(wlan_private *priv,
67 struct assoc_request * assoc_req)
68{
69 wlan_adapter *adapter = priv->adapter;
70 int ret = 0;
Dan Williamsfcdb53d2007-05-25 16:15:56 -040071 struct bss_descriptor * bss;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020072
Holger Schurig9012b282007-05-25 11:27:16 -040073 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020074
Dan Williamsef9a2642007-05-25 16:46:33 -040075 /* FIXME: take channel into account when picking SSIDs if a channel
76 * is set.
77 */
78
Holger Schurig9012b282007-05-25 11:27:16 -040079 lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
Dan Williams0dc5a292007-05-10 22:58:02 -040080 if (assoc_req->mode == IW_MODE_INFRA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020081 if (adapter->prescan) {
Dan Williamseb8f7332007-05-25 16:25:21 -040082 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020083 }
84
Dan Williamsfcdb53d2007-05-25 16:15:56 -040085 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
Dan Williams0dc5a292007-05-10 22:58:02 -040086 NULL, IW_MODE_INFRA);
Dan Williamsfcdb53d2007-05-25 16:15:56 -040087 if (bss != NULL) {
88 lbs_deb_assoc("SSID found in scan list, associating\n");
Dan Williamse76850d2007-05-25 17:09:41 -040089 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
90 ret = wlan_associate(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020091 } else {
Holger Schurig9012b282007-05-25 11:27:16 -040092 lbs_deb_assoc("SSID '%s' not found; cannot associate\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020093 assoc_req->ssid.ssid);
94 }
Dan Williams0dc5a292007-05-10 22:58:02 -040095 } else if (assoc_req->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020096 /* Scan for the network, do not save previous results. Stale
97 * scan data will cause us to join a non-existant adhoc network
98 */
Dan Williamseb8f7332007-05-25 16:25:21 -040099 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200100
101 /* Search for the requested SSID in the scan table */
Dan Williamsfcdb53d2007-05-25 16:15:56 -0400102 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
Dan Williams0dc5a292007-05-10 22:58:02 -0400103 IW_MODE_ADHOC);
Dan Williamsfcdb53d2007-05-25 16:15:56 -0400104 if (bss != NULL) {
105 lbs_deb_assoc("SSID found joining\n");
Dan Williamse76850d2007-05-25 17:09:41 -0400106 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
107 libertas_join_adhoc_network(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200108 } else {
109 /* else send START command */
Holger Schurig9012b282007-05-25 11:27:16 -0400110 lbs_deb_assoc("SSID not found in list, so creating adhoc"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200111 " with SSID '%s'\n", assoc_req->ssid.ssid);
Dan Williamse76850d2007-05-25 17:09:41 -0400112 memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
113 sizeof(struct WLAN_802_11_SSID));
114 libertas_start_adhoc_network(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200115 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200116 }
117
Holger Schurig9012b282007-05-25 11:27:16 -0400118 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200119 return ret;
120}
121
122
123static int assoc_helper_bssid(wlan_private *priv,
124 struct assoc_request * assoc_req)
125{
126 wlan_adapter *adapter = priv->adapter;
Dan Williamsfcdb53d2007-05-25 16:15:56 -0400127 int ret = 0;
128 struct bss_descriptor * bss;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200129
Holger Schurig9012b282007-05-25 11:27:16 -0400130 lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID" MAC_FMT "\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200131 MAC_ARG(assoc_req->bssid));
132
133 /* Search for index position in list for requested MAC */
Dan Williamsfcdb53d2007-05-25 16:15:56 -0400134 bss = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200135 assoc_req->mode);
Dan Williamsfcdb53d2007-05-25 16:15:56 -0400136 if (bss == NULL) {
Holger Schurig9012b282007-05-25 11:27:16 -0400137 lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200138 "cannot associate.\n", MAC_ARG(assoc_req->bssid));
139 goto out;
140 }
141
Dan Williamse76850d2007-05-25 17:09:41 -0400142 memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
Dan Williams0dc5a292007-05-10 22:58:02 -0400143 if (assoc_req->mode == IW_MODE_INFRA) {
Dan Williamse76850d2007-05-25 17:09:41 -0400144 ret = wlan_associate(priv, assoc_req);
Dan Williamsfcdb53d2007-05-25 16:15:56 -0400145 lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
Dan Williams0dc5a292007-05-10 22:58:02 -0400146 } else if (assoc_req->mode == IW_MODE_ADHOC) {
Dan Williamse76850d2007-05-25 17:09:41 -0400147 libertas_join_adhoc_network(priv, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200148 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200149
150out:
Holger Schurig9012b282007-05-25 11:27:16 -0400151 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200152 return ret;
153}
154
155
156static int assoc_helper_associate(wlan_private *priv,
157 struct assoc_request * assoc_req)
158{
159 int ret = 0, done = 0;
160
161 /* If we're given and 'any' BSSID, try associating based on SSID */
162
163 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
164 if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
165 && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
166 ret = assoc_helper_bssid(priv, assoc_req);
167 done = 1;
168 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400169 lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200170 }
171 }
172 }
173
174 if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
175 ret = assoc_helper_essid(priv, assoc_req);
176 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400177 lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200178 }
179 }
180
181 return ret;
182}
183
184
185static int assoc_helper_mode(wlan_private *priv,
186 struct assoc_request * assoc_req)
187{
188 wlan_adapter *adapter = priv->adapter;
189 int ret = 0;
190
Holger Schurig9012b282007-05-25 11:27:16 -0400191 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200192
Holger Schurig9012b282007-05-25 11:27:16 -0400193 if (assoc_req->mode == adapter->mode)
194 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200195
Dan Williams0dc5a292007-05-10 22:58:02 -0400196 if (assoc_req->mode == IW_MODE_INFRA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200197 if (adapter->psstate != PS_STATE_FULL_POWER)
198 libertas_ps_wakeup(priv, cmd_option_waitforrsp);
199 adapter->psmode = wlan802_11powermodecam;
200 }
201
Dan Williams0dc5a292007-05-10 22:58:02 -0400202 adapter->mode = assoc_req->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200203 ret = libertas_prepare_and_send_command(priv,
204 cmd_802_11_snmp_mib,
205 0, cmd_option_waitforrsp,
206 OID_802_11_INFRASTRUCTURE_MODE,
Dan Williams0dc5a292007-05-10 22:58:02 -0400207 (void *) (size_t) assoc_req->mode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200208
Holger Schurig9012b282007-05-25 11:27:16 -0400209done:
210 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200211 return ret;
212}
213
214
Dan Williamsef9a2642007-05-25 16:46:33 -0400215static int update_channel(wlan_private * priv)
216{
217 /* the channel in f/w could be out of sync, get the current channel */
218 return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
219 cmd_opt_802_11_rf_channel_get,
220 cmd_option_waitforrsp, 0, NULL);
221}
222
223static int assoc_helper_channel(wlan_private *priv,
224 struct assoc_request * assoc_req)
225{
226 wlan_adapter *adapter = priv->adapter;
227 int ret = 0;
228
229 lbs_deb_enter(LBS_DEB_ASSOC);
230
231 ret = update_channel(priv);
232 if (ret < 0) {
233 lbs_deb_assoc("ASSOC: channel: error getting channel.");
234 }
235
236 if (assoc_req->channel == adapter->curbssparams.channel)
237 goto done;
238
239 lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
240 adapter->curbssparams.channel, assoc_req->channel);
241
242 ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
243 cmd_opt_802_11_rf_channel_set,
244 cmd_option_waitforrsp, 0, &assoc_req->channel);
245 if (ret < 0) {
246 lbs_deb_assoc("ASSOC: channel: error setting channel.");
247 }
248
249 ret = update_channel(priv);
250 if (ret < 0) {
251 lbs_deb_assoc("ASSOC: channel: error getting channel.");
252 }
253
254 if (assoc_req->channel != adapter->curbssparams.channel) {
255 lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
256 assoc_req->channel);
257 goto done;
258 }
259
260 if ( assoc_req->secinfo.wep_enabled
261 && (assoc_req->wep_keys[0].len
262 || assoc_req->wep_keys[1].len
263 || assoc_req->wep_keys[2].len
264 || assoc_req->wep_keys[3].len)) {
265 /* Make sure WEP keys are re-sent to firmware */
266 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
267 }
268
269 /* Must restart/rejoin adhoc networks after channel change */
270 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
271
272done:
273 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
274 return ret;
275}
276
277
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200278static int assoc_helper_wep_keys(wlan_private *priv,
279 struct assoc_request * assoc_req)
280{
281 wlan_adapter *adapter = priv->adapter;
282 int i;
283 int ret = 0;
284
Holger Schurig9012b282007-05-25 11:27:16 -0400285 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200286
287 /* Set or remove WEP keys */
288 if ( assoc_req->wep_keys[0].len
289 || assoc_req->wep_keys[1].len
290 || assoc_req->wep_keys[2].len
291 || assoc_req->wep_keys[3].len) {
292 ret = libertas_prepare_and_send_command(priv,
293 cmd_802_11_set_wep,
294 cmd_act_add,
295 cmd_option_waitforrsp,
296 0, assoc_req);
297 } else {
298 ret = libertas_prepare_and_send_command(priv,
299 cmd_802_11_set_wep,
300 cmd_act_remove,
301 cmd_option_waitforrsp,
302 0, NULL);
303 }
304
305 if (ret)
306 goto out;
307
308 /* enable/disable the MAC's WEP packet filter */
Dan Williams889c05b2007-05-10 22:57:23 -0400309 if (assoc_req->secinfo.wep_enabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200310 adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
311 else
312 adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
313 ret = libertas_set_mac_packet_filter(priv);
314 if (ret)
315 goto out;
316
317 mutex_lock(&adapter->lock);
318
319 /* Copy WEP keys into adapter wep key fields */
320 for (i = 0; i < 4; i++) {
321 memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
322 sizeof(struct WLAN_802_11_KEY));
323 }
324 adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
325
326 mutex_unlock(&adapter->lock);
327
328out:
Holger Schurig9012b282007-05-25 11:27:16 -0400329 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200330 return ret;
331}
332
333static int assoc_helper_secinfo(wlan_private *priv,
334 struct assoc_request * assoc_req)
335{
336 wlan_adapter *adapter = priv->adapter;
337 int ret = 0;
338
Holger Schurig9012b282007-05-25 11:27:16 -0400339 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200340
341 memcpy(&adapter->secinfo, &assoc_req->secinfo,
342 sizeof(struct wlan_802_11_security));
343
344 ret = libertas_set_mac_packet_filter(priv);
345
Holger Schurig9012b282007-05-25 11:27:16 -0400346 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200347 return ret;
348}
349
350
351static int assoc_helper_wpa_keys(wlan_private *priv,
352 struct assoc_request * assoc_req)
353{
354 int ret = 0;
355
Holger Schurig9012b282007-05-25 11:27:16 -0400356 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200357
358 /* enable/Disable RSN */
359 ret = libertas_prepare_and_send_command(priv,
360 cmd_802_11_enable_rsn,
361 cmd_act_set,
362 cmd_option_waitforrsp,
363 0, assoc_req);
364 if (ret)
365 goto out;
366
367 ret = libertas_prepare_and_send_command(priv,
368 cmd_802_11_key_material,
369 cmd_act_set,
370 cmd_option_waitforrsp,
371 0, assoc_req);
372
373out:
Holger Schurig9012b282007-05-25 11:27:16 -0400374 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200375 return ret;
376}
377
378
379static int assoc_helper_wpa_ie(wlan_private *priv,
380 struct assoc_request * assoc_req)
381{
382 wlan_adapter *adapter = priv->adapter;
383 int ret = 0;
384
Holger Schurig9012b282007-05-25 11:27:16 -0400385 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200386
387 if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
388 memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
389 adapter->wpa_ie_len = assoc_req->wpa_ie_len;
390 } else {
391 memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
392 adapter->wpa_ie_len = 0;
393 }
394
Holger Schurig9012b282007-05-25 11:27:16 -0400395 lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200396 return ret;
397}
398
399
400static int should_deauth_infrastructure(wlan_adapter *adapter,
401 struct assoc_request * assoc_req)
402{
403 if (adapter->connect_status != libertas_connected)
404 return 0;
405
406 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400407 lbs_deb_assoc("Deauthenticating due to new SSID in "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200408 " configuration request.\n");
409 return 1;
410 }
411
412 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
Dan Williams6affe782007-05-10 22:56:42 -0400413 if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
Holger Schurig9012b282007-05-25 11:27:16 -0400414 lbs_deb_assoc("Deauthenticating due to updated security "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200415 "info in configuration request.\n");
416 return 1;
417 }
418 }
419
420 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400421 lbs_deb_assoc("Deauthenticating due to new BSSID in "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200422 " configuration request.\n");
423 return 1;
424 }
425
426 /* FIXME: deal with 'auto' mode somehow */
427 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400428 if (assoc_req->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200429 return 1;
430 }
431
432 return 0;
433}
434
435
436static int should_stop_adhoc(wlan_adapter *adapter,
437 struct assoc_request * assoc_req)
438{
439 if (adapter->connect_status != libertas_connected)
440 return 0;
441
442 if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
443 return 1;
444 if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
Dan Williamsad1f3292007-05-10 22:52:37 -0400445 adapter->curbssparams.ssid.ssidlength))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200446 return 1;
447
448 /* FIXME: deal with 'auto' mode somehow */
449 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400450 if (assoc_req->mode != IW_MODE_ADHOC)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200451 return 1;
452 }
453
Dan Williamsef9a2642007-05-25 16:46:33 -0400454 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
455 if (assoc_req->channel != adapter->curbssparams.channel)
456 return 1;
457 }
458
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200459 return 0;
460}
461
462
Holger Schurigeb3ce632007-05-24 23:41:15 -0400463void libertas_association_worker(struct work_struct *work)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200464{
465 wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
466 wlan_adapter *adapter = priv->adapter;
467 struct assoc_request * assoc_req = NULL;
468 int ret = 0;
469 int find_any_ssid = 0;
470
Holger Schurig9012b282007-05-25 11:27:16 -0400471 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200472
473 mutex_lock(&adapter->lock);
Dan Williamse76850d2007-05-25 17:09:41 -0400474 assoc_req = adapter->pending_assoc_req;
475 adapter->pending_assoc_req = NULL;
476 adapter->in_progress_assoc_req = assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200477 mutex_unlock(&adapter->lock);
478
Holger Schurig9012b282007-05-25 11:27:16 -0400479 if (!assoc_req)
480 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200481
Dan Williamse76850d2007-05-25 17:09:41 -0400482 print_assoc_req(__func__, assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200483
484 /* If 'any' SSID was specified, find an SSID to associate with */
485 if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
486 && !assoc_req->ssid.ssidlength)
487 find_any_ssid = 1;
488
489 /* But don't use 'any' SSID if there's a valid locked BSSID to use */
490 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
491 if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
492 && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
493 find_any_ssid = 0;
494 }
495
496 if (find_any_ssid) {
Dan Williams0dc5a292007-05-10 22:58:02 -0400497 u8 new_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200498
499 ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
500 assoc_req->mode, &new_mode);
501 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400502 lbs_deb_assoc("Could not find best network\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200503 ret = -ENETUNREACH;
504 goto out;
505 }
506
507 /* Ensure we switch to the mode of the AP */
Dan Williams0dc5a292007-05-10 22:58:02 -0400508 if (assoc_req->mode == IW_MODE_AUTO) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200509 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
510 assoc_req->mode = new_mode;
511 }
512 }
513
514 /*
515 * Check if the attributes being changing require deauthentication
516 * from the currently associated infrastructure access point.
517 */
Dan Williams0dc5a292007-05-10 22:58:02 -0400518 if (adapter->mode == IW_MODE_INFRA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200519 if (should_deauth_infrastructure(adapter, assoc_req)) {
520 ret = libertas_send_deauthentication(priv);
521 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400522 lbs_deb_assoc("Deauthentication due to new "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200523 "configuration request failed: %d\n",
524 ret);
525 }
526 }
Dan Williams0dc5a292007-05-10 22:58:02 -0400527 } else if (adapter->mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200528 if (should_stop_adhoc(adapter, assoc_req)) {
529 ret = libertas_stop_adhoc_network(priv);
530 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400531 lbs_deb_assoc("Teardown of AdHoc network due to "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200532 "new configuration request failed: %d\n",
533 ret);
534 }
535
536 }
537 }
538
539 /* Send the various configuration bits to the firmware */
540 if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
541 ret = assoc_helper_mode(priv, assoc_req);
542 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400543lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200544 goto out;
545 }
546 }
547
Dan Williamsef9a2642007-05-25 16:46:33 -0400548 if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
549 ret = assoc_helper_channel(priv, assoc_req);
550 if (ret) {
551 lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n",
552 __LINE__, ret);
553 goto out;
554 }
555 }
556
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200557 if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
558 || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
559 ret = assoc_helper_wep_keys(priv, assoc_req);
560 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400561lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200562 goto out;
563 }
564 }
565
566 if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
567 ret = assoc_helper_secinfo(priv, assoc_req);
568 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400569lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200570 goto out;
571 }
572 }
573
574 if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
575 ret = assoc_helper_wpa_ie(priv, assoc_req);
576 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400577lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200578 goto out;
579 }
580 }
581
582 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
583 || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
584 ret = assoc_helper_wpa_keys(priv, assoc_req);
585 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400586lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200587 goto out;
588 }
589 }
590
591 /* SSID/BSSID should be the _last_ config option set, because they
592 * trigger the association attempt.
593 */
594 if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
595 || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
596 int success = 1;
597
598 ret = assoc_helper_associate(priv, assoc_req);
599 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400600 lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200601 ret);
602 success = 0;
603 }
604
605 if (adapter->connect_status != libertas_connected) {
Holger Schurig9012b282007-05-25 11:27:16 -0400606 lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200607 "not connected.\n");
608 success = 0;
609 }
610
611 if (success) {
Holger Schurig9012b282007-05-25 11:27:16 -0400612 lbs_deb_assoc("ASSOC: association attempt successful. "
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200613 "Associated to '%s' (" MAC_FMT ")\n",
Dan Williamse76850d2007-05-25 17:09:41 -0400614 libertas_escape_essid(adapter->curbssparams.ssid.ssid,
615 adapter->curbssparams.ssid.ssidlength),
616 MAC_ARG(adapter->curbssparams.bssid));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200617 libertas_prepare_and_send_command(priv,
618 cmd_802_11_rssi,
619 0, cmd_option_waitforrsp, 0, NULL);
620
621 libertas_prepare_and_send_command(priv,
622 cmd_802_11_get_log,
623 0, cmd_option_waitforrsp, 0, NULL);
624 } else {
625
626 ret = -1;
627 }
628 }
629
630out:
631 if (ret) {
Holger Schurig9012b282007-05-25 11:27:16 -0400632 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200633 ret);
634 }
Dan Williamse76850d2007-05-25 17:09:41 -0400635
636 mutex_lock(&adapter->lock);
637 adapter->in_progress_assoc_req = NULL;
638 mutex_unlock(&adapter->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200639 kfree(assoc_req);
Holger Schurig9012b282007-05-25 11:27:16 -0400640
641done:
642 lbs_deb_leave(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200643}
644
645
646/*
647 * Caller MUST hold any necessary locks
648 */
649struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
650{
651 struct assoc_request * assoc_req;
652
Dan Williamse76850d2007-05-25 17:09:41 -0400653 if (!adapter->pending_assoc_req) {
654 adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
655 GFP_KERNEL);
656 if (!adapter->pending_assoc_req) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200657 lbs_pr_info("Not enough memory to allocate association"
658 " request!\n");
659 return NULL;
660 }
661 }
662
663 /* Copy current configuration attributes to the association request,
664 * but don't overwrite any that are already set.
665 */
Dan Williamse76850d2007-05-25 17:09:41 -0400666 assoc_req = adapter->pending_assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200667 if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
Dan Williamse76850d2007-05-25 17:09:41 -0400668 memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
669 sizeof(struct WLAN_802_11_SSID));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200670 }
671
672 if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
673 assoc_req->channel = adapter->curbssparams.channel;
674
Dan Williamse76850d2007-05-25 17:09:41 -0400675 if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
676 assoc_req->band = adapter->curbssparams.band;
677
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200678 if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
Dan Williams0dc5a292007-05-10 22:58:02 -0400679 assoc_req->mode = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200680
681 if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
682 memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
683 ETH_ALEN);
684 }
685
686 if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
687 int i;
688 for (i = 0; i < 4; i++) {
689 memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
690 sizeof(struct WLAN_802_11_KEY));
691 }
692 }
693
694 if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
695 assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
696
697 if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
698 memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
699 sizeof(struct WLAN_802_11_KEY));
700 }
701
702 if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
703 memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
704 sizeof(struct WLAN_802_11_KEY));
705 }
706
707 if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
708 memcpy(&assoc_req->secinfo, &adapter->secinfo,
709 sizeof(struct wlan_802_11_security));
710 }
711
712 if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
713 memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
714 MAX_WPA_IE_LEN);
715 assoc_req->wpa_ie_len = adapter->wpa_ie_len;
716 }
717
Dan Williamse76850d2007-05-25 17:09:41 -0400718 print_assoc_req(__func__, assoc_req);
719
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200720 return assoc_req;
721}