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