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