]> err.no Git - linux-2.6/blob - drivers/net/wireless/libertas/join.c
[PATCH] libertas: remove WLAN_802_11_AUTHENTICATION_MODE
[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 = &cmd->params.auth;
402         int ret = -1;
403         u8 *bssid = pdata_buf;
404
405         cmd->command = cpu_to_le16(cmd_802_11_authenticate);
406         cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
407                                 + S_DS_GEN);
408
409         /* translate auth mode to 802.11 defined wire value */
410         switch (adapter->secinfo.auth_mode) {
411         case IW_AUTH_ALG_OPEN_SYSTEM:
412                 pauthenticate->authtype = 0x00;
413                 break;
414         case IW_AUTH_ALG_SHARED_KEY:
415                 pauthenticate->authtype = 0x01;
416                 break;
417         case IW_AUTH_ALG_LEAP:
418                 pauthenticate->authtype = 0x80;
419                 break;
420         default:
421                 lbs_pr_debug(1, "AUTH_CMD: invalid auth alg 0x%X\n",
422                              adapter->secinfo.auth_mode);
423                 goto out;
424         }
425
426         memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
427
428         lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n",
429                bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
430         ret = 0;
431
432 out:
433         return ret;
434 }
435
436 int libertas_cmd_80211_deauthenticate(wlan_private * priv,
437                                    struct cmd_ds_command *cmd)
438 {
439         wlan_adapter *adapter = priv->adapter;
440         struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
441
442         ENTER();
443
444         cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
445         cmd->size =
446             cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
447                              S_DS_GEN);
448
449         /* set AP MAC address */
450         memmove(dauth->macaddr, adapter->curbssparams.bssid,
451                 ETH_ALEN);
452
453         /* Reason code 3 = Station is leaving */
454 #define REASON_CODE_STA_LEAVING 3
455         dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
456
457         LEAVE();
458         return 0;
459 }
460
461 int libertas_cmd_80211_associate(wlan_private * priv,
462                               struct cmd_ds_command *cmd, void *pdata_buf)
463 {
464         wlan_adapter *adapter = priv->adapter;
465         struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
466         int ret = 0;
467         struct bss_descriptor *pbssdesc;
468         u8 *card_rates;
469         u8 *pos;
470         int card_rates_size;
471         u16 tmpcap;
472         struct mrvlietypes_ssidparamset *ssid;
473         struct mrvlietypes_phyparamset *phy;
474         struct mrvlietypes_ssparamset *ss;
475         struct mrvlietypes_ratesparamset *rates;
476         struct mrvlietypes_rsnparamset *rsn;
477
478         ENTER();
479
480         pbssdesc = pdata_buf;
481         pos = (u8 *) passo;
482
483         if (!adapter) {
484                 ret = -1;
485                 goto done;
486         }
487
488         cmd->command = cpu_to_le16(cmd_802_11_associate);
489
490         /* Save so we know which BSS Desc to use in the response handler */
491         adapter->pattemptedbssdesc = pbssdesc;
492
493         memcpy(passo->peerstaaddr,
494                pbssdesc->macaddress, sizeof(passo->peerstaaddr));
495         pos += sizeof(passo->peerstaaddr);
496
497         /* set the listen interval */
498         passo->listeninterval = adapter->listeninterval;
499
500         pos += sizeof(passo->capinfo);
501         pos += sizeof(passo->listeninterval);
502         pos += sizeof(passo->bcnperiod);
503         pos += sizeof(passo->dtimperiod);
504
505         ssid = (struct mrvlietypes_ssidparamset *) pos;
506         ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
507         ssid->header.len = pbssdesc->ssid.ssidlength;
508         memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len);
509         pos += sizeof(ssid->header) + ssid->header.len;
510         ssid->header.len = cpu_to_le16(ssid->header.len);
511
512         phy = (struct mrvlietypes_phyparamset *) pos;
513         phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
514         phy->header.len = sizeof(phy->fh_ds.dsparamset);
515         memcpy(&phy->fh_ds.dsparamset,
516                &pbssdesc->phyparamset.dsparamset.currentchan,
517                sizeof(phy->fh_ds.dsparamset));
518         pos += sizeof(phy->header) + phy->header.len;
519         phy->header.len = cpu_to_le16(phy->header.len);
520
521         ss = (struct mrvlietypes_ssparamset *) pos;
522         ss->header.type = cpu_to_le16(TLV_TYPE_CF);
523         ss->header.len = sizeof(ss->cf_ibss.cfparamset);
524         pos += sizeof(ss->header) + ss->header.len;
525         ss->header.len = cpu_to_le16(ss->header.len);
526
527         rates = (struct mrvlietypes_ratesparamset *) pos;
528         rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
529
530         memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES);
531
532         card_rates = libertas_supported_rates;
533         card_rates_size = sizeof(libertas_supported_rates);
534
535         if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
536                              card_rates, card_rates_size)) {
537                 ret = -1;
538                 goto done;
539         }
540
541         rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
542         adapter->curbssparams.numofrates = rates->header.len;
543
544         pos += sizeof(rates->header) + rates->header.len;
545         rates->header.len = cpu_to_le16(rates->header.len);
546
547         if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
548                 rsn = (struct mrvlietypes_rsnparamset *) pos;
549                 rsn->header.type = (u16) adapter->wpa_ie[0];    /* WPA_IE or WPA2_IE */
550                 rsn->header.type = cpu_to_le16(rsn->header.type);
551                 rsn->header.len = (u16) adapter->wpa_ie[1];
552                 memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len);
553                 lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
554                         sizeof(rsn->header) + rsn->header.len);
555                 pos += sizeof(rsn->header) + rsn->header.len;
556                 rsn->header.len = cpu_to_le16(rsn->header.len);
557         }
558
559         /* update curbssparams */
560         adapter->curbssparams.channel =
561             (pbssdesc->phyparamset.dsparamset.currentchan);
562
563         /* Copy the infra. association rates into Current BSS state structure */
564         memcpy(&adapter->curbssparams.datarates, &rates->rates,
565                min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len));
566
567         lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len);
568
569         /* set IBSS field */
570         if (pbssdesc->inframode == wlan802_11infrastructure) {
571 #define CAPINFO_ESS_MODE 1
572                 passo->capinfo.ess = CAPINFO_ESS_MODE;
573         }
574
575         if (libertas_parse_dnld_countryinfo_11d(priv)) {
576                 ret = -1;
577                 goto done;
578         }
579
580         cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
581
582         /* set the capability info at last */
583         memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo));
584         tmpcap &= CAPINFO_MASK;
585         lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
586                tmpcap, CAPINFO_MASK);
587         tmpcap = cpu_to_le16(tmpcap);
588         memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
589
590       done:
591         LEAVE();
592         return ret;
593 }
594
595 int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
596                                  struct cmd_ds_command *cmd, void *pssid)
597 {
598         wlan_adapter *adapter = priv->adapter;
599         struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
600         int ret = 0;
601         int cmdappendsize = 0;
602         int i;
603         u16 tmpcap;
604         struct bss_descriptor *pbssdesc;
605         struct WLAN_802_11_SSID *ssid = pssid;
606
607         ENTER();
608
609         if (!adapter) {
610                 ret = -1;
611                 goto done;
612         }
613
614         cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
615
616         pbssdesc = &adapter->curbssparams.bssdescriptor;
617         adapter->pattemptedbssdesc = pbssdesc;
618
619         /*
620          * Fill in the parameters for 2 data structures:
621          *   1. cmd_ds_802_11_ad_hoc_start command
622          *   2. adapter->scantable[i]
623          *
624          * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
625          *   probe delay, and cap info.
626          *
627          * Firmware will fill up beacon period, DTIM, Basic rates
628          *   and operational rates.
629          */
630
631         memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
632
633         memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength);
634
635         lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
636
637         memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE);
638         memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength);
639
640         pbssdesc->ssid.ssidlength = ssid->ssidlength;
641
642         /* set the BSS type */
643         adhs->bsstype = cmd_bss_type_ibss;
644         pbssdesc->inframode = wlan802_11ibss;
645         adhs->beaconperiod = adapter->beaconperiod;
646
647         /* set Physical param set */
648 #define DS_PARA_IE_ID   3
649 #define DS_PARA_IE_LEN  1
650
651         adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
652         adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
653
654         WARN_ON(!adapter->adhocchannel);
655
656         lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n",
657                adapter->adhocchannel);
658
659         adapter->curbssparams.channel = adapter->adhocchannel;
660
661         pbssdesc->channel = adapter->adhocchannel;
662         adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel;
663
664         memcpy(&pbssdesc->phyparamset,
665                &adhs->phyparamset, sizeof(union ieeetypes_phyparamset));
666
667         /* set IBSS param set */
668 #define IBSS_PARA_IE_ID   6
669 #define IBSS_PARA_IE_LEN  2
670
671         adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
672         adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
673         adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow;
674         memcpy(&pbssdesc->ssparamset,
675                &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset));
676
677         /* set capability info */
678         adhs->cap.ess = 0;
679         adhs->cap.ibss = 1;
680         pbssdesc->cap.ibss = 1;
681
682         /* probedelay */
683         adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
684
685         /* set up privacy in adapter->scantable[i] */
686         if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
687
688 #define AD_HOC_CAP_PRIVACY_ON 1
689                 lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n");
690                 pbssdesc->privacy = wlan802_11privfilter8021xWEP;
691                 adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
692         } else {
693                 lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting "
694                        "privacy to ACCEPT ALL\n");
695                 pbssdesc->privacy = wlan802_11privfilteracceptall;
696         }
697
698         memset(adhs->datarate, 0, sizeof(adhs->datarate));
699
700         if (adapter->adhoc_grate_enabled) {
701                 memcpy(adhs->datarate, libertas_adhoc_rates_g,
702                        min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
703         } else {
704                 memcpy(adhs->datarate, libertas_adhoc_rates_b,
705                        min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
706         }
707
708         /* Find the last non zero */
709         for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
710
711         adapter->curbssparams.numofrates = i;
712
713         /* Copy the ad-hoc creating rates into Current BSS state structure */
714         memcpy(&adapter->curbssparams.datarates,
715                &adhs->datarate, adapter->curbssparams.numofrates);
716
717         lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
718                adhs->datarate[0], adhs->datarate[1],
719                adhs->datarate[2], adhs->datarate[3]);
720
721         lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n");
722
723         if (libertas_create_dnld_countryinfo_11d(priv)) {
724                 lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
725                 ret = -1;
726                 goto done;
727         }
728
729         cmd->size =
730             cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start)
731                              + S_DS_GEN + cmdappendsize);
732
733         memcpy(&tmpcap, &adhs->cap, sizeof(u16));
734         tmpcap = cpu_to_le16(tmpcap);
735         memcpy(&adhs->cap, &tmpcap, sizeof(u16));
736
737         ret = 0;
738 done:
739         LEAVE();
740         return ret;
741 }
742
743 int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
744                                 struct cmd_ds_command *cmd)
745 {
746         cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
747         cmd->size = cpu_to_le16(S_DS_GEN);
748
749         return 0;
750 }
751
752 int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
753                                 struct cmd_ds_command *cmd, void *pdata_buf)
754 {
755         wlan_adapter *adapter = priv->adapter;
756         struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
757         struct bss_descriptor *pbssdesc = pdata_buf;
758         int cmdappendsize = 0;
759         int ret = 0;
760         u8 *card_rates;
761         int card_rates_size;
762         u16 tmpcap;
763         int i;
764
765         ENTER();
766
767         adapter->pattemptedbssdesc = pbssdesc;
768
769         cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
770
771         padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
772
773         padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod;
774
775         memcpy(&padhocjoin->bssdescriptor.BSSID,
776                &pbssdesc->macaddress, ETH_ALEN);
777
778         memcpy(&padhocjoin->bssdescriptor.SSID,
779                &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength);
780
781         memcpy(&padhocjoin->bssdescriptor.phyparamset,
782                &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset));
783
784         memcpy(&padhocjoin->bssdescriptor.ssparamset,
785                &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset));
786
787         memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo));
788         tmpcap &= CAPINFO_MASK;
789
790         lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
791                tmpcap, CAPINFO_MASK);
792         memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
793                sizeof(struct ieeetypes_capinfo));
794
795         /* information on BSSID descriptor passed to FW */
796     lbs_pr_debug(1,
797                "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n",
798                padhocjoin->bssdescriptor.BSSID[0],
799                padhocjoin->bssdescriptor.BSSID[1],
800                padhocjoin->bssdescriptor.BSSID[2],
801                padhocjoin->bssdescriptor.BSSID[3],
802                padhocjoin->bssdescriptor.BSSID[4],
803                padhocjoin->bssdescriptor.BSSID[5],
804                padhocjoin->bssdescriptor.SSID);
805
806         lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n",
807                (u32) padhocjoin->bssdescriptor.datarates);
808
809         /* failtimeout */
810         padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
811
812         /* probedelay */
813         padhocjoin->probedelay =
814             cpu_to_le16(cmd_scan_probe_delay_time);
815
816         /* Copy Data rates from the rates recorded in scan response */
817         memset(padhocjoin->bssdescriptor.datarates, 0,
818                sizeof(padhocjoin->bssdescriptor.datarates));
819         memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates,
820                min(sizeof(padhocjoin->bssdescriptor.datarates),
821                    sizeof(pbssdesc->datarates)));
822
823         card_rates = libertas_supported_rates;
824         card_rates_size = sizeof(libertas_supported_rates);
825
826         adapter->curbssparams.channel = pbssdesc->channel;
827
828         if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
829                              sizeof(padhocjoin->bssdescriptor.datarates),
830                              card_rates, card_rates_size)) {
831                 lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n");
832                 ret = -1;
833                 goto done;
834         }
835
836         /* Find the last non zero */
837         for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
838              && padhocjoin->bssdescriptor.datarates[i]; i++) ;
839
840         adapter->curbssparams.numofrates = i;
841
842         /*
843          * Copy the adhoc joining rates to Current BSS State structure
844          */
845         memcpy(adapter->curbssparams.datarates,
846                padhocjoin->bssdescriptor.datarates,
847                adapter->curbssparams.numofrates);
848
849         padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
850             cpu_to_le16(pbssdesc->atimwindow);
851
852         if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
853                 padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
854         }
855
856         if (adapter->psmode == wlan802_11powermodemax_psp) {
857                 /* wake up first */
858                 enum WLAN_802_11_POWER_MODE Localpsmode;
859
860                 Localpsmode = wlan802_11powermodecam;
861                 ret = libertas_prepare_and_send_command(priv,
862                                             cmd_802_11_ps_mode,
863                                             cmd_act_set,
864                                             0, 0, &Localpsmode);
865
866                 if (ret) {
867                         ret = -1;
868                         goto done;
869                 }
870         }
871
872         if (libertas_parse_dnld_countryinfo_11d(priv)) {
873                 ret = -1;
874                 goto done;
875         }
876
877         cmd->size =
878             cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join)
879                              + S_DS_GEN + cmdappendsize);
880
881         memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap,
882                sizeof(struct ieeetypes_capinfo));
883         tmpcap = cpu_to_le16(tmpcap);
884
885         memcpy(&padhocjoin->bssdescriptor.cap,
886                &tmpcap, sizeof(struct ieeetypes_capinfo));
887
888       done:
889         LEAVE();
890         return ret;
891 }
892
893 int libertas_ret_80211_associate(wlan_private * priv,
894                               struct cmd_ds_command *resp)
895 {
896         wlan_adapter *adapter = priv->adapter;
897         int ret = 0;
898         union iwreq_data wrqu;
899         struct ieeetypes_assocrsp *passocrsp;
900         struct bss_descriptor *pbssdesc;
901
902         ENTER();
903
904         passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
905
906         if (passocrsp->statuscode) {
907
908                 libertas_mac_event_disconnected(priv);
909
910         lbs_pr_debug(1,
911                        "ASSOC_RESP: Association failed, status code = %d\n",
912                        passocrsp->statuscode);
913
914                 ret = -1;
915                 goto done;
916         }
917
918         lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
919                 le16_to_cpu(resp->size) - S_DS_GEN);
920
921         /* Send a Media Connected event, according to the Spec */
922         adapter->connect_status = libertas_connected;
923
924         /* Set the attempted BSSID Index to current */
925         pbssdesc = adapter->pattemptedbssdesc;
926
927         lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid);
928
929         /* Set the new SSID to current SSID */
930         memcpy(&adapter->curbssparams.ssid,
931                &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
932
933         /* Set the new BSSID (AP's MAC address) to current BSSID */
934         memcpy(adapter->curbssparams.bssid,
935                pbssdesc->macaddress, ETH_ALEN);
936
937         /* Make a copy of current BSSID descriptor */
938         memcpy(&adapter->curbssparams.bssdescriptor,
939                pbssdesc, sizeof(struct bss_descriptor));
940
941         lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n",
942                adapter->currentpacketfilter);
943
944         adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
945         adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
946
947         memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
948         memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
949         adapter->nextSNRNF = 0;
950         adapter->numSNRNF = 0;
951
952         netif_carrier_on(priv->wlan_dev.netdev);
953         netif_wake_queue(priv->wlan_dev.netdev);
954
955         lbs_pr_debug(1, "ASSOC_RESP: Associated \n");
956
957         memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
958         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
959         wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
960
961       done:
962         LEAVE();
963         return ret;
964 }
965
966 int libertas_ret_80211_disassociate(wlan_private * priv,
967                                  struct cmd_ds_command *resp)
968 {
969         ENTER();
970
971         libertas_mac_event_disconnected(priv);
972
973         LEAVE();
974         return 0;
975 }
976
977 int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
978                                  struct cmd_ds_command *resp)
979 {
980         wlan_adapter *adapter = priv->adapter;
981         int ret = 0;
982         u16 command = le16_to_cpu(resp->command);
983         u16 result = le16_to_cpu(resp->result);
984         struct cmd_ds_802_11_ad_hoc_result *padhocresult;
985         union iwreq_data wrqu;
986         struct bss_descriptor *pbssdesc;
987
988         ENTER();
989
990         padhocresult = &resp->params.result;
991
992         lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size));
993         lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command);
994         lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result);
995
996         pbssdesc = adapter->pattemptedbssdesc;
997
998         /*
999          * Join result code 0 --> SUCCESS
1000          */
1001         if (result) {
1002                 lbs_pr_debug(1, "ADHOC_RESP failed\n");
1003                 if (adapter->connect_status == libertas_connected) {
1004                         libertas_mac_event_disconnected(priv);
1005                 }
1006
1007                 memset(&adapter->curbssparams.bssdescriptor,
1008                        0x00, sizeof(adapter->curbssparams.bssdescriptor));
1009
1010                 LEAVE();
1011                 return -1;
1012         }
1013
1014         /*
1015          * Now the join cmd should be successful
1016          * If BSSID has changed use SSID to compare instead of BSSID
1017          */
1018         lbs_pr_debug(1, "ADHOC_J_RESP  %s\n", pbssdesc->ssid.ssid);
1019
1020         /* Send a Media Connected event, according to the Spec */
1021         adapter->connect_status = libertas_connected;
1022
1023         if (command == cmd_ret_802_11_ad_hoc_start) {
1024                 /* Update the created network descriptor with the new BSSID */
1025                 memcpy(pbssdesc->macaddress,
1026                        padhocresult->BSSID, ETH_ALEN);
1027         } else {
1028
1029                 /* Make a copy of current BSSID descriptor, only needed for join since
1030                  *   the current descriptor is already being used for adhoc start
1031                  */
1032                 memmove(&adapter->curbssparams.bssdescriptor,
1033                         pbssdesc, sizeof(struct bss_descriptor));
1034         }
1035
1036         /* Set the BSSID from the joined/started descriptor */
1037         memcpy(&adapter->curbssparams.bssid,
1038                pbssdesc->macaddress, ETH_ALEN);
1039
1040         /* Set the new SSID to current SSID */
1041         memcpy(&adapter->curbssparams.ssid,
1042                &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
1043
1044         netif_carrier_on(priv->wlan_dev.netdev);
1045         netif_wake_queue(priv->wlan_dev.netdev);
1046
1047         memset(&wrqu, 0, sizeof(wrqu));
1048         memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
1049         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1050         wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
1051
1052         lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n");
1053         lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
1054         lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
1055                padhocresult->BSSID[0], padhocresult->BSSID[1],
1056                padhocresult->BSSID[2], padhocresult->BSSID[3],
1057                padhocresult->BSSID[4], padhocresult->BSSID[5]);
1058
1059         LEAVE();
1060         return ret;
1061 }
1062
1063 int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
1064                                 struct cmd_ds_command *resp)
1065 {
1066         ENTER();
1067
1068         libertas_mac_event_disconnected(priv);
1069
1070         LEAVE();
1071         return 0;
1072 }