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 Associate to a specific BSS discovered in a scan
104 * @param priv A pointer to struct lbs_private structure
105 * @param pbssdesc Pointer to the BSS descriptor to associate with.
107 * @return 0-success, otherwise fail
109 int lbs_associate(struct lbs_private
*priv
, struct assoc_request
*assoc_req
)
113 lbs_deb_enter(LBS_DEB_ASSOC
);
115 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_AUTHENTICATE
,
116 0, CMD_OPTION_WAITFORRSP
,
117 0, assoc_req
->bss
.bssid
);
122 /* set preamble to firmware */
123 if ( (priv
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
124 && (assoc_req
->bss
.capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
))
125 priv
->preamble
= CMD_TYPE_SHORT_PREAMBLE
;
127 priv
->preamble
= CMD_TYPE_LONG_PREAMBLE
;
129 lbs_set_radio_control(priv
);
131 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_ASSOCIATE
,
132 0, CMD_OPTION_WAITFORRSP
, 0, assoc_req
);
135 lbs_deb_leave_args(LBS_DEB_ASSOC
, "ret %d", ret
);
140 * @brief Start an Adhoc Network
142 * @param priv A pointer to struct lbs_private structure
143 * @param adhocssid The ssid of the Adhoc Network
144 * @return 0--success, -1--fail
146 int lbs_start_adhoc_network(struct lbs_private
*priv
,
147 struct assoc_request
*assoc_req
)
151 priv
->adhoccreate
= 1;
153 if (priv
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
) {
154 lbs_deb_join("AdhocStart: Short preamble\n");
155 priv
->preamble
= CMD_TYPE_SHORT_PREAMBLE
;
157 lbs_deb_join("AdhocStart: Long preamble\n");
158 priv
->preamble
= CMD_TYPE_LONG_PREAMBLE
;
161 lbs_set_radio_control(priv
);
163 lbs_deb_join("AdhocStart: channel = %d\n", assoc_req
->channel
);
164 lbs_deb_join("AdhocStart: band = %d\n", assoc_req
->band
);
166 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_AD_HOC_START
,
167 0, CMD_OPTION_WAITFORRSP
, 0, assoc_req
);
173 * @brief Join an adhoc network found in a previous scan
175 * @param priv A pointer to struct lbs_private structure
176 * @param pbssdesc Pointer to a BSS descriptor found in a previous scan
179 * @return 0--success, -1--fail
181 int lbs_join_adhoc_network(struct lbs_private
*priv
,
182 struct assoc_request
*assoc_req
)
184 struct bss_descriptor
* bss
= &assoc_req
->bss
;
187 lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
189 escape_essid(priv
->curbssparams
.ssid
,
190 priv
->curbssparams
.ssid_len
),
191 priv
->curbssparams
.ssid_len
);
192 lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
193 __func__
, escape_essid(bss
->ssid
, bss
->ssid_len
),
196 /* check if the requested SSID is already joined */
197 if ( priv
->curbssparams
.ssid_len
198 && !lbs_ssid_cmp(priv
->curbssparams
.ssid
,
199 priv
->curbssparams
.ssid_len
,
200 bss
->ssid
, bss
->ssid_len
)
201 && (priv
->mode
== IW_MODE_ADHOC
)
202 && (priv
->connect_status
== LBS_CONNECTED
)) {
203 union iwreq_data wrqu
;
205 lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
206 "current, not attempting to re-join");
208 /* Send the re-association event though, because the association
209 * request really was successful, even if just a null-op.
211 memset(&wrqu
, 0, sizeof(wrqu
));
212 memcpy(wrqu
.ap_addr
.sa_data
, priv
->curbssparams
.bssid
,
214 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
215 wireless_send_event(priv
->dev
, SIOCGIWAP
, &wrqu
, NULL
);
219 /* Use shortpreamble only when both creator and card supports
221 if ( !(bss
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
222 || !(priv
->capability
& WLAN_CAPABILITY_SHORT_PREAMBLE
)) {
223 lbs_deb_join("AdhocJoin: Long preamble\n");
224 priv
->preamble
= CMD_TYPE_LONG_PREAMBLE
;
226 lbs_deb_join("AdhocJoin: Short preamble\n");
227 priv
->preamble
= CMD_TYPE_SHORT_PREAMBLE
;
230 lbs_set_radio_control(priv
);
232 lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req
->channel
);
233 lbs_deb_join("AdhocJoin: band = %c\n", assoc_req
->band
);
235 priv
->adhoccreate
= 0;
237 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_AD_HOC_JOIN
,
238 0, CMD_OPTION_WAITFORRSP
,
239 OID_802_11_SSID
, assoc_req
);
245 int lbs_stop_adhoc_network(struct lbs_private
*priv
)
247 return lbs_prepare_and_send_command(priv
, CMD_802_11_AD_HOC_STOP
,
248 0, CMD_OPTION_WAITFORRSP
, 0, NULL
);
252 * @brief Send Deauthentication Request
254 * @param priv A pointer to struct lbs_private structure
255 * @return 0--success, -1--fail
257 int lbs_send_deauthentication(struct lbs_private
*priv
)
259 return lbs_prepare_and_send_command(priv
, CMD_802_11_DEAUTHENTICATE
,
260 0, CMD_OPTION_WAITFORRSP
, 0, NULL
);
264 * @brief This function prepares command of authenticate.
266 * @param priv A pointer to struct lbs_private structure
267 * @param cmd A pointer to cmd_ds_command structure
268 * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
272 int lbs_cmd_80211_authenticate(struct lbs_private
*priv
,
273 struct cmd_ds_command
*cmd
,
276 struct cmd_ds_802_11_authenticate
*pauthenticate
= &cmd
->params
.auth
;
278 u8
*bssid
= pdata_buf
;
279 DECLARE_MAC_BUF(mac
);
281 lbs_deb_enter(LBS_DEB_JOIN
);
283 cmd
->command
= cpu_to_le16(CMD_802_11_AUTHENTICATE
);
284 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate
)
287 /* translate auth mode to 802.11 defined wire value */
288 switch (priv
->secinfo
.auth_mode
) {
289 case IW_AUTH_ALG_OPEN_SYSTEM
:
290 pauthenticate
->authtype
= 0x00;
292 case IW_AUTH_ALG_SHARED_KEY
:
293 pauthenticate
->authtype
= 0x01;
295 case IW_AUTH_ALG_LEAP
:
296 pauthenticate
->authtype
= 0x80;
299 lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
300 priv
->secinfo
.auth_mode
);
304 memcpy(pauthenticate
->macaddr
, bssid
, ETH_ALEN
);
306 lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
307 print_mac(mac
, bssid
), pauthenticate
->authtype
);
311 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
315 int lbs_cmd_80211_deauthenticate(struct lbs_private
*priv
,
316 struct cmd_ds_command
*cmd
)
318 struct cmd_ds_802_11_deauthenticate
*dauth
= &cmd
->params
.deauth
;
320 lbs_deb_enter(LBS_DEB_JOIN
);
322 cmd
->command
= cpu_to_le16(CMD_802_11_DEAUTHENTICATE
);
323 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate
) +
326 /* set AP MAC address */
327 memmove(dauth
->macaddr
, priv
->curbssparams
.bssid
, ETH_ALEN
);
329 /* Reason code 3 = Station is leaving */
330 #define REASON_CODE_STA_LEAVING 3
331 dauth
->reasoncode
= cpu_to_le16(REASON_CODE_STA_LEAVING
);
333 lbs_deb_leave(LBS_DEB_JOIN
);
337 int lbs_cmd_80211_associate(struct lbs_private
*priv
,
338 struct cmd_ds_command
*cmd
, void *pdata_buf
)
340 struct cmd_ds_802_11_associate
*passo
= &cmd
->params
.associate
;
342 struct assoc_request
* assoc_req
= pdata_buf
;
343 struct bss_descriptor
* bss
= &assoc_req
->bss
;
346 struct mrvlietypes_ssidparamset
*ssid
;
347 struct mrvlietypes_phyparamset
*phy
;
348 struct mrvlietypes_ssparamset
*ss
;
349 struct mrvlietypes_ratesparamset
*rates
;
350 struct mrvlietypes_rsnparamset
*rsn
;
352 lbs_deb_enter(LBS_DEB_ASSOC
);
361 cmd
->command
= cpu_to_le16(CMD_802_11_ASSOCIATE
);
363 memcpy(passo
->peerstaaddr
, bss
->bssid
, sizeof(passo
->peerstaaddr
));
364 pos
+= sizeof(passo
->peerstaaddr
);
366 /* set the listen interval */
367 passo
->listeninterval
= cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL
);
369 pos
+= sizeof(passo
->capability
);
370 pos
+= sizeof(passo
->listeninterval
);
371 pos
+= sizeof(passo
->bcnperiod
);
372 pos
+= sizeof(passo
->dtimperiod
);
374 ssid
= (struct mrvlietypes_ssidparamset
*) pos
;
375 ssid
->header
.type
= cpu_to_le16(TLV_TYPE_SSID
);
376 tmplen
= bss
->ssid_len
;
377 ssid
->header
.len
= cpu_to_le16(tmplen
);
378 memcpy(ssid
->ssid
, bss
->ssid
, tmplen
);
379 pos
+= sizeof(ssid
->header
) + tmplen
;
381 phy
= (struct mrvlietypes_phyparamset
*) pos
;
382 phy
->header
.type
= cpu_to_le16(TLV_TYPE_PHY_DS
);
383 tmplen
= sizeof(phy
->fh_ds
.dsparamset
);
384 phy
->header
.len
= cpu_to_le16(tmplen
);
385 memcpy(&phy
->fh_ds
.dsparamset
,
386 &bss
->phyparamset
.dsparamset
.currentchan
,
388 pos
+= sizeof(phy
->header
) + tmplen
;
390 ss
= (struct mrvlietypes_ssparamset
*) pos
;
391 ss
->header
.type
= cpu_to_le16(TLV_TYPE_CF
);
392 tmplen
= sizeof(ss
->cf_ibss
.cfparamset
);
393 ss
->header
.len
= cpu_to_le16(tmplen
);
394 pos
+= sizeof(ss
->header
) + tmplen
;
396 rates
= (struct mrvlietypes_ratesparamset
*) pos
;
397 rates
->header
.type
= cpu_to_le16(TLV_TYPE_RATES
);
398 memcpy(&rates
->rates
, &bss
->rates
, MAX_RATES
);
400 if (get_common_rates(priv
, rates
->rates
, &tmplen
)) {
404 pos
+= sizeof(rates
->header
) + tmplen
;
405 rates
->header
.len
= cpu_to_le16(tmplen
);
406 lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen
);
408 /* Copy the infra. association rates into Current BSS state structure */
409 memset(&priv
->curbssparams
.rates
, 0, sizeof(priv
->curbssparams
.rates
));
410 memcpy(&priv
->curbssparams
.rates
, &rates
->rates
, tmplen
);
412 /* Set MSB on basic rates as the firmware requires, but _after_
413 * copying to current bss rates.
415 lbs_set_basic_rate_flags(rates
->rates
, tmplen
);
417 if (assoc_req
->secinfo
.WPAenabled
|| assoc_req
->secinfo
.WPA2enabled
) {
418 rsn
= (struct mrvlietypes_rsnparamset
*) pos
;
419 /* WPA_IE or WPA2_IE */
420 rsn
->header
.type
= cpu_to_le16((u16
) assoc_req
->wpa_ie
[0]);
421 tmplen
= (u16
) assoc_req
->wpa_ie
[1];
422 rsn
->header
.len
= cpu_to_le16(tmplen
);
423 memcpy(rsn
->rsnie
, &assoc_req
->wpa_ie
[2], tmplen
);
424 lbs_deb_hex(LBS_DEB_JOIN
, "ASSOC_CMD: RSN IE", (u8
*) rsn
,
425 sizeof(rsn
->header
) + tmplen
);
426 pos
+= sizeof(rsn
->header
) + tmplen
;
429 /* update curbssparams */
430 priv
->curbssparams
.channel
= bss
->phyparamset
.dsparamset
.currentchan
;
432 if (lbs_parse_dnld_countryinfo_11d(priv
, bss
)) {
437 cmd
->size
= cpu_to_le16((u16
) (pos
- (u8
*) passo
) + S_DS_GEN
);
439 /* set the capability info */
440 tmpcap
= (bss
->capability
& CAPINFO_MASK
);
441 if (bss
->mode
== IW_MODE_INFRA
)
442 tmpcap
|= WLAN_CAPABILITY_ESS
;
443 passo
->capability
= cpu_to_le16(tmpcap
);
444 lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap
);
447 lbs_deb_leave_args(LBS_DEB_ASSOC
, "ret %d", ret
);
451 int lbs_cmd_80211_ad_hoc_start(struct lbs_private
*priv
,
452 struct cmd_ds_command
*cmd
, void *pdata_buf
)
454 struct cmd_ds_802_11_ad_hoc_start
*adhs
= &cmd
->params
.ads
;
456 int cmdappendsize
= 0;
457 struct assoc_request
* assoc_req
= pdata_buf
;
461 lbs_deb_enter(LBS_DEB_JOIN
);
468 cmd
->command
= cpu_to_le16(CMD_802_11_AD_HOC_START
);
471 * Fill in the parameters for 2 data structures:
472 * 1. cmd_ds_802_11_ad_hoc_start command
473 * 2. priv->scantable[i]
475 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
476 * probe delay, and cap info.
478 * Firmware will fill up beacon period, DTIM, Basic rates
479 * and operational rates.
482 memset(adhs
->ssid
, 0, IW_ESSID_MAX_SIZE
);
483 memcpy(adhs
->ssid
, assoc_req
->ssid
, assoc_req
->ssid_len
);
485 lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
486 escape_essid(assoc_req
->ssid
, assoc_req
->ssid_len
),
487 assoc_req
->ssid_len
);
489 /* set the BSS type */
490 adhs
->bsstype
= CMD_BSS_TYPE_IBSS
;
491 priv
->mode
= IW_MODE_ADHOC
;
492 if (priv
->beacon_period
== 0)
493 priv
->beacon_period
= MRVDRV_BEACON_INTERVAL
;
494 adhs
->beaconperiod
= cpu_to_le16(priv
->beacon_period
);
496 /* set Physical param set */
497 #define DS_PARA_IE_ID 3
498 #define DS_PARA_IE_LEN 1
500 adhs
->phyparamset
.dsparamset
.elementid
= DS_PARA_IE_ID
;
501 adhs
->phyparamset
.dsparamset
.len
= DS_PARA_IE_LEN
;
503 WARN_ON(!assoc_req
->channel
);
505 lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
508 adhs
->phyparamset
.dsparamset
.currentchan
= assoc_req
->channel
;
510 /* set IBSS param set */
511 #define IBSS_PARA_IE_ID 6
512 #define IBSS_PARA_IE_LEN 2
514 adhs
->ssparamset
.ibssparamset
.elementid
= IBSS_PARA_IE_ID
;
515 adhs
->ssparamset
.ibssparamset
.len
= IBSS_PARA_IE_LEN
;
516 adhs
->ssparamset
.ibssparamset
.atimwindow
= 0;
518 /* set capability info */
519 tmpcap
= WLAN_CAPABILITY_IBSS
;
520 if (assoc_req
->secinfo
.wep_enabled
) {
521 lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
522 tmpcap
|= WLAN_CAPABILITY_PRIVACY
;
524 lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
526 adhs
->capability
= cpu_to_le16(tmpcap
);
529 adhs
->probedelay
= cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME
);
531 memset(adhs
->rates
, 0, sizeof(adhs
->rates
));
532 ratesize
= min(sizeof(adhs
->rates
), sizeof(lbs_bg_rates
));
533 memcpy(adhs
->rates
, lbs_bg_rates
, ratesize
);
535 /* Copy the ad-hoc creating rates into Current BSS state structure */
536 memset(&priv
->curbssparams
.rates
, 0, sizeof(priv
->curbssparams
.rates
));
537 memcpy(&priv
->curbssparams
.rates
, &adhs
->rates
, ratesize
);
539 /* Set MSB on basic rates as the firmware requires, but _after_
540 * copying to current bss rates.
542 lbs_set_basic_rate_flags(adhs
->rates
, ratesize
);
544 lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
545 adhs
->rates
[0], adhs
->rates
[1], adhs
->rates
[2], adhs
->rates
[3]);
547 lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
549 if (lbs_create_dnld_countryinfo_11d(priv
)) {
550 lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
555 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start
) +
556 S_DS_GEN
+ cmdappendsize
);
560 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
564 int lbs_cmd_80211_ad_hoc_stop(struct lbs_private
*priv
,
565 struct cmd_ds_command
*cmd
)
567 cmd
->command
= cpu_to_le16(CMD_802_11_AD_HOC_STOP
);
568 cmd
->size
= cpu_to_le16(S_DS_GEN
);
573 int lbs_cmd_80211_ad_hoc_join(struct lbs_private
*priv
,
574 struct cmd_ds_command
*cmd
, void *pdata_buf
)
576 struct cmd_ds_802_11_ad_hoc_join
*join_cmd
= &cmd
->params
.adj
;
577 struct assoc_request
* assoc_req
= pdata_buf
;
578 struct bss_descriptor
*bss
= &assoc_req
->bss
;
579 int cmdappendsize
= 0;
582 DECLARE_MAC_BUF(mac
);
584 lbs_deb_enter(LBS_DEB_JOIN
);
586 cmd
->command
= cpu_to_le16(CMD_802_11_AD_HOC_JOIN
);
588 join_cmd
->bss
.type
= CMD_BSS_TYPE_IBSS
;
589 join_cmd
->bss
.beaconperiod
= cpu_to_le16(bss
->beaconperiod
);
591 memcpy(&join_cmd
->bss
.bssid
, &bss
->bssid
, ETH_ALEN
);
592 memcpy(&join_cmd
->bss
.ssid
, &bss
->ssid
, bss
->ssid_len
);
594 memcpy(&join_cmd
->bss
.phyparamset
, &bss
->phyparamset
,
595 sizeof(union ieeetypes_phyparamset
));
597 memcpy(&join_cmd
->bss
.ssparamset
, &bss
->ssparamset
,
598 sizeof(union IEEEtypes_ssparamset
));
600 join_cmd
->bss
.capability
= cpu_to_le16(bss
->capability
& CAPINFO_MASK
);
601 lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
602 bss
->capability
, CAPINFO_MASK
);
604 /* information on BSSID descriptor passed to FW */
606 "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
607 print_mac(mac
, join_cmd
->bss
.bssid
),
611 join_cmd
->failtimeout
= cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT
);
614 join_cmd
->probedelay
= cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME
);
616 priv
->curbssparams
.channel
= bss
->channel
;
618 /* Copy Data rates from the rates recorded in scan response */
619 memset(join_cmd
->bss
.rates
, 0, sizeof(join_cmd
->bss
.rates
));
620 ratesize
= min_t(u16
, sizeof(join_cmd
->bss
.rates
), MAX_RATES
);
621 memcpy(join_cmd
->bss
.rates
, bss
->rates
, ratesize
);
622 if (get_common_rates(priv
, join_cmd
->bss
.rates
, &ratesize
)) {
623 lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
628 /* Copy the ad-hoc creating rates into Current BSS state structure */
629 memset(&priv
->curbssparams
.rates
, 0, sizeof(priv
->curbssparams
.rates
));
630 memcpy(&priv
->curbssparams
.rates
, join_cmd
->bss
.rates
, ratesize
);
632 /* Set MSB on basic rates as the firmware requires, but _after_
633 * copying to current bss rates.
635 lbs_set_basic_rate_flags(join_cmd
->bss
.rates
, ratesize
);
637 join_cmd
->bss
.ssparamset
.ibssparamset
.atimwindow
=
638 cpu_to_le16(bss
->atimwindow
);
640 if (assoc_req
->secinfo
.wep_enabled
) {
641 u16 tmp
= le16_to_cpu(join_cmd
->bss
.capability
);
642 tmp
|= WLAN_CAPABILITY_PRIVACY
;
643 join_cmd
->bss
.capability
= cpu_to_le16(tmp
);
646 if (priv
->psmode
== LBS802_11POWERMODEMAX_PSP
) {
650 Localpsmode
= cpu_to_le32(LBS802_11POWERMODECAM
);
651 ret
= lbs_prepare_and_send_command(priv
,
662 if (lbs_parse_dnld_countryinfo_11d(priv
, bss
)) {
667 cmd
->size
= cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join
) +
668 S_DS_GEN
+ cmdappendsize
);
671 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
675 int lbs_ret_80211_associate(struct lbs_private
*priv
,
676 struct cmd_ds_command
*resp
)
679 union iwreq_data wrqu
;
680 struct ieeetypes_assocrsp
*passocrsp
;
681 struct bss_descriptor
* bss
;
684 lbs_deb_enter(LBS_DEB_ASSOC
);
686 if (!priv
->in_progress_assoc_req
) {
687 lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
691 bss
= &priv
->in_progress_assoc_req
->bss
;
693 passocrsp
= (struct ieeetypes_assocrsp
*) & resp
->params
;
696 * Older FW versions map the IEEE 802.11 Status Code in the association
697 * response to the following values returned in passocrsp->statuscode:
699 * IEEE Status Code Marvell Status Code
700 * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
701 * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
702 * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
703 * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
704 * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
705 * others -> 0x0003 ASSOC_RESULT_REFUSED
707 * Other response codes:
708 * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
709 * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
710 * association response from the AP)
713 status_code
= le16_to_cpu(passocrsp
->statuscode
);
714 switch (status_code
) {
718 lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
721 lbs_deb_assoc("ASSOC_RESP: internal timer "
722 "expired while waiting for the AP\n");
725 lbs_deb_assoc("ASSOC_RESP: association "
729 lbs_deb_assoc("ASSOC_RESP: authentication "
733 lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
734 " unknown\n", status_code
);
739 lbs_mac_event_disconnected(priv
);
744 lbs_deb_hex(LBS_DEB_ASSOC
, "ASSOC_RESP", (void *)&resp
->params
,
745 le16_to_cpu(resp
->size
) - S_DS_GEN
);
747 /* Send a Media Connected event, according to the Spec */
748 priv
->connect_status
= LBS_CONNECTED
;
750 /* Update current SSID and BSSID */
751 memcpy(&priv
->curbssparams
.ssid
, &bss
->ssid
, IW_ESSID_MAX_SIZE
);
752 priv
->curbssparams
.ssid_len
= bss
->ssid_len
;
753 memcpy(priv
->curbssparams
.bssid
, bss
->bssid
, ETH_ALEN
);
755 priv
->SNR
[TYPE_RXPD
][TYPE_AVG
] = 0;
756 priv
->NF
[TYPE_RXPD
][TYPE_AVG
] = 0;
758 memset(priv
->rawSNR
, 0x00, sizeof(priv
->rawSNR
));
759 memset(priv
->rawNF
, 0x00, sizeof(priv
->rawNF
));
763 netif_carrier_on(priv
->dev
);
764 if (!priv
->tx_pending_len
)
765 netif_wake_queue(priv
->dev
);
767 memcpy(wrqu
.ap_addr
.sa_data
, priv
->curbssparams
.bssid
, ETH_ALEN
);
768 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
769 wireless_send_event(priv
->dev
, SIOCGIWAP
, &wrqu
, NULL
);
772 lbs_deb_leave_args(LBS_DEB_ASSOC
, "ret %d", ret
);
776 int lbs_ret_80211_disassociate(struct lbs_private
*priv
,
777 struct cmd_ds_command
*resp
)
779 lbs_deb_enter(LBS_DEB_JOIN
);
781 lbs_mac_event_disconnected(priv
);
783 lbs_deb_leave(LBS_DEB_JOIN
);
787 int lbs_ret_80211_ad_hoc_start(struct lbs_private
*priv
,
788 struct cmd_ds_command
*resp
)
791 u16 command
= le16_to_cpu(resp
->command
);
792 u16 result
= le16_to_cpu(resp
->result
);
793 struct cmd_ds_802_11_ad_hoc_result
*padhocresult
;
794 union iwreq_data wrqu
;
795 struct bss_descriptor
*bss
;
796 DECLARE_MAC_BUF(mac
);
798 lbs_deb_enter(LBS_DEB_JOIN
);
800 padhocresult
= &resp
->params
.result
;
802 lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp
->size
));
803 lbs_deb_join("ADHOC_RESP: command = %x\n", command
);
804 lbs_deb_join("ADHOC_RESP: result = %x\n", result
);
806 if (!priv
->in_progress_assoc_req
) {
807 lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
811 bss
= &priv
->in_progress_assoc_req
->bss
;
814 * Join result code 0 --> SUCCESS
817 lbs_deb_join("ADHOC_RESP: failed\n");
818 if (priv
->connect_status
== LBS_CONNECTED
) {
819 lbs_mac_event_disconnected(priv
);
826 * Now the join cmd should be successful
827 * If BSSID has changed use SSID to compare instead of BSSID
829 lbs_deb_join("ADHOC_RESP: associated to '%s'\n",
830 escape_essid(bss
->ssid
, bss
->ssid_len
));
832 /* Send a Media Connected event, according to the Spec */
833 priv
->connect_status
= LBS_CONNECTED
;
835 if (command
== CMD_RET(CMD_802_11_AD_HOC_START
)) {
836 /* Update the created network descriptor with the new BSSID */
837 memcpy(bss
->bssid
, padhocresult
->bssid
, ETH_ALEN
);
840 /* Set the BSSID from the joined/started descriptor */
841 memcpy(&priv
->curbssparams
.bssid
, bss
->bssid
, ETH_ALEN
);
843 /* Set the new SSID to current SSID */
844 memcpy(&priv
->curbssparams
.ssid
, &bss
->ssid
, IW_ESSID_MAX_SIZE
);
845 priv
->curbssparams
.ssid_len
= bss
->ssid_len
;
847 netif_carrier_on(priv
->dev
);
848 if (!priv
->tx_pending_len
)
849 netif_wake_queue(priv
->dev
);
851 memset(&wrqu
, 0, sizeof(wrqu
));
852 memcpy(wrqu
.ap_addr
.sa_data
, priv
->curbssparams
.bssid
, ETH_ALEN
);
853 wrqu
.ap_addr
.sa_family
= ARPHRD_ETHER
;
854 wireless_send_event(priv
->dev
, SIOCGIWAP
, &wrqu
, NULL
);
856 lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
857 lbs_deb_join("ADHOC_RESP: channel = %d\n", priv
->curbssparams
.channel
);
858 lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
859 print_mac(mac
, padhocresult
->bssid
));
862 lbs_deb_leave_args(LBS_DEB_JOIN
, "ret %d", ret
);
866 int lbs_ret_80211_ad_hoc_stop(struct lbs_private
*priv
,
867 struct cmd_ds_command
*resp
)
869 lbs_deb_enter(LBS_DEB_JOIN
);
871 lbs_mac_event_disconnected(priv
);
873 lbs_deb_leave(LBS_DEB_JOIN
);