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