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