]> err.no Git - linux-2.6/blob - drivers/net/wireless/libertas/join.c
Pull battery into release branch
[linux-2.6] / drivers / net / wireless / libertas / join.c
1 /**
2   *  Functions implementing wlan infrastructure and adhoc join routines,
3   *  IOCTL handlers as well as command preperation and response routines
4   *  for sending adhoc start, adhoc join, and association commands
5   *  to the firmware.
6   */
7 #include <linux/netdevice.h>
8 #include <linux/if_arp.h>
9 #include <linux/wireless.h>
10 #include <linux/etherdevice.h>
11
12 #include <net/iw_handler.h>
13
14 #include "host.h"
15 #include "decl.h"
16 #include "join.h"
17 #include "dev.h"
18 #include "assoc.h"
19
20 #define AD_HOC_CAP_PRIVACY_ON 1
21
22 /**
23  *  @brief This function finds out the common rates between rate1 and rate2.
24  *
25  * It will fill common rates in rate1 as output if found.
26  *
27  * NOTE: Setting the MSB of the basic rates need to be taken
28  *   care, either before or after calling this function
29  *
30  *  @param adapter     A pointer to wlan_adapter structure
31  *  @param rate1       the buffer which keeps input and output
32  *  @param rate1_size  the size of rate1 buffer
33  *  @param rate2       the buffer which keeps rate2
34  *  @param rate2_size  the size of rate2 buffer.
35  *
36  *  @return            0 or -1
37  */
38 static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
39                             int rate1_size, u8 * rate2, int rate2_size)
40 {
41         u8 *ptr = rate1;
42         int ret = 0;
43         u8 tmp[30];
44         int i;
45
46         memset(&tmp, 0, sizeof(tmp));
47         memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
48         memset(rate1, 0, rate1_size);
49
50         /* Mask the top bit of the original values */
51         for (i = 0; tmp[i] && i < sizeof(tmp); i++)
52                 tmp[i] &= 0x7F;
53
54         for (i = 0; rate2[i] && i < rate2_size; i++) {
55                 /* Check for Card Rate in tmp, excluding the top bit */
56                 if (strchr(tmp, rate2[i] & 0x7F)) {
57                         /* values match, so copy the Card Rate to rate1 */
58                         *rate1++ = rate2[i];
59                 }
60         }
61
62         lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
63         lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
64         lbs_dbg_hex("Common rates:", ptr, rate1_size);
65         lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate);
66
67         if (!adapter->is_datarate_auto) {
68                 while (*ptr) {
69                         if ((*ptr & 0x7f) == adapter->datarate) {
70                                 ret = 0;
71                                 goto done;
72                         }
73                         ptr++;
74                 }
75                 lbs_pr_alert( "Previously set fixed data rate %#x isn't "
76                        "compatible with the network.\n", adapter->datarate);
77
78                 ret = -1;
79                 goto done;
80         }
81
82         ret = 0;
83 done:
84         return ret;
85 }
86
87 int libertas_send_deauth(wlan_private * priv)
88 {
89         wlan_adapter *adapter = priv->adapter;
90         int ret = 0;
91
92         if (adapter->mode == IW_MODE_INFRA &&
93             adapter->connect_status == libertas_connected)
94                 ret = libertas_send_deauthentication(priv);
95         else
96                 ret = -ENOTSUPP;
97
98         return ret;
99 }
100
101 /**
102  *  @brief Associate to a specific BSS discovered in a scan
103  *
104  *  @param priv      A pointer to wlan_private structure
105  *  @param pbssdesc  Pointer to the BSS descriptor to associate with.
106  *
107  *  @return          0-success, otherwise fail
108  */
109 int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req)
110 {
111         wlan_adapter *adapter = priv->adapter;
112         int ret;
113
114         lbs_deb_enter(LBS_DEB_JOIN);
115
116         ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
117                                     0, cmd_option_waitforrsp,
118                                     0, assoc_req->bss.bssid);
119
120         if (ret)
121                 goto done;
122
123         /* set preamble to firmware */
124         if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble)
125                 adapter->preamble = cmd_type_short_preamble;
126         else
127                 adapter->preamble = cmd_type_long_preamble;
128
129         libertas_set_radio_control(priv);
130
131         ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
132                                     0, cmd_option_waitforrsp, 0, assoc_req);
133
134 done:
135         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
136         return ret;
137 }
138
139 /**
140  *  @brief Start an Adhoc Network
141  *
142  *  @param priv         A pointer to wlan_private structure
143  *  @param adhocssid    The ssid of the Adhoc Network
144  *  @return             0--success, -1--fail
145  */
146 int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
147 {
148         wlan_adapter *adapter = priv->adapter;
149         int ret = 0;
150
151         adapter->adhoccreate = 1;
152
153         if (!adapter->capinfo.shortpreamble) {
154                 lbs_deb_join("AdhocStart: Long preamble\n");
155                 adapter->preamble = cmd_type_long_preamble;
156         } else {
157                 lbs_deb_join("AdhocStart: Short preamble\n");
158                 adapter->preamble = cmd_type_short_preamble;
159         }
160
161         libertas_set_radio_control(priv);
162
163         lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
164         lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
165
166         ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
167                                     0, cmd_option_waitforrsp, 0, assoc_req);
168
169         return ret;
170 }
171
172 /**
173  *  @brief Join an adhoc network found in a previous scan
174  *
175  *  @param priv         A pointer to wlan_private structure
176  *  @param pbssdesc     Pointer to a BSS descriptor found in a previous scan
177  *                      to attempt to join
178  *
179  *  @return             0--success, -1--fail
180  */
181 int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
182 {
183         wlan_adapter *adapter = priv->adapter;
184         struct bss_descriptor * bss = &assoc_req->bss;
185         int ret = 0;
186
187         lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
188                      __func__,
189                      escape_essid(adapter->curbssparams.ssid,
190                                   adapter->curbssparams.ssid_len),
191                      adapter->curbssparams.ssid_len);
192         lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
193                      __func__, escape_essid(bss->ssid, bss->ssid_len),
194                      bss->ssid_len);
195
196         /* check if the requested SSID is already joined */
197         if (adapter->curbssparams.ssid_len
198             && !libertas_ssid_cmp(adapter->curbssparams.ssid,
199                                   adapter->curbssparams.ssid_len,
200                                   bss->ssid, bss->ssid_len)
201             && (adapter->mode == IW_MODE_ADHOC)) {
202                 lbs_deb_join(
203                        "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
204                        "not attempting to re-join");
205                 return -1;
206         }
207
208         /*Use shortpreamble only when both creator and card supports
209            short preamble */
210         if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
211                 lbs_deb_join("AdhocJoin: Long preamble\n");
212                 adapter->preamble = cmd_type_long_preamble;
213         } else {
214                 lbs_deb_join("AdhocJoin: Short preamble\n");
215                 adapter->preamble = cmd_type_short_preamble;
216         }
217
218         libertas_set_radio_control(priv);
219
220         lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
221         lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
222
223         adapter->adhoccreate = 0;
224
225         ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
226                                     0, cmd_option_waitforrsp,
227                                     OID_802_11_SSID, assoc_req);
228
229         return ret;
230 }
231
232 int libertas_stop_adhoc_network(wlan_private * priv)
233 {
234         return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
235                                      0, cmd_option_waitforrsp, 0, NULL);
236 }
237
238 /**
239  *  @brief Send Deauthentication Request
240  *
241  *  @param priv      A pointer to wlan_private structure
242  *  @return          0--success, -1--fail
243  */
244 int libertas_send_deauthentication(wlan_private * priv)
245 {
246         return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
247                                      0, cmd_option_waitforrsp, 0, NULL);
248 }
249
250 /**
251  *  @brief This function prepares command of authenticate.
252  *
253  *  @param priv      A pointer to wlan_private structure
254  *  @param cmd       A pointer to cmd_ds_command structure
255  *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
256  *
257  *  @return         0 or -1
258  */
259 int libertas_cmd_80211_authenticate(wlan_private * priv,
260                                  struct cmd_ds_command *cmd,
261                                  void *pdata_buf)
262 {
263         wlan_adapter *adapter = priv->adapter;
264         struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
265         int ret = -1;
266         u8 *bssid = pdata_buf;
267
268         lbs_deb_enter(LBS_DEB_JOIN);
269
270         cmd->command = cpu_to_le16(cmd_802_11_authenticate);
271         cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
272                                 + S_DS_GEN);
273
274         /* translate auth mode to 802.11 defined wire value */
275         switch (adapter->secinfo.auth_mode) {
276         case IW_AUTH_ALG_OPEN_SYSTEM:
277                 pauthenticate->authtype = 0x00;
278                 break;
279         case IW_AUTH_ALG_SHARED_KEY:
280                 pauthenticate->authtype = 0x01;
281                 break;
282         case IW_AUTH_ALG_LEAP:
283                 pauthenticate->authtype = 0x80;
284                 break;
285         default:
286                 lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
287                              adapter->secinfo.auth_mode);
288                 goto out;
289         }
290
291         memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
292
293         lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n",
294                      MAC_ARG(bssid), pauthenticate->authtype);
295         ret = 0;
296
297 out:
298         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
299         return ret;
300 }
301
302 int libertas_cmd_80211_deauthenticate(wlan_private * priv,
303                                    struct cmd_ds_command *cmd)
304 {
305         wlan_adapter *adapter = priv->adapter;
306         struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
307
308         lbs_deb_enter(LBS_DEB_JOIN);
309
310         cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
311         cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
312                              S_DS_GEN);
313
314         /* set AP MAC address */
315         memmove(dauth->macaddr, adapter->curbssparams.bssid, ETH_ALEN);
316
317         /* Reason code 3 = Station is leaving */
318 #define REASON_CODE_STA_LEAVING 3
319         dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
320
321         lbs_deb_leave(LBS_DEB_JOIN);
322         return 0;
323 }
324
325 int libertas_cmd_80211_associate(wlan_private * priv,
326                               struct cmd_ds_command *cmd, void *pdata_buf)
327 {
328         wlan_adapter *adapter = priv->adapter;
329         struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
330         int ret = 0;
331         struct assoc_request * assoc_req = pdata_buf;
332         struct bss_descriptor * bss = &assoc_req->bss;
333         u8 *card_rates;
334         u8 *pos;
335         int card_rates_size;
336         u16 tmpcap, tmplen;
337         struct mrvlietypes_ssidparamset *ssid;
338         struct mrvlietypes_phyparamset *phy;
339         struct mrvlietypes_ssparamset *ss;
340         struct mrvlietypes_ratesparamset *rates;
341         struct mrvlietypes_rsnparamset *rsn;
342
343         lbs_deb_enter(LBS_DEB_JOIN);
344
345         pos = (u8 *) passo;
346
347         if (!adapter) {
348                 ret = -1;
349                 goto done;
350         }
351
352         cmd->command = cpu_to_le16(cmd_802_11_associate);
353
354         memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
355         pos += sizeof(passo->peerstaaddr);
356
357         /* set the listen interval */
358         passo->listeninterval = cpu_to_le16(adapter->listeninterval);
359
360         pos += sizeof(passo->capinfo);
361         pos += sizeof(passo->listeninterval);
362         pos += sizeof(passo->bcnperiod);
363         pos += sizeof(passo->dtimperiod);
364
365         ssid = (struct mrvlietypes_ssidparamset *) pos;
366         ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
367         tmplen = bss->ssid_len;
368         ssid->header.len = cpu_to_le16(tmplen);
369         memcpy(ssid->ssid, bss->ssid, tmplen);
370         pos += sizeof(ssid->header) + tmplen;
371
372         phy = (struct mrvlietypes_phyparamset *) pos;
373         phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
374         tmplen = sizeof(phy->fh_ds.dsparamset);
375         phy->header.len = cpu_to_le16(tmplen);
376         memcpy(&phy->fh_ds.dsparamset,
377                &bss->phyparamset.dsparamset.currentchan,
378                tmplen);
379         pos += sizeof(phy->header) + tmplen;
380
381         ss = (struct mrvlietypes_ssparamset *) pos;
382         ss->header.type = cpu_to_le16(TLV_TYPE_CF);
383         tmplen = sizeof(ss->cf_ibss.cfparamset);
384         ss->header.len = cpu_to_le16(tmplen);
385         pos += sizeof(ss->header) + tmplen;
386
387         rates = (struct mrvlietypes_ratesparamset *) pos;
388         rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
389
390         memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES);
391
392         card_rates = libertas_supported_rates;
393         card_rates_size = sizeof(libertas_supported_rates);
394
395         if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
396                              card_rates, card_rates_size)) {
397                 ret = -1;
398                 goto done;
399         }
400
401         tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
402         adapter->curbssparams.numofrates = tmplen;
403
404         pos += sizeof(rates->header) + tmplen;
405         rates->header.len = cpu_to_le16(tmplen);
406
407         if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
408                 rsn = (struct mrvlietypes_rsnparamset *) pos;
409                 /* WPA_IE or WPA2_IE */
410                 rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
411                 tmplen = (u16) assoc_req->wpa_ie[1];
412                 rsn->header.len = cpu_to_le16(tmplen);
413                 memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
414                 lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
415                         sizeof(rsn->header) + tmplen);
416                 pos += sizeof(rsn->header) + tmplen;
417         }
418
419         /* update curbssparams */
420         adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
421
422         /* Copy the infra. association rates into Current BSS state structure */
423         memcpy(&adapter->curbssparams.datarates, &rates->rates,
424                min_t(size_t, sizeof(adapter->curbssparams.datarates),
425                      cpu_to_le16(rates->header.len)));
426
427         lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n",
428                      cpu_to_le16(rates->header.len));
429
430         /* set IBSS field */
431         if (bss->mode == IW_MODE_INFRA) {
432 #define CAPINFO_ESS_MODE 1
433                 passo->capinfo.ess = CAPINFO_ESS_MODE;
434         }
435
436         if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
437                 ret = -1;
438                 goto done;
439         }
440
441         cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
442
443         /* set the capability info at last */
444         memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo));
445         tmpcap &= CAPINFO_MASK;
446         lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
447                      tmpcap, CAPINFO_MASK);
448         memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
449
450 done:
451         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
452         return ret;
453 }
454
455 int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
456                                  struct cmd_ds_command *cmd, void *pdata_buf)
457 {
458         wlan_adapter *adapter = priv->adapter;
459         struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
460         int ret = 0;
461         int cmdappendsize = 0;
462         int i;
463         struct assoc_request * assoc_req = pdata_buf;
464
465         lbs_deb_enter(LBS_DEB_JOIN);
466
467         if (!adapter) {
468                 ret = -1;
469                 goto done;
470         }
471
472         cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
473
474         /*
475          * Fill in the parameters for 2 data structures:
476          *   1. cmd_ds_802_11_ad_hoc_start command
477          *   2. adapter->scantable[i]
478          *
479          * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
480          *   probe delay, and cap info.
481          *
482          * Firmware will fill up beacon period, DTIM, Basic rates
483          *   and operational rates.
484          */
485
486         memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
487         memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len);
488
489         lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
490                      escape_essid(assoc_req->ssid, assoc_req->ssid_len),
491                      assoc_req->ssid_len);
492
493         /* set the BSS type */
494         adhs->bsstype = cmd_bss_type_ibss;
495         adapter->mode = IW_MODE_ADHOC;
496         adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod);
497
498         /* set Physical param set */
499 #define DS_PARA_IE_ID   3
500 #define DS_PARA_IE_LEN  1
501
502         adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
503         adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
504
505         WARN_ON(!assoc_req->channel);
506
507         lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
508                      assoc_req->channel);
509
510         adhs->phyparamset.dsparamset.currentchan = assoc_req->channel;
511
512         /* set IBSS param set */
513 #define IBSS_PARA_IE_ID   6
514 #define IBSS_PARA_IE_LEN  2
515
516         adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
517         adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
518         adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow);
519
520         /* set capability info */
521         adhs->cap.ess = 0;
522         adhs->cap.ibss = 1;
523
524         /* probedelay */
525         adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
526
527         /* set up privacy in adapter->scantable[i] */
528         if (assoc_req->secinfo.wep_enabled) {
529                 lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
530                 adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
531         } else {
532                 lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
533         }
534
535         memset(adhs->datarate, 0, sizeof(adhs->datarate));
536
537         if (adapter->adhoc_grate_enabled) {
538                 memcpy(adhs->datarate, libertas_adhoc_rates_g,
539                        min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
540         } else {
541                 memcpy(adhs->datarate, libertas_adhoc_rates_b,
542                        min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
543         }
544
545         /* Find the last non zero */
546         for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
547
548         adapter->curbssparams.numofrates = i;
549
550         /* Copy the ad-hoc creating rates into Current BSS state structure */
551         memcpy(&adapter->curbssparams.datarates,
552                &adhs->datarate, adapter->curbssparams.numofrates);
553
554         lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
555                adhs->datarate[0], adhs->datarate[1],
556                adhs->datarate[2], adhs->datarate[3]);
557
558         lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
559
560         if (libertas_create_dnld_countryinfo_11d(priv)) {
561                 lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
562                 ret = -1;
563                 goto done;
564         }
565
566         cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) +
567                                 S_DS_GEN + cmdappendsize);
568
569         ret = 0;
570 done:
571         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
572         return ret;
573 }
574
575 int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
576                                 struct cmd_ds_command *cmd)
577 {
578         cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
579         cmd->size = cpu_to_le16(S_DS_GEN);
580
581         return 0;
582 }
583
584 int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
585                                 struct cmd_ds_command *cmd, void *pdata_buf)
586 {
587         wlan_adapter *adapter = priv->adapter;
588         struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
589         struct assoc_request * assoc_req = pdata_buf;
590         struct bss_descriptor *bss = &assoc_req->bss;
591         int cmdappendsize = 0;
592         int ret = 0;
593         u8 *card_rates;
594         int card_rates_size;
595         u16 tmpcap;
596         int i;
597
598         lbs_deb_enter(LBS_DEB_JOIN);
599
600         cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
601
602         padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
603
604         padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod);
605
606         memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN);
607         memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len);
608
609         memcpy(&padhocjoin->bssdescriptor.phyparamset,
610                &bss->phyparamset, sizeof(union ieeetypes_phyparamset));
611
612         memcpy(&padhocjoin->bssdescriptor.ssparamset,
613                &bss->ssparamset, sizeof(union IEEEtypes_ssparamset));
614
615         memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo));
616         tmpcap &= CAPINFO_MASK;
617
618         lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
619                tmpcap, CAPINFO_MASK);
620         memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
621                sizeof(struct ieeetypes_capinfo));
622
623         /* information on BSSID descriptor passed to FW */
624         lbs_deb_join(
625                "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n",
626                MAC_ARG(padhocjoin->bssdescriptor.BSSID),
627                padhocjoin->bssdescriptor.SSID);
628
629         /* failtimeout */
630         padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
631
632         /* probedelay */
633         padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
634
635         /* Copy Data rates from the rates recorded in scan response */
636         memset(padhocjoin->bssdescriptor.datarates, 0,
637                sizeof(padhocjoin->bssdescriptor.datarates));
638         memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates,
639                min(sizeof(padhocjoin->bssdescriptor.datarates),
640                    sizeof(bss->datarates)));
641
642         card_rates = libertas_supported_rates;
643         card_rates_size = sizeof(libertas_supported_rates);
644
645         adapter->curbssparams.channel = bss->channel;
646
647         if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
648                              sizeof(padhocjoin->bssdescriptor.datarates),
649                              card_rates, card_rates_size)) {
650                 lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
651                 ret = -1;
652                 goto done;
653         }
654
655         /* Find the last non zero */
656         for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
657              && padhocjoin->bssdescriptor.datarates[i]; i++) ;
658
659         adapter->curbssparams.numofrates = i;
660
661         /*
662          * Copy the adhoc joining rates to Current BSS State structure
663          */
664         memcpy(adapter->curbssparams.datarates,
665                padhocjoin->bssdescriptor.datarates,
666                adapter->curbssparams.numofrates);
667
668         padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
669             cpu_to_le16(bss->atimwindow);
670
671         if (assoc_req->secinfo.wep_enabled) {
672                 padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
673         }
674
675         if (adapter->psmode == wlan802_11powermodemax_psp) {
676                 /* wake up first */
677                 __le32 Localpsmode;
678
679                 Localpsmode = cpu_to_le32(wlan802_11powermodecam);
680                 ret = libertas_prepare_and_send_command(priv,
681                                             cmd_802_11_ps_mode,
682                                             cmd_act_set,
683                                             0, 0, &Localpsmode);
684
685                 if (ret) {
686                         ret = -1;
687                         goto done;
688                 }
689         }
690
691         if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
692                 ret = -1;
693                 goto done;
694         }
695
696         cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) +
697                                 S_DS_GEN + cmdappendsize);
698
699 done:
700         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
701         return ret;
702 }
703
704 int libertas_ret_80211_associate(wlan_private * priv,
705                               struct cmd_ds_command *resp)
706 {
707         wlan_adapter *adapter = priv->adapter;
708         int ret = 0;
709         union iwreq_data wrqu;
710         struct ieeetypes_assocrsp *passocrsp;
711         struct bss_descriptor * bss;
712
713         lbs_deb_enter(LBS_DEB_JOIN);
714
715         if (!adapter->in_progress_assoc_req) {
716                 lbs_deb_join("ASSOC_RESP: no in-progress association request\n");
717                 ret = -1;
718                 goto done;
719         }
720         bss = &adapter->in_progress_assoc_req->bss;
721
722         passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
723
724         if (le16_to_cpu(passocrsp->statuscode)) {
725                 libertas_mac_event_disconnected(priv);
726
727                 lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n",
728                              le16_to_cpu(passocrsp->statuscode));
729
730                 ret = -1;
731                 goto done;
732         }
733
734         lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
735                 le16_to_cpu(resp->size) - S_DS_GEN);
736
737         /* Send a Media Connected event, according to the Spec */
738         adapter->connect_status = libertas_connected;
739
740         lbs_deb_join("ASSOC_RESP: assocated to '%s'\n",
741                      escape_essid(bss->ssid, bss->ssid_len));
742
743         /* Update current SSID and BSSID */
744         memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
745         adapter->curbssparams.ssid_len = bss->ssid_len;
746         memcpy(adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
747
748         lbs_deb_join("ASSOC_RESP: currentpacketfilter is %x\n",
749                adapter->currentpacketfilter);
750
751         adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
752         adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
753
754         memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
755         memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
756         adapter->nextSNRNF = 0;
757         adapter->numSNRNF = 0;
758
759         netif_carrier_on(priv->dev);
760         netif_wake_queue(priv->dev);
761
762         netif_carrier_on(priv->mesh_dev);
763         netif_wake_queue(priv->mesh_dev);
764
765         lbs_deb_join("ASSOC_RESP: Associated \n");
766
767         memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
768         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
769         wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
770
771 done:
772         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
773         return ret;
774 }
775
776 int libertas_ret_80211_disassociate(wlan_private * priv,
777                                  struct cmd_ds_command *resp)
778 {
779         lbs_deb_enter(LBS_DEB_JOIN);
780
781         libertas_mac_event_disconnected(priv);
782
783         lbs_deb_leave(LBS_DEB_JOIN);
784         return 0;
785 }
786
787 int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
788                                  struct cmd_ds_command *resp)
789 {
790         wlan_adapter *adapter = priv->adapter;
791         int ret = 0;
792         u16 command = le16_to_cpu(resp->command);
793         u16 result = le16_to_cpu(resp->result);
794         struct cmd_ds_802_11_ad_hoc_result *padhocresult;
795         union iwreq_data wrqu;
796         struct bss_descriptor *bss;
797
798         lbs_deb_enter(LBS_DEB_JOIN);
799
800         padhocresult = &resp->params.result;
801
802         lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size));
803         lbs_deb_join("ADHOC_RESP: command = %x\n", command);
804         lbs_deb_join("ADHOC_RESP: result = %x\n", result);
805
806         if (!adapter->in_progress_assoc_req) {
807                 lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
808                 ret = -1;
809                 goto done;
810         }
811         bss = &adapter->in_progress_assoc_req->bss;
812
813         /*
814          * Join result code 0 --> SUCCESS
815          */
816         if (result) {
817                 lbs_deb_join("ADHOC_RESP: failed\n");
818                 if (adapter->connect_status == libertas_connected) {
819                         libertas_mac_event_disconnected(priv);
820                 }
821                 ret = -1;
822                 goto done;
823         }
824
825         /*
826          * Now the join cmd should be successful
827          * If BSSID has changed use SSID to compare instead of BSSID
828          */
829         lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
830                      escape_essid(bss->ssid, bss->ssid_len));
831
832         /* Send a Media Connected event, according to the Spec */
833         adapter->connect_status = libertas_connected;
834
835         if (command == cmd_ret_802_11_ad_hoc_start) {
836                 /* Update the created network descriptor with the new BSSID */
837                 memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN);
838         }
839
840         /* Set the BSSID from the joined/started descriptor */
841         memcpy(&adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
842
843         /* Set the new SSID to current SSID */
844         memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
845         adapter->curbssparams.ssid_len = bss->ssid_len;
846
847         netif_carrier_on(priv->dev);
848         netif_wake_queue(priv->dev);
849
850         netif_carrier_on(priv->mesh_dev);
851         netif_wake_queue(priv->mesh_dev);
852
853         memset(&wrqu, 0, sizeof(wrqu));
854         memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
855         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
856         wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
857
858         lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
859         lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
860         lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n",
861                MAC_ARG(padhocresult->BSSID));
862
863 done:
864         lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
865         return ret;
866 }
867
868 int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
869                                 struct cmd_ds_command *resp)
870 {
871         lbs_deb_enter(LBS_DEB_JOIN);
872
873         libertas_mac_event_disconnected(priv);
874
875         lbs_deb_leave(LBS_DEB_JOIN);
876         return 0;
877 }