blob: 149531c77938f2272d271acdc7cae75a1b4d214d [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
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 */
34static 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;
79done:
80 return ret;
81}
82
83int 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
97int 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 */
119int 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 */
157int 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 */
194int 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
245int 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 */
257int 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 */
269int 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 */
362int 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 */
396int libertas_cmd_80211_authenticate(wlan_private * priv,
397 struct cmd_ds_command *cmd,
398 void *pdata_buf)
399{
400 wlan_adapter *adapter = priv->adapter;
Dan Williams6affe782007-05-10 22:56:42 -0400401 struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
402 int ret = -1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200403 u8 *bssid = pdata_buf;
404
405 cmd->command = cpu_to_le16(cmd_802_11_authenticate);
Dan Williams6affe782007-05-10 22:56:42 -0400406 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
407 + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200408
Dan Williams6affe782007-05-10 22:56:42 -0400409 /* 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
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426 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]);
Dan Williams6affe782007-05-10 22:56:42 -0400430 ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200431
Dan Williams6affe782007-05-10 22:56:42 -0400432out:
433 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200434}
435
436int 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
461int 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
595int 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;
738done:
739 LEAVE();
740 return ret;
741}
742
743int 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
752int 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
893int 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
966int 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
977int 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
1063int 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}