]> err.no Git - linux-2.6/blob - drivers/net/wireless/libertas/assoc.c
[PATCH] libertas: remove unused variables in wlan_dev_t
[linux-2.6] / drivers / net / wireless / libertas / assoc.c
1 /* 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
13 static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
14 static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
15
16 static int assoc_helper_essid(wlan_private *priv,
17                               struct assoc_request * assoc_req)
18 {
19         wlan_adapter *adapter = priv->adapter;
20         int ret = 0;
21         int i;
22
23         lbs_deb_enter(LBS_DEB_ASSOC);
24
25         lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
26         if (assoc_req->mode == IW_MODE_INFRA) {
27                 if (adapter->prescan) {
28                         libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
29                 }
30
31                 i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
32                                 NULL, IW_MODE_INFRA);
33                 if (i >= 0) {
34                         lbs_deb_assoc(
35                                "SSID found in scan list ... associating...\n");
36
37                         ret = wlan_associate(priv, &adapter->scantable[i]);
38                         if (ret == 0) {
39                                 memcpy(&assoc_req->bssid,
40                                        &adapter->scantable[i].macaddress,
41                                        ETH_ALEN);
42                         }
43                 } else {
44                         lbs_deb_assoc("SSID '%s' not found; cannot associate\n",
45                                 assoc_req->ssid.ssid);
46                 }
47         } else if (assoc_req->mode == IW_MODE_ADHOC) {
48                 /* Scan for the network, do not save previous results.  Stale
49                  *   scan data will cause us to join a non-existant adhoc network
50                  */
51                 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
52
53                 /* Search for the requested SSID in the scan table */
54                 i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
55                                 IW_MODE_ADHOC);
56                 if (i >= 0) {
57                         lbs_deb_assoc("SSID found at %d in List, so join\n", ret);
58                         libertas_join_adhoc_network(priv, &adapter->scantable[i]);
59                 } else {
60                         /* else send START command */
61                         lbs_deb_assoc("SSID not found in list, so creating adhoc"
62                                 " 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
68         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
69         return ret;
70 }
71
72
73 static int assoc_helper_bssid(wlan_private *priv,
74                               struct assoc_request * assoc_req)
75 {
76         wlan_adapter *adapter = priv->adapter;
77         int i, ret = 0;
78
79         lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID" MAC_FMT "\n",
80                 MAC_ARG(assoc_req->bssid));
81
82         /* Search for index position in list for requested MAC */
83         i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
84                             assoc_req->mode);
85         if (i < 0) {
86                 lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
87                         "cannot associate.\n", MAC_ARG(assoc_req->bssid));
88                 goto out;
89         }
90
91         if (assoc_req->mode == IW_MODE_INFRA) {
92                 ret = wlan_associate(priv, &adapter->scantable[i]);
93                 lbs_deb_assoc("ASSOC: return from wlan_associate(bssd) was %d\n", ret);
94         } else if (assoc_req->mode == IW_MODE_ADHOC) {
95                 libertas_join_adhoc_network(priv, &adapter->scantable[i]);
96         }
97         memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid,
98                 sizeof(struct WLAN_802_11_SSID));
99
100 out:
101         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
102         return ret;
103 }
104
105
106 static 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) {
119                                 lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
120                         }
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) {
127                         lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
128                 }
129         }
130
131         return ret;
132 }
133
134
135 static 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
141         lbs_deb_enter(LBS_DEB_ASSOC);
142
143         if (assoc_req->mode == adapter->mode)
144                 goto done;
145
146         if (assoc_req->mode == IW_MODE_INFRA) {
147                 if (adapter->psstate != PS_STATE_FULL_POWER)
148                         libertas_ps_wakeup(priv, cmd_option_waitforrsp);
149                 adapter->psmode = wlan802_11powermodecam;
150         }
151
152         adapter->mode = assoc_req->mode;
153         ret = libertas_prepare_and_send_command(priv,
154                                     cmd_802_11_snmp_mib,
155                                     0, cmd_option_waitforrsp,
156                                     OID_802_11_INFRASTRUCTURE_MODE,
157                                     (void *) (size_t) assoc_req->mode);
158
159 done:
160         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
161         return ret;
162 }
163
164
165 static int assoc_helper_wep_keys(wlan_private *priv,
166                                  struct assoc_request * assoc_req)
167 {
168         wlan_adapter *adapter = priv->adapter;
169         int i;
170         int ret = 0;
171
172         lbs_deb_enter(LBS_DEB_ASSOC);
173
174         /* Set or remove WEP keys */
175         if (   assoc_req->wep_keys[0].len
176             || assoc_req->wep_keys[1].len
177             || assoc_req->wep_keys[2].len
178             || assoc_req->wep_keys[3].len) {
179                 ret = libertas_prepare_and_send_command(priv,
180                                             cmd_802_11_set_wep,
181                                             cmd_act_add,
182                                             cmd_option_waitforrsp,
183                                             0, assoc_req);
184         } else {
185                 ret = libertas_prepare_and_send_command(priv,
186                                             cmd_802_11_set_wep,
187                                             cmd_act_remove,
188                                             cmd_option_waitforrsp,
189                                             0, NULL);
190         }
191
192         if (ret)
193                 goto out;
194
195         /* enable/disable the MAC's WEP packet filter */
196         if (assoc_req->secinfo.wep_enabled)
197                 adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
198         else
199                 adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
200         ret = libertas_set_mac_packet_filter(priv);
201         if (ret)
202                 goto out;
203
204         mutex_lock(&adapter->lock);
205
206         /* Copy WEP keys into adapter wep key fields */
207         for (i = 0; i < 4; i++) {
208                 memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
209                         sizeof(struct WLAN_802_11_KEY));
210         }
211         adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
212
213         mutex_unlock(&adapter->lock);
214
215 out:
216         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
217         return ret;
218 }
219
220 static int assoc_helper_secinfo(wlan_private *priv,
221                                 struct assoc_request * assoc_req)
222 {
223         wlan_adapter *adapter = priv->adapter;
224         int ret = 0;
225
226         lbs_deb_enter(LBS_DEB_ASSOC);
227
228         memcpy(&adapter->secinfo, &assoc_req->secinfo,
229                 sizeof(struct wlan_802_11_security));
230
231         ret = libertas_set_mac_packet_filter(priv);
232
233         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
234         return ret;
235 }
236
237
238 static int assoc_helper_wpa_keys(wlan_private *priv,
239                                  struct assoc_request * assoc_req)
240 {
241         int ret = 0;
242
243         lbs_deb_enter(LBS_DEB_ASSOC);
244
245         /* enable/Disable RSN */
246         ret = libertas_prepare_and_send_command(priv,
247                                     cmd_802_11_enable_rsn,
248                                     cmd_act_set,
249                                     cmd_option_waitforrsp,
250                                     0, assoc_req);
251         if (ret)
252                 goto out;
253
254         ret = libertas_prepare_and_send_command(priv,
255                                     cmd_802_11_key_material,
256                                     cmd_act_set,
257                                     cmd_option_waitforrsp,
258                                     0, assoc_req);
259
260 out:
261         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
262         return ret;
263 }
264
265
266 static int assoc_helper_wpa_ie(wlan_private *priv,
267                                struct assoc_request * assoc_req)
268 {
269         wlan_adapter *adapter = priv->adapter;
270         int ret = 0;
271
272         lbs_deb_enter(LBS_DEB_ASSOC);
273
274         if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
275                 memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
276                 adapter->wpa_ie_len = assoc_req->wpa_ie_len;
277         } else {
278                 memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
279                 adapter->wpa_ie_len = 0;
280         }
281
282         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
283         return ret;
284 }
285
286
287 static int should_deauth_infrastructure(wlan_adapter *adapter,
288                                         struct assoc_request * assoc_req)
289 {
290         if (adapter->connect_status != libertas_connected)
291                 return 0;
292
293         if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
294                 lbs_deb_assoc("Deauthenticating due to new SSID in "
295                         " configuration request.\n");
296                 return 1;
297         }
298
299         if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
300                 if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
301                         lbs_deb_assoc("Deauthenticating due to updated security "
302                                 "info in configuration request.\n");
303                         return 1;
304                 }
305         }
306
307         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
308                 lbs_deb_assoc("Deauthenticating due to new BSSID in "
309                         " configuration request.\n");
310                 return 1;
311         }
312
313         /* FIXME: deal with 'auto' mode somehow */
314         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
315                 if (assoc_req->mode != IW_MODE_INFRA)
316                         return 1;
317         }
318
319         return 0;
320 }
321
322
323 static int should_stop_adhoc(wlan_adapter *adapter,
324                              struct assoc_request * assoc_req)
325 {
326         if (adapter->connect_status != libertas_connected)
327                 return 0;
328
329         if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
330                 return 1;
331         if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
332                         adapter->curbssparams.ssid.ssidlength))
333                 return 1;
334
335         /* FIXME: deal with 'auto' mode somehow */
336         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
337                 if (assoc_req->mode != IW_MODE_ADHOC)
338                         return 1;
339         }
340
341         return 0;
342 }
343
344
345 void libertas_association_worker(struct work_struct *work)
346 {
347         wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
348         wlan_adapter *adapter = priv->adapter;
349         struct assoc_request * assoc_req = NULL;
350         int ret = 0;
351         int find_any_ssid = 0;
352
353         lbs_deb_enter(LBS_DEB_ASSOC);
354
355         mutex_lock(&adapter->lock);
356         assoc_req = adapter->assoc_req;
357         adapter->assoc_req = NULL;
358         mutex_unlock(&adapter->lock);
359
360         if (!assoc_req)
361                 goto done;
362
363         lbs_deb_assoc("ASSOC: starting new association request: flags = 0x%lX\n",
364                 assoc_req->flags);
365
366         /* If 'any' SSID was specified, find an SSID to associate with */
367         if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
368             && !assoc_req->ssid.ssidlength)
369                 find_any_ssid = 1;
370
371         /* But don't use 'any' SSID if there's a valid locked BSSID to use */
372         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
373                 if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
374                     && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
375                         find_any_ssid = 0;
376         }
377
378         if (find_any_ssid) {
379                 u8 new_mode;
380
381                 ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
382                                 assoc_req->mode, &new_mode);
383                 if (ret) {
384                         lbs_deb_assoc("Could not find best network\n");
385                         ret = -ENETUNREACH;
386                         goto out;
387                 }
388
389                 /* Ensure we switch to the mode of the AP */
390                 if (assoc_req->mode == IW_MODE_AUTO) {
391                         set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
392                         assoc_req->mode = new_mode;
393                 }
394         }
395
396         /*
397          * Check if the attributes being changing require deauthentication
398          * from the currently associated infrastructure access point.
399          */
400         if (adapter->mode == IW_MODE_INFRA) {
401                 if (should_deauth_infrastructure(adapter, assoc_req)) {
402                         ret = libertas_send_deauthentication(priv);
403                         if (ret) {
404                                 lbs_deb_assoc("Deauthentication due to new "
405                                         "configuration request failed: %d\n",
406                                         ret);
407                         }
408                 }
409         } else if (adapter->mode == IW_MODE_ADHOC) {
410                 if (should_stop_adhoc(adapter, assoc_req)) {
411                         ret = libertas_stop_adhoc_network(priv);
412                         if (ret) {
413                                 lbs_deb_assoc("Teardown of AdHoc network due to "
414                                         "new configuration request failed: %d\n",
415                                         ret);
416                         }
417
418                 }
419         }
420
421         /* Send the various configuration bits to the firmware */
422         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
423                 ret = assoc_helper_mode(priv, assoc_req);
424                 if (ret) {
425 lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
426                         goto out;
427                 }
428         }
429
430         if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
431             || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
432                 ret = assoc_helper_wep_keys(priv, assoc_req);
433                 if (ret) {
434 lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
435                         goto out;
436                 }
437         }
438
439         if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
440                 ret = assoc_helper_secinfo(priv, assoc_req);
441                 if (ret) {
442 lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
443                         goto out;
444                 }
445         }
446
447         if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
448                 ret = assoc_helper_wpa_ie(priv, assoc_req);
449                 if (ret) {
450 lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
451                         goto out;
452                 }
453         }
454
455         if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
456             || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
457                 ret = assoc_helper_wpa_keys(priv, assoc_req);
458                 if (ret) {
459 lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
460                         goto out;
461                 }
462         }
463
464         /* SSID/BSSID should be the _last_ config option set, because they
465          * trigger the association attempt.
466          */
467         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
468             || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
469                 int success = 1;
470
471                 ret = assoc_helper_associate(priv, assoc_req);
472                 if (ret) {
473                         lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
474                                 ret);
475                         success = 0;
476                 }
477
478                 if (adapter->connect_status != libertas_connected) {
479                         lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
480                                 "not connected.\n");
481                         success = 0;
482                 }
483
484                 if (success) {
485                         lbs_deb_assoc("ASSOC: association attempt successful. "
486                                 "Associated to '%s' (" MAC_FMT ")\n",
487                                 assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
488                         libertas_prepare_and_send_command(priv,
489                                 cmd_802_11_rssi,
490                                 0, cmd_option_waitforrsp, 0, NULL);
491
492                         libertas_prepare_and_send_command(priv,
493                                 cmd_802_11_get_log,
494                                 0, cmd_option_waitforrsp, 0, NULL);
495                 } else {
496
497                         ret = -1;
498                 }
499         }
500
501 out:
502         if (ret) {
503                 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
504                         ret);
505         }
506         kfree(assoc_req);
507
508 done:
509         lbs_deb_leave(LBS_DEB_ASSOC);
510 }
511
512
513 /*
514  * Caller MUST hold any necessary locks
515  */
516 struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
517 {
518         struct assoc_request * assoc_req;
519
520         if (!adapter->assoc_req) {
521                 adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
522                 if (!adapter->assoc_req) {
523                         lbs_pr_info("Not enough memory to allocate association"
524                                 " request!\n");
525                         return NULL;
526                 }
527         }
528
529         /* Copy current configuration attributes to the association request,
530          * but don't overwrite any that are already set.
531          */
532         assoc_req = adapter->assoc_req;
533         if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
534                 memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
535                         adapter->curbssparams.ssid.ssidlength);
536         }
537
538         if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
539                 assoc_req->channel = adapter->curbssparams.channel;
540
541         if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
542                 assoc_req->mode = adapter->mode;
543
544         if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
545                 memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
546                         ETH_ALEN);
547         }
548
549         if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
550                 int i;
551                 for (i = 0; i < 4; i++) {
552                         memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
553                                 sizeof(struct WLAN_802_11_KEY));
554                 }
555         }
556
557         if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
558                 assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
559
560         if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
561                 memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
562                         sizeof(struct WLAN_802_11_KEY));
563         }
564
565         if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
566                 memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
567                         sizeof(struct WLAN_802_11_KEY));
568         }
569
570         if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
571                 memcpy(&assoc_req->secinfo, &adapter->secinfo,
572                         sizeof(struct wlan_802_11_security));
573         }
574
575         if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
576                 memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
577                         MAX_WPA_IE_LEN);
578                 assoc_req->wpa_ie_len = adapter->wpa_ie_len;
579         }
580
581         return assoc_req;
582 }
583
584