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