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