Commit | Line | Data |
---|---|---|
876c9d3a MT |
1 | /** |
2 | * This file contains the handling of command | |
3 | * responses as well as events generated by firmware. | |
4 | */ | |
5 | #include <linux/delay.h> | |
6 | #include <linux/if_arp.h> | |
7 | #include <linux/netdevice.h> | |
8 | ||
9 | #include <net/iw_handler.h> | |
10 | ||
11 | #include "host.h" | |
876c9d3a MT |
12 | #include "decl.h" |
13 | #include "defs.h" | |
14 | #include "dev.h" | |
15 | #include "join.h" | |
16 | #include "wext.h" | |
17 | ||
18 | /** | |
19 | * @brief This function handles disconnect event. it | |
20 | * reports disconnect to upper layer, clean tx/rx packets, | |
21 | * reset link state etc. | |
22 | * | |
69f9032d | 23 | * @param priv A pointer to struct lbs_private structure |
876c9d3a MT |
24 | * @return n/a |
25 | */ | |
69f9032d | 26 | void lbs_mac_event_disconnected(struct lbs_private *priv) |
876c9d3a | 27 | { |
876c9d3a MT |
28 | union iwreq_data wrqu; |
29 | ||
aa21c004 | 30 | if (priv->connect_status != LBS_CONNECTED) |
876c9d3a MT |
31 | return; |
32 | ||
91843463 | 33 | lbs_deb_enter(LBS_DEB_ASSOC); |
876c9d3a MT |
34 | |
35 | memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); | |
36 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | |
37 | ||
38 | /* | |
39 | * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. | |
40 | * It causes problem in the Supplicant | |
41 | */ | |
42 | ||
43 | msleep_interruptible(1000); | |
634b8f49 | 44 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); |
876c9d3a MT |
45 | |
46 | /* Free Tx and Rx packets */ | |
aa21c004 DW |
47 | kfree_skb(priv->currenttxskb); |
48 | priv->currenttxskb = NULL; | |
876c9d3a MT |
49 | |
50 | /* report disconnect to upper layer */ | |
634b8f49 HS |
51 | netif_stop_queue(priv->dev); |
52 | netif_carrier_off(priv->dev); | |
876c9d3a MT |
53 | |
54 | /* reset SNR/NF/RSSI values */ | |
aa21c004 DW |
55 | memset(priv->SNR, 0x00, sizeof(priv->SNR)); |
56 | memset(priv->NF, 0x00, sizeof(priv->NF)); | |
57 | memset(priv->RSSI, 0x00, sizeof(priv->RSSI)); | |
58 | memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); | |
59 | memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); | |
60 | priv->nextSNRNF = 0; | |
61 | priv->numSNRNF = 0; | |
62 | priv->connect_status = LBS_DISCONNECTED; | |
876c9d3a | 63 | |
e76850d6 DW |
64 | /* Clear out associated SSID and BSSID since connection is |
65 | * no longer valid. | |
66 | */ | |
aa21c004 DW |
67 | memset(&priv->curbssparams.bssid, 0, ETH_ALEN); |
68 | memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE); | |
69 | priv->curbssparams.ssid_len = 0; | |
876c9d3a | 70 | |
aa21c004 | 71 | if (priv->psstate != PS_STATE_FULL_POWER) { |
876c9d3a | 72 | /* make firmware to exit PS mode */ |
a6c8700f | 73 | lbs_deb_cmd("disconnected, so exit PS mode\n"); |
10078321 | 74 | lbs_ps_wakeup(priv, 0); |
876c9d3a | 75 | } |
a6c8700f | 76 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
77 | } |
78 | ||
79 | /** | |
80 | * @brief This function handles MIC failure event. | |
81 | * | |
69f9032d | 82 | * @param priv A pointer to struct lbs_private structure |
876c9d3a MT |
83 | * @para event the event id |
84 | * @return n/a | |
85 | */ | |
69f9032d | 86 | static void handle_mic_failureevent(struct lbs_private *priv, u32 event) |
876c9d3a MT |
87 | { |
88 | char buf[50]; | |
89 | ||
a6c8700f | 90 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
91 | memset(buf, 0, sizeof(buf)); |
92 | ||
93 | sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); | |
94 | ||
95 | if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) { | |
96 | strcat(buf, "unicast "); | |
97 | } else { | |
98 | strcat(buf, "multicast "); | |
99 | } | |
100 | ||
10078321 | 101 | lbs_send_iwevcustom_event(priv, buf); |
a6c8700f | 102 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
103 | } |
104 | ||
69f9032d | 105 | static int lbs_ret_reg_access(struct lbs_private *priv, |
876c9d3a MT |
106 | u16 type, struct cmd_ds_command *resp) |
107 | { | |
9012b28a | 108 | int ret = 0; |
876c9d3a | 109 | |
9012b28a | 110 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
111 | |
112 | switch (type) { | |
6b63cd0f | 113 | case CMD_RET(CMD_MAC_REG_ACCESS): |
876c9d3a | 114 | { |
981f187b | 115 | struct cmd_ds_mac_reg_access *reg = &resp->params.macreg; |
876c9d3a | 116 | |
aa21c004 DW |
117 | priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); |
118 | priv->offsetvalue.value = le32_to_cpu(reg->value); | |
876c9d3a MT |
119 | break; |
120 | } | |
121 | ||
6b63cd0f | 122 | case CMD_RET(CMD_BBP_REG_ACCESS): |
876c9d3a | 123 | { |
981f187b | 124 | struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg; |
876c9d3a | 125 | |
aa21c004 DW |
126 | priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); |
127 | priv->offsetvalue.value = reg->value; | |
876c9d3a MT |
128 | break; |
129 | } | |
130 | ||
6b63cd0f | 131 | case CMD_RET(CMD_RF_REG_ACCESS): |
876c9d3a | 132 | { |
981f187b | 133 | struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg; |
876c9d3a | 134 | |
aa21c004 DW |
135 | priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); |
136 | priv->offsetvalue.value = reg->value; | |
876c9d3a MT |
137 | break; |
138 | } | |
139 | ||
140 | default: | |
9012b28a | 141 | ret = -1; |
876c9d3a MT |
142 | } |
143 | ||
8b17d723 | 144 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); |
9012b28a | 145 | return ret; |
876c9d3a MT |
146 | } |
147 | ||
69f9032d | 148 | static int lbs_ret_802_11_sleep_params(struct lbs_private *priv, |
876c9d3a MT |
149 | struct cmd_ds_command *resp) |
150 | { | |
151 | struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params; | |
876c9d3a | 152 | |
9012b28a | 153 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 154 | |
a6c8700f HS |
155 | lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x " |
156 | "extsleepclk 0x%x\n", le16_to_cpu(sp->error), | |
981f187b DW |
157 | le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime), |
158 | sp->calcontrol, sp->externalsleepclk); | |
159 | ||
aa21c004 DW |
160 | priv->sp.sp_error = le16_to_cpu(sp->error); |
161 | priv->sp.sp_offset = le16_to_cpu(sp->offset); | |
162 | priv->sp.sp_stabletime = le16_to_cpu(sp->stabletime); | |
163 | priv->sp.sp_calcontrol = sp->calcontrol; | |
164 | priv->sp.sp_extsleepclk = sp->externalsleepclk; | |
165 | priv->sp.sp_reserved = le16_to_cpu(sp->reserved); | |
876c9d3a | 166 | |
9012b28a | 167 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
168 | return 0; |
169 | } | |
170 | ||
69f9032d | 171 | static int lbs_ret_802_11_stat(struct lbs_private *priv, |
876c9d3a MT |
172 | struct cmd_ds_command *resp) |
173 | { | |
a6c8700f | 174 | lbs_deb_enter(LBS_DEB_CMD); |
aa21c004 | 175 | /* currently priv->wlan802_11Stat is unused |
876c9d3a MT |
176 | |
177 | struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; | |
876c9d3a MT |
178 | |
179 | // TODO Convert it to Big endian befor copy | |
aa21c004 | 180 | memcpy(&priv->wlan802_11Stat, |
876c9d3a MT |
181 | p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); |
182 | */ | |
a6c8700f | 183 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
184 | return 0; |
185 | } | |
186 | ||
69f9032d | 187 | static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, |
876c9d3a MT |
188 | struct cmd_ds_command *resp) |
189 | { | |
190 | struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; | |
191 | u16 oid = le16_to_cpu(smib->oid); | |
192 | u16 querytype = le16_to_cpu(smib->querytype); | |
193 | ||
9012b28a | 194 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 195 | |
a6c8700f | 196 | lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid, |
876c9d3a | 197 | querytype); |
a6c8700f | 198 | lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize)); |
876c9d3a | 199 | |
0aef64d7 | 200 | if (querytype == CMD_ACT_GET) { |
876c9d3a | 201 | switch (oid) { |
0aef64d7 | 202 | case FRAGTHRESH_I: |
aa21c004 | 203 | priv->fragthsd = |
981f187b | 204 | le16_to_cpu(*((__le16 *)(smib->value))); |
a6c8700f | 205 | lbs_deb_cmd("SNMP_RESP: frag threshold %u\n", |
aa21c004 | 206 | priv->fragthsd); |
876c9d3a | 207 | break; |
0aef64d7 | 208 | case RTSTHRESH_I: |
aa21c004 | 209 | priv->rtsthsd = |
981f187b | 210 | le16_to_cpu(*((__le16 *)(smib->value))); |
a6c8700f | 211 | lbs_deb_cmd("SNMP_RESP: rts threshold %u\n", |
aa21c004 | 212 | priv->rtsthsd); |
876c9d3a | 213 | break; |
0aef64d7 | 214 | case SHORT_RETRYLIM_I: |
aa21c004 | 215 | priv->txretrycount = |
981f187b | 216 | le16_to_cpu(*((__le16 *)(smib->value))); |
a6c8700f | 217 | lbs_deb_cmd("SNMP_RESP: tx retry count %u\n", |
aa21c004 | 218 | priv->rtsthsd); |
876c9d3a MT |
219 | break; |
220 | default: | |
221 | break; | |
222 | } | |
223 | } | |
224 | ||
9012b28a | 225 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
226 | return 0; |
227 | } | |
228 | ||
69f9032d | 229 | static int lbs_ret_802_11_key_material(struct lbs_private *priv, |
876c9d3a MT |
230 | struct cmd_ds_command *resp) |
231 | { | |
232 | struct cmd_ds_802_11_key_material *pkeymaterial = | |
233 | &resp->params.keymaterial; | |
876c9d3a MT |
234 | u16 action = le16_to_cpu(pkeymaterial->action); |
235 | ||
9012b28a | 236 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
237 | |
238 | /* Copy the returned key to driver private data */ | |
0aef64d7 | 239 | if (action == CMD_ACT_GET) { |
876c9d3a MT |
240 | u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; |
241 | u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); | |
242 | ||
243 | while (buf_ptr < resp_end) { | |
244 | struct MrvlIEtype_keyParamSet * pkeyparamset = | |
245 | (struct MrvlIEtype_keyParamSet *) buf_ptr; | |
1443b653 | 246 | struct enc_key * pkey; |
876c9d3a | 247 | u16 param_set_len = le16_to_cpu(pkeyparamset->length); |
876c9d3a | 248 | u16 key_len = le16_to_cpu(pkeyparamset->keylen); |
1443b653 DW |
249 | u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo); |
250 | u16 key_type = le16_to_cpu(pkeyparamset->keytypeid); | |
251 | u8 * end; | |
876c9d3a MT |
252 | |
253 | end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) | |
254 | + sizeof (pkeyparamset->length) | |
255 | + param_set_len; | |
256 | /* Make sure we don't access past the end of the IEs */ | |
257 | if (end > resp_end) | |
258 | break; | |
259 | ||
1443b653 | 260 | if (key_flags & KEY_INFO_WPA_UNICAST) |
aa21c004 | 261 | pkey = &priv->wpa_unicast_key; |
1443b653 | 262 | else if (key_flags & KEY_INFO_WPA_MCAST) |
aa21c004 | 263 | pkey = &priv->wpa_mcast_key; |
876c9d3a MT |
264 | else |
265 | break; | |
266 | ||
267 | /* Copy returned key into driver */ | |
1443b653 | 268 | memset(pkey, 0, sizeof(struct enc_key)); |
876c9d3a MT |
269 | if (key_len > sizeof(pkey->key)) |
270 | break; | |
1443b653 DW |
271 | pkey->type = key_type; |
272 | pkey->flags = key_flags; | |
273 | pkey->len = key_len; | |
876c9d3a MT |
274 | memcpy(pkey->key, pkeyparamset->key, pkey->len); |
275 | ||
276 | buf_ptr = end + 1; | |
277 | } | |
278 | } | |
279 | ||
9012b28a | 280 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
281 | return 0; |
282 | } | |
283 | ||
69f9032d | 284 | static int lbs_ret_802_11_mac_address(struct lbs_private *priv, |
876c9d3a MT |
285 | struct cmd_ds_command *resp) |
286 | { | |
287 | struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd; | |
876c9d3a | 288 | |
9012b28a | 289 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 290 | |
aa21c004 | 291 | memcpy(priv->current_addr, macadd->macadd, ETH_ALEN); |
876c9d3a | 292 | |
9012b28a | 293 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
294 | return 0; |
295 | } | |
296 | ||
69f9032d | 297 | static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, |
876c9d3a MT |
298 | struct cmd_ds_command *resp) |
299 | { | |
300 | struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; | |
876c9d3a | 301 | |
9012b28a | 302 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 303 | |
aa21c004 | 304 | priv->txpowerlevel = le16_to_cpu(rtp->currentlevel); |
876c9d3a | 305 | |
aa21c004 | 306 | lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel); |
876c9d3a | 307 | |
a6c8700f | 308 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
309 | return 0; |
310 | } | |
311 | ||
69f9032d | 312 | static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv, |
876c9d3a MT |
313 | struct cmd_ds_command *resp) |
314 | { | |
981f187b | 315 | struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset; |
876c9d3a | 316 | |
9012b28a | 317 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 318 | |
0aef64d7 | 319 | if (rates->action == CMD_ACT_GET) { |
aa21c004 DW |
320 | priv->enablehwauto = le16_to_cpu(rates->enablehwauto); |
321 | priv->ratebitmap = le16_to_cpu(rates->bitmap); | |
876c9d3a MT |
322 | } |
323 | ||
a6c8700f | 324 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
325 | return 0; |
326 | } | |
327 | ||
69f9032d | 328 | static int lbs_ret_802_11_data_rate(struct lbs_private *priv, |
876c9d3a MT |
329 | struct cmd_ds_command *resp) |
330 | { | |
331 | struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; | |
876c9d3a | 332 | |
9012b28a | 333 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 334 | |
a6c8700f | 335 | lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate, |
8c512765 | 336 | sizeof(struct cmd_ds_802_11_data_rate)); |
876c9d3a | 337 | |
8c512765 DW |
338 | /* FIXME: get actual rates FW can do if this command actually returns |
339 | * all data rates supported. | |
340 | */ | |
aa21c004 DW |
341 | priv->cur_rate = lbs_fw_index_to_data_rate(pdatarate->rates[0]); |
342 | lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", priv->cur_rate); | |
876c9d3a | 343 | |
8c512765 | 344 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
345 | return 0; |
346 | } | |
347 | ||
69f9032d | 348 | static int lbs_ret_802_11_rf_channel(struct lbs_private *priv, |
876c9d3a MT |
349 | struct cmd_ds_command *resp) |
350 | { | |
981f187b | 351 | struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel; |
876c9d3a MT |
352 | u16 action = le16_to_cpu(rfchannel->action); |
353 | u16 newchannel = le16_to_cpu(rfchannel->currentchannel); | |
354 | ||
9012b28a | 355 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 356 | |
0aef64d7 | 357 | if (action == CMD_OPT_802_11_RF_CHANNEL_GET |
aa21c004 | 358 | && priv->curbssparams.channel != newchannel) { |
a6c8700f | 359 | lbs_deb_cmd("channel switch from %d to %d\n", |
aa21c004 | 360 | priv->curbssparams.channel, newchannel); |
876c9d3a MT |
361 | |
362 | /* Update the channel again */ | |
aa21c004 | 363 | priv->curbssparams.channel = newchannel; |
876c9d3a MT |
364 | } |
365 | ||
9012b28a | 366 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a MT |
367 | return 0; |
368 | } | |
369 | ||
69f9032d | 370 | static int lbs_ret_802_11_rssi(struct lbs_private *priv, |
876c9d3a MT |
371 | struct cmd_ds_command *resp) |
372 | { | |
373 | struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; | |
876c9d3a | 374 | |
a6c8700f HS |
375 | lbs_deb_enter(LBS_DEB_CMD); |
376 | ||
876c9d3a | 377 | /* store the non average value */ |
aa21c004 DW |
378 | priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); |
379 | priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); | |
876c9d3a | 380 | |
aa21c004 DW |
381 | priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); |
382 | priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); | |
876c9d3a | 383 | |
aa21c004 DW |
384 | priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = |
385 | CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], | |
386 | priv->NF[TYPE_BEACON][TYPE_NOAVG]); | |
876c9d3a | 387 | |
aa21c004 DW |
388 | priv->RSSI[TYPE_BEACON][TYPE_AVG] = |
389 | CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, | |
390 | priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); | |
876c9d3a | 391 | |
a6c8700f | 392 | lbs_deb_cmd("RSSI: beacon %d, avg %d\n", |
aa21c004 DW |
393 | priv->RSSI[TYPE_BEACON][TYPE_NOAVG], |
394 | priv->RSSI[TYPE_BEACON][TYPE_AVG]); | |
876c9d3a | 395 | |
a6c8700f | 396 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
397 | return 0; |
398 | } | |
399 | ||
69f9032d | 400 | static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv, |
876c9d3a MT |
401 | struct cmd_ds_command *resp) |
402 | { | |
10078321 | 403 | struct lbs_ioctl_regrdwr *pbuf; |
aa21c004 | 404 | pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom; |
876c9d3a | 405 | |
a6c8700f | 406 | lbs_deb_enter_args(LBS_DEB_CMD, "len %d", |
876c9d3a MT |
407 | le16_to_cpu(resp->params.rdeeprom.bytecount)); |
408 | if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { | |
409 | pbuf->NOB = 0; | |
a6c8700f | 410 | lbs_deb_cmd("EEPROM read length too big\n"); |
876c9d3a MT |
411 | return -1; |
412 | } | |
413 | pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); | |
414 | if (pbuf->NOB > 0) { | |
415 | ||
416 | memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, | |
417 | le16_to_cpu(resp->params.rdeeprom.bytecount)); | |
a6c8700f | 418 | lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value, |
876c9d3a MT |
419 | le16_to_cpu(resp->params.rdeeprom.bytecount)); |
420 | } | |
a6c8700f | 421 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
422 | return 0; |
423 | } | |
424 | ||
69f9032d | 425 | static int lbs_ret_get_log(struct lbs_private *priv, |
876c9d3a MT |
426 | struct cmd_ds_command *resp) |
427 | { | |
981f187b | 428 | struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog; |
876c9d3a | 429 | |
9012b28a | 430 | lbs_deb_enter(LBS_DEB_CMD); |
876c9d3a | 431 | |
981f187b | 432 | /* Stored little-endian */ |
aa21c004 | 433 | memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log)); |
876c9d3a | 434 | |
a6c8700f | 435 | lbs_deb_leave(LBS_DEB_CMD); |
876c9d3a MT |
436 | return 0; |
437 | } | |
438 | ||
69f9032d | 439 | static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv, |
18c96c34 DW |
440 | struct cmd_ds_command *resp) |
441 | { | |
442 | struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn; | |
aa21c004 | 443 | u32 * pdata_buf = priv->cur_cmd->pdata_buf; |
18c96c34 DW |
444 | |
445 | lbs_deb_enter(LBS_DEB_CMD); | |
446 | ||
0aef64d7 | 447 | if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) { |
18c96c34 DW |
448 | if (pdata_buf) |
449 | *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable); | |
450 | } | |
451 | ||
a6c8700f | 452 | lbs_deb_leave(LBS_DEB_CMD); |
18c96c34 DW |
453 | return 0; |
454 | } | |
455 | ||
96287ac4 BD |
456 | static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv, |
457 | struct cmd_ds_command *resp) | |
458 | { | |
459 | struct cmd_ds_802_11_beacon_control *bcn_ctrl = | |
460 | &resp->params.bcn_ctrl; | |
96287ac4 BD |
461 | |
462 | lbs_deb_enter(LBS_DEB_CMD); | |
463 | ||
464 | if (bcn_ctrl->action == CMD_ACT_GET) { | |
aa21c004 DW |
465 | priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable); |
466 | priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period); | |
96287ac4 BD |
467 | } |
468 | ||
469 | lbs_deb_enter(LBS_DEB_CMD); | |
470 | return 0; | |
471 | } | |
472 | ||
3a188649 HS |
473 | static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv, |
474 | struct cmd_ds_command *resp) | |
475 | { | |
3a188649 HS |
476 | struct cmd_ds_802_11_subscribe_event *cmd_event = |
477 | &resp->params.subscribe_event; | |
478 | struct cmd_ds_802_11_subscribe_event *dst_event = | |
aa21c004 | 479 | priv->cur_cmd->pdata_buf; |
3a188649 HS |
480 | |
481 | lbs_deb_enter(LBS_DEB_CMD); | |
482 | ||
483 | if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) { | |
c2df2efe | 484 | dst_event->events = cmd_event->events; |
3a188649 HS |
485 | memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv)); |
486 | } | |
487 | ||
488 | lbs_deb_leave(LBS_DEB_CMD); | |
489 | return 0; | |
490 | } | |
491 | ||
1309b55b DW |
492 | static inline int handle_cmd_response(struct lbs_private *priv, |
493 | unsigned long dummy, | |
494 | struct cmd_ds_command *resp) | |
876c9d3a MT |
495 | { |
496 | int ret = 0; | |
497 | unsigned long flags; | |
1309b55b | 498 | uint16_t respcmd = le16_to_cpu(resp->command); |
876c9d3a | 499 | |
a6c8700f HS |
500 | lbs_deb_enter(LBS_DEB_HOST); |
501 | ||
876c9d3a | 502 | switch (respcmd) { |
6b63cd0f HS |
503 | case CMD_RET(CMD_MAC_REG_ACCESS): |
504 | case CMD_RET(CMD_BBP_REG_ACCESS): | |
505 | case CMD_RET(CMD_RF_REG_ACCESS): | |
10078321 | 506 | ret = lbs_ret_reg_access(priv, respcmd, resp); |
876c9d3a MT |
507 | break; |
508 | ||
6b63cd0f | 509 | case CMD_RET(CMD_802_11_SCAN): |
10078321 | 510 | ret = lbs_ret_80211_scan(priv, resp); |
876c9d3a MT |
511 | break; |
512 | ||
6b63cd0f | 513 | case CMD_RET(CMD_802_11_GET_LOG): |
10078321 | 514 | ret = lbs_ret_get_log(priv, resp); |
876c9d3a MT |
515 | break; |
516 | ||
0aef64d7 | 517 | case CMD_RET_802_11_ASSOCIATE: |
6b63cd0f HS |
518 | case CMD_RET(CMD_802_11_ASSOCIATE): |
519 | case CMD_RET(CMD_802_11_REASSOCIATE): | |
10078321 | 520 | ret = lbs_ret_80211_associate(priv, resp); |
876c9d3a MT |
521 | break; |
522 | ||
6b63cd0f HS |
523 | case CMD_RET(CMD_802_11_DISASSOCIATE): |
524 | case CMD_RET(CMD_802_11_DEAUTHENTICATE): | |
10078321 | 525 | ret = lbs_ret_80211_disassociate(priv, resp); |
876c9d3a MT |
526 | break; |
527 | ||
6b63cd0f HS |
528 | case CMD_RET(CMD_802_11_AD_HOC_START): |
529 | case CMD_RET(CMD_802_11_AD_HOC_JOIN): | |
10078321 | 530 | ret = lbs_ret_80211_ad_hoc_start(priv, resp); |
876c9d3a MT |
531 | break; |
532 | ||
6b63cd0f | 533 | case CMD_RET(CMD_802_11_GET_STAT): |
10078321 | 534 | ret = lbs_ret_802_11_stat(priv, resp); |
876c9d3a MT |
535 | break; |
536 | ||
6b63cd0f | 537 | case CMD_RET(CMD_802_11_SNMP_MIB): |
10078321 | 538 | ret = lbs_ret_802_11_snmp_mib(priv, resp); |
876c9d3a MT |
539 | break; |
540 | ||
6b63cd0f | 541 | case CMD_RET(CMD_802_11_RF_TX_POWER): |
10078321 | 542 | ret = lbs_ret_802_11_rf_tx_power(priv, resp); |
876c9d3a MT |
543 | break; |
544 | ||
6b63cd0f HS |
545 | case CMD_RET(CMD_802_11_SET_AFC): |
546 | case CMD_RET(CMD_802_11_GET_AFC): | |
aa21c004 DW |
547 | spin_lock_irqsave(&priv->driver_lock, flags); |
548 | memmove(priv->cur_cmd->pdata_buf, &resp->params.afc, | |
876c9d3a | 549 | sizeof(struct cmd_ds_802_11_afc)); |
aa21c004 | 550 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a MT |
551 | |
552 | break; | |
876c9d3a | 553 | |
6b63cd0f HS |
554 | case CMD_RET(CMD_MAC_MULTICAST_ADR): |
555 | case CMD_RET(CMD_MAC_CONTROL): | |
556 | case CMD_RET(CMD_802_11_SET_WEP): | |
557 | case CMD_RET(CMD_802_11_RESET): | |
558 | case CMD_RET(CMD_802_11_AUTHENTICATE): | |
559 | case CMD_RET(CMD_802_11_RADIO_CONTROL): | |
560 | case CMD_RET(CMD_802_11_BEACON_STOP): | |
18c96c34 DW |
561 | break; |
562 | ||
6b63cd0f | 563 | case CMD_RET(CMD_802_11_ENABLE_RSN): |
10078321 | 564 | ret = lbs_ret_802_11_enable_rsn(priv, resp); |
876c9d3a MT |
565 | break; |
566 | ||
6b63cd0f | 567 | case CMD_RET(CMD_802_11_DATA_RATE): |
10078321 | 568 | ret = lbs_ret_802_11_data_rate(priv, resp); |
876c9d3a | 569 | break; |
6b63cd0f | 570 | case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): |
10078321 | 571 | ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp); |
876c9d3a | 572 | break; |
6b63cd0f | 573 | case CMD_RET(CMD_802_11_RF_CHANNEL): |
10078321 | 574 | ret = lbs_ret_802_11_rf_channel(priv, resp); |
876c9d3a MT |
575 | break; |
576 | ||
6b63cd0f | 577 | case CMD_RET(CMD_802_11_RSSI): |
10078321 | 578 | ret = lbs_ret_802_11_rssi(priv, resp); |
876c9d3a MT |
579 | break; |
580 | ||
6b63cd0f | 581 | case CMD_RET(CMD_802_11_MAC_ADDRESS): |
10078321 | 582 | ret = lbs_ret_802_11_mac_address(priv, resp); |
876c9d3a MT |
583 | break; |
584 | ||
6b63cd0f | 585 | case CMD_RET(CMD_802_11_AD_HOC_STOP): |
10078321 | 586 | ret = lbs_ret_80211_ad_hoc_stop(priv, resp); |
876c9d3a MT |
587 | break; |
588 | ||
6b63cd0f | 589 | case CMD_RET(CMD_802_11_KEY_MATERIAL): |
10078321 | 590 | ret = lbs_ret_802_11_key_material(priv, resp); |
876c9d3a MT |
591 | break; |
592 | ||
6b63cd0f | 593 | case CMD_RET(CMD_802_11_EEPROM_ACCESS): |
10078321 | 594 | ret = lbs_ret_802_11_eeprom_access(priv, resp); |
876c9d3a MT |
595 | break; |
596 | ||
6b63cd0f | 597 | case CMD_RET(CMD_802_11D_DOMAIN_INFO): |
10078321 | 598 | ret = lbs_ret_802_11d_domain_info(priv, resp); |
876c9d3a MT |
599 | break; |
600 | ||
6b63cd0f | 601 | case CMD_RET(CMD_802_11_SLEEP_PARAMS): |
10078321 | 602 | ret = lbs_ret_802_11_sleep_params(priv, resp); |
876c9d3a | 603 | break; |
6b63cd0f | 604 | case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT): |
aa21c004 DW |
605 | spin_lock_irqsave(&priv->driver_lock, flags); |
606 | *((u16 *) priv->cur_cmd->pdata_buf) = | |
876c9d3a | 607 | le16_to_cpu(resp->params.inactivity_timeout.timeout); |
aa21c004 | 608 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a MT |
609 | break; |
610 | ||
6b63cd0f | 611 | case CMD_RET(CMD_802_11_TPC_CFG): |
aa21c004 DW |
612 | spin_lock_irqsave(&priv->driver_lock, flags); |
613 | memmove(priv->cur_cmd->pdata_buf, &resp->params.tpccfg, | |
876c9d3a | 614 | sizeof(struct cmd_ds_802_11_tpc_cfg)); |
aa21c004 | 615 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a | 616 | break; |
6b63cd0f | 617 | case CMD_RET(CMD_802_11_LED_GPIO_CTRL): |
aa21c004 DW |
618 | spin_lock_irqsave(&priv->driver_lock, flags); |
619 | memmove(priv->cur_cmd->pdata_buf, &resp->params.ledgpio, | |
876c9d3a | 620 | sizeof(struct cmd_ds_802_11_led_ctrl)); |
aa21c004 | 621 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a | 622 | break; |
3a188649 HS |
623 | case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT): |
624 | ret = lbs_ret_802_11_subscribe_event(priv, resp); | |
625 | break; | |
626 | ||
6b63cd0f | 627 | case CMD_RET(CMD_802_11_PWR_CFG): |
aa21c004 DW |
628 | spin_lock_irqsave(&priv->driver_lock, flags); |
629 | memmove(priv->cur_cmd->pdata_buf, &resp->params.pwrcfg, | |
876c9d3a | 630 | sizeof(struct cmd_ds_802_11_pwr_cfg)); |
aa21c004 | 631 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a MT |
632 | |
633 | break; | |
634 | ||
6b63cd0f | 635 | case CMD_RET(CMD_GET_TSF): |
aa21c004 DW |
636 | spin_lock_irqsave(&priv->driver_lock, flags); |
637 | memcpy(priv->cur_cmd->pdata_buf, | |
876c9d3a | 638 | &resp->params.gettsf.tsfvalue, sizeof(u64)); |
aa21c004 | 639 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a | 640 | break; |
6b63cd0f | 641 | case CMD_RET(CMD_BT_ACCESS): |
aa21c004 DW |
642 | spin_lock_irqsave(&priv->driver_lock, flags); |
643 | if (priv->cur_cmd->pdata_buf) | |
644 | memcpy(priv->cur_cmd->pdata_buf, | |
876c9d3a | 645 | &resp->params.bt.addr1, 2 * ETH_ALEN); |
aa21c004 | 646 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a | 647 | break; |
6b63cd0f | 648 | case CMD_RET(CMD_FWT_ACCESS): |
aa21c004 DW |
649 | spin_lock_irqsave(&priv->driver_lock, flags); |
650 | if (priv->cur_cmd->pdata_buf) | |
651 | memcpy(priv->cur_cmd->pdata_buf, &resp->params.fwt, | |
981f187b | 652 | sizeof(resp->params.fwt)); |
aa21c004 | 653 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a | 654 | break; |
6b63cd0f | 655 | case CMD_RET(CMD_MESH_ACCESS): |
aa21c004 DW |
656 | if (priv->cur_cmd->pdata_buf) |
657 | memcpy(priv->cur_cmd->pdata_buf, &resp->params.mesh, | |
876c9d3a MT |
658 | sizeof(resp->params.mesh)); |
659 | break; | |
96287ac4 BD |
660 | case CMD_RET(CMD_802_11_BEACON_CTRL): |
661 | ret = lbs_ret_802_11_bcn_ctrl(priv, resp); | |
662 | break; | |
663 | ||
876c9d3a | 664 | default: |
a6c8700f | 665 | lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", |
981f187b | 666 | resp->command); |
876c9d3a MT |
667 | break; |
668 | } | |
a6c8700f | 669 | lbs_deb_leave(LBS_DEB_HOST); |
876c9d3a MT |
670 | return ret; |
671 | } | |
672 | ||
69f9032d | 673 | int lbs_process_rx_command(struct lbs_private *priv) |
876c9d3a MT |
674 | { |
675 | u16 respcmd; | |
676 | struct cmd_ds_command *resp; | |
876c9d3a MT |
677 | int ret = 0; |
678 | ulong flags; | |
679 | u16 result; | |
680 | ||
a6c8700f | 681 | lbs_deb_enter(LBS_DEB_HOST); |
876c9d3a MT |
682 | |
683 | /* Now we got response from FW, cancel the command timer */ | |
aa21c004 | 684 | del_timer(&priv->command_timer); |
876c9d3a | 685 | |
aa21c004 DW |
686 | mutex_lock(&priv->lock); |
687 | spin_lock_irqsave(&priv->driver_lock, flags); | |
876c9d3a | 688 | |
aa21c004 | 689 | if (!priv->cur_cmd) { |
a6c8700f | 690 | lbs_deb_host("CMD_RESP: cur_cmd is NULL\n"); |
876c9d3a | 691 | ret = -1; |
aa21c004 | 692 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a MT |
693 | goto done; |
694 | } | |
aa21c004 | 695 | resp = (struct cmd_ds_command *)(priv->cur_cmd->bufvirtualaddr); |
876c9d3a | 696 | |
876c9d3a | 697 | respcmd = le16_to_cpu(resp->command); |
876c9d3a MT |
698 | result = le16_to_cpu(resp->result); |
699 | ||
a6c8700f HS |
700 | lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", |
701 | respcmd, priv->upld_len, jiffies); | |
aa21c004 | 702 | lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", priv->cur_cmd->bufvirtualaddr, |
a6c8700f | 703 | priv->upld_len); |
876c9d3a MT |
704 | |
705 | if (!(respcmd & 0x8000)) { | |
a6c8700f | 706 | lbs_deb_host("invalid response!\n"); |
aa21c004 DW |
707 | priv->cur_cmd_retcode = -1; |
708 | __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); | |
709 | priv->cur_cmd = NULL; | |
710 | spin_unlock_irqrestore(&priv->driver_lock, flags); | |
876c9d3a MT |
711 | ret = -1; |
712 | goto done; | |
713 | } | |
714 | ||
715 | /* Store the response code to cur_cmd_retcode. */ | |
aa21c004 | 716 | priv->cur_cmd_retcode = result; |
876c9d3a | 717 | |
6b63cd0f | 718 | if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { |
981f187b DW |
719 | struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; |
720 | u16 action = le16_to_cpu(psmode->action); | |
876c9d3a | 721 | |
a6c8700f HS |
722 | lbs_deb_host( |
723 | "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n", | |
981f187b | 724 | result, action); |
876c9d3a MT |
725 | |
726 | if (result) { | |
a6c8700f | 727 | lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n", |
981f187b DW |
728 | result); |
729 | /* | |
730 | * We should not re-try enter-ps command in | |
731 | * ad-hoc mode. It takes place in | |
10078321 | 732 | * lbs_execute_next_command(). |
981f187b | 733 | */ |
aa21c004 | 734 | if (priv->mode == IW_MODE_ADHOC && |
0aef64d7 | 735 | action == CMD_SUBCMD_ENTER_PS) |
aa21c004 | 736 | priv->psmode = LBS802_11POWERMODECAM; |
0aef64d7 | 737 | } else if (action == CMD_SUBCMD_ENTER_PS) { |
aa21c004 DW |
738 | priv->needtowakeup = 0; |
739 | priv->psstate = PS_STATE_AWAKE; | |
876c9d3a | 740 | |
a6c8700f | 741 | lbs_deb_host("CMD_RESP: ENTER_PS command response\n"); |
aa21c004 | 742 | if (priv->connect_status != LBS_CONNECTED) { |
876c9d3a MT |
743 | /* |
744 | * When Deauth Event received before Enter_PS command | |
745 | * response, We need to wake up the firmware. | |
746 | */ | |
a6c8700f | 747 | lbs_deb_host( |
10078321 | 748 | "disconnected, invoking lbs_ps_wakeup\n"); |
876c9d3a | 749 | |
aa21c004 DW |
750 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
751 | mutex_unlock(&priv->lock); | |
10078321 | 752 | lbs_ps_wakeup(priv, 0); |
aa21c004 DW |
753 | mutex_lock(&priv->lock); |
754 | spin_lock_irqsave(&priv->driver_lock, flags); | |
876c9d3a | 755 | } |
0aef64d7 | 756 | } else if (action == CMD_SUBCMD_EXIT_PS) { |
aa21c004 DW |
757 | priv->needtowakeup = 0; |
758 | priv->psstate = PS_STATE_FULL_POWER; | |
a6c8700f | 759 | lbs_deb_host("CMD_RESP: EXIT_PS command response\n"); |
876c9d3a | 760 | } else { |
a6c8700f | 761 | lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); |
876c9d3a MT |
762 | } |
763 | ||
aa21c004 DW |
764 | __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); |
765 | priv->cur_cmd = NULL; | |
766 | spin_unlock_irqrestore(&priv->driver_lock, flags); | |
876c9d3a MT |
767 | |
768 | ret = 0; | |
769 | goto done; | |
770 | } | |
771 | ||
876c9d3a MT |
772 | /* If the command is not successful, cleanup and return failure */ |
773 | if ((result != 0 || !(respcmd & 0x8000))) { | |
a6c8700f HS |
774 | lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n", |
775 | result, respcmd); | |
876c9d3a MT |
776 | /* |
777 | * Handling errors here | |
778 | */ | |
779 | switch (respcmd) { | |
6b63cd0f HS |
780 | case CMD_RET(CMD_GET_HW_SPEC): |
781 | case CMD_RET(CMD_802_11_RESET): | |
a6c8700f | 782 | lbs_deb_host("CMD_RESP: reset failed\n"); |
876c9d3a MT |
783 | break; |
784 | ||
785 | } | |
786 | ||
aa21c004 DW |
787 | __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); |
788 | priv->cur_cmd = NULL; | |
789 | spin_unlock_irqrestore(&priv->driver_lock, flags); | |
876c9d3a MT |
790 | |
791 | ret = -1; | |
792 | goto done; | |
793 | } | |
794 | ||
aa21c004 | 795 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
1723047d | 796 | |
7ad994de DW |
797 | if (priv->cur_cmd && priv->cur_cmd->callback) { |
798 | ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg, | |
799 | (struct cmd_header *) resp); | |
800 | } else | |
1309b55b | 801 | ret = handle_cmd_response(priv, 0, resp); |
1723047d | 802 | |
aa21c004 | 803 | spin_lock_irqsave(&priv->driver_lock, flags); |
1723047d | 804 | |
aa21c004 | 805 | if (priv->cur_cmd) { |
876c9d3a | 806 | /* Clean up and Put current command back to cmdfreeq */ |
aa21c004 DW |
807 | __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); |
808 | priv->cur_cmd = NULL; | |
876c9d3a | 809 | } |
aa21c004 | 810 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
876c9d3a MT |
811 | |
812 | done: | |
aa21c004 | 813 | mutex_unlock(&priv->lock); |
a6c8700f | 814 | lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); |
876c9d3a MT |
815 | return ret; |
816 | } | |
817 | ||
69f9032d | 818 | int lbs_process_event(struct lbs_private *priv) |
876c9d3a MT |
819 | { |
820 | int ret = 0; | |
876c9d3a MT |
821 | u32 eventcause; |
822 | ||
9556d212 HS |
823 | lbs_deb_enter(LBS_DEB_CMD); |
824 | ||
aa21c004 DW |
825 | spin_lock_irq(&priv->driver_lock); |
826 | eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT; | |
827 | spin_unlock_irq(&priv->driver_lock); | |
876c9d3a | 828 | |
0b3c07ff | 829 | lbs_deb_cmd("event cause %d\n", eventcause); |
876c9d3a | 830 | |
0b3c07ff | 831 | switch (eventcause) { |
876c9d3a | 832 | case MACREG_INT_CODE_LINK_SENSED: |
9012b28a | 833 | lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n"); |
876c9d3a MT |
834 | break; |
835 | ||
836 | case MACREG_INT_CODE_DEAUTHENTICATED: | |
a6c8700f | 837 | lbs_deb_cmd("EVENT: deauthenticated\n"); |
10078321 | 838 | lbs_mac_event_disconnected(priv); |
876c9d3a MT |
839 | break; |
840 | ||
841 | case MACREG_INT_CODE_DISASSOCIATED: | |
a6c8700f | 842 | lbs_deb_cmd("EVENT: disassociated\n"); |
10078321 | 843 | lbs_mac_event_disconnected(priv); |
876c9d3a MT |
844 | break; |
845 | ||
0b3c07ff | 846 | case MACREG_INT_CODE_LINK_LOST_NO_SCAN: |
a6c8700f | 847 | lbs_deb_cmd("EVENT: link lost\n"); |
10078321 | 848 | lbs_mac_event_disconnected(priv); |
876c9d3a MT |
849 | break; |
850 | ||
851 | case MACREG_INT_CODE_PS_SLEEP: | |
a6c8700f | 852 | lbs_deb_cmd("EVENT: sleep\n"); |
876c9d3a MT |
853 | |
854 | /* handle unexpected PS SLEEP event */ | |
aa21c004 | 855 | if (priv->psstate == PS_STATE_FULL_POWER) { |
9012b28a | 856 | lbs_deb_cmd( |
a6c8700f | 857 | "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); |
876c9d3a MT |
858 | break; |
859 | } | |
aa21c004 | 860 | priv->psstate = PS_STATE_PRE_SLEEP; |
876c9d3a | 861 | |
aa21c004 | 862 | lbs_ps_confirm_sleep(priv, (u16) priv->psmode); |
876c9d3a MT |
863 | |
864 | break; | |
865 | ||
866 | case MACREG_INT_CODE_PS_AWAKE: | |
a6c8700f | 867 | lbs_deb_cmd("EVENT: awake\n"); |
876c9d3a MT |
868 | |
869 | /* handle unexpected PS AWAKE event */ | |
aa21c004 | 870 | if (priv->psstate == PS_STATE_FULL_POWER) { |
9012b28a | 871 | lbs_deb_cmd( |
876c9d3a MT |
872 | "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); |
873 | break; | |
874 | } | |
875 | ||
aa21c004 | 876 | priv->psstate = PS_STATE_AWAKE; |
876c9d3a | 877 | |
aa21c004 | 878 | if (priv->needtowakeup) { |
876c9d3a MT |
879 | /* |
880 | * wait for the command processing to finish | |
881 | * before resuming sending | |
aa21c004 | 882 | * priv->needtowakeup will be set to FALSE |
10078321 | 883 | * in lbs_ps_wakeup() |
876c9d3a | 884 | */ |
a6c8700f | 885 | lbs_deb_cmd("waking up ...\n"); |
10078321 | 886 | lbs_ps_wakeup(priv, 0); |
876c9d3a MT |
887 | } |
888 | break; | |
889 | ||
890 | case MACREG_INT_CODE_MIC_ERR_UNICAST: | |
9012b28a | 891 | lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n"); |
876c9d3a MT |
892 | handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); |
893 | break; | |
894 | ||
895 | case MACREG_INT_CODE_MIC_ERR_MULTICAST: | |
9012b28a | 896 | lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); |
876c9d3a MT |
897 | handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); |
898 | break; | |
899 | case MACREG_INT_CODE_MIB_CHANGED: | |
900 | case MACREG_INT_CODE_INIT_DONE: | |
901 | break; | |
902 | ||
903 | case MACREG_INT_CODE_ADHOC_BCN_LOST: | |
a6c8700f | 904 | lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); |
876c9d3a MT |
905 | break; |
906 | ||
907 | case MACREG_INT_CODE_RSSI_LOW: | |
a6c8700f | 908 | lbs_pr_alert("EVENT: rssi low\n"); |
876c9d3a MT |
909 | break; |
910 | case MACREG_INT_CODE_SNR_LOW: | |
a6c8700f | 911 | lbs_pr_alert("EVENT: snr low\n"); |
876c9d3a MT |
912 | break; |
913 | case MACREG_INT_CODE_MAX_FAIL: | |
a6c8700f | 914 | lbs_pr_alert("EVENT: max fail\n"); |
876c9d3a MT |
915 | break; |
916 | case MACREG_INT_CODE_RSSI_HIGH: | |
a6c8700f | 917 | lbs_pr_alert("EVENT: rssi high\n"); |
876c9d3a MT |
918 | break; |
919 | case MACREG_INT_CODE_SNR_HIGH: | |
a6c8700f | 920 | lbs_pr_alert("EVENT: snr high\n"); |
876c9d3a MT |
921 | break; |
922 | ||
7d8d28b3 | 923 | case MACREG_INT_CODE_MESH_AUTO_STARTED: |
5612c014 DW |
924 | /* Ignore spurious autostart events if autostart is disabled */ |
925 | if (!priv->mesh_autostart_enabled) { | |
926 | lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); | |
927 | break; | |
928 | } | |
9cdc6d29 | 929 | lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); |
aa21c004 | 930 | priv->mesh_connect_status = LBS_CONNECTED; |
7d8d28b3 | 931 | if (priv->mesh_open == 1) { |
9cdc6d29 LCC |
932 | netif_wake_queue(priv->mesh_dev); |
933 | netif_carrier_on(priv->mesh_dev); | |
7d8d28b3 | 934 | } |
aa21c004 | 935 | priv->mode = IW_MODE_ADHOC; |
b8bedefd | 936 | schedule_work(&priv->sync_channel); |
7d8d28b3 LCCR |
937 | break; |
938 | ||
876c9d3a | 939 | default: |
0b3c07ff | 940 | lbs_pr_alert("EVENT: unknown event id %d\n", eventcause); |
876c9d3a MT |
941 | break; |
942 | } | |
943 | ||
aa21c004 DW |
944 | spin_lock_irq(&priv->driver_lock); |
945 | priv->eventcause = 0; | |
946 | spin_unlock_irq(&priv->driver_lock); | |
9012b28a | 947 | |
9556d212 | 948 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); |
876c9d3a MT |
949 | return ret; |
950 | } |