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