b18464224b952eeb55c82ea306f0042744748ddd
[safe/jmp/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 /* From ieee80211_module.c */
17 static 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
40 static 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
66 static int assoc_helper_essid(wlan_private *priv,
67                               struct assoc_request * assoc_req)
68 {
69         wlan_adapter *adapter = priv->adapter;
70         int ret = 0;
71         struct bss_descriptor * bss;
72
73         lbs_deb_enter(LBS_DEB_ASSOC);
74
75         /* FIXME: take channel into account when picking SSIDs if a channel
76          * is set.
77          */
78
79         lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
80         if (assoc_req->mode == IW_MODE_INFRA) {
81                 if (adapter->prescan) {
82                         libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
83                 }
84
85                 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
86                                 NULL, IW_MODE_INFRA);
87                 if (bss != NULL) {
88                         lbs_deb_assoc("SSID found in scan list, associating\n");
89                         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
90                         ret = wlan_associate(priv, assoc_req);
91                 } else {
92                         lbs_deb_assoc("SSID '%s' not found; cannot associate\n",
93                                 assoc_req->ssid.ssid);
94                 }
95         } else if (assoc_req->mode == IW_MODE_ADHOC) {
96                 /* Scan for the network, do not save previous results.  Stale
97                  *   scan data will cause us to join a non-existant adhoc network
98                  */
99                 libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
100
101                 /* Search for the requested SSID in the scan table */
102                 bss = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
103                                 IW_MODE_ADHOC);
104                 if (bss != NULL) {
105                         lbs_deb_assoc("SSID found joining\n");
106                         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
107                         libertas_join_adhoc_network(priv, assoc_req);
108                 } else {
109                         /* else send START command */
110                         lbs_deb_assoc("SSID not found in list, so creating adhoc"
111                                 " with SSID '%s'\n", assoc_req->ssid.ssid);
112                         memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
113                                 sizeof(struct WLAN_802_11_SSID));
114                         libertas_start_adhoc_network(priv, assoc_req);
115                 }
116         }
117
118         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
119         return ret;
120 }
121
122
123 static int assoc_helper_bssid(wlan_private *priv,
124                               struct assoc_request * assoc_req)
125 {
126         wlan_adapter *adapter = priv->adapter;
127         int ret = 0;
128         struct bss_descriptor * bss;
129
130         lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID" MAC_FMT "\n",
131                 MAC_ARG(assoc_req->bssid));
132
133         /* Search for index position in list for requested MAC */
134         bss = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
135                             assoc_req->mode);
136         if (bss == NULL) {
137                 lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
138                         "cannot associate.\n", MAC_ARG(assoc_req->bssid));
139                 goto out;
140         }
141
142         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
143         if (assoc_req->mode == IW_MODE_INFRA) {
144                 ret = wlan_associate(priv, assoc_req);
145                 lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
146         } else if (assoc_req->mode == IW_MODE_ADHOC) {
147                 libertas_join_adhoc_network(priv, assoc_req);
148         }
149
150 out:
151         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
152         return ret;
153 }
154
155
156 static 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) {
169                                 lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
170                         }
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) {
177                         lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
178                 }
179         }
180
181         return ret;
182 }
183
184
185 static 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
191         lbs_deb_enter(LBS_DEB_ASSOC);
192
193         if (assoc_req->mode == adapter->mode)
194                 goto done;
195
196         if (assoc_req->mode == IW_MODE_INFRA) {
197                 if (adapter->psstate != PS_STATE_FULL_POWER)
198                         libertas_ps_wakeup(priv, cmd_option_waitforrsp);
199                 adapter->psmode = wlan802_11powermodecam;
200         }
201
202         adapter->mode = assoc_req->mode;
203         ret = libertas_prepare_and_send_command(priv,
204                                     cmd_802_11_snmp_mib,
205                                     0, cmd_option_waitforrsp,
206                                     OID_802_11_INFRASTRUCTURE_MODE,
207                                     (void *) (size_t) assoc_req->mode);
208
209 done:
210         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
211         return ret;
212 }
213
214
215 static 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
223 static 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
272 done:
273         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
274         return ret;
275 }
276
277
278 static 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
285         lbs_deb_enter(LBS_DEB_ASSOC);
286
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 */
309         if (assoc_req->secinfo.wep_enabled)
310                 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
328 out:
329         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
330         return ret;
331 }
332
333 static 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
339         lbs_deb_enter(LBS_DEB_ASSOC);
340
341         memcpy(&adapter->secinfo, &assoc_req->secinfo,
342                 sizeof(struct wlan_802_11_security));
343
344         ret = libertas_set_mac_packet_filter(priv);
345
346         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
347         return ret;
348 }
349
350
351 static int assoc_helper_wpa_keys(wlan_private *priv,
352                                  struct assoc_request * assoc_req)
353 {
354         int ret = 0;
355
356         lbs_deb_enter(LBS_DEB_ASSOC);
357
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
373 out:
374         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
375         return ret;
376 }
377
378
379 static 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
385         lbs_deb_enter(LBS_DEB_ASSOC);
386
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
395         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
396         return ret;
397 }
398
399
400 static 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)) {
407                 lbs_deb_assoc("Deauthenticating due to new SSID in "
408                         " configuration request.\n");
409                 return 1;
410         }
411
412         if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
413                 if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
414                         lbs_deb_assoc("Deauthenticating due to updated security "
415                                 "info in configuration request.\n");
416                         return 1;
417                 }
418         }
419
420         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
421                 lbs_deb_assoc("Deauthenticating due to new BSSID in "
422                         " 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)) {
428                 if (assoc_req->mode != IW_MODE_INFRA)
429                         return 1;
430         }
431
432         return 0;
433 }
434
435
436 static 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,
445                         adapter->curbssparams.ssid.ssidlength))
446                 return 1;
447
448         /* FIXME: deal with 'auto' mode somehow */
449         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
450                 if (assoc_req->mode != IW_MODE_ADHOC)
451                         return 1;
452         }
453
454         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
455                 if (assoc_req->channel != adapter->curbssparams.channel)
456                         return 1;
457         }
458
459         return 0;
460 }
461
462
463 void libertas_association_worker(struct work_struct *work)
464 {
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
471         lbs_deb_enter(LBS_DEB_ASSOC);
472
473         mutex_lock(&adapter->lock);
474         assoc_req = adapter->pending_assoc_req;
475         adapter->pending_assoc_req = NULL;
476         adapter->in_progress_assoc_req = assoc_req;
477         mutex_unlock(&adapter->lock);
478
479         if (!assoc_req)
480                 goto done;
481
482         print_assoc_req(__func__, assoc_req);
483
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) {
497                 u8 new_mode;
498
499                 ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
500                                 assoc_req->mode, &new_mode);
501                 if (ret) {
502                         lbs_deb_assoc("Could not find best network\n");
503                         ret = -ENETUNREACH;
504                         goto out;
505                 }
506
507                 /* Ensure we switch to the mode of the AP */
508                 if (assoc_req->mode == IW_MODE_AUTO) {
509                         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          */
518         if (adapter->mode == IW_MODE_INFRA) {
519                 if (should_deauth_infrastructure(adapter, assoc_req)) {
520                         ret = libertas_send_deauthentication(priv);
521                         if (ret) {
522                                 lbs_deb_assoc("Deauthentication due to new "
523                                         "configuration request failed: %d\n",
524                                         ret);
525                         }
526                 }
527         } else if (adapter->mode == IW_MODE_ADHOC) {
528                 if (should_stop_adhoc(adapter, assoc_req)) {
529                         ret = libertas_stop_adhoc_network(priv);
530                         if (ret) {
531                                 lbs_deb_assoc("Teardown of AdHoc network due to "
532                                         "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) {
543 lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
544                         goto out;
545                 }
546         }
547
548         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
557         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) {
561 lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
562                         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) {
569 lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
570                         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) {
577 lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
578                         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) {
586 lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
587                         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) {
600                         lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
601                                 ret);
602                         success = 0;
603                 }
604
605                 if (adapter->connect_status != libertas_connected) {
606                         lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
607                                 "not connected.\n");
608                         success = 0;
609                 }
610
611                 if (success) {
612                         lbs_deb_assoc("ASSOC: association attempt successful. "
613                                 "Associated to '%s' (" MAC_FMT ")\n",
614                                 libertas_escape_essid(adapter->curbssparams.ssid.ssid,
615                                              adapter->curbssparams.ssid.ssidlength),
616                                 MAC_ARG(adapter->curbssparams.bssid));
617                         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
630 out:
631         if (ret) {
632                 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
633                         ret);
634         }
635
636         mutex_lock(&adapter->lock);
637         adapter->in_progress_assoc_req = NULL;
638         mutex_unlock(&adapter->lock);
639         kfree(assoc_req);
640
641 done:
642         lbs_deb_leave(LBS_DEB_ASSOC);
643 }
644
645
646 /*
647  * Caller MUST hold any necessary locks
648  */
649 struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
650 {
651         struct assoc_request * assoc_req;
652
653         if (!adapter->pending_assoc_req) {
654                 adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
655                                                      GFP_KERNEL);
656                 if (!adapter->pending_assoc_req) {
657                         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          */
666         assoc_req = adapter->pending_assoc_req;
667         if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
668                 memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
669                        sizeof(struct WLAN_802_11_SSID));
670         }
671
672         if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
673                 assoc_req->channel = adapter->curbssparams.channel;
674
675         if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
676                 assoc_req->band = adapter->curbssparams.band;
677
678         if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
679                 assoc_req->mode = adapter->mode;
680
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
718         print_assoc_req(__func__, assoc_req);
719
720         return assoc_req;
721 }