libertas: remove unused 11d code
[safe/jmp/linux-2.6] / drivers / net / wireless / libertas / assoc.c
1 /* Copyright (C) 2006, Red Hat, Inc. */
2
3 #include <linux/types.h>
4 #include <linux/etherdevice.h>
5 #include <linux/ieee80211.h>
6 #include <linux/if_arp.h>
7 #include <net/lib80211.h>
8
9 #include "assoc.h"
10 #include "decl.h"
11 #include "host.h"
12 #include "scan.h"
13 #include "cmd.h"
14
15 static const u8 bssid_any[ETH_ALEN]  __attribute__ ((aligned (2))) =
16         { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
17 static const u8 bssid_off[ETH_ALEN]  __attribute__ ((aligned (2))) =
18         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
19
20 /* The firmware needs the following bits masked out of the beacon-derived
21  * capability field when associating/joining to a BSS:
22  *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
23  */
24 #define CAPINFO_MASK    (~(0xda00))
25
26
27 /**
28  *  @brief This function finds common rates between rates and card rates.
29  *
30  * It will fill common rates in rates as output if found.
31  *
32  * NOTE: Setting the MSB of the basic rates need to be taken
33  *   care, either before or after calling this function
34  *
35  *  @param priv     A pointer to struct lbs_private structure
36  *  @param rates       the buffer which keeps input and output
37  *  @param rates_size  the size of rates buffer; new size of buffer on return,
38  *                     which will be less than or equal to original rates_size
39  *
40  *  @return            0 on success, or -1 on error
41  */
42 static int get_common_rates(struct lbs_private *priv,
43         u8 *rates,
44         u16 *rates_size)
45 {
46         int i, j;
47         u8 intersection[MAX_RATES];
48         u16 intersection_size;
49         u16 num_rates = 0;
50
51         intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
52
53         /* Allow each rate from 'rates' that is supported by the hardware */
54         for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
55                 for (j = 0; j < intersection_size && rates[j]; j++) {
56                         if (rates[j] == lbs_bg_rates[i])
57                                 intersection[num_rates++] = rates[j];
58                 }
59         }
60
61         lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
62         lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", lbs_bg_rates,
63                         ARRAY_SIZE(lbs_bg_rates));
64         lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
65         lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
66
67         if (!priv->enablehwauto) {
68                 for (i = 0; i < num_rates; i++) {
69                         if (intersection[i] == priv->cur_rate)
70                                 goto done;
71                 }
72                 lbs_pr_alert("Previously set fixed data rate %#x isn't "
73                        "compatible with the network.\n", priv->cur_rate);
74                 return -1;
75         }
76
77 done:
78         memset(rates, 0, *rates_size);
79         *rates_size = num_rates;
80         memcpy(rates, intersection, num_rates);
81         return 0;
82 }
83
84
85 /**
86  *  @brief Sets the MSB on basic rates as the firmware requires
87  *
88  * Scan through an array and set the MSB for basic data rates.
89  *
90  *  @param rates     buffer of data rates
91  *  @param len       size of buffer
92  */
93 static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
94 {
95         int i;
96
97         for (i = 0; i < len; i++) {
98                 if (rates[i] == 0x02 || rates[i] == 0x04 ||
99                     rates[i] == 0x0b || rates[i] == 0x16)
100                         rates[i] |= 0x80;
101         }
102 }
103
104
105 static u8 iw_auth_to_ieee_auth(u8 auth)
106 {
107         if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
108                 return 0x00;
109         else if (auth == IW_AUTH_ALG_SHARED_KEY)
110                 return 0x01;
111         else if (auth == IW_AUTH_ALG_LEAP)
112                 return 0x80;
113
114         lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
115         return 0;
116 }
117
118 /**
119  *  @brief This function prepares the authenticate command.  AUTHENTICATE only
120  *  sets the authentication suite for future associations, as the firmware
121  *  handles authentication internally during the ASSOCIATE command.
122  *
123  *  @param priv      A pointer to struct lbs_private structure
124  *  @param bssid     The peer BSSID with which to authenticate
125  *  @param auth      The authentication mode to use (from wireless.h)
126  *
127  *  @return         0 or -1
128  */
129 static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
130 {
131         struct cmd_ds_802_11_authenticate cmd;
132         int ret = -1;
133
134         lbs_deb_enter(LBS_DEB_JOIN);
135
136         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
137         memcpy(cmd.bssid, bssid, ETH_ALEN);
138
139         cmd.authtype = iw_auth_to_ieee_auth(auth);
140
141         lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
142
143         ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
144
145         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
146         return ret;
147 }
148
149
150 static int lbs_assoc_post(struct lbs_private *priv,
151                           struct cmd_ds_802_11_associate_response *resp)
152 {
153         int ret = 0;
154         union iwreq_data wrqu;
155         struct bss_descriptor *bss;
156         u16 status_code;
157
158         lbs_deb_enter(LBS_DEB_ASSOC);
159
160         if (!priv->in_progress_assoc_req) {
161                 lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
162                 ret = -1;
163                 goto done;
164         }
165         bss = &priv->in_progress_assoc_req->bss;
166
167         /*
168          * Older FW versions map the IEEE 802.11 Status Code in the association
169          * response to the following values returned in resp->statuscode:
170          *
171          *    IEEE Status Code                Marvell Status Code
172          *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
173          *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
174          *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
175          *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
176          *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
177          *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
178          *
179          * Other response codes:
180          *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
181          *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
182          *                                    association response from the AP)
183          */
184
185         status_code = le16_to_cpu(resp->statuscode);
186         if (priv->fwrelease < 0x09000000) {
187                 switch (status_code) {
188                 case 0x00:
189                         break;
190                 case 0x01:
191                         lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
192                         break;
193                 case 0x02:
194                         lbs_deb_assoc("ASSOC_RESP: internal timer "
195                                 "expired while waiting for the AP\n");
196                         break;
197                 case 0x03:
198                         lbs_deb_assoc("ASSOC_RESP: association "
199                                 "refused by AP\n");
200                         break;
201                 case 0x04:
202                         lbs_deb_assoc("ASSOC_RESP: authentication "
203                                 "refused by AP\n");
204                         break;
205                 default:
206                         lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
207                                 " unknown\n", status_code);
208                         break;
209                 }
210         } else {
211                 /* v9+ returns the AP's association response */
212                 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
213         }
214
215         if (status_code) {
216                 lbs_mac_event_disconnected(priv);
217                 ret = -1;
218                 goto done;
219         }
220
221         lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
222                     (void *) (resp + sizeof (resp->hdr)),
223                     le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
224
225         /* Send a Media Connected event, according to the Spec */
226         priv->connect_status = LBS_CONNECTED;
227
228         /* Update current SSID and BSSID */
229         memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
230         priv->curbssparams.ssid_len = bss->ssid_len;
231         memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
232
233         priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
234         priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
235
236         memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
237         memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
238         priv->nextSNRNF = 0;
239         priv->numSNRNF = 0;
240
241         netif_carrier_on(priv->dev);
242         if (!priv->tx_pending_len)
243                 netif_wake_queue(priv->dev);
244
245         memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
246         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
247         wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
248
249 done:
250         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
251         return ret;
252 }
253
254 /**
255  *  @brief This function prepares an association-class command.
256  *
257  *  @param priv      A pointer to struct lbs_private structure
258  *  @param assoc_req The association request describing the BSS to associate
259  *                   or reassociate with
260  *  @param command   The actual command, either CMD_802_11_ASSOCIATE or
261  *                   CMD_802_11_REASSOCIATE
262  *
263  *  @return         0 or -1
264  */
265 static int lbs_associate(struct lbs_private *priv,
266                          struct assoc_request *assoc_req,
267                          u16 command)
268 {
269         struct cmd_ds_802_11_associate cmd;
270         int ret = 0;
271         struct bss_descriptor *bss = &assoc_req->bss;
272         u8 *pos = &(cmd.iebuf[0]);
273         u16 tmpcap, tmplen, tmpauth;
274         struct mrvl_ie_ssid_param_set *ssid;
275         struct mrvl_ie_ds_param_set *ds;
276         struct mrvl_ie_cf_param_set *cf;
277         struct mrvl_ie_rates_param_set *rates;
278         struct mrvl_ie_rsn_param_set *rsn;
279         struct mrvl_ie_auth_type *auth;
280
281         lbs_deb_enter(LBS_DEB_ASSOC);
282
283         BUG_ON((command != CMD_802_11_ASSOCIATE) &&
284                 (command != CMD_802_11_REASSOCIATE));
285
286         memset(&cmd, 0, sizeof(cmd));
287         cmd.hdr.command = cpu_to_le16(command);
288
289         /* Fill in static fields */
290         memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
291         cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
292
293         /* Capability info */
294         tmpcap = (bss->capability & CAPINFO_MASK);
295         if (bss->mode == IW_MODE_INFRA)
296                 tmpcap |= WLAN_CAPABILITY_ESS;
297         cmd.capability = cpu_to_le16(tmpcap);
298         lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
299
300         /* SSID */
301         ssid = (struct mrvl_ie_ssid_param_set *) pos;
302         ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
303         tmplen = bss->ssid_len;
304         ssid->header.len = cpu_to_le16(tmplen);
305         memcpy(ssid->ssid, bss->ssid, tmplen);
306         pos += sizeof(ssid->header) + tmplen;
307
308         ds = (struct mrvl_ie_ds_param_set *) pos;
309         ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
310         ds->header.len = cpu_to_le16(1);
311         ds->channel = bss->phy.ds.channel;
312         pos += sizeof(ds->header) + 1;
313
314         cf = (struct mrvl_ie_cf_param_set *) pos;
315         cf->header.type = cpu_to_le16(TLV_TYPE_CF);
316         tmplen = sizeof(*cf) - sizeof (cf->header);
317         cf->header.len = cpu_to_le16(tmplen);
318         /* IE payload should be zeroed, firmware fills it in for us */
319         pos += sizeof(*cf);
320
321         rates = (struct mrvl_ie_rates_param_set *) pos;
322         rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
323         tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
324         memcpy(&rates->rates, &bss->rates, tmplen);
325         if (get_common_rates(priv, rates->rates, &tmplen)) {
326                 ret = -1;
327                 goto done;
328         }
329         pos += sizeof(rates->header) + tmplen;
330         rates->header.len = cpu_to_le16(tmplen);
331         lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
332
333         /* Copy the infra. association rates into Current BSS state structure */
334         memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
335         memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
336
337         /* Set MSB on basic rates as the firmware requires, but _after_
338          * copying to current bss rates.
339          */
340         lbs_set_basic_rate_flags(rates->rates, tmplen);
341
342         /* Firmware v9+ indicate authentication suites as a TLV */
343         if (priv->fwrelease >= 0x09000000) {
344                 auth = (struct mrvl_ie_auth_type *) pos;
345                 auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
346                 auth->header.len = cpu_to_le16(2);
347                 tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
348                 auth->auth = cpu_to_le16(tmpauth);
349                 pos += sizeof(auth->header) + 2;
350
351                 lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
352                         bss->bssid, priv->secinfo.auth_mode);
353         }
354
355         /* WPA/WPA2 IEs */
356         if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
357                 rsn = (struct mrvl_ie_rsn_param_set *) pos;
358                 /* WPA_IE or WPA2_IE */
359                 rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
360                 tmplen = (u16) assoc_req->wpa_ie[1];
361                 rsn->header.len = cpu_to_le16(tmplen);
362                 memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
363                 lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
364                         sizeof(rsn->header) + tmplen);
365                 pos += sizeof(rsn->header) + tmplen;
366         }
367
368         cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
369                                    (u16)(pos - (u8 *) &cmd.iebuf));
370
371         /* update curbssparams */
372         priv->curbssparams.channel = bss->phy.ds.channel;
373
374         ret = lbs_cmd_with_response(priv, command, &cmd);
375         if (ret == 0) {
376                 ret = lbs_assoc_post(priv,
377                         (struct cmd_ds_802_11_associate_response *) &cmd);
378         }
379
380 done:
381         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
382         return ret;
383 }
384
385 /**
386  *  @brief Associate to a specific BSS discovered in a scan
387  *
388  *  @param priv      A pointer to struct lbs_private structure
389  *  @param assoc_req The association request describing the BSS to associate with
390  *
391  *  @return          0-success, otherwise fail
392  */
393 static int lbs_try_associate(struct lbs_private *priv,
394         struct assoc_request *assoc_req)
395 {
396         int ret;
397         u8 preamble = RADIO_PREAMBLE_LONG;
398
399         lbs_deb_enter(LBS_DEB_ASSOC);
400
401         /* FW v9 and higher indicate authentication suites as a TLV in the
402          * association command, not as a separate authentication command.
403          */
404         if (priv->fwrelease < 0x09000000) {
405                 ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
406                                              priv->secinfo.auth_mode);
407                 if (ret)
408                         goto out;
409         }
410
411         /* Use short preamble only when both the BSS and firmware support it */
412         if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
413             (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
414                 preamble = RADIO_PREAMBLE_SHORT;
415
416         ret = lbs_set_radio(priv, preamble, 1);
417         if (ret)
418                 goto out;
419
420         ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
421
422 out:
423         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
424         return ret;
425 }
426
427 static int lbs_adhoc_post(struct lbs_private *priv,
428                           struct cmd_ds_802_11_ad_hoc_result *resp)
429 {
430         int ret = 0;
431         u16 command = le16_to_cpu(resp->hdr.command);
432         u16 result = le16_to_cpu(resp->hdr.result);
433         union iwreq_data wrqu;
434         struct bss_descriptor *bss;
435         DECLARE_SSID_BUF(ssid);
436
437         lbs_deb_enter(LBS_DEB_JOIN);
438
439         if (!priv->in_progress_assoc_req) {
440                 lbs_deb_join("ADHOC_RESP: no in-progress association "
441                         "request\n");
442                 ret = -1;
443                 goto done;
444         }
445         bss = &priv->in_progress_assoc_req->bss;
446
447         /*
448          * Join result code 0 --> SUCCESS
449          */
450         if (result) {
451                 lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
452                 if (priv->connect_status == LBS_CONNECTED)
453                         lbs_mac_event_disconnected(priv);
454                 ret = -1;
455                 goto done;
456         }
457
458         /* Send a Media Connected event, according to the Spec */
459         priv->connect_status = LBS_CONNECTED;
460
461         if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
462                 /* Update the created network descriptor with the new BSSID */
463                 memcpy(bss->bssid, resp->bssid, ETH_ALEN);
464         }
465
466         /* Set the BSSID from the joined/started descriptor */
467         memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
468
469         /* Set the new SSID to current SSID */
470         memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
471         priv->curbssparams.ssid_len = bss->ssid_len;
472
473         netif_carrier_on(priv->dev);
474         if (!priv->tx_pending_len)
475                 netif_wake_queue(priv->dev);
476
477         memset(&wrqu, 0, sizeof(wrqu));
478         memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
479         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
480         wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
481
482         lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
483                      print_ssid(ssid, bss->ssid, bss->ssid_len),
484                      priv->curbssparams.bssid,
485                      priv->curbssparams.channel);
486
487 done:
488         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
489         return ret;
490 }
491
492 /**
493  *  @brief Join an adhoc network found in a previous scan
494  *
495  *  @param priv         A pointer to struct lbs_private structure
496  *  @param assoc_req    The association request describing the BSS to join
497  *
498  *  @return             0 on success, error on failure
499  */
500 static int lbs_adhoc_join(struct lbs_private *priv,
501         struct assoc_request *assoc_req)
502 {
503         struct cmd_ds_802_11_ad_hoc_join cmd;
504         struct bss_descriptor *bss = &assoc_req->bss;
505         u8 preamble = RADIO_PREAMBLE_LONG;
506         DECLARE_SSID_BUF(ssid);
507         u16 ratesize = 0;
508         int ret = 0;
509
510         lbs_deb_enter(LBS_DEB_ASSOC);
511
512         lbs_deb_join("current SSID '%s', ssid length %u\n",
513                 print_ssid(ssid, priv->curbssparams.ssid,
514                 priv->curbssparams.ssid_len),
515                 priv->curbssparams.ssid_len);
516         lbs_deb_join("requested ssid '%s', ssid length %u\n",
517                 print_ssid(ssid, bss->ssid, bss->ssid_len),
518                 bss->ssid_len);
519
520         /* check if the requested SSID is already joined */
521         if (priv->curbssparams.ssid_len &&
522             !lbs_ssid_cmp(priv->curbssparams.ssid,
523                         priv->curbssparams.ssid_len,
524                         bss->ssid, bss->ssid_len) &&
525             (priv->mode == IW_MODE_ADHOC) &&
526             (priv->connect_status == LBS_CONNECTED)) {
527                 union iwreq_data wrqu;
528
529                 lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
530                         "current, not attempting to re-join");
531
532                 /* Send the re-association event though, because the association
533                  * request really was successful, even if just a null-op.
534                  */
535                 memset(&wrqu, 0, sizeof(wrqu));
536                 memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
537                        ETH_ALEN);
538                 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
539                 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
540                 goto out;
541         }
542
543         /* Use short preamble only when both the BSS and firmware support it */
544         if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
545             (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
546                 lbs_deb_join("AdhocJoin: Short preamble\n");
547                 preamble = RADIO_PREAMBLE_SHORT;
548         }
549
550         ret = lbs_set_radio(priv, preamble, 1);
551         if (ret)
552                 goto out;
553
554         lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
555         lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
556
557         priv->adhoccreate = 0;
558         priv->curbssparams.channel = bss->channel;
559
560         /* Build the join command */
561         memset(&cmd, 0, sizeof(cmd));
562         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
563
564         cmd.bss.type = CMD_BSS_TYPE_IBSS;
565         cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
566
567         memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
568         memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
569
570         memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
571
572         memcpy(&cmd.bss.ibss, &bss->ss.ibss,
573                sizeof(struct ieee_ie_ibss_param_set));
574
575         cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
576         lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
577                bss->capability, CAPINFO_MASK);
578
579         /* information on BSSID descriptor passed to FW */
580         lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n",
581                         cmd.bss.bssid, cmd.bss.ssid);
582
583         /* Only v8 and below support setting these */
584         if (priv->fwrelease < 0x09000000) {
585                 /* failtimeout */
586                 cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
587                 /* probedelay */
588                 cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
589         }
590
591         /* Copy Data rates from the rates recorded in scan response */
592         memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
593         ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
594         memcpy(cmd.bss.rates, bss->rates, ratesize);
595         if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
596                 lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
597                 ret = -1;
598                 goto out;
599         }
600
601         /* Copy the ad-hoc creation rates into Current BSS state structure */
602         memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
603         memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize);
604
605         /* Set MSB on basic rates as the firmware requires, but _after_
606          * copying to current bss rates.
607          */
608         lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
609
610         cmd.bss.ibss.atimwindow = bss->atimwindow;
611
612         if (assoc_req->secinfo.wep_enabled) {
613                 u16 tmp = le16_to_cpu(cmd.bss.capability);
614                 tmp |= WLAN_CAPABILITY_PRIVACY;
615                 cmd.bss.capability = cpu_to_le16(tmp);
616         }
617
618         if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
619                 __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
620
621                 /* wake up first */
622                 ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
623                                                    CMD_ACT_SET, 0, 0,
624                                                    &local_ps_mode);
625                 if (ret) {
626                         ret = -1;
627                         goto out;
628                 }
629         }
630
631         ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
632         if (ret == 0) {
633                 ret = lbs_adhoc_post(priv,
634                                      (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
635         }
636
637 out:
638         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
639         return ret;
640 }
641
642 /**
643  *  @brief Start an Adhoc Network
644  *
645  *  @param priv         A pointer to struct lbs_private structure
646  *  @param assoc_req    The association request describing the BSS to start
647  *
648  *  @return             0 on success, error on failure
649  */
650 static int lbs_adhoc_start(struct lbs_private *priv,
651         struct assoc_request *assoc_req)
652 {
653         struct cmd_ds_802_11_ad_hoc_start cmd;
654         u8 preamble = RADIO_PREAMBLE_LONG;
655         size_t ratesize = 0;
656         u16 tmpcap = 0;
657         int ret = 0;
658         DECLARE_SSID_BUF(ssid);
659
660         lbs_deb_enter(LBS_DEB_ASSOC);
661
662         if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
663                 lbs_deb_join("ADHOC_START: Will use short preamble\n");
664                 preamble = RADIO_PREAMBLE_SHORT;
665         }
666
667         ret = lbs_set_radio(priv, preamble, 1);
668         if (ret)
669                 goto out;
670
671         /* Build the start command */
672         memset(&cmd, 0, sizeof(cmd));
673         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
674
675         memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
676
677         lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
678                 print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
679                 assoc_req->ssid_len);
680
681         cmd.bsstype = CMD_BSS_TYPE_IBSS;
682
683         if (priv->beacon_period == 0)
684                 priv->beacon_period = MRVDRV_BEACON_INTERVAL;
685         cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
686
687         WARN_ON(!assoc_req->channel);
688
689         /* set Physical parameter set */
690         cmd.ds.header.id = WLAN_EID_DS_PARAMS;
691         cmd.ds.header.len = 1;
692         cmd.ds.channel = assoc_req->channel;
693
694         /* set IBSS parameter set */
695         cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
696         cmd.ibss.header.len = 2;
697         cmd.ibss.atimwindow = cpu_to_le16(0);
698
699         /* set capability info */
700         tmpcap = WLAN_CAPABILITY_IBSS;
701         if (assoc_req->secinfo.wep_enabled ||
702             assoc_req->secinfo.WPAenabled ||
703             assoc_req->secinfo.WPA2enabled) {
704                 lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
705                 tmpcap |= WLAN_CAPABILITY_PRIVACY;
706         } else
707                 lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
708
709         cmd.capability = cpu_to_le16(tmpcap);
710
711         /* Only v8 and below support setting probe delay */
712         if (priv->fwrelease < 0x09000000)
713                 cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
714
715         ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
716         memcpy(cmd.rates, lbs_bg_rates, ratesize);
717
718         /* Copy the ad-hoc creating rates into Current BSS state structure */
719         memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
720         memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize);
721
722         /* Set MSB on basic rates as the firmware requires, but _after_
723          * copying to current bss rates.
724          */
725         lbs_set_basic_rate_flags(cmd.rates, ratesize);
726
727         lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
728                cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
729
730         lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
731                      assoc_req->channel, assoc_req->band);
732
733         priv->adhoccreate = 1;
734         priv->mode = IW_MODE_ADHOC;
735
736         ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
737         if (ret == 0)
738                 ret = lbs_adhoc_post(priv,
739                                      (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
740
741 out:
742         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
743         return ret;
744 }
745
746 /**
747  *  @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
748  *
749  *  @param priv         A pointer to struct lbs_private structure
750  *  @return             0 on success, or an error
751  */
752 int lbs_adhoc_stop(struct lbs_private *priv)
753 {
754         struct cmd_ds_802_11_ad_hoc_stop cmd;
755         int ret;
756
757         lbs_deb_enter(LBS_DEB_JOIN);
758
759         memset(&cmd, 0, sizeof (cmd));
760         cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
761
762         ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
763
764         /* Clean up everything even if there was an error */
765         lbs_mac_event_disconnected(priv);
766
767         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
768         return ret;
769 }
770
771 static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
772                                         struct bss_descriptor *match_bss)
773 {
774         if (!secinfo->wep_enabled  && !secinfo->WPAenabled
775             && !secinfo->WPA2enabled
776             && match_bss->wpa_ie[0] != WLAN_EID_GENERIC
777             && match_bss->rsn_ie[0] != WLAN_EID_RSN
778             && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
779                 return 1;
780         else
781                 return 0;
782 }
783
784 static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
785                                        struct bss_descriptor *match_bss)
786 {
787         if (secinfo->wep_enabled && !secinfo->WPAenabled
788             && !secinfo->WPA2enabled
789             && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
790                 return 1;
791         else
792                 return 0;
793 }
794
795 static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
796                                 struct bss_descriptor *match_bss)
797 {
798         if (!secinfo->wep_enabled && secinfo->WPAenabled
799             && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
800             /* privacy bit may NOT be set in some APs like LinkSys WRT54G
801             && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
802            )
803                 return 1;
804         else
805                 return 0;
806 }
807
808 static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
809                                  struct bss_descriptor *match_bss)
810 {
811         if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
812             (match_bss->rsn_ie[0] == WLAN_EID_RSN)
813             /* privacy bit may NOT be set in some APs like LinkSys WRT54G
814             (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
815            )
816                 return 1;
817         else
818                 return 0;
819 }
820
821 static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
822                                         struct bss_descriptor *match_bss)
823 {
824         if (!secinfo->wep_enabled && !secinfo->WPAenabled
825             && !secinfo->WPA2enabled
826             && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC)
827             && (match_bss->rsn_ie[0] != WLAN_EID_RSN)
828             && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
829                 return 1;
830         else
831                 return 0;
832 }
833
834 /**
835  *  @brief Check if a scanned network compatible with the driver settings
836  *
837  *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
838  * enabled enabled  enabled   AES     mode   privacy  WPA  WPA2  Compatible
839  *    0       0        0       0      NONE      0      0    0   yes No security
840  *    1       0        0       0      NONE      1      0    0   yes Static WEP
841  *    0       1        0       0       x        1x     1    x   yes WPA
842  *    0       0        1       0       x        1x     x    1   yes WPA2
843  *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
844  *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
845  *
846  *
847  *  @param priv A pointer to struct lbs_private
848  *  @param index   Index in scantable to check against current driver settings
849  *  @param mode    Network mode: Infrastructure or IBSS
850  *
851  *  @return        Index in scantable, or error code if negative
852  */
853 static int is_network_compatible(struct lbs_private *priv,
854                                  struct bss_descriptor *bss, uint8_t mode)
855 {
856         int matched = 0;
857
858         lbs_deb_enter(LBS_DEB_SCAN);
859
860         if (bss->mode != mode)
861                 goto done;
862
863         matched = match_bss_no_security(&priv->secinfo, bss);
864         if (matched)
865                 goto done;
866         matched = match_bss_static_wep(&priv->secinfo, bss);
867         if (matched)
868                 goto done;
869         matched = match_bss_wpa(&priv->secinfo, bss);
870         if (matched) {
871                 lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x "
872                              "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
873                              "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
874                              priv->secinfo.wep_enabled ? "e" : "d",
875                              priv->secinfo.WPAenabled ? "e" : "d",
876                              priv->secinfo.WPA2enabled ? "e" : "d",
877                              (bss->capability & WLAN_CAPABILITY_PRIVACY));
878                 goto done;
879         }
880         matched = match_bss_wpa2(&priv->secinfo, bss);
881         if (matched) {
882                 lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x "
883                              "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
884                              "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
885                              priv->secinfo.wep_enabled ? "e" : "d",
886                              priv->secinfo.WPAenabled ? "e" : "d",
887                              priv->secinfo.WPA2enabled ? "e" : "d",
888                              (bss->capability & WLAN_CAPABILITY_PRIVACY));
889                 goto done;
890         }
891         matched = match_bss_dynamic_wep(&priv->secinfo, bss);
892         if (matched) {
893                 lbs_deb_scan("is_network_compatible() dynamic WEP: "
894                              "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
895                              bss->wpa_ie[0], bss->rsn_ie[0],
896                              (bss->capability & WLAN_CAPABILITY_PRIVACY));
897                 goto done;
898         }
899
900         /* bss security settings don't match those configured on card */
901         lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x "
902                      "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
903                      bss->wpa_ie[0], bss->rsn_ie[0],
904                      priv->secinfo.wep_enabled ? "e" : "d",
905                      priv->secinfo.WPAenabled ? "e" : "d",
906                      priv->secinfo.WPA2enabled ? "e" : "d",
907                      (bss->capability & WLAN_CAPABILITY_PRIVACY));
908
909 done:
910         lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
911         return matched;
912 }
913
914 /**
915  *  @brief This function finds a specific compatible BSSID in the scan list
916  *
917  *  Used in association code
918  *
919  *  @param priv  A pointer to struct lbs_private
920  *  @param bssid    BSSID to find in the scan list
921  *  @param mode     Network mode: Infrastructure or IBSS
922  *
923  *  @return         index in BSSID list, or error return code (< 0)
924  */
925 static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
926                                               uint8_t *bssid, uint8_t mode)
927 {
928         struct bss_descriptor *iter_bss;
929         struct bss_descriptor *found_bss = NULL;
930
931         lbs_deb_enter(LBS_DEB_SCAN);
932
933         if (!bssid)
934                 goto out;
935
936         lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
937
938         /* Look through the scan table for a compatible match.  The loop will
939          *   continue past a matched bssid that is not compatible in case there
940          *   is an AP with multiple SSIDs assigned to the same BSSID
941          */
942         mutex_lock(&priv->lock);
943         list_for_each_entry(iter_bss, &priv->network_list, list) {
944                 if (compare_ether_addr(iter_bss->bssid, bssid))
945                         continue; /* bssid doesn't match */
946                 switch (mode) {
947                 case IW_MODE_INFRA:
948                 case IW_MODE_ADHOC:
949                         if (!is_network_compatible(priv, iter_bss, mode))
950                                 break;
951                         found_bss = iter_bss;
952                         break;
953                 default:
954                         found_bss = iter_bss;
955                         break;
956                 }
957         }
958         mutex_unlock(&priv->lock);
959
960 out:
961         lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
962         return found_bss;
963 }
964
965 /**
966  *  @brief This function finds ssid in ssid list.
967  *
968  *  Used in association code
969  *
970  *  @param priv  A pointer to struct lbs_private
971  *  @param ssid     SSID to find in the list
972  *  @param bssid    BSSID to qualify the SSID selection (if provided)
973  *  @param mode     Network mode: Infrastructure or IBSS
974  *
975  *  @return         index in BSSID list
976  */
977 static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
978                                              uint8_t *ssid, uint8_t ssid_len,
979                                              uint8_t *bssid, uint8_t mode,
980                                              int channel)
981 {
982         u32 bestrssi = 0;
983         struct bss_descriptor *iter_bss = NULL;
984         struct bss_descriptor *found_bss = NULL;
985         struct bss_descriptor *tmp_oldest = NULL;
986
987         lbs_deb_enter(LBS_DEB_SCAN);
988
989         mutex_lock(&priv->lock);
990
991         list_for_each_entry(iter_bss, &priv->network_list, list) {
992                 if (!tmp_oldest ||
993                     (iter_bss->last_scanned < tmp_oldest->last_scanned))
994                         tmp_oldest = iter_bss;
995
996                 if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
997                                  ssid, ssid_len) != 0)
998                         continue; /* ssid doesn't match */
999                 if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
1000                         continue; /* bssid doesn't match */
1001                 if ((channel > 0) && (iter_bss->channel != channel))
1002                         continue; /* channel doesn't match */
1003
1004                 switch (mode) {
1005                 case IW_MODE_INFRA:
1006                 case IW_MODE_ADHOC:
1007                         if (!is_network_compatible(priv, iter_bss, mode))
1008                                 break;
1009
1010                         if (bssid) {
1011                                 /* Found requested BSSID */
1012                                 found_bss = iter_bss;
1013                                 goto out;
1014                         }
1015
1016                         if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
1017                                 bestrssi = SCAN_RSSI(iter_bss->rssi);
1018                                 found_bss = iter_bss;
1019                         }
1020                         break;
1021                 case IW_MODE_AUTO:
1022                 default:
1023                         if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
1024                                 bestrssi = SCAN_RSSI(iter_bss->rssi);
1025                                 found_bss = iter_bss;
1026                         }
1027                         break;
1028                 }
1029         }
1030
1031 out:
1032         mutex_unlock(&priv->lock);
1033         lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
1034         return found_bss;
1035 }
1036
1037 static int assoc_helper_essid(struct lbs_private *priv,
1038                               struct assoc_request * assoc_req)
1039 {
1040         int ret = 0;
1041         struct bss_descriptor * bss;
1042         int channel = -1;
1043         DECLARE_SSID_BUF(ssid);
1044
1045         lbs_deb_enter(LBS_DEB_ASSOC);
1046
1047         /* FIXME: take channel into account when picking SSIDs if a channel
1048          * is set.
1049          */
1050
1051         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
1052                 channel = assoc_req->channel;
1053
1054         lbs_deb_assoc("SSID '%s' requested\n",
1055                       print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len));
1056         if (assoc_req->mode == IW_MODE_INFRA) {
1057                 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
1058                         assoc_req->ssid_len);
1059
1060                 bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
1061                                 assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
1062                 if (bss != NULL) {
1063                         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
1064                         ret = lbs_try_associate(priv, assoc_req);
1065                 } else {
1066                         lbs_deb_assoc("SSID not found; cannot associate\n");
1067                 }
1068         } else if (assoc_req->mode == IW_MODE_ADHOC) {
1069                 /* Scan for the network, do not save previous results.  Stale
1070                  *   scan data will cause us to join a non-existant adhoc network
1071                  */
1072                 lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
1073                         assoc_req->ssid_len);
1074
1075                 /* Search for the requested SSID in the scan table */
1076                 bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
1077                                 assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
1078                 if (bss != NULL) {
1079                         lbs_deb_assoc("SSID found, will join\n");
1080                         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
1081                         lbs_adhoc_join(priv, assoc_req);
1082                 } else {
1083                         /* else send START command */
1084                         lbs_deb_assoc("SSID not found, creating adhoc network\n");
1085                         memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
1086                                 IW_ESSID_MAX_SIZE);
1087                         assoc_req->bss.ssid_len = assoc_req->ssid_len;
1088                         lbs_adhoc_start(priv, assoc_req);
1089                 }
1090         }
1091
1092         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1093         return ret;
1094 }
1095
1096
1097 static int assoc_helper_bssid(struct lbs_private *priv,
1098                               struct assoc_request * assoc_req)
1099 {
1100         int ret = 0;
1101         struct bss_descriptor * bss;
1102
1103         lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid);
1104
1105         /* Search for index position in list for requested MAC */
1106         bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
1107                             assoc_req->mode);
1108         if (bss == NULL) {
1109                 lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, "
1110                         "cannot associate.\n", assoc_req->bssid);
1111                 goto out;
1112         }
1113
1114         memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
1115         if (assoc_req->mode == IW_MODE_INFRA) {
1116                 ret = lbs_try_associate(priv, assoc_req);
1117                 lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
1118                               ret);
1119         } else if (assoc_req->mode == IW_MODE_ADHOC) {
1120                 lbs_adhoc_join(priv, assoc_req);
1121         }
1122
1123 out:
1124         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1125         return ret;
1126 }
1127
1128
1129 static int assoc_helper_associate(struct lbs_private *priv,
1130                                   struct assoc_request * assoc_req)
1131 {
1132         int ret = 0, done = 0;
1133
1134         lbs_deb_enter(LBS_DEB_ASSOC);
1135
1136         /* If we're given and 'any' BSSID, try associating based on SSID */
1137
1138         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
1139                 if (compare_ether_addr(bssid_any, assoc_req->bssid)
1140                     && compare_ether_addr(bssid_off, assoc_req->bssid)) {
1141                         ret = assoc_helper_bssid(priv, assoc_req);
1142                         done = 1;
1143                 }
1144         }
1145
1146         if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
1147                 ret = assoc_helper_essid(priv, assoc_req);
1148         }
1149
1150         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1151         return ret;
1152 }
1153
1154
1155 static int assoc_helper_mode(struct lbs_private *priv,
1156                              struct assoc_request * assoc_req)
1157 {
1158         int ret = 0;
1159
1160         lbs_deb_enter(LBS_DEB_ASSOC);
1161
1162         if (assoc_req->mode == priv->mode)
1163                 goto done;
1164
1165         if (assoc_req->mode == IW_MODE_INFRA) {
1166                 if (priv->psstate != PS_STATE_FULL_POWER)
1167                         lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
1168                 priv->psmode = LBS802_11POWERMODECAM;
1169         }
1170
1171         priv->mode = assoc_req->mode;
1172         ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode);
1173
1174 done:
1175         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1176         return ret;
1177 }
1178
1179 static int assoc_helper_channel(struct lbs_private *priv,
1180                                 struct assoc_request * assoc_req)
1181 {
1182         int ret = 0;
1183
1184         lbs_deb_enter(LBS_DEB_ASSOC);
1185
1186         ret = lbs_update_channel(priv);
1187         if (ret) {
1188                 lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
1189                 goto done;
1190         }
1191
1192         if (assoc_req->channel == priv->curbssparams.channel)
1193                 goto done;
1194
1195         if (priv->mesh_dev) {
1196                 /* Change mesh channel first; 21.p21 firmware won't let
1197                    you change channel otherwise (even though it'll return
1198                    an error to this */
1199                 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
1200                                 assoc_req->channel);
1201         }
1202
1203         lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
1204                       priv->curbssparams.channel, assoc_req->channel);
1205
1206         ret = lbs_set_channel(priv, assoc_req->channel);
1207         if (ret < 0)
1208                 lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
1209
1210         /* FIXME: shouldn't need to grab the channel _again_ after setting
1211          * it since the firmware is supposed to return the new channel, but
1212          * whatever... */
1213         ret = lbs_update_channel(priv);
1214         if (ret) {
1215                 lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
1216                 goto done;
1217         }
1218
1219         if (assoc_req->channel != priv->curbssparams.channel) {
1220                 lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
1221                               assoc_req->channel);
1222                 goto restore_mesh;
1223         }
1224
1225         if (   assoc_req->secinfo.wep_enabled
1226             &&   (assoc_req->wep_keys[0].len
1227                || assoc_req->wep_keys[1].len
1228                || assoc_req->wep_keys[2].len
1229                || assoc_req->wep_keys[3].len)) {
1230                 /* Make sure WEP keys are re-sent to firmware */
1231                 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1232         }
1233
1234         /* Must restart/rejoin adhoc networks after channel change */
1235         set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
1236
1237  restore_mesh:
1238         if (priv->mesh_dev)
1239                 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
1240                                 priv->curbssparams.channel);
1241
1242  done:
1243         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1244         return ret;
1245 }
1246
1247
1248 static int assoc_helper_wep_keys(struct lbs_private *priv,
1249                                  struct assoc_request *assoc_req)
1250 {
1251         int i;
1252         int ret = 0;
1253
1254         lbs_deb_enter(LBS_DEB_ASSOC);
1255
1256         /* Set or remove WEP keys */
1257         if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
1258             assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
1259                 ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
1260         else
1261                 ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
1262
1263         if (ret)
1264                 goto out;
1265
1266         /* enable/disable the MAC's WEP packet filter */
1267         if (assoc_req->secinfo.wep_enabled)
1268                 priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
1269         else
1270                 priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
1271
1272         lbs_set_mac_control(priv);
1273
1274         mutex_lock(&priv->lock);
1275
1276         /* Copy WEP keys into priv wep key fields */
1277         for (i = 0; i < 4; i++) {
1278                 memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
1279                        sizeof(struct enc_key));
1280         }
1281         priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
1282
1283         mutex_unlock(&priv->lock);
1284
1285 out:
1286         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1287         return ret;
1288 }
1289
1290 static int assoc_helper_secinfo(struct lbs_private *priv,
1291                                 struct assoc_request * assoc_req)
1292 {
1293         int ret = 0;
1294         uint16_t do_wpa;
1295         uint16_t rsn = 0;
1296
1297         lbs_deb_enter(LBS_DEB_ASSOC);
1298
1299         memcpy(&priv->secinfo, &assoc_req->secinfo,
1300                 sizeof(struct lbs_802_11_security));
1301
1302         lbs_set_mac_control(priv);
1303
1304         /* If RSN is already enabled, don't try to enable it again, since
1305          * ENABLE_RSN resets internal state machines and will clobber the
1306          * 4-way WPA handshake.
1307          */
1308
1309         /* Get RSN enabled/disabled */
1310         ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
1311         if (ret) {
1312                 lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
1313                 goto out;
1314         }
1315
1316         /* Don't re-enable RSN if it's already enabled */
1317         do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
1318         if (do_wpa == rsn)
1319                 goto out;
1320
1321         /* Set RSN enabled/disabled */
1322         ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
1323
1324 out:
1325         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1326         return ret;
1327 }
1328
1329
1330 static int assoc_helper_wpa_keys(struct lbs_private *priv,
1331                                  struct assoc_request * assoc_req)
1332 {
1333         int ret = 0;
1334         unsigned int flags = assoc_req->flags;
1335
1336         lbs_deb_enter(LBS_DEB_ASSOC);
1337
1338         /* Work around older firmware bug where WPA unicast and multicast
1339          * keys must be set independently.  Seen in SDIO parts with firmware
1340          * version 5.0.11p0.
1341          */
1342
1343         if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
1344                 clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1345                 ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
1346                 assoc_req->flags = flags;
1347         }
1348
1349         if (ret)
1350                 goto out;
1351
1352         memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
1353                         sizeof(struct enc_key));
1354
1355         if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
1356                 clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1357
1358                 ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
1359                 assoc_req->flags = flags;
1360
1361                 memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
1362                                 sizeof(struct enc_key));
1363         }
1364
1365 out:
1366         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1367         return ret;
1368 }
1369
1370
1371 static int assoc_helper_wpa_ie(struct lbs_private *priv,
1372                                struct assoc_request * assoc_req)
1373 {
1374         int ret = 0;
1375
1376         lbs_deb_enter(LBS_DEB_ASSOC);
1377
1378         if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
1379                 memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
1380                 priv->wpa_ie_len = assoc_req->wpa_ie_len;
1381         } else {
1382                 memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
1383                 priv->wpa_ie_len = 0;
1384         }
1385
1386         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1387         return ret;
1388 }
1389
1390
1391 static int should_deauth_infrastructure(struct lbs_private *priv,
1392                                         struct assoc_request * assoc_req)
1393 {
1394         int ret = 0;
1395
1396         if (priv->connect_status != LBS_CONNECTED)
1397                 return 0;
1398
1399         lbs_deb_enter(LBS_DEB_ASSOC);
1400         if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
1401                 lbs_deb_assoc("Deauthenticating due to new SSID\n");
1402                 ret = 1;
1403                 goto out;
1404         }
1405
1406         if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
1407                 if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
1408                         lbs_deb_assoc("Deauthenticating due to new security\n");
1409                         ret = 1;
1410                         goto out;
1411                 }
1412         }
1413
1414         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
1415                 lbs_deb_assoc("Deauthenticating due to new BSSID\n");
1416                 ret = 1;
1417                 goto out;
1418         }
1419
1420         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
1421                 lbs_deb_assoc("Deauthenticating due to channel switch\n");
1422                 ret = 1;
1423                 goto out;
1424         }
1425
1426         /* FIXME: deal with 'auto' mode somehow */
1427         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
1428                 if (assoc_req->mode != IW_MODE_INFRA) {
1429                         lbs_deb_assoc("Deauthenticating due to leaving "
1430                                 "infra mode\n");
1431                         ret = 1;
1432                         goto out;
1433                 }
1434         }
1435
1436 out:
1437         lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
1438         return ret;
1439 }
1440
1441
1442 static int should_stop_adhoc(struct lbs_private *priv,
1443                              struct assoc_request * assoc_req)
1444 {
1445         lbs_deb_enter(LBS_DEB_ASSOC);
1446
1447         if (priv->connect_status != LBS_CONNECTED)
1448                 return 0;
1449
1450         if (lbs_ssid_cmp(priv->curbssparams.ssid,
1451                               priv->curbssparams.ssid_len,
1452                               assoc_req->ssid, assoc_req->ssid_len) != 0)
1453                 return 1;
1454
1455         /* FIXME: deal with 'auto' mode somehow */
1456         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
1457                 if (assoc_req->mode != IW_MODE_ADHOC)
1458                         return 1;
1459         }
1460
1461         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
1462                 if (assoc_req->channel != priv->curbssparams.channel)
1463                         return 1;
1464         }
1465
1466         lbs_deb_leave(LBS_DEB_ASSOC);
1467         return 0;
1468 }
1469
1470
1471 /**
1472  *  @brief This function finds the best SSID in the Scan List
1473  *
1474  *  Search the scan table for the best SSID that also matches the current
1475  *   adapter network preference (infrastructure or adhoc)
1476  *
1477  *  @param priv  A pointer to struct lbs_private
1478  *
1479  *  @return         index in BSSID list
1480  */
1481 static struct bss_descriptor *lbs_find_best_ssid_in_list(
1482         struct lbs_private *priv, uint8_t mode)
1483 {
1484         uint8_t bestrssi = 0;
1485         struct bss_descriptor *iter_bss;
1486         struct bss_descriptor *best_bss = NULL;
1487
1488         lbs_deb_enter(LBS_DEB_SCAN);
1489
1490         mutex_lock(&priv->lock);
1491
1492         list_for_each_entry(iter_bss, &priv->network_list, list) {
1493                 switch (mode) {
1494                 case IW_MODE_INFRA:
1495                 case IW_MODE_ADHOC:
1496                         if (!is_network_compatible(priv, iter_bss, mode))
1497                                 break;
1498                         if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
1499                                 break;
1500                         bestrssi = SCAN_RSSI(iter_bss->rssi);
1501                         best_bss = iter_bss;
1502                         break;
1503                 case IW_MODE_AUTO:
1504                 default:
1505                         if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
1506                                 break;
1507                         bestrssi = SCAN_RSSI(iter_bss->rssi);
1508                         best_bss = iter_bss;
1509                         break;
1510                 }
1511         }
1512
1513         mutex_unlock(&priv->lock);
1514         lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
1515         return best_bss;
1516 }
1517
1518 /**
1519  *  @brief Find the best AP
1520  *
1521  *  Used from association worker.
1522  *
1523  *  @param priv         A pointer to struct lbs_private structure
1524  *  @param pSSID        A pointer to AP's ssid
1525  *
1526  *  @return             0--success, otherwise--fail
1527  */
1528 static int lbs_find_best_network_ssid(struct lbs_private *priv,
1529         uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode,
1530         uint8_t *out_mode)
1531 {
1532         int ret = -1;
1533         struct bss_descriptor *found;
1534
1535         lbs_deb_enter(LBS_DEB_SCAN);
1536
1537         priv->scan_ssid_len = 0;
1538         lbs_scan_networks(priv, 1);
1539         if (priv->surpriseremoved)
1540                 goto out;
1541
1542         found = lbs_find_best_ssid_in_list(priv, preferred_mode);
1543         if (found && (found->ssid_len > 0)) {
1544                 memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
1545                 *out_ssid_len = found->ssid_len;
1546                 *out_mode = found->mode;
1547                 ret = 0;
1548         }
1549
1550 out:
1551         lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
1552         return ret;
1553 }
1554
1555
1556 void lbs_association_worker(struct work_struct *work)
1557 {
1558         struct lbs_private *priv = container_of(work, struct lbs_private,
1559                 assoc_work.work);
1560         struct assoc_request * assoc_req = NULL;
1561         int ret = 0;
1562         int find_any_ssid = 0;
1563         DECLARE_SSID_BUF(ssid);
1564
1565         lbs_deb_enter(LBS_DEB_ASSOC);
1566
1567         mutex_lock(&priv->lock);
1568         assoc_req = priv->pending_assoc_req;
1569         priv->pending_assoc_req = NULL;
1570         priv->in_progress_assoc_req = assoc_req;
1571         mutex_unlock(&priv->lock);
1572
1573         if (!assoc_req)
1574                 goto done;
1575
1576         lbs_deb_assoc(
1577                 "Association Request:\n"
1578                 "    flags:     0x%08lx\n"
1579                 "    SSID:      '%s'\n"
1580                 "    chann:     %d\n"
1581                 "    band:      %d\n"
1582                 "    mode:      %d\n"
1583                 "    BSSID:     %pM\n"
1584                 "    secinfo:  %s%s%s\n"
1585                 "    auth_mode: %d\n",
1586                 assoc_req->flags,
1587                 print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
1588                 assoc_req->channel, assoc_req->band, assoc_req->mode,
1589                 assoc_req->bssid,
1590                 assoc_req->secinfo.WPAenabled ? " WPA" : "",
1591                 assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
1592                 assoc_req->secinfo.wep_enabled ? " WEP" : "",
1593                 assoc_req->secinfo.auth_mode);
1594
1595         /* If 'any' SSID was specified, find an SSID to associate with */
1596         if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
1597             && !assoc_req->ssid_len)
1598                 find_any_ssid = 1;
1599
1600         /* But don't use 'any' SSID if there's a valid locked BSSID to use */
1601         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
1602                 if (compare_ether_addr(assoc_req->bssid, bssid_any)
1603                     && compare_ether_addr(assoc_req->bssid, bssid_off))
1604                         find_any_ssid = 0;
1605         }
1606
1607         if (find_any_ssid) {
1608                 u8 new_mode = assoc_req->mode;
1609
1610                 ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
1611                                 &assoc_req->ssid_len, assoc_req->mode, &new_mode);
1612                 if (ret) {
1613                         lbs_deb_assoc("Could not find best network\n");
1614                         ret = -ENETUNREACH;
1615                         goto out;
1616                 }
1617
1618                 /* Ensure we switch to the mode of the AP */
1619                 if (assoc_req->mode == IW_MODE_AUTO) {
1620                         set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
1621                         assoc_req->mode = new_mode;
1622                 }
1623         }
1624
1625         /*
1626          * Check if the attributes being changing require deauthentication
1627          * from the currently associated infrastructure access point.
1628          */
1629         if (priv->mode == IW_MODE_INFRA) {
1630                 if (should_deauth_infrastructure(priv, assoc_req)) {
1631                         ret = lbs_cmd_80211_deauthenticate(priv,
1632                                                            priv->curbssparams.bssid,
1633                                                            WLAN_REASON_DEAUTH_LEAVING);
1634                         if (ret) {
1635                                 lbs_deb_assoc("Deauthentication due to new "
1636                                         "configuration request failed: %d\n",
1637                                         ret);
1638                         }
1639                 }
1640         } else if (priv->mode == IW_MODE_ADHOC) {
1641                 if (should_stop_adhoc(priv, assoc_req)) {
1642                         ret = lbs_adhoc_stop(priv);
1643                         if (ret) {
1644                                 lbs_deb_assoc("Teardown of AdHoc network due to "
1645                                         "new configuration request failed: %d\n",
1646                                         ret);
1647                         }
1648
1649                 }
1650         }
1651
1652         /* Send the various configuration bits to the firmware */
1653         if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
1654                 ret = assoc_helper_mode(priv, assoc_req);
1655                 if (ret)
1656                         goto out;
1657         }
1658
1659         if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
1660                 ret = assoc_helper_channel(priv, assoc_req);
1661                 if (ret)
1662                         goto out;
1663         }
1664
1665         if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
1666             || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
1667                 ret = assoc_helper_wep_keys(priv, assoc_req);
1668                 if (ret)
1669                         goto out;
1670         }
1671
1672         if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
1673                 ret = assoc_helper_secinfo(priv, assoc_req);
1674                 if (ret)
1675                         goto out;
1676         }
1677
1678         if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
1679                 ret = assoc_helper_wpa_ie(priv, assoc_req);
1680                 if (ret)
1681                         goto out;
1682         }
1683
1684         if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
1685             || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
1686                 ret = assoc_helper_wpa_keys(priv, assoc_req);
1687                 if (ret)
1688                         goto out;
1689         }
1690
1691         /* SSID/BSSID should be the _last_ config option set, because they
1692          * trigger the association attempt.
1693          */
1694         if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
1695             || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
1696                 int success = 1;
1697
1698                 ret = assoc_helper_associate(priv, assoc_req);
1699                 if (ret) {
1700                         lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
1701                                 ret);
1702                         success = 0;
1703                 }
1704
1705                 if (priv->connect_status != LBS_CONNECTED) {
1706                         lbs_deb_assoc("ASSOC: association unsuccessful, "
1707                                 "not connected\n");
1708                         success = 0;
1709                 }
1710
1711                 if (success) {
1712                         lbs_deb_assoc("associated to %pM\n",
1713                                 priv->curbssparams.bssid);
1714                         lbs_prepare_and_send_command(priv,
1715                                 CMD_802_11_RSSI,
1716                                 0, CMD_OPTION_WAITFORRSP, 0, NULL);
1717                 } else {
1718                         ret = -1;
1719                 }
1720         }
1721
1722 out:
1723         if (ret) {
1724                 lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
1725                         ret);
1726         }
1727
1728         mutex_lock(&priv->lock);
1729         priv->in_progress_assoc_req = NULL;
1730         mutex_unlock(&priv->lock);
1731         kfree(assoc_req);
1732
1733 done:
1734         lbs_deb_leave(LBS_DEB_ASSOC);
1735 }
1736
1737
1738 /*
1739  * Caller MUST hold any necessary locks
1740  */
1741 struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
1742 {
1743         struct assoc_request * assoc_req;
1744
1745         lbs_deb_enter(LBS_DEB_ASSOC);
1746         if (!priv->pending_assoc_req) {
1747                 priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
1748                                                      GFP_KERNEL);
1749                 if (!priv->pending_assoc_req) {
1750                         lbs_pr_info("Not enough memory to allocate association"
1751                                 " request!\n");
1752                         return NULL;
1753                 }
1754         }
1755
1756         /* Copy current configuration attributes to the association request,
1757          * but don't overwrite any that are already set.
1758          */
1759         assoc_req = priv->pending_assoc_req;
1760         if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
1761                 memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
1762                        IW_ESSID_MAX_SIZE);
1763                 assoc_req->ssid_len = priv->curbssparams.ssid_len;
1764         }
1765
1766         if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
1767                 assoc_req->channel = priv->curbssparams.channel;
1768
1769         if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
1770                 assoc_req->band = priv->curbssparams.band;
1771
1772         if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
1773                 assoc_req->mode = priv->mode;
1774
1775         if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
1776                 memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
1777                         ETH_ALEN);
1778         }
1779
1780         if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
1781                 int i;
1782                 for (i = 0; i < 4; i++) {
1783                         memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
1784                                 sizeof(struct enc_key));
1785                 }
1786         }
1787
1788         if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
1789                 assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
1790
1791         if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
1792                 memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
1793                         sizeof(struct enc_key));
1794         }
1795
1796         if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
1797                 memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
1798                         sizeof(struct enc_key));
1799         }
1800
1801         if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
1802                 memcpy(&assoc_req->secinfo, &priv->secinfo,
1803                         sizeof(struct lbs_802_11_security));
1804         }
1805
1806         if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
1807                 memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
1808                         MAX_WPA_IE_LEN);
1809                 assoc_req->wpa_ie_len = priv->wpa_ie_len;
1810         }
1811
1812         lbs_deb_leave(LBS_DEB_ASSOC);
1813         return assoc_req;
1814 }
1815
1816
1817 /**
1818  *  @brief Deauthenticate from a specific BSS
1819  *
1820  *  @param priv        A pointer to struct lbs_private structure
1821  *  @param bssid       The specific BSS to deauthenticate from
1822  *  @param reason      The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
1823  *
1824  *  @return            0 on success, error on failure
1825  */
1826 int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
1827                                  u16 reason)
1828 {
1829         struct cmd_ds_802_11_deauthenticate cmd;
1830         int ret;
1831
1832         lbs_deb_enter(LBS_DEB_JOIN);
1833
1834         memset(&cmd, 0, sizeof(cmd));
1835         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1836         memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
1837         cmd.reasoncode = cpu_to_le16(reason);
1838
1839         ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
1840
1841         /* Clean up everything even if there was an error; can't assume that
1842          * we're still authenticated to the AP after trying to deauth.
1843          */
1844         lbs_mac_event_disconnected(priv);
1845
1846         lbs_deb_leave(LBS_DEB_JOIN);
1847         return ret;
1848 }
1849