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
7 #include <linux/netdevice.h>
8 #include <linux/if_arp.h>
9 #include <linux/wireless.h>
10 #include <linux/etherdevice.h>
12 #include <net/iw_handler.h>
20 /* The firmware needs certain bits masked out of the beacon-derviced capability
21 * field when associating/joining to BSSs.
23 #define CAPINFO_MASK (~(0xda00))
26 * @brief This function finds common rates between rate1 and card rates.
28 * It will fill common rates in rate1 as output if found.
30 * NOTE: Setting the MSB of the basic rates need to be taken
31 * care, either before or after calling this function
33 * @param priv A pointer to struct lbs_private structure
34 * @param rate1 the buffer which keeps input and output
35 * @param rate1_size the size of rate1 buffer; new size of buffer on return
39 static int get_common_rates(struct lbs_private
*priv
,
43 u8
*card_rates
= lbs_bg_rates
;
44 size_t num_card_rates
= sizeof(lbs_bg_rates
);
49 /* For each rate in card_rates that exists in rate1, copy to tmp */
50 for (i
= 0; card_rates
[i
] && (i
< num_card_rates
); i
++) {
51 for (j
= 0; rates
[j
] && (j
< *rates_size
); j
++) {
52 if (rates
[j
] == card_rates
[i
])
53 tmp
[tmp_size
++] = card_rates
[i
];
57 lbs_deb_hex(LBS_DEB_JOIN
, "AP rates ", rates
, *rates_size
);
58 lbs_deb_hex(LBS_DEB_JOIN
, "card rates ", card_rates
, num_card_rates
);
59 lbs_deb_hex(LBS_DEB_JOIN
, "common rates", tmp
, tmp_size
);
60 lbs_deb_join("TX data rate 0x%02x\n", priv
->cur_rate
);
62 if (!priv
->auto_rate
) {
63 for (i
= 0; i
< tmp_size
; i
++) {
64 if (tmp
[i
] == priv
->cur_rate
)
67 lbs_pr_alert("Previously set fixed data rate %#x isn't "
68 "compatible with the network.\n", priv
->cur_rate
);
75 memset(rates
, 0, *rates_size
);
76 *rates_size
= min_t(int, tmp_size
, *rates_size
);
77 memcpy(rates
, tmp
, *rates_size
);
83 * @brief Sets the MSB on basic rates as the firmware requires
85 * Scan through an array and set the MSB for basic data rates.
87 * @param rates buffer of data rates
88 * @param len size of buffer
90 static void lbs_set_basic_rate_flags(u8
*rates
, size_t len
)
94 for (i
= 0; i
< len
; i
++) {
95 if (rates
[i
] == 0x02 || rates
[i
] == 0x04 ||
96 rates
[i
] == 0x0b || rates
[i
] == 0x16)
102 * @brief Unsets the MSB on basic rates
104 * Scan through an array and unset the MSB for basic data rates.
106 * @param rates buffer of data rates
107 * @param len size of buffer
109 void lbs_unset_basic_rate_flags(u8
*rates
, size_t len
)
113 for (i
= 0; i
< len
; i
++)
119 * @brief Associate to a specific BSS discovered in a scan
121 * @param priv A pointer to struct lbs_private structure
122 * @param pbssdesc Pointer to the BSS descriptor to associate with.
124 * @return 0-success, otherwise fail
126 int lbs_associate(struct lbs_private
*priv
, struct assoc_request
*assoc_req
)
130 lbs_deb_enter(LBS_DEB_ASSOC
);
132 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_AUTHENTICATE
,
133 0, CMD_OPTION_WAITFORRSP
,
134 0, assoc_req
->bss
.bssid
);
139 /* set preamble to firmware */
140 if ( (priv
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
141 && (assoc_req
->bss
.capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
))
142 priv
->preamble
= CMD_TYPE_SHORT_PREAMBLE
;
144 priv
->preamble
= CMD_TYPE_LONG_PREAMBLE
;
146 lbs_set_radio_control(priv
);
148 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_ASSOCIATE
,
149 0, CMD_OPTION_WAITFORRSP
, 0, assoc_req
);
152 lbs_deb_leave_args(LBS_DEB_ASSOC
, "ret %d", ret
);
157 * @brief Start an Adhoc Network
159 * @param priv A pointer to struct lbs_private structure
160 * @param adhocssid The ssid of the Adhoc Network
161 * @return 0--success, -1--fail
163 int lbs_start_adhoc_network(struct lbs_private
*priv
,
164 struct assoc_request
*assoc_req
)
168 priv
->adhoccreate
= 1;
170 if (priv
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
) {
171 lbs_deb_join("AdhocStart: Short preamble\n");
172 priv
->preamble
= CMD_TYPE_SHORT_PREAMBLE
;
174 lbs_deb_join("AdhocStart: Long preamble\n");
175 priv
->preamble
= CMD_TYPE_LONG_PREAMBLE
;
178 lbs_set_radio_control(priv
);
180 lbs_deb_join("AdhocStart: channel = %d\n", assoc_req
->channel
);
181 lbs_deb_join("AdhocStart: band = %d\n", assoc_req
->band
);
183 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_AD_HOC_START
,
184 0, CMD_OPTION_WAITFORRSP
, 0, assoc_req
);
190 * @brief Join an adhoc network found in a previous scan
192 * @param priv A pointer to struct lbs_private structure
193 * @param pbssdesc Pointer to a BSS descriptor found in a previous scan
196 * @return 0--success, -1--fail
198 int lbs_join_adhoc_network(struct lbs_private
*priv
,
199 struct assoc_request
*assoc_req
)
201 struct bss_descriptor
* bss
= &assoc_req
->bss
;
204 lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
206 escape_essid(priv
->curbssparams
.ssid
,
207 priv
->curbssparams
.ssid_len
),
208 priv
->curbssparams
.ssid_len
);
209 lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
210 __func__
, escape_essid(bss
->ssid
, bss
->ssid_len
),
213 /* check if the requested SSID is already joined */
214 if ( priv
->curbssparams
.ssid_len
215 && !lbs_ssid_cmp(priv
->curbssparams
.ssid
,
216 priv
->curbssparams
.ssid_len
,
217 bss
->ssid
, bss
->ssid_len
)
218 && (priv
->mode
== IW_MODE_ADHOC
)
219 && (priv
->connect_status
== LBS_CONNECTED
)) {
220 union iwreq_data wrqu
;
222 lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
223 "current, not attempting to re-join");
225 /* Send the re-association event though, because the association
226 * request really was successful, even if just a null-op.
228 memset(&wrqu
, 0, sizeof(wrqu
));
229 memcpy(wrqu
.ap_addr
.sa_data
, priv
->curbssparams
.bssid
,
231 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
232 wireless_send_event(priv
->dev
, SIOCGIWAP
, &wrqu
, NULL
);
236 /* Use shortpreamble only when both creator and card supports
238 if ( !(bss
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
239 || !(priv
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
)) {
240 lbs_deb_join("AdhocJoin: Long preamble\n");
241 priv
->preamble
= CMD_TYPE_LONG_PREAMBLE
;
243 lbs_deb_join("AdhocJoin: Short preamble\n");
244 priv
->preamble
= CMD_TYPE_SHORT_PREAMBLE
;
247 lbs_set_radio_control(priv
);
249 lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req
->channel
);
250 lbs_deb_join("AdhocJoin: band = %c\n", assoc_req
->band
);
252 priv
->adhoccreate
= 0;
254 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_AD_HOC_JOIN
,
255 0, CMD_OPTION_WAITFORRSP
,
256 OID_802_11_SSID
, assoc_req
);
262 int lbs_stop_adhoc_network(struct lbs_private
*priv
)
264 return lbs_prepare_and_send_command(priv
, CMD_802_11_AD_HOC_STOP
,
265 0, CMD_OPTION_WAITFORRSP
, 0, NULL
);
269 * @brief Send Deauthentication Request
271 * @param priv A pointer to struct lbs_private structure
272 * @return 0--success, -1--fail
274 int lbs_send_deauthentication(struct lbs_private
*priv
)
276 return lbs_prepare_and_send_command(priv
, CMD_802_11_DEAUTHENTICATE
,
277 0, CMD_OPTION_WAITFORRSP
, 0, NULL
);
281 * @brief This function prepares command of authenticate.
283 * @param priv A pointer to struct lbs_private structure
284 * @param cmd A pointer to cmd_ds_command structure
285 * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
289 int lbs_cmd_80211_authenticate(struct lbs_private
*priv
,
290 struct cmd_ds_command
*cmd
,
293 struct cmd_ds_802_11_authenticate
*pauthenticate
= &cmd
->params
.auth
;
295 u8
*bssid
= pdata_buf
;
296 DECLARE_MAC_BUF(mac
);
298 lbs_deb_enter(LBS_DEB_JOIN
);
300 cmd
->command
= cpu_to_le16(CMD_802_11_AUTHENTICATE
);
301 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate
)
304 /* translate auth mode to 802.11 defined wire value */
305 switch (priv
->secinfo
.auth_mode
) {
306 case IW_AUTH_ALG_OPEN_SYSTEM
:
307 pauthenticate
->authtype
= 0x00;
309 case IW_AUTH_ALG_SHARED_KEY
:
310 pauthenticate
->authtype
= 0x01;
312 case IW_AUTH_ALG_LEAP
:
313 pauthenticate
->authtype
= 0x80;
316 lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
317 priv
->secinfo
.auth_mode
);
321 memcpy(pauthenticate
->macaddr
, bssid
, ETH_ALEN
);
323 lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
324 print_mac(mac
, bssid
), pauthenticate
->authtype
);
328 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
332 int lbs_cmd_80211_deauthenticate(struct lbs_private
*priv
,
333 struct cmd_ds_command
*cmd
)
335 struct cmd_ds_802_11_deauthenticate
*dauth
= &cmd
->params
.deauth
;
337 lbs_deb_enter(LBS_DEB_JOIN
);
339 cmd
->command
= cpu_to_le16(CMD_802_11_DEAUTHENTICATE
);
340 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate
) +
343 /* set AP MAC address */
344 memmove(dauth
->macaddr
, priv
->curbssparams
.bssid
, ETH_ALEN
);
346 /* Reason code 3 = Station is leaving */
347 #define REASON_CODE_STA_LEAVING 3
348 dauth
->reasoncode
= cpu_to_le16(REASON_CODE_STA_LEAVING
);
350 lbs_deb_leave(LBS_DEB_JOIN
);
354 int lbs_cmd_80211_associate(struct lbs_private
*priv
,
355 struct cmd_ds_command
*cmd
, void *pdata_buf
)
357 struct cmd_ds_802_11_associate
*passo
= &cmd
->params
.associate
;
359 struct assoc_request
* assoc_req
= pdata_buf
;
360 struct bss_descriptor
* bss
= &assoc_req
->bss
;
363 struct mrvlietypes_ssidparamset
*ssid
;
364 struct mrvlietypes_phyparamset
*phy
;
365 struct mrvlietypes_ssparamset
*ss
;
366 struct mrvlietypes_ratesparamset
*rates
;
367 struct mrvlietypes_rsnparamset
*rsn
;
369 lbs_deb_enter(LBS_DEB_ASSOC
);
378 cmd
->command
= cpu_to_le16(CMD_802_11_ASSOCIATE
);
380 memcpy(passo
->peerstaaddr
, bss
->bssid
, sizeof(passo
->peerstaaddr
));
381 pos
+= sizeof(passo
->peerstaaddr
);
383 /* set the listen interval */
384 passo
->listeninterval
= cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL
);
386 pos
+= sizeof(passo
->capability
);
387 pos
+= sizeof(passo
->listeninterval
);
388 pos
+= sizeof(passo
->bcnperiod
);
389 pos
+= sizeof(passo
->dtimperiod
);
391 ssid
= (struct mrvlietypes_ssidparamset
*) pos
;
392 ssid
->header
.type
= cpu_to_le16(TLV_TYPE_SSID
);
393 tmplen
= bss
->ssid_len
;
394 ssid
->header
.len
= cpu_to_le16(tmplen
);
395 memcpy(ssid
->ssid
, bss
->ssid
, tmplen
);
396 pos
+= sizeof(ssid
->header
) + tmplen
;
398 phy
= (struct mrvlietypes_phyparamset
*) pos
;
399 phy
->header
.type
= cpu_to_le16(TLV_TYPE_PHY_DS
);
400 tmplen
= sizeof(phy
->fh_ds
.dsparamset
);
401 phy
->header
.len
= cpu_to_le16(tmplen
);
402 memcpy(&phy
->fh_ds
.dsparamset
,
403 &bss
->phyparamset
.dsparamset
.currentchan
,
405 pos
+= sizeof(phy
->header
) + tmplen
;
407 ss
= (struct mrvlietypes_ssparamset
*) pos
;
408 ss
->header
.type
= cpu_to_le16(TLV_TYPE_CF
);
409 tmplen
= sizeof(ss
->cf_ibss
.cfparamset
);
410 ss
->header
.len
= cpu_to_le16(tmplen
);
411 pos
+= sizeof(ss
->header
) + tmplen
;
413 rates
= (struct mrvlietypes_ratesparamset
*) pos
;
414 rates
->header
.type
= cpu_to_le16(TLV_TYPE_RATES
);
415 memcpy(&rates
->rates
, &bss
->rates
, MAX_RATES
);
417 if (get_common_rates(priv
, rates
->rates
, &tmplen
)) {
421 pos
+= sizeof(rates
->header
) + tmplen
;
422 rates
->header
.len
= cpu_to_le16(tmplen
);
423 lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen
);
425 /* Copy the infra. association rates into Current BSS state structure */
426 memset(&priv
->curbssparams
.rates
, 0, sizeof(priv
->curbssparams
.rates
));
427 memcpy(&priv
->curbssparams
.rates
, &rates
->rates
, tmplen
);
429 /* Set MSB on basic rates as the firmware requires, but _after_
430 * copying to current bss rates.
432 lbs_set_basic_rate_flags(rates
->rates
, tmplen
);
434 if (assoc_req
->secinfo
.WPAenabled
|| assoc_req
->secinfo
.WPA2enabled
) {
435 rsn
= (struct mrvlietypes_rsnparamset
*) pos
;
436 /* WPA_IE or WPA2_IE */
437 rsn
->header
.type
= cpu_to_le16((u16
) assoc_req
->wpa_ie
[0]);
438 tmplen
= (u16
) assoc_req
->wpa_ie
[1];
439 rsn
->header
.len
= cpu_to_le16(tmplen
);
440 memcpy(rsn
->rsnie
, &assoc_req
->wpa_ie
[2], tmplen
);
441 lbs_deb_hex(LBS_DEB_JOIN
, "ASSOC_CMD: RSN IE", (u8
*) rsn
,
442 sizeof(rsn
->header
) + tmplen
);
443 pos
+= sizeof(rsn
->header
) + tmplen
;
446 /* update curbssparams */
447 priv
->curbssparams
.channel
= bss
->phyparamset
.dsparamset
.currentchan
;
449 if (lbs_parse_dnld_countryinfo_11d(priv
, bss
)) {
454 cmd
->size
= cpu_to_le16((u16
) (pos
- (u8
*) passo
) + S_DS_GEN
);
456 /* set the capability info */
457 tmpcap
= (bss
->capability
& CAPINFO_MASK
);
458 if (bss
->mode
== IW_MODE_INFRA
)
459 tmpcap
|= WLAN_CAPABILITY_ESS
;
460 passo
->capability
= cpu_to_le16(tmpcap
);
461 lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap
);
464 lbs_deb_leave_args(LBS_DEB_ASSOC
, "ret %d", ret
);
468 int lbs_cmd_80211_ad_hoc_start(struct lbs_private
*priv
,
469 struct cmd_ds_command
*cmd
, void *pdata_buf
)
471 struct cmd_ds_802_11_ad_hoc_start
*adhs
= &cmd
->params
.ads
;
473 int cmdappendsize
= 0;
474 struct assoc_request
* assoc_req
= pdata_buf
;
478 lbs_deb_enter(LBS_DEB_JOIN
);
485 cmd
->command
= cpu_to_le16(CMD_802_11_AD_HOC_START
);
488 * Fill in the parameters for 2 data structures:
489 * 1. cmd_ds_802_11_ad_hoc_start command
490 * 2. priv->scantable[i]
492 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
493 * probe delay, and cap info.
495 * Firmware will fill up beacon period, DTIM, Basic rates
496 * and operational rates.
499 memset(adhs
->ssid
, 0, IW_ESSID_MAX_SIZE
);
500 memcpy(adhs
->ssid
, assoc_req
->ssid
, assoc_req
->ssid_len
);
502 lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
503 escape_essid(assoc_req
->ssid
, assoc_req
->ssid_len
),
504 assoc_req
->ssid_len
);
506 /* set the BSS type */
507 adhs
->bsstype
= CMD_BSS_TYPE_IBSS
;
508 priv
->mode
= IW_MODE_ADHOC
;
509 if (priv
->beacon_period
== 0)
510 priv
->beacon_period
= MRVDRV_BEACON_INTERVAL
;
511 adhs
->beaconperiod
= cpu_to_le16(priv
->beacon_period
);
513 /* set Physical param set */
514 #define DS_PARA_IE_ID 3
515 #define DS_PARA_IE_LEN 1
517 adhs
->phyparamset
.dsparamset
.elementid
= DS_PARA_IE_ID
;
518 adhs
->phyparamset
.dsparamset
.len
= DS_PARA_IE_LEN
;
520 WARN_ON(!assoc_req
->channel
);
522 lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
525 adhs
->phyparamset
.dsparamset
.currentchan
= assoc_req
->channel
;
527 /* set IBSS param set */
528 #define IBSS_PARA_IE_ID 6
529 #define IBSS_PARA_IE_LEN 2
531 adhs
->ssparamset
.ibssparamset
.elementid
= IBSS_PARA_IE_ID
;
532 adhs
->ssparamset
.ibssparamset
.len
= IBSS_PARA_IE_LEN
;
533 adhs
->ssparamset
.ibssparamset
.atimwindow
= 0;
535 /* set capability info */
536 tmpcap
= WLAN_CAPABILITY_IBSS
;
537 if (assoc_req
->secinfo
.wep_enabled
) {
538 lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
539 tmpcap
|= WLAN_CAPABILITY_PRIVACY
;
541 lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
543 adhs
->capability
= cpu_to_le16(tmpcap
);
546 adhs
->probedelay
= cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME
);
548 memset(adhs
->rates
, 0, sizeof(adhs
->rates
));
549 ratesize
= min(sizeof(adhs
->rates
), sizeof(lbs_bg_rates
));
550 memcpy(adhs
->rates
, lbs_bg_rates
, ratesize
);
552 /* Copy the ad-hoc creating rates into Current BSS state structure */
553 memset(&priv
->curbssparams
.rates
, 0, sizeof(priv
->curbssparams
.rates
));
554 memcpy(&priv
->curbssparams
.rates
, &adhs
->rates
, ratesize
);
556 /* Set MSB on basic rates as the firmware requires, but _after_
557 * copying to current bss rates.
559 lbs_set_basic_rate_flags(adhs
->rates
, ratesize
);
561 lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
562 adhs
->rates
[0], adhs
->rates
[1], adhs
->rates
[2], adhs
->rates
[3]);
564 lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
566 if (lbs_create_dnld_countryinfo_11d(priv
)) {
567 lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
572 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start
) +
573 S_DS_GEN
+ cmdappendsize
);
577 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
581 int lbs_cmd_80211_ad_hoc_stop(struct lbs_private
*priv
,
582 struct cmd_ds_command
*cmd
)
584 cmd
->command
= cpu_to_le16(CMD_802_11_AD_HOC_STOP
);
585 cmd
->size
= cpu_to_le16(S_DS_GEN
);
590 int lbs_cmd_80211_ad_hoc_join(struct lbs_private
*priv
,
591 struct cmd_ds_command
*cmd
, void *pdata_buf
)
593 struct cmd_ds_802_11_ad_hoc_join
*join_cmd
= &cmd
->params
.adj
;
594 struct assoc_request
* assoc_req
= pdata_buf
;
595 struct bss_descriptor
*bss
= &assoc_req
->bss
;
596 int cmdappendsize
= 0;
599 DECLARE_MAC_BUF(mac
);
601 lbs_deb_enter(LBS_DEB_JOIN
);
603 cmd
->command
= cpu_to_le16(CMD_802_11_AD_HOC_JOIN
);
605 join_cmd
->bss
.type
= CMD_BSS_TYPE_IBSS
;
606 join_cmd
->bss
.beaconperiod
= cpu_to_le16(bss
->beaconperiod
);
608 memcpy(&join_cmd
->bss
.bssid
, &bss
->bssid
, ETH_ALEN
);
609 memcpy(&join_cmd
->bss
.ssid
, &bss
->ssid
, bss
->ssid_len
);
611 memcpy(&join_cmd
->bss
.phyparamset
, &bss
->phyparamset
,
612 sizeof(union ieeetypes_phyparamset
));
614 memcpy(&join_cmd
->bss
.ssparamset
, &bss
->ssparamset
,
615 sizeof(union IEEEtypes_ssparamset
));
617 join_cmd
->bss
.capability
= cpu_to_le16(bss
->capability
& CAPINFO_MASK
);
618 lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
619 bss
->capability
, CAPINFO_MASK
);
621 /* information on BSSID descriptor passed to FW */
623 "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
624 print_mac(mac
, join_cmd
->bss
.bssid
),
628 join_cmd
->failtimeout
= cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT
);
631 join_cmd
->probedelay
= cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME
);
633 priv
->curbssparams
.channel
= bss
->channel
;
635 /* Copy Data rates from the rates recorded in scan response */
636 memset(join_cmd
->bss
.rates
, 0, sizeof(join_cmd
->bss
.rates
));
637 ratesize
= min_t(u16
, sizeof(join_cmd
->bss
.rates
), MAX_RATES
);
638 memcpy(join_cmd
->bss
.rates
, bss
->rates
, ratesize
);
639 if (get_common_rates(priv
, join_cmd
->bss
.rates
, &ratesize
)) {
640 lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
645 /* Copy the ad-hoc creating rates into Current BSS state structure */
646 memset(&priv
->curbssparams
.rates
, 0, sizeof(priv
->curbssparams
.rates
));
647 memcpy(&priv
->curbssparams
.rates
, join_cmd
->bss
.rates
, ratesize
);
649 /* Set MSB on basic rates as the firmware requires, but _after_
650 * copying to current bss rates.
652 lbs_set_basic_rate_flags(join_cmd
->bss
.rates
, ratesize
);
654 join_cmd
->bss
.ssparamset
.ibssparamset
.atimwindow
=
655 cpu_to_le16(bss
->atimwindow
);
657 if (assoc_req
->secinfo
.wep_enabled
) {
658 u16 tmp
= le16_to_cpu(join_cmd
->bss
.capability
);
659 tmp
|= WLAN_CAPABILITY_PRIVACY
;
660 join_cmd
->bss
.capability
= cpu_to_le16(tmp
);
663 if (priv
->psmode
== LBS802_11POWERMODEMAX_PSP
) {
667 Localpsmode
= cpu_to_le32(LBS802_11POWERMODECAM
);
668 ret
= lbs_prepare_and_send_command(priv
,
679 if (lbs_parse_dnld_countryinfo_11d(priv
, bss
)) {
684 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join
) +
685 S_DS_GEN
+ cmdappendsize
);
688 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
692 int lbs_ret_80211_associate(struct lbs_private
*priv
,
693 struct cmd_ds_command
*resp
)
696 union iwreq_data wrqu
;
697 struct ieeetypes_assocrsp
*passocrsp
;
698 struct bss_descriptor
* bss
;
701 lbs_deb_enter(LBS_DEB_ASSOC
);
703 if (!priv
->in_progress_assoc_req
) {
704 lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
708 bss
= &priv
->in_progress_assoc_req
->bss
;
710 passocrsp
= (struct ieeetypes_assocrsp
*) & resp
->params
;
713 * Older FW versions map the IEEE 802.11 Status Code in the association
714 * response to the following values returned in passocrsp->statuscode:
716 * IEEE Status Code Marvell Status Code
717 * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
718 * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
719 * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
720 * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
721 * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
722 * others -> 0x0003 ASSOC_RESULT_REFUSED
724 * Other response codes:
725 * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
726 * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
727 * association response from the AP)
730 status_code
= le16_to_cpu(passocrsp
->statuscode
);
731 switch (status_code
) {
735 lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
738 lbs_deb_assoc("ASSOC_RESP: internal timer "
739 "expired while waiting for the AP\n");
742 lbs_deb_assoc("ASSOC_RESP: association "
746 lbs_deb_assoc("ASSOC_RESP: authentication "
750 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
751 " unknown\n", status_code
);
756 lbs_mac_event_disconnected(priv
);
761 lbs_deb_hex(LBS_DEB_ASSOC
, "ASSOC_RESP", (void *)&resp
->params
,
762 le16_to_cpu(resp
->size
) - S_DS_GEN
);
764 /* Send a Media Connected event, according to the Spec */
765 priv
->connect_status
= LBS_CONNECTED
;
767 /* Update current SSID and BSSID */
768 memcpy(&priv
->curbssparams
.ssid
, &bss
->ssid
, IW_ESSID_MAX_SIZE
);
769 priv
->curbssparams
.ssid_len
= bss
->ssid_len
;
770 memcpy(priv
->curbssparams
.bssid
, bss
->bssid
, ETH_ALEN
);
772 lbs_deb_assoc("ASSOC_RESP: currentpacketfilter is 0x%x\n",
773 priv
->currentpacketfilter
);
775 priv
->SNR
[TYPE_RXPD
][TYPE_AVG
] = 0;
776 priv
->NF
[TYPE_RXPD
][TYPE_AVG
] = 0;
778 memset(priv
->rawSNR
, 0x00, sizeof(priv
->rawSNR
));
779 memset(priv
->rawNF
, 0x00, sizeof(priv
->rawNF
));
783 netif_carrier_on(priv
->dev
);
784 if (!priv
->tx_pending_len
)
785 netif_wake_queue(priv
->dev
);
787 memcpy(wrqu
.ap_addr
.sa_data
, priv
->curbssparams
.bssid
, ETH_ALEN
);
788 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
789 wireless_send_event(priv
->dev
, SIOCGIWAP
, &wrqu
, NULL
);
792 lbs_deb_leave_args(LBS_DEB_ASSOC
, "ret %d", ret
);
796 int lbs_ret_80211_disassociate(struct lbs_private
*priv
,
797 struct cmd_ds_command
*resp
)
799 lbs_deb_enter(LBS_DEB_JOIN
);
801 lbs_mac_event_disconnected(priv
);
803 lbs_deb_leave(LBS_DEB_JOIN
);
807 int lbs_ret_80211_ad_hoc_start(struct lbs_private
*priv
,
808 struct cmd_ds_command
*resp
)
811 u16 command
= le16_to_cpu(resp
->command
);
812 u16 result
= le16_to_cpu(resp
->result
);
813 struct cmd_ds_802_11_ad_hoc_result
*padhocresult
;
814 union iwreq_data wrqu
;
815 struct bss_descriptor
*bss
;
816 DECLARE_MAC_BUF(mac
);
818 lbs_deb_enter(LBS_DEB_JOIN
);
820 padhocresult
= &resp
->params
.result
;
822 lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp
->size
));
823 lbs_deb_join("ADHOC_RESP: command = %x\n", command
);
824 lbs_deb_join("ADHOC_RESP: result = %x\n", result
);
826 if (!priv
->in_progress_assoc_req
) {
827 lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
831 bss
= &priv
->in_progress_assoc_req
->bss
;
834 * Join result code 0 --> SUCCESS
837 lbs_deb_join("ADHOC_RESP: failed\n");
838 if (priv
->connect_status
== LBS_CONNECTED
) {
839 lbs_mac_event_disconnected(priv
);
846 * Now the join cmd should be successful
847 * If BSSID has changed use SSID to compare instead of BSSID
849 lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
850 escape_essid(bss
->ssid
, bss
->ssid_len
));
852 /* Send a Media Connected event, according to the Spec */
853 priv
->connect_status
= LBS_CONNECTED
;
855 if (command
== CMD_RET(CMD_802_11_AD_HOC_START
)) {
856 /* Update the created network descriptor with the new BSSID */
857 memcpy(bss
->bssid
, padhocresult
->bssid
, ETH_ALEN
);
860 /* Set the BSSID from the joined/started descriptor */
861 memcpy(&priv
->curbssparams
.bssid
, bss
->bssid
, ETH_ALEN
);
863 /* Set the new SSID to current SSID */
864 memcpy(&priv
->curbssparams
.ssid
, &bss
->ssid
, IW_ESSID_MAX_SIZE
);
865 priv
->curbssparams
.ssid_len
= bss
->ssid_len
;
867 netif_carrier_on(priv
->dev
);
868 if (!priv
->tx_pending_len
)
869 netif_wake_queue(priv
->dev
);
871 memset(&wrqu
, 0, sizeof(wrqu
));
872 memcpy(wrqu
.ap_addr
.sa_data
, priv
->curbssparams
.bssid
, ETH_ALEN
);
873 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
874 wireless_send_event(priv
->dev
, SIOCGIWAP
, &wrqu
, NULL
);
876 lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
877 lbs_deb_join("ADHOC_RESP: channel = %d\n", priv
->curbssparams
.channel
);
878 lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
879 print_mac(mac
, padhocresult
->bssid
));
882 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
886 int lbs_ret_80211_ad_hoc_stop(struct lbs_private
*priv
,
887 struct cmd_ds_command
*resp
)
889 lbs_deb_enter(LBS_DEB_JOIN
);
891 lbs_mac_event_disconnected(priv
);
893 lbs_deb_leave(LBS_DEB_JOIN
);