]> err.no Git - linux-2.6/blob - drivers/net/wireless/libertas/assoc.c
48fc6d171d5854e4c487a76d142e9018cc75bdd7
[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 #include <linux/etherdevice.h>
6
7 #include "assoc.h"
8 #include "join.h"
9 #include "decl.h"
10 #include "hostcmd.h"
11 #include "host.h"
12
13
14 static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
15 static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
16
17 /* From ieee80211_module.c */
18 static const char *libertas_escape_essid(const char *essid, u8 essid_len)
19 {
20         static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
21         const char *s = essid;
22         char *d = escaped;
23
24         if (ieee80211_is_empty_essid(essid, essid_len))
25                 return "";
26
27         essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
28         while (essid_len--) {
29                 if (*s == '\0') {
30                         *d++ = '\\';
31                         *d++ = '0';
32                         s++;
33                 } else {
34                         *d++ = *s++;
35                 }
36         }
37         *d = '\0';
38         return escaped;
39 }
40
41 static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
42 {
43         lbs_deb_assoc(
44                "#### Association Request: %s\n"
45                "       flags:      0x%08lX\n"
46                "       SSID:       '%s'\n"
47                "       channel:    %d\n"
48                "       band:       %d\n"
49                "       mode:       %d\n"
50                "       BSSID:      " MAC_FMT "\n"
51                "       WPA:        %d\n"
52                "       WPA2:       %d\n"
53                "       WEP status: %d\n"
54                "       auth:       %d\n"
55                "       auth_alg:   %d\n"
56                "       encmode:    %d\n",
57                extra, assoc_req->flags,
58                libertas_escape_essid(assoc_req->ssid.ssid, assoc_req->ssid.ssidlength),
59                assoc_req->channel, assoc_req->band, assoc_req->mode,
60                MAC_ARG(assoc_req->bssid), assoc_req->secinfo.WPAenabled,
61                assoc_req->secinfo.WPA2enabled, assoc_req->secinfo.WEPstatus,
62                assoc_req->secinfo.authmode, assoc_req->secinfo.auth1xalg,
63                assoc_req->secinfo.Encryptionmode);
64 }
65
66
67 static int assoc_helper_essid(wlan_private *priv,
68                               struct assoc_request * assoc_req)
69 {
70         wlan_adapter *adapter = priv->adapter;
71         int ret = 0;
72         struct bss_descriptor * bss;
73         int channel = -1;
74
75         lbs_deb_enter(LBS_DEB_ASSOC);
76
77         /* FIXME: take channel into account when picking SSIDs if a channel
78          * is set.
79          */
80
81         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
82                 channel = assoc_req->channel;
83
84         lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
85         if (assoc_req->mode == IW_MODE_INFRA) {
86                 if (adapter->prescan) {
87                         libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
88                 }
89
90                 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
91                                 NULL, IW_MODE_INFRA, channel);
92                 if (bss != NULL) {
93                         lbs_deb_assoc("SSID found in scan list, associating\n");
94                         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
95                         ret = wlan_associate(priv, assoc_req);
96                 } else {
97                         lbs_deb_assoc("SSID '%s' not found; cannot associate\n",
98                                 assoc_req->ssid.ssid);
99                 }
100         } else if (assoc_req->mode == IW_MODE_ADHOC) {
101                 /* Scan for the network, do not save previous results.  Stale
102                  *   scan data will cause us to join a non-existant adhoc network
103                  */
104                 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
105
106                 /* Search for the requested SSID in the scan table */
107                 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
108                                 IW_MODE_ADHOC, channel);
109                 if (bss != NULL) {
110                         lbs_deb_assoc("SSID found joining\n");
111                         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
112                         libertas_join_adhoc_network(priv, assoc_req);
113                 } else {
114                         /* else send START command */
115                         lbs_deb_assoc("SSID not found in list, so creating adhoc"
116                                 " with SSID '%s'\n", assoc_req->ssid.ssid);
117                         memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
118                                 sizeof(struct WLAN_802_11_SSID));
119                         libertas_start_adhoc_network(priv, assoc_req);
120                 }
121         }
122
123         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
124         return ret;
125 }
126
127
128 static int assoc_helper_bssid(wlan_private *priv,
129                               struct assoc_request * assoc_req)
130 {
131         wlan_adapter *adapter = priv->adapter;
132         int ret = 0;
133         struct bss_descriptor * bss;
134
135         lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT "\n",
136                 MAC_ARG(assoc_req->bssid));
137
138         /* Search for index position in list for requested MAC */
139         bss = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
140                             assoc_req->mode);
141         if (bss == NULL) {
142                 lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
143                         "cannot associate.\n", MAC_ARG(assoc_req->bssid));
144                 goto out;
145         }
146
147         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
148         if (assoc_req->mode == IW_MODE_INFRA) {
149                 ret = wlan_associate(priv, assoc_req);
150                 lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
151         } else if (assoc_req->mode == IW_MODE_ADHOC) {
152                 libertas_join_adhoc_network(priv, assoc_req);
153         }
154
155 out:
156         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
157         return ret;
158 }
159
160
161 static int assoc_helper_associate(wlan_private *priv,
162                                   struct assoc_request * assoc_req)
163 {
164         int ret = 0, done = 0;
165
166         /* If we're given and 'any' BSSID, try associating based on SSID */
167
168         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
169                 if (compare_ether_addr(bssid_any, assoc_req->bssid)
170                     && compare_ether_addr(bssid_off, assoc_req->bssid)) {
171                         ret = assoc_helper_bssid(priv, assoc_req);
172                         done = 1;
173                         if (ret) {
174                                 lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
175                         }
176                 }
177         }
178
179         if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
180                 ret = assoc_helper_essid(priv, assoc_req);
181                 if (ret) {
182                         lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
183                 }
184         }
185
186         return ret;
187 }
188
189
190 static int assoc_helper_mode(wlan_private *priv,
191                              struct assoc_request * assoc_req)
192 {
193         wlan_adapter *adapter = priv->adapter;
194         int ret = 0;
195
196         lbs_deb_enter(LBS_DEB_ASSOC);
197
198         if (assoc_req->mode == adapter->mode)
199                 goto done;
200
201         if (assoc_req->mode == IW_MODE_INFRA) {
202                 if (adapter->psstate != PS_STATE_FULL_POWER)
203                         libertas_ps_wakeup(priv, cmd_option_waitforrsp);
204                 adapter->psmode = wlan802_11powermodecam;
205         }
206
207         adapter->mode = assoc_req->mode;
208         ret = libertas_prepare_and_send_command(priv,
209                                     cmd_802_11_snmp_mib,
210                                     0, cmd_option_waitforrsp,
211                                     OID_802_11_INFRASTRUCTURE_MODE,
212                                     (void *) (size_t) assoc_req->mode);
213
214 done:
215         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
216         return ret;
217 }
218
219
220 static int update_channel(wlan_private * priv)
221 {
222         /* the channel in f/w could be out of sync, get the current channel */
223         return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
224                                     cmd_opt_802_11_rf_channel_get,
225                                     cmd_option_waitforrsp, 0, NULL);
226 }
227
228 static int assoc_helper_channel(wlan_private *priv,
229                                 struct assoc_request * assoc_req)
230 {
231         wlan_adapter *adapter = priv->adapter;
232         int ret = 0;
233
234         lbs_deb_enter(LBS_DEB_ASSOC);
235
236         ret = update_channel(priv);
237         if (ret < 0) {
238                 lbs_deb_assoc("ASSOC: channel: error getting channel.");
239         }
240
241         if (assoc_req->channel == adapter->curbssparams.channel)
242                 goto done;
243
244         lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
245                adapter->curbssparams.channel, assoc_req->channel);
246
247         ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
248                                 cmd_opt_802_11_rf_channel_set,
249                                 cmd_option_waitforrsp, 0, &assoc_req->channel);
250         if (ret < 0) {
251                 lbs_deb_assoc("ASSOC: channel: error setting channel.");
252         }
253
254         ret = update_channel(priv);
255         if (ret < 0) {
256                 lbs_deb_assoc("ASSOC: channel: error getting channel.");
257         }
258
259         if (assoc_req->channel != adapter->curbssparams.channel) {
260                 lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
261                               assoc_req->channel);
262                 goto done;
263         }
264
265         if (   assoc_req->secinfo.wep_enabled
266             &&   (assoc_req->wep_keys[0].len
267                || assoc_req->wep_keys[1].len
268                || assoc_req->wep_keys[2].len
269                || assoc_req->wep_keys[3].len)) {
270                 /* Make sure WEP keys are re-sent to firmware */
271                 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
272         }
273
274         /* Must restart/rejoin adhoc networks after channel change */
275         set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
276
277 done:
278         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
279         return ret;
280 }
281
282
283 static int assoc_helper_wep_keys(wlan_private *priv,
284                                  struct assoc_request * assoc_req)
285 {
286         wlan_adapter *adapter = priv->adapter;
287         int i;
288         int ret = 0;
289
290         lbs_deb_enter(LBS_DEB_ASSOC);
291
292         /* Set or remove WEP keys */
293         if (   assoc_req->wep_keys[0].len
294             || assoc_req->wep_keys[1].len
295             || assoc_req->wep_keys[2].len
296             || assoc_req->wep_keys[3].len) {
297                 ret = libertas_prepare_and_send_command(priv,
298                                             cmd_802_11_set_wep,
299                                             cmd_act_add,
300                                             cmd_option_waitforrsp,
301                                             0, assoc_req);
302         } else {
303                 ret = libertas_prepare_and_send_command(priv,
304                                             cmd_802_11_set_wep,
305                                             cmd_act_remove,
306                                             cmd_option_waitforrsp,
307                                             0, NULL);
308         }
309
310         if (ret)
311                 goto out;
312
313         /* enable/disable the MAC's WEP packet filter */
314         if (assoc_req->secinfo.wep_enabled)
315                 adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
316         else
317                 adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
318         ret = libertas_set_mac_packet_filter(priv);
319         if (ret)
320                 goto out;
321
322         mutex_lock(&adapter->lock);
323
324         /* Copy WEP keys into adapter wep key fields */
325         for (i = 0; i < 4; i++) {
326                 memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
327                         sizeof(struct WLAN_802_11_KEY));
328         }
329         adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
330
331         mutex_unlock(&adapter->lock);
332
333 out:
334         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
335         return ret;
336 }
337
338 static int assoc_helper_secinfo(wlan_private *priv,
339                                 struct assoc_request * assoc_req)
340 {
341         wlan_adapter *adapter = priv->adapter;
342         int ret = 0;
343
344         lbs_deb_enter(LBS_DEB_ASSOC);
345
346         memcpy(&adapter->secinfo, &assoc_req->secinfo,
347                 sizeof(struct wlan_802_11_security));
348
349         ret = libertas_set_mac_packet_filter(priv);
350
351         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
352         return ret;
353 }
354
355
356 static int assoc_helper_wpa_keys(wlan_private *priv,
357                                  struct assoc_request * assoc_req)
358 {
359         int ret = 0;
360
361         lbs_deb_enter(LBS_DEB_ASSOC);
362
363         /* enable/Disable RSN */
364         ret = libertas_prepare_and_send_command(priv,
365                                     cmd_802_11_enable_rsn,
366                                     cmd_act_set,
367                                     cmd_option_waitforrsp,
368                                     0, assoc_req);
369         if (ret)
370                 goto out;
371
372         ret = libertas_prepare_and_send_command(priv,
373                                     cmd_802_11_key_material,
374                                     cmd_act_set,
375                                     cmd_option_waitforrsp,
376                                     0, assoc_req);
377
378 out:
379         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
380         return ret;
381 }
382
383
384 static int assoc_helper_wpa_ie(wlan_private *priv,
385                                struct assoc_request * assoc_req)
386 {
387         wlan_adapter *adapter = priv->adapter;
388         int ret = 0;
389
390         lbs_deb_enter(LBS_DEB_ASSOC);
391
392         if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
393                 memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
394                 adapter->wpa_ie_len = assoc_req->wpa_ie_len;
395         } else {
396                 memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
397                 adapter->wpa_ie_len = 0;
398         }
399
400         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
401         return ret;
402 }
403
404
405 static int should_deauth_infrastructure(wlan_adapter *adapter,
406                                         struct assoc_request * assoc_req)
407 {
408         if (adapter->connect_status != libertas_connected)
409                 return 0;
410
411         if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
412                 lbs_deb_assoc("Deauthenticating due to new SSID in "
413                         " configuration request.\n");
414                 return 1;
415         }
416
417         if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
418                 if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
419                         lbs_deb_assoc("Deauthenticating due to updated security "
420                                 "info in configuration request.\n");
421                         return 1;
422                 }
423         }
424
425         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
426                 lbs_deb_assoc("Deauthenticating due to new BSSID in "
427                         " configuration request.\n");
428                 return 1;
429         }
430
431         /* FIXME: deal with 'auto' mode somehow */
432         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
433                 if (assoc_req->mode != IW_MODE_INFRA)
434                         return 1;
435         }
436
437         return 0;
438 }
439
440
441 static int should_stop_adhoc(wlan_adapter *adapter,
442                              struct assoc_request * assoc_req)
443 {
444         if (adapter->connect_status != libertas_connected)
445                 return 0;
446
447         if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
448                 return 1;
449         if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
450                         adapter->curbssparams.ssid.ssidlength))
451                 return 1;
452
453         /* FIXME: deal with 'auto' mode somehow */
454         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
455                 if (assoc_req->mode != IW_MODE_ADHOC)
456                         return 1;
457         }
458
459         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
460                 if (assoc_req->channel != adapter->curbssparams.channel)
461                         return 1;
462         }
463
464         return 0;
465 }
466
467
468 void libertas_association_worker(struct work_struct *work)
469 {
470         wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
471         wlan_adapter *adapter = priv->adapter;
472         struct assoc_request * assoc_req = NULL;
473         int ret = 0;
474         int find_any_ssid = 0;
475
476         lbs_deb_enter(LBS_DEB_ASSOC);
477
478         mutex_lock(&adapter->lock);
479         assoc_req = adapter->pending_assoc_req;
480         adapter->pending_assoc_req = NULL;
481         adapter->in_progress_assoc_req = assoc_req;
482         mutex_unlock(&adapter->lock);
483
484         if (!assoc_req)
485                 goto done;
486
487         print_assoc_req(__func__, assoc_req);
488
489         /* If 'any' SSID was specified, find an SSID to associate with */
490         if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
491             && !assoc_req->ssid.ssidlength)
492                 find_any_ssid = 1;
493
494         /* But don't use 'any' SSID if there's a valid locked BSSID to use */
495         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
496                 if (compare_ether_addr(assoc_req->bssid, bssid_any)
497                     && compare_ether_addr(assoc_req->bssid, bssid_off))
498                         find_any_ssid = 0;
499         }
500
501         if (find_any_ssid) {
502                 u8 new_mode;
503
504                 ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
505                                 assoc_req->mode, &new_mode);
506                 if (ret) {
507                         lbs_deb_assoc("Could not find best network\n");
508                         ret = -ENETUNREACH;
509                         goto out;
510                 }
511
512                 /* Ensure we switch to the mode of the AP */
513                 if (assoc_req->mode == IW_MODE_AUTO) {
514                         set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
515                         assoc_req->mode = new_mode;
516                 }
517         }
518
519         /*
520          * Check if the attributes being changing require deauthentication
521          * from the currently associated infrastructure access point.
522          */
523         if (adapter->mode == IW_MODE_INFRA) {
524                 if (should_deauth_infrastructure(adapter, assoc_req)) {
525                         ret = libertas_send_deauthentication(priv);
526                         if (ret) {
527                                 lbs_deb_assoc("Deauthentication due to new "
528                                         "configuration request failed: %d\n",
529                                         ret);
530                         }
531                 }
532         } else if (adapter->mode == IW_MODE_ADHOC) {
533                 if (should_stop_adhoc(adapter, assoc_req)) {
534                         ret = libertas_stop_adhoc_network(priv);
535                         if (ret) {
536                                 lbs_deb_assoc("Teardown of AdHoc network due to "
537                                         "new configuration request failed: %d\n",
538                                         ret);
539                         }
540
541                 }
542         }
543
544         /* Send the various configuration bits to the firmware */
545         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
546                 ret = assoc_helper_mode(priv, assoc_req);
547                 if (ret) {
548 lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
549                         goto out;
550                 }
551         }
552
553         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
554                 ret = assoc_helper_channel(priv, assoc_req);
555                 if (ret) {
556                         lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n",
557                                       __LINE__, ret);
558                         goto out;
559                 }
560         }
561
562         if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
563             || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
564                 ret = assoc_helper_wep_keys(priv, assoc_req);
565                 if (ret) {
566 lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
567                         goto out;
568                 }
569         }
570
571         if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
572                 ret = assoc_helper_secinfo(priv, assoc_req);
573                 if (ret) {
574 lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
575                         goto out;
576                 }
577         }
578
579         if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
580                 ret = assoc_helper_wpa_ie(priv, assoc_req);
581                 if (ret) {
582 lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
583                         goto out;
584                 }
585         }
586
587         if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
588             || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
589                 ret = assoc_helper_wpa_keys(priv, assoc_req);
590                 if (ret) {
591 lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
592                         goto out;
593                 }
594         }
595
596         /* SSID/BSSID should be the _last_ config option set, because they
597          * trigger the association attempt.
598          */
599         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
600             || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
601                 int success = 1;
602
603                 ret = assoc_helper_associate(priv, assoc_req);
604                 if (ret) {
605                         lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
606                                 ret);
607                         success = 0;
608                 }
609
610                 if (adapter->connect_status != libertas_connected) {
611                         lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
612                                 "not connected.\n");
613                         success = 0;
614                 }
615
616                 if (success) {
617                         lbs_deb_assoc("ASSOC: association attempt successful. "
618                                 "Associated to '%s' (" MAC_FMT ")\n",
619                                 libertas_escape_essid(adapter->curbssparams.ssid.ssid,
620                                              adapter->curbssparams.ssid.ssidlength),
621                                 MAC_ARG(adapter->curbssparams.bssid));
622                         libertas_prepare_and_send_command(priv,
623                                 cmd_802_11_rssi,
624                                 0, cmd_option_waitforrsp, 0, NULL);
625
626                         libertas_prepare_and_send_command(priv,
627                                 cmd_802_11_get_log,
628                                 0, cmd_option_waitforrsp, 0, NULL);
629                 } else {
630                         ret = -1;
631                 }
632         }
633
634 out:
635         if (ret) {
636                 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
637                         ret);
638         }
639
640         mutex_lock(&adapter->lock);
641         adapter->in_progress_assoc_req = NULL;
642         mutex_unlock(&adapter->lock);
643         kfree(assoc_req);
644
645 done:
646         lbs_deb_leave(LBS_DEB_ASSOC);
647 }
648
649
650 /*
651  * Caller MUST hold any necessary locks
652  */
653 struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
654 {
655         struct assoc_request * assoc_req;
656
657         if (!adapter->pending_assoc_req) {
658                 adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
659                                                      GFP_KERNEL);
660                 if (!adapter->pending_assoc_req) {
661                         lbs_pr_info("Not enough memory to allocate association"
662                                 " request!\n");
663                         return NULL;
664                 }
665         }
666
667         /* Copy current configuration attributes to the association request,
668          * but don't overwrite any that are already set.
669          */
670         assoc_req = adapter->pending_assoc_req;
671         if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
672                 memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
673                        sizeof(struct WLAN_802_11_SSID));
674         }
675
676         if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
677                 assoc_req->channel = adapter->curbssparams.channel;
678
679         if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
680                 assoc_req->band = adapter->curbssparams.band;
681
682         if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
683                 assoc_req->mode = adapter->mode;
684
685         if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
686                 memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
687                         ETH_ALEN);
688         }
689
690         if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
691                 int i;
692                 for (i = 0; i < 4; i++) {
693                         memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
694                                 sizeof(struct WLAN_802_11_KEY));
695                 }
696         }
697
698         if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
699                 assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
700
701         if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
702                 memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
703                         sizeof(struct WLAN_802_11_KEY));
704         }
705
706         if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
707                 memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
708                         sizeof(struct WLAN_802_11_KEY));
709         }
710
711         if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
712                 memcpy(&assoc_req->secinfo, &adapter->secinfo,
713                         sizeof(struct wlan_802_11_security));
714         }
715
716         if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
717                 memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
718                         MAX_WPA_IE_LEN);
719                 assoc_req->wpa_ie_len = adapter->wpa_ie_len;
720         }
721
722         print_assoc_req(__func__, assoc_req);
723
724         return assoc_req;
725 }