blob: ea123c9d30c3a8b446f19d380c6ccaf9522d86d9 [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/ip.h>
18#include "core.h"
19#include "debug.h"
20
21static int ath6kl_wmi_sync_point(struct wmi *wmi);
22
23static const s32 wmi_rate_tbl[][2] = {
24 /* {W/O SGI, with SGI} */
25 {1000, 1000},
26 {2000, 2000},
27 {5500, 5500},
28 {11000, 11000},
29 {6000, 6000},
30 {9000, 9000},
31 {12000, 12000},
32 {18000, 18000},
33 {24000, 24000},
34 {36000, 36000},
35 {48000, 48000},
36 {54000, 54000},
37 {6500, 7200},
38 {13000, 14400},
39 {19500, 21700},
40 {26000, 28900},
41 {39000, 43300},
42 {52000, 57800},
43 {58500, 65000},
44 {65000, 72200},
45 {13500, 15000},
46 {27000, 30000},
47 {40500, 45000},
48 {54000, 60000},
49 {81000, 90000},
50 {108000, 120000},
51 {121500, 135000},
52 {135000, 150000},
53 {0, 0}
54};
55
56/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
57static const u8 up_to_ac[] = {
58 WMM_AC_BE,
59 WMM_AC_BK,
60 WMM_AC_BK,
61 WMM_AC_BE,
62 WMM_AC_VI,
63 WMM_AC_VI,
64 WMM_AC_VO,
65 WMM_AC_VO,
66};
67
68void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id)
69{
70 if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX))
71 return;
72
73 wmi->ep_id = ep_id;
74}
75
76enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)
77{
78 return wmi->ep_id;
79}
80
81/* Performs DIX to 802.3 encapsulation for transmit packets.
82 * Assumes the entire DIX header is contigous and that there is
83 * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
84 */
85int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
86{
87 struct ath6kl_llc_snap_hdr *llc_hdr;
88 struct ethhdr *eth_hdr;
89 size_t new_len;
90 __be16 type;
91 u8 *datap;
92 u16 size;
93
94 if (WARN_ON(skb == NULL))
95 return -EINVAL;
96
97 size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr);
98 if (skb_headroom(skb) < size)
99 return -ENOMEM;
100
101 eth_hdr = (struct ethhdr *) skb->data;
102 type = eth_hdr->h_proto;
103
104 if (!is_ethertype(be16_to_cpu(type))) {
105 ath6kl_dbg(ATH6KL_DBG_WMI,
106 "%s: pkt is already in 802.3 format\n", __func__);
107 return 0;
108 }
109
110 new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr);
111
112 skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr));
113 datap = skb->data;
114
115 eth_hdr->h_proto = cpu_to_be16(new_len);
116
117 memcpy(datap, eth_hdr, sizeof(*eth_hdr));
118
119 llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr));
120 llc_hdr->dsap = 0xAA;
121 llc_hdr->ssap = 0xAA;
122 llc_hdr->cntl = 0x03;
123 llc_hdr->org_code[0] = 0x0;
124 llc_hdr->org_code[1] = 0x0;
125 llc_hdr->org_code[2] = 0x0;
126 llc_hdr->eth_type = type;
127
128 return 0;
129}
130
131static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
132 u8 *version, void *tx_meta_info)
133{
134 struct wmi_tx_meta_v1 *v1;
135 struct wmi_tx_meta_v2 *v2;
136
137 if (WARN_ON(skb == NULL || version == NULL))
138 return -EINVAL;
139
140 switch (*version) {
141 case WMI_META_VERSION_1:
142 skb_push(skb, WMI_MAX_TX_META_SZ);
143 v1 = (struct wmi_tx_meta_v1 *) skb->data;
144 v1->pkt_id = 0;
145 v1->rate_plcy_id = 0;
146 *version = WMI_META_VERSION_1;
147 break;
148 case WMI_META_VERSION_2:
149 skb_push(skb, WMI_MAX_TX_META_SZ);
150 v2 = (struct wmi_tx_meta_v2 *) skb->data;
151 memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info,
152 sizeof(struct wmi_tx_meta_v2));
153 break;
154 }
155
156 return 0;
157}
158
159int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
160 u8 msg_type, bool more_data,
161 enum wmi_data_hdr_data_type data_type,
162 u8 meta_ver, void *tx_meta_info)
163{
164 struct wmi_data_hdr *data_hdr;
165 int ret;
166
167 if (WARN_ON(skb == NULL))
168 return -EINVAL;
169
170 ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info);
171 if (ret)
172 return ret;
173
174 skb_push(skb, sizeof(struct wmi_data_hdr));
175
176 data_hdr = (struct wmi_data_hdr *)skb->data;
177 memset(data_hdr, 0, sizeof(struct wmi_data_hdr));
178
179 data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
180 data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
181
182 if (more_data)
183 data_hdr->info |=
184 WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT;
185
186 data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
187 data_hdr->info3 = 0;
188
189 return 0;
190}
191
192static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
193{
194 struct iphdr *ip_hdr = (struct iphdr *) pkt;
195 u8 ip_pri;
196
197 /*
198 * Determine IPTOS priority
199 *
200 * IP-TOS - 8bits
201 * : DSCP(6-bits) ECN(2-bits)
202 * : DSCP - P2 P1 P0 X X X
203 * where (P2 P1 P0) form 802.1D
204 */
205 ip_pri = ip_hdr->tos >> 5;
206 ip_pri &= 0x7;
207
208 if ((layer2_pri & 0x7) > ip_pri)
209 return (u8) layer2_pri & 0x7;
210 else
211 return ip_pri;
212}
213
214int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb,
215 u32 layer2_priority, bool wmm_enabled,
216 u8 *ac)
217{
218 struct wmi_data_hdr *data_hdr;
219 struct ath6kl_llc_snap_hdr *llc_hdr;
220 struct wmi_create_pstream_cmd cmd;
221 u32 meta_size, hdr_size;
222 u16 ip_type = IP_ETHERTYPE;
223 u8 stream_exist, usr_pri;
224 u8 traffic_class = WMM_AC_BE;
225 u8 *datap;
226
227 if (WARN_ON(skb == NULL))
228 return -EINVAL;
229
230 datap = skb->data;
231 data_hdr = (struct wmi_data_hdr *) datap;
232
233 meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
234 WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0;
235
236 if (!wmm_enabled) {
237 /* If WMM is disabled all traffic goes as BE traffic */
238 usr_pri = 0;
239 } else {
240 hdr_size = sizeof(struct ethhdr);
241
242 llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap +
243 sizeof(struct
244 wmi_data_hdr) +
245 meta_size + hdr_size);
246
247 if (llc_hdr->eth_type == htons(ip_type)) {
248 /*
249 * Extract the endpoint info from the TOS field
250 * in the IP header.
251 */
252 usr_pri =
253 ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +
254 sizeof(struct ath6kl_llc_snap_hdr),
255 layer2_priority);
256 } else
257 usr_pri = layer2_priority & 0x7;
258 }
259
260 /* workaround for WMM S5 */
261 if ((wmi->traffic_class == WMM_AC_VI) &&
262 ((usr_pri == 5) || (usr_pri == 4)))
263 usr_pri = 1;
264
265 /* Convert user priority to traffic class */
266 traffic_class = up_to_ac[usr_pri & 0x7];
267
268 wmi_data_hdr_set_up(data_hdr, usr_pri);
269
270 spin_lock_bh(&wmi->lock);
271 stream_exist = wmi->fat_pipe_exist;
272 spin_unlock_bh(&wmi->lock);
273
274 if (!(stream_exist & (1 << traffic_class))) {
275 memset(&cmd, 0, sizeof(cmd));
276 cmd.traffic_class = traffic_class;
277 cmd.user_pri = usr_pri;
278 cmd.inactivity_int =
279 cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT);
280 /* Implicit streams are created with TSID 0xFF */
281 cmd.tsid = WMI_IMPLICIT_PSTREAM;
282 ath6kl_wmi_create_pstream_cmd(wmi, &cmd);
283 }
284
285 *ac = traffic_class;
286
287 return 0;
288}
289
290int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
291{
292 struct ieee80211_hdr_3addr *pwh, wh;
293 struct ath6kl_llc_snap_hdr *llc_hdr;
294 struct ethhdr eth_hdr;
295 u32 hdr_size;
296 u8 *datap;
297 __le16 sub_type;
298
299 if (WARN_ON(skb == NULL))
300 return -EINVAL;
301
302 datap = skb->data;
303 pwh = (struct ieee80211_hdr_3addr *) datap;
304
305 sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
306
307 memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr));
308
309 /* Strip off the 802.11 header */
310 if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
311 hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),
312 sizeof(u32));
313 skb_pull(skb, hdr_size);
314 } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA))
315 skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));
316
317 datap = skb->data;
318 llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);
319
Raja Manic8790cba2011-07-19 19:27:32 +0530320 memset(&eth_hdr, 0, sizeof(eth_hdr));
Kalle Valobdcd8172011-07-18 00:22:30 +0300321 eth_hdr.h_proto = llc_hdr->eth_type;
Kalle Valobdcd8172011-07-18 00:22:30 +0300322
323 switch ((le16_to_cpu(wh.frame_control)) &
324 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
325 case 0:
326 memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
327 memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
328 break;
329 case IEEE80211_FCTL_TODS:
330 memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN);
331 memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
332 break;
333 case IEEE80211_FCTL_FROMDS:
334 memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
335 memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN);
336 break;
337 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
338 break;
339 }
340
341 skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
342 skb_push(skb, sizeof(eth_hdr));
343
344 datap = skb->data;
345
346 memcpy(datap, &eth_hdr, sizeof(eth_hdr));
347
348 return 0;
349}
350
351/*
352 * Performs 802.3 to DIX encapsulation for received packets.
353 * Assumes the entire 802.3 header is contigous.
354 */
355int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)
356{
357 struct ath6kl_llc_snap_hdr *llc_hdr;
358 struct ethhdr eth_hdr;
359 u8 *datap;
360
361 if (WARN_ON(skb == NULL))
362 return -EINVAL;
363
364 datap = skb->data;
365
366 memcpy(&eth_hdr, datap, sizeof(eth_hdr));
367
368 llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr));
369 eth_hdr.h_proto = llc_hdr->eth_type;
370
371 skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
372 datap = skb->data;
373
374 memcpy(datap, &eth_hdr, sizeof(eth_hdr));
375
376 return 0;
377}
378
379int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
380{
381 if (WARN_ON(skb == NULL))
382 return -EINVAL;
383
384 skb_pull(skb, sizeof(struct wmi_data_hdr));
385
386 return 0;
387}
388
389void ath6kl_wmi_iterate_nodes(struct wmi *wmi,
390 void (*f) (void *arg, struct bss *),
391 void *arg)
392{
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +0530393 wlan_iterate_nodes(&wmi->parent_dev->scan_table, f, arg);
Kalle Valobdcd8172011-07-18 00:22:30 +0300394}
395
396static void ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(struct sk_buff *skb,
397 u8 *datap)
398{
399 struct wmi_bss_info_hdr2 bih2;
400 struct wmi_bss_info_hdr *bih;
401
402 memcpy(&bih2, datap, sizeof(struct wmi_bss_info_hdr2));
403
404 skb_push(skb, 4);
405 bih = (struct wmi_bss_info_hdr *) skb->data;
406
407 bih->ch = bih2.ch;
408 bih->frame_type = bih2.frame_type;
409 bih->snr = bih2.snr;
410 bih->rssi = a_cpu_to_sle16(bih2.snr - 95);
411 bih->ie_mask = cpu_to_le32(le16_to_cpu(bih2.ie_mask));
412 memcpy(bih->bssid, bih2.bssid, ETH_ALEN);
413}
414
415static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
416{
417 struct tx_complete_msg_v1 *msg_v1;
418 struct wmi_tx_complete_event *evt;
419 int index;
420 u16 size;
421
422 evt = (struct wmi_tx_complete_event *) datap;
423
424 ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
425 evt->num_msg, evt->msg_len, evt->msg_type);
426
427 if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI))
428 return 0;
429
430 for (index = 0; index < evt->num_msg; index++) {
431 size = sizeof(struct wmi_tx_complete_event) +
432 (index * sizeof(struct tx_complete_msg_v1));
433 msg_v1 = (struct tx_complete_msg_v1 *)(datap + size);
434
435 ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n",
436 msg_v1->status, msg_v1->pkt_id,
437 msg_v1->rate_idx, msg_v1->ack_failures);
438 }
439
440 return 0;
441}
442
443static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
444{
445 struct sk_buff *skb;
446
447 skb = ath6kl_buf_alloc(size);
448 if (!skb)
449 return NULL;
450
451 skb_put(skb, size);
452 if (size)
453 memset(skb->data, 0, size);
454
455 return skb;
456}
457
458/* Send a "simple" wmi command -- one with no arguments */
459static int ath6kl_wmi_simple_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id)
460{
461 struct sk_buff *skb;
462 int ret;
463
464 skb = ath6kl_wmi_get_new_buf(0);
465 if (!skb)
466 return -ENOMEM;
467
468 ret = ath6kl_wmi_cmd_send(wmi, skb, cmd_id, NO_SYNC_WMIFLAG);
469
470 return ret;
471}
472
473static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
474{
475 struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap;
476
477 if (len < sizeof(struct wmi_ready_event_2))
478 return -EINVAL;
479
480 wmi->ready = true;
481 ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
482 le32_to_cpu(ev->sw_version),
483 le32_to_cpu(ev->abi_version));
484
485 return 0;
486}
487
488static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len)
489{
490 struct wmi_connect_event *ev;
491 u8 *pie, *peie;
492
493 if (len < sizeof(struct wmi_connect_event))
494 return -EINVAL;
495
496 ev = (struct wmi_connect_event *) datap;
497
498 ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM\n",
499 __func__, ev->ch, ev->bssid);
500
501 memcpy(wmi->bssid, ev->bssid, ETH_ALEN);
502
503 /* Start of assoc rsp IEs */
504 pie = ev->assoc_info + ev->beacon_ie_len +
505 ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */
506
507 /* End of assoc rsp IEs */
508 peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len +
509 ev->assoc_resp_len;
510
511 while (pie < peie) {
512 switch (*pie) {
513 case WLAN_EID_VENDOR_SPECIFIC:
514 if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
515 pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
516 /* WMM OUT (00:50:F2) */
517 if (pie[1] > 5
518 && pie[6] == WMM_PARAM_OUI_SUBTYPE)
519 wmi->is_wmm_enabled = true;
520 }
521 break;
522 }
523
524 if (wmi->is_wmm_enabled)
525 break;
526
527 pie += pie[1] + 2;
528 }
529
530 ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->ch), ev->bssid,
531 le16_to_cpu(ev->listen_intvl),
532 le16_to_cpu(ev->beacon_intvl),
533 le32_to_cpu(ev->nw_type),
534 ev->beacon_ie_len, ev->assoc_req_len,
535 ev->assoc_resp_len, ev->assoc_info);
536
537 return 0;
538}
539
540static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len)
541{
542 struct wmi_disconnect_event *ev;
543 wmi->traffic_class = 100;
544
545 if (len < sizeof(struct wmi_disconnect_event))
546 return -EINVAL;
547
548 ev = (struct wmi_disconnect_event *) datap;
549 memset(wmi->bssid, 0, sizeof(wmi->bssid));
550
551 wmi->is_wmm_enabled = false;
552 wmi->pair_crypto_type = NONE_CRYPT;
553 wmi->grp_crypto_type = NONE_CRYPT;
554
555 ath6kl_disconnect_event(wmi->parent_dev, ev->disconn_reason,
556 ev->bssid, ev->assoc_resp_len, ev->assoc_info,
557 le16_to_cpu(ev->proto_reason_status));
558
559 return 0;
560}
561
562static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)
563{
564 struct wmi_peer_node_event *ev;
565
566 if (len < sizeof(struct wmi_peer_node_event))
567 return -EINVAL;
568
569 ev = (struct wmi_peer_node_event *) datap;
570
571 if (ev->event_code == PEER_NODE_JOIN_EVENT)
572 ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n",
573 ev->peer_mac_addr);
574 else if (ev->event_code == PEER_NODE_LEAVE_EVENT)
575 ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n",
576 ev->peer_mac_addr);
577
578 return 0;
579}
580
581static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len)
582{
583 struct wmi_tkip_micerr_event *ev;
584
585 if (len < sizeof(struct wmi_tkip_micerr_event))
586 return -EINVAL;
587
588 ev = (struct wmi_tkip_micerr_event *) datap;
589
590 ath6kl_tkip_micerr_event(wmi->parent_dev, ev->key_id, ev->is_mcast);
591
592 return 0;
593}
594
595static int ath6kl_wlan_parse_beacon(u8 *buf, int frame_len,
596 struct ath6kl_common_ie *cie)
597{
598 u8 *frm, *efrm;
599 u8 elemid_ssid = false;
600
601 frm = buf;
602 efrm = (u8 *) (frm + frame_len);
603
604 /*
605 * beacon/probe response frame format
606 * [8] time stamp
607 * [2] beacon interval
608 * [2] capability information
609 * [tlv] ssid
610 * [tlv] supported rates
611 * [tlv] country information
612 * [tlv] parameter set (FH/DS)
613 * [tlv] erp information
614 * [tlv] extended supported rates
615 * [tlv] WMM
616 * [tlv] WPA or RSN
617 * [tlv] Atheros Advanced Capabilities
618 */
619 if ((efrm - frm) < 12)
620 return -EINVAL;
621
622 memset(cie, 0, sizeof(*cie));
623
624 cie->ie_tstamp = frm;
625 frm += 8;
626 cie->ie_beaconInt = *(u16 *) frm;
627 frm += 2;
628 cie->ie_capInfo = *(u16 *) frm;
629 frm += 2;
630 cie->ie_chan = 0;
631
632 while (frm < efrm) {
633 switch (*frm) {
634 case WLAN_EID_SSID:
635 if (!elemid_ssid) {
636 cie->ie_ssid = frm;
637 elemid_ssid = true;
638 }
639 break;
640 case WLAN_EID_SUPP_RATES:
641 cie->ie_rates = frm;
642 break;
643 case WLAN_EID_COUNTRY:
644 cie->ie_country = frm;
645 break;
646 case WLAN_EID_FH_PARAMS:
647 break;
648 case WLAN_EID_DS_PARAMS:
649 cie->ie_chan = frm[2];
650 break;
651 case WLAN_EID_TIM:
652 cie->ie_tim = frm;
653 break;
654 case WLAN_EID_IBSS_PARAMS:
655 break;
656 case WLAN_EID_EXT_SUPP_RATES:
657 cie->ie_xrates = frm;
658 break;
659 case WLAN_EID_ERP_INFO:
660 if (frm[1] != 1)
661 return -EINVAL;
662
663 cie->ie_erp = frm[2];
664 break;
665 case WLAN_EID_RSN:
666 cie->ie_rsn = frm;
667 break;
668 case WLAN_EID_HT_CAPABILITY:
669 cie->ie_htcap = frm;
670 break;
671 case WLAN_EID_HT_INFORMATION:
672 cie->ie_htop = frm;
673 break;
674 case WLAN_EID_VENDOR_SPECIFIC:
675 if (frm[1] > 3 && frm[2] == 0x00 && frm[3] == 0x50 &&
676 frm[4] == 0xf2) {
677 /* OUT Type (00:50:F2) */
678
679 if (frm[5] == WPA_OUI_TYPE) {
680 /* WPA OUT */
681 cie->ie_wpa = frm;
682 } else if (frm[5] == WMM_OUI_TYPE) {
683 /* WMM OUT */
684 cie->ie_wmm = frm;
685 } else if (frm[5] == WSC_OUT_TYPE) {
686 /* WSC OUT */
687 cie->ie_wsc = frm;
688 }
689
690 } else if (frm[1] > 3 && frm[2] == 0x00
691 && frm[3] == 0x03 && frm[4] == 0x7f
692 && frm[5] == ATH_OUI_TYPE) {
693 /* Atheros OUI (00:03:7f) */
694 cie->ie_ath = frm;
695 }
696 break;
697 default:
698 break;
699 }
700 frm += frm[1] + 2;
701 }
702
703 if ((cie->ie_rates == NULL)
704 || (cie->ie_rates[1] > ATH6KL_RATE_MAXSIZE))
705 return -EINVAL;
706
707 if ((cie->ie_ssid == NULL)
708 || (cie->ie_ssid[1] > IEEE80211_MAX_SSID_LEN))
709 return -EINVAL;
710
711 return 0;
712}
713
714static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
715{
716 struct bss *bss = NULL;
717 struct wmi_bss_info_hdr *bih;
718 u8 cached_ssid_len = 0;
719 u8 cached_ssid[IEEE80211_MAX_SSID_LEN] = { 0 };
720 u8 beacon_ssid_len = 0;
721 u8 *buf, *ie_ssid;
722 u8 *ni_buf;
723 int buf_len;
724
725 int ret;
726
727 if (len <= sizeof(struct wmi_bss_info_hdr))
728 return -EINVAL;
729
730 bih = (struct wmi_bss_info_hdr *) datap;
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +0530731 bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid);
Kalle Valobdcd8172011-07-18 00:22:30 +0300732
733 if (a_sle16_to_cpu(bih->rssi) > 0) {
734 if (bss == NULL)
735 return 0;
736 else
737 bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
738 }
739
740 buf = datap + sizeof(struct wmi_bss_info_hdr);
741 len -= sizeof(struct wmi_bss_info_hdr);
742
743 ath6kl_dbg(ATH6KL_DBG_WMI,
744 "bss info evt - ch %u, rssi %02x, bssid \"%pM\"\n",
745 bih->ch, a_sle16_to_cpu(bih->rssi), bih->bssid);
746
747 if (bss != NULL) {
748 /*
749 * Free up the node. We are about to allocate a new node.
750 * In case of hidden AP, beacon will not have ssid,
751 * but a directed probe response will have it,
752 * so cache the probe-resp-ssid if already present.
753 */
754 if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE)) {
755 ie_ssid = bss->ni_cie.ie_ssid;
756 if (ie_ssid && (ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
757 (ie_ssid[2] != 0)) {
758 cached_ssid_len = ie_ssid[1];
759 memcpy(cached_ssid, ie_ssid + 2,
760 cached_ssid_len);
761 }
762 }
763
764 /*
765 * Use the current average rssi of associated AP base on
766 * assumption
767 * 1. Most os with GUI will update RSSI by
768 * ath6kl_wmi_get_stats_cmd() periodically.
769 * 2. ath6kl_wmi_get_stats_cmd(..) will be called when calling
770 * ath6kl_wmi_startscan_cmd(...)
771 * The average value of RSSI give end-user better feeling for
772 * instance value of scan result. It also sync up RSSI info
773 * in GUI between scan result and RSSI signal icon.
774 */
775 if (memcmp(wmi->bssid, bih->bssid, ETH_ALEN) == 0) {
776 bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
777 bih->snr = bss->ni_snr;
778 }
779
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +0530780 wlan_node_reclaim(&wmi->parent_dev->scan_table, bss);
Kalle Valobdcd8172011-07-18 00:22:30 +0300781 }
782
783 /*
784 * beacon/probe response frame format
785 * [8] time stamp
786 * [2] beacon interval
787 * [2] capability information
788 * [tlv] ssid
789 */
790 beacon_ssid_len = buf[SSID_IE_LEN_INDEX];
791
792 /*
793 * If ssid is cached for this hidden AP, then change
794 * buffer len accordingly.
795 */
796 if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) &&
797 (cached_ssid_len != 0) &&
798 (beacon_ssid_len == 0 || (cached_ssid_len > beacon_ssid_len &&
799 buf[SSID_IE_LEN_INDEX + 1] == 0))) {
800
801 len += (cached_ssid_len - beacon_ssid_len);
802 }
803
804 bss = wlan_node_alloc(len);
805 if (!bss)
806 return -ENOMEM;
807
808 bss->ni_snr = bih->snr;
809 bss->ni_rssi = a_sle16_to_cpu(bih->rssi);
810
811 if (WARN_ON(!bss->ni_buf))
812 return -EINVAL;
813
814 /*
815 * In case of hidden AP, beacon will not have ssid,
816 * but a directed probe response will have it,
817 * so place the cached-ssid(probe-resp) in the bss info.
818 */
819 if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) &&
820 (cached_ssid_len != 0) &&
821 (beacon_ssid_len == 0 || (beacon_ssid_len &&
822 buf[SSID_IE_LEN_INDEX + 1] == 0))) {
823 ni_buf = bss->ni_buf;
824 buf_len = len;
825
826 /*
827 * Copy the first 14 bytes:
828 * time-stamp(8), beacon-interval(2),
829 * cap-info(2), ssid-id(1), ssid-len(1).
830 */
831 memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1);
832
833 ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len;
834 ni_buf += (SSID_IE_LEN_INDEX + 1);
835
836 buf += (SSID_IE_LEN_INDEX + 1);
837 buf_len -= (SSID_IE_LEN_INDEX + 1);
838
839 memcpy(ni_buf, cached_ssid, cached_ssid_len);
840 ni_buf += cached_ssid_len;
841
842 buf += beacon_ssid_len;
843 buf_len -= beacon_ssid_len;
844
845 if (cached_ssid_len > beacon_ssid_len)
846 buf_len -= (cached_ssid_len - beacon_ssid_len);
847
848 memcpy(ni_buf, buf, buf_len);
849 } else
850 memcpy(bss->ni_buf, buf, len);
851
852 bss->ni_framelen = len;
853
854 ret = ath6kl_wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie);
855 if (ret) {
856 wlan_node_free(bss);
857 return -EINVAL;
858 }
859
860 /*
861 * Update the frequency in ie_chan, overwriting of channel number
862 * which is done in ath6kl_wlan_parse_beacon
863 */
864 bss->ni_cie.ie_chan = le16_to_cpu(bih->ch);
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +0530865 wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid);
Kalle Valobdcd8172011-07-18 00:22:30 +0300866
867 return 0;
868}
869
870static int ath6kl_wmi_opt_frame_event_rx(struct wmi *wmi, u8 *datap, int len)
871{
872 struct bss *bss;
873 struct wmi_opt_rx_info_hdr *bih;
874 u8 *buf;
875
876 if (len <= sizeof(struct wmi_opt_rx_info_hdr))
877 return -EINVAL;
878
879 bih = (struct wmi_opt_rx_info_hdr *) datap;
880 buf = datap + sizeof(struct wmi_opt_rx_info_hdr);
881 len -= sizeof(struct wmi_opt_rx_info_hdr);
882
883 ath6kl_dbg(ATH6KL_DBG_WMI, "opt frame event %2.2x:%2.2x\n",
884 bih->bssid[4], bih->bssid[5]);
885
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +0530886 bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid);
Kalle Valobdcd8172011-07-18 00:22:30 +0300887 if (bss != NULL) {
888 /* Free up the node. We are about to allocate a new node. */
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +0530889 wlan_node_reclaim(&wmi->parent_dev->scan_table, bss);
Kalle Valobdcd8172011-07-18 00:22:30 +0300890 }
891
892 bss = wlan_node_alloc(len);
893 if (!bss)
894 return -ENOMEM;
895
896 bss->ni_snr = bih->snr;
897 bss->ni_cie.ie_chan = le16_to_cpu(bih->ch);
898
899 if (WARN_ON(!bss->ni_buf))
900 return -EINVAL;
901
902 memcpy(bss->ni_buf, buf, len);
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +0530903 wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid);
Kalle Valobdcd8172011-07-18 00:22:30 +0300904
905 return 0;
906}
907
908/* Inactivity timeout of a fatpipe(pstream) at the target */
909static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
910 int len)
911{
912 struct wmi_pstream_timeout_event *ev;
913
914 if (len < sizeof(struct wmi_pstream_timeout_event))
915 return -EINVAL;
916
917 ev = (struct wmi_pstream_timeout_event *) datap;
918
919 /*
920 * When the pstream (fat pipe == AC) timesout, it means there were
921 * no thinStreams within this pstream & it got implicitly created
922 * due to data flow on this AC. We start the inactivity timer only
923 * for implicitly created pstream. Just reset the host state.
924 */
925 spin_lock_bh(&wmi->lock);
926 wmi->stream_exist_for_ac[ev->traffic_class] = 0;
927 wmi->fat_pipe_exist &= ~(1 << ev->traffic_class);
928 spin_unlock_bh(&wmi->lock);
929
930 /* Indicate inactivity to driver layer for this fatpipe (pstream) */
931 ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false);
932
933 return 0;
934}
935
936static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
937{
938 struct wmi_bit_rate_reply *reply;
939 s32 rate;
940 u32 sgi, index;
941
942 if (len < sizeof(struct wmi_bit_rate_reply))
943 return -EINVAL;
944
945 reply = (struct wmi_bit_rate_reply *) datap;
946
947 ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index);
948
949 if (reply->rate_index == (s8) RATE_AUTO) {
950 rate = RATE_AUTO;
951 } else {
952 index = reply->rate_index & 0x7f;
953 sgi = (reply->rate_index & 0x80) ? 1 : 0;
954 rate = wmi_rate_tbl[index][sgi];
955 }
956
957 ath6kl_wakeup_event(wmi->parent_dev);
958
959 return 0;
960}
961
962static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len)
963{
964 if (len < sizeof(struct wmi_fix_rates_reply))
965 return -EINVAL;
966
967 ath6kl_wakeup_event(wmi->parent_dev);
968
969 return 0;
970}
971
972static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len)
973{
974 if (len < sizeof(struct wmi_channel_list_reply))
975 return -EINVAL;
976
977 ath6kl_wakeup_event(wmi->parent_dev);
978
979 return 0;
980}
981
982static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len)
983{
984 struct wmi_tx_pwr_reply *reply;
985
986 if (len < sizeof(struct wmi_tx_pwr_reply))
987 return -EINVAL;
988
989 reply = (struct wmi_tx_pwr_reply *) datap;
990 ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM);
991
992 return 0;
993}
994
995static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)
996{
997 if (len < sizeof(struct wmi_get_keepalive_cmd))
998 return -EINVAL;
999
1000 ath6kl_wakeup_event(wmi->parent_dev);
1001
1002 return 0;
1003}
1004
1005static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len)
1006{
1007 struct wmi_scan_complete_event *ev;
1008
1009 ev = (struct wmi_scan_complete_event *) datap;
1010
1011 if (a_sle32_to_cpu(ev->status) == 0)
Vasanthakumar Thiagarajane4c7ffc2011-07-21 13:49:32 +05301012 wlan_refresh_inactive_nodes(wmi->parent_dev);
Kalle Valobdcd8172011-07-18 00:22:30 +03001013
1014 ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status));
1015 wmi->is_probe_ssid = false;
1016
1017 return 0;
1018}
1019
1020/*
1021 * Target is reporting a programming error. This is for
1022 * developer aid only. Target only checks a few common violations
1023 * and it is responsibility of host to do all error checking.
1024 * Behavior of target after wmi error event is undefined.
1025 * A reset is recommended.
1026 */
1027static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)
1028{
1029 const char *type = "unknown error";
1030 struct wmi_cmd_error_event *ev;
1031 ev = (struct wmi_cmd_error_event *) datap;
1032
1033 switch (ev->err_code) {
1034 case INVALID_PARAM:
1035 type = "invalid parameter";
1036 break;
1037 case ILLEGAL_STATE:
1038 type = "invalid state";
1039 break;
1040 case INTERNAL_ERROR:
1041 type = "internal error";
1042 break;
1043 }
1044
1045 ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n",
1046 ev->cmd_id, type);
1047
1048 return 0;
1049}
1050
1051static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len)
1052{
1053 ath6kl_tgt_stats_event(wmi->parent_dev, datap, len);
1054
1055 return 0;
1056}
1057
1058static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,
1059 struct sq_threshold_params *sq_thresh,
1060 u32 size)
1061{
1062 u32 index;
1063 u8 threshold = (u8) sq_thresh->upper_threshold[size - 1];
1064
1065 /* The list is already in sorted order. Get the next lower value */
1066 for (index = 0; index < size; index++) {
1067 if (rssi < sq_thresh->upper_threshold[index]) {
1068 threshold = (u8) sq_thresh->upper_threshold[index];
1069 break;
1070 }
1071 }
1072
1073 return threshold;
1074}
1075
1076static u8 ath6kl_wmi_get_lower_threshold(s16 rssi,
1077 struct sq_threshold_params *sq_thresh,
1078 u32 size)
1079{
1080 u32 index;
1081 u8 threshold = (u8) sq_thresh->lower_threshold[size - 1];
1082
1083 /* The list is already in sorted order. Get the next lower value */
1084 for (index = 0; index < size; index++) {
1085 if (rssi > sq_thresh->lower_threshold[index]) {
1086 threshold = (u8) sq_thresh->lower_threshold[index];
1087 break;
1088 }
1089 }
1090
1091 return threshold;
1092}
1093
1094static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,
1095 struct wmi_rssi_threshold_params_cmd *rssi_cmd)
1096{
1097 struct sk_buff *skb;
1098 struct wmi_rssi_threshold_params_cmd *cmd;
1099
1100 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1101 if (!skb)
1102 return -ENOMEM;
1103
1104 cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data;
1105 memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd));
1106
1107 return ath6kl_wmi_cmd_send(wmi, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
1108 NO_SYNC_WMIFLAG);
1109}
1110
1111static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
1112 int len)
1113{
1114 struct wmi_rssi_threshold_event *reply;
1115 struct wmi_rssi_threshold_params_cmd cmd;
1116 struct sq_threshold_params *sq_thresh;
1117 enum wmi_rssi_threshold_val new_threshold;
1118 u8 upper_rssi_threshold, lower_rssi_threshold;
1119 s16 rssi;
1120 int ret;
1121
1122 if (len < sizeof(struct wmi_rssi_threshold_event))
1123 return -EINVAL;
1124
1125 reply = (struct wmi_rssi_threshold_event *) datap;
1126 new_threshold = (enum wmi_rssi_threshold_val) reply->range;
1127 rssi = a_sle16_to_cpu(reply->rssi);
1128
1129 sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI];
1130
1131 /*
1132 * Identify the threshold breached and communicate that to the app.
1133 * After that install a new set of thresholds based on the signal
1134 * quality reported by the target
1135 */
1136 if (new_threshold) {
1137 /* Upper threshold breached */
1138 if (rssi < sq_thresh->upper_threshold[0]) {
1139 ath6kl_dbg(ATH6KL_DBG_WMI,
1140 "spurious upper rssi threshold event: %d\n",
1141 rssi);
1142 } else if ((rssi < sq_thresh->upper_threshold[1]) &&
1143 (rssi >= sq_thresh->upper_threshold[0])) {
1144 new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
1145 } else if ((rssi < sq_thresh->upper_threshold[2]) &&
1146 (rssi >= sq_thresh->upper_threshold[1])) {
1147 new_threshold = WMI_RSSI_THRESHOLD2_ABOVE;
1148 } else if ((rssi < sq_thresh->upper_threshold[3]) &&
1149 (rssi >= sq_thresh->upper_threshold[2])) {
1150 new_threshold = WMI_RSSI_THRESHOLD3_ABOVE;
1151 } else if ((rssi < sq_thresh->upper_threshold[4]) &&
1152 (rssi >= sq_thresh->upper_threshold[3])) {
1153 new_threshold = WMI_RSSI_THRESHOLD4_ABOVE;
1154 } else if ((rssi < sq_thresh->upper_threshold[5]) &&
1155 (rssi >= sq_thresh->upper_threshold[4])) {
1156 new_threshold = WMI_RSSI_THRESHOLD5_ABOVE;
1157 } else if (rssi >= sq_thresh->upper_threshold[5]) {
1158 new_threshold = WMI_RSSI_THRESHOLD6_ABOVE;
1159 }
1160 } else {
1161 /* Lower threshold breached */
1162 if (rssi > sq_thresh->lower_threshold[0]) {
1163 ath6kl_dbg(ATH6KL_DBG_WMI,
1164 "spurious lower rssi threshold event: %d %d\n",
1165 rssi, sq_thresh->lower_threshold[0]);
1166 } else if ((rssi > sq_thresh->lower_threshold[1]) &&
1167 (rssi <= sq_thresh->lower_threshold[0])) {
1168 new_threshold = WMI_RSSI_THRESHOLD6_BELOW;
1169 } else if ((rssi > sq_thresh->lower_threshold[2]) &&
1170 (rssi <= sq_thresh->lower_threshold[1])) {
1171 new_threshold = WMI_RSSI_THRESHOLD5_BELOW;
1172 } else if ((rssi > sq_thresh->lower_threshold[3]) &&
1173 (rssi <= sq_thresh->lower_threshold[2])) {
1174 new_threshold = WMI_RSSI_THRESHOLD4_BELOW;
1175 } else if ((rssi > sq_thresh->lower_threshold[4]) &&
1176 (rssi <= sq_thresh->lower_threshold[3])) {
1177 new_threshold = WMI_RSSI_THRESHOLD3_BELOW;
1178 } else if ((rssi > sq_thresh->lower_threshold[5]) &&
1179 (rssi <= sq_thresh->lower_threshold[4])) {
1180 new_threshold = WMI_RSSI_THRESHOLD2_BELOW;
1181 } else if (rssi <= sq_thresh->lower_threshold[5]) {
1182 new_threshold = WMI_RSSI_THRESHOLD1_BELOW;
1183 }
1184 }
1185
1186 /* Calculate and install the next set of thresholds */
1187 lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh,
1188 sq_thresh->lower_threshold_valid_count);
1189 upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh,
1190 sq_thresh->upper_threshold_valid_count);
1191
1192 /* Issue a wmi command to install the thresholds */
1193 cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold);
1194 cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold);
1195 cmd.weight = sq_thresh->weight;
1196 cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1197
1198 ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd);
1199 if (ret) {
1200 ath6kl_err("unable to configure rssi thresholds\n");
1201 return -EIO;
1202 }
1203
1204 return 0;
1205}
1206
1207static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len)
1208{
1209 struct wmi_cac_event *reply;
1210 struct ieee80211_tspec_ie *ts;
1211 u16 active_tsids, tsinfo;
1212 u8 tsid, index;
1213 u8 ts_id;
1214
1215 if (len < sizeof(struct wmi_cac_event))
1216 return -EINVAL;
1217
1218 reply = (struct wmi_cac_event *) datap;
1219
1220 if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
1221 (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
1222
1223 ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1224 tsinfo = le16_to_cpu(ts->tsinfo);
1225 tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1226 IEEE80211_WMM_IE_TSPEC_TID_MASK;
1227
1228 ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, tsid);
1229 } else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
1230 /*
1231 * Following assumes that there is only one outstanding
1232 * ADDTS request when this event is received
1233 */
1234 spin_lock_bh(&wmi->lock);
1235 active_tsids = wmi->stream_exist_for_ac[reply->ac];
1236 spin_unlock_bh(&wmi->lock);
1237
1238 for (index = 0; index < sizeof(active_tsids) * 8; index++) {
1239 if ((active_tsids >> index) & 1)
1240 break;
1241 }
1242 if (index < (sizeof(active_tsids) * 8))
1243 ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, index);
1244 }
1245
1246 /*
1247 * Clear active tsids and Add missing handling
1248 * for delete qos stream from AP
1249 */
1250 else if (reply->cac_indication == CAC_INDICATION_DELETE) {
1251
1252 ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1253 tsinfo = le16_to_cpu(ts->tsinfo);
1254 ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1255 IEEE80211_WMM_IE_TSPEC_TID_MASK);
1256
1257 spin_lock_bh(&wmi->lock);
1258 wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id);
1259 active_tsids = wmi->stream_exist_for_ac[reply->ac];
1260 spin_unlock_bh(&wmi->lock);
1261
1262 /* Indicate stream inactivity to driver layer only if all tsids
1263 * within this AC are deleted.
1264 */
1265 if (!active_tsids) {
1266 ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac,
1267 false);
1268 wmi->fat_pipe_exist &= ~(1 << reply->ac);
1269 }
1270 }
1271
1272 return 0;
1273}
1274
1275static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
1276 struct wmi_snr_threshold_params_cmd *snr_cmd)
1277{
1278 struct sk_buff *skb;
1279 struct wmi_snr_threshold_params_cmd *cmd;
1280
1281 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1282 if (!skb)
1283 return -ENOMEM;
1284
1285 cmd = (struct wmi_snr_threshold_params_cmd *) skb->data;
1286 memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd));
1287
1288 return ath6kl_wmi_cmd_send(wmi, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID,
1289 NO_SYNC_WMIFLAG);
1290}
1291
1292static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
1293 int len)
1294{
1295 struct wmi_snr_threshold_event *reply;
1296 struct sq_threshold_params *sq_thresh;
1297 struct wmi_snr_threshold_params_cmd cmd;
1298 enum wmi_snr_threshold_val new_threshold;
1299 u8 upper_snr_threshold, lower_snr_threshold;
1300 s16 snr;
1301 int ret;
1302
1303 if (len < sizeof(struct wmi_snr_threshold_event))
1304 return -EINVAL;
1305
1306 reply = (struct wmi_snr_threshold_event *) datap;
1307
1308 new_threshold = (enum wmi_snr_threshold_val) reply->range;
1309 snr = reply->snr;
1310
1311 sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR];
1312
1313 /*
1314 * Identify the threshold breached and communicate that to the app.
1315 * After that install a new set of thresholds based on the signal
1316 * quality reported by the target.
1317 */
1318 if (new_threshold) {
1319 /* Upper threshold breached */
1320 if (snr < sq_thresh->upper_threshold[0]) {
1321 ath6kl_dbg(ATH6KL_DBG_WMI,
1322 "spurious upper snr threshold event: %d\n",
1323 snr);
1324 } else if ((snr < sq_thresh->upper_threshold[1]) &&
1325 (snr >= sq_thresh->upper_threshold[0])) {
1326 new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
1327 } else if ((snr < sq_thresh->upper_threshold[2]) &&
1328 (snr >= sq_thresh->upper_threshold[1])) {
1329 new_threshold = WMI_SNR_THRESHOLD2_ABOVE;
1330 } else if ((snr < sq_thresh->upper_threshold[3]) &&
1331 (snr >= sq_thresh->upper_threshold[2])) {
1332 new_threshold = WMI_SNR_THRESHOLD3_ABOVE;
1333 } else if (snr >= sq_thresh->upper_threshold[3]) {
1334 new_threshold = WMI_SNR_THRESHOLD4_ABOVE;
1335 }
1336 } else {
1337 /* Lower threshold breached */
1338 if (snr > sq_thresh->lower_threshold[0]) {
1339 ath6kl_dbg(ATH6KL_DBG_WMI,
1340 "spurious lower snr threshold event: %d\n",
1341 sq_thresh->lower_threshold[0]);
1342 } else if ((snr > sq_thresh->lower_threshold[1]) &&
1343 (snr <= sq_thresh->lower_threshold[0])) {
1344 new_threshold = WMI_SNR_THRESHOLD4_BELOW;
1345 } else if ((snr > sq_thresh->lower_threshold[2]) &&
1346 (snr <= sq_thresh->lower_threshold[1])) {
1347 new_threshold = WMI_SNR_THRESHOLD3_BELOW;
1348 } else if ((snr > sq_thresh->lower_threshold[3]) &&
1349 (snr <= sq_thresh->lower_threshold[2])) {
1350 new_threshold = WMI_SNR_THRESHOLD2_BELOW;
1351 } else if (snr <= sq_thresh->lower_threshold[3]) {
1352 new_threshold = WMI_SNR_THRESHOLD1_BELOW;
1353 }
1354 }
1355
1356 /* Calculate and install the next set of thresholds */
1357 lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh,
1358 sq_thresh->lower_threshold_valid_count);
1359 upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh,
1360 sq_thresh->upper_threshold_valid_count);
1361
1362 /* Issue a wmi command to install the thresholds */
1363 cmd.thresh_above1_val = upper_snr_threshold;
1364 cmd.thresh_below1_val = lower_snr_threshold;
1365 cmd.weight = sq_thresh->weight;
1366 cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1367
1368 ath6kl_dbg(ATH6KL_DBG_WMI,
1369 "snr: %d, threshold: %d, lower: %d, upper: %d\n",
1370 snr, new_threshold,
1371 lower_snr_threshold, upper_snr_threshold);
1372
1373 ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd);
1374 if (ret) {
1375 ath6kl_err("unable to configure snr threshold\n");
1376 return -EIO;
1377 }
1378
1379 return 0;
1380}
1381
1382static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)
1383{
1384 u16 ap_info_entry_size;
1385 struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap;
1386 struct wmi_ap_info_v1 *ap_info_v1;
1387 u8 index;
1388
1389 if (len < sizeof(struct wmi_aplist_event) ||
1390 ev->ap_list_ver != APLIST_VER1)
1391 return -EINVAL;
1392
1393 ap_info_entry_size = sizeof(struct wmi_ap_info_v1);
1394 ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list;
1395
1396 ath6kl_dbg(ATH6KL_DBG_WMI,
1397 "number of APs in aplist event: %d\n", ev->num_ap);
1398
1399 if (len < (int) (sizeof(struct wmi_aplist_event) +
1400 (ev->num_ap - 1) * ap_info_entry_size))
1401 return -EINVAL;
1402
1403 /* AP list version 1 contents */
1404 for (index = 0; index < ev->num_ap; index++) {
1405 ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n",
1406 index, ap_info_v1->bssid, ap_info_v1->channel);
1407 ap_info_v1++;
1408 }
1409
1410 return 0;
1411}
1412
1413int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb,
1414 enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag)
1415{
1416 struct wmi_cmd_hdr *cmd_hdr;
1417 enum htc_endpoint_id ep_id = wmi->ep_id;
1418 int ret;
1419
1420 if (WARN_ON(skb == NULL))
1421 return -EINVAL;
1422
1423 if (sync_flag >= END_WMIFLAG) {
1424 dev_kfree_skb(skb);
1425 return -EINVAL;
1426 }
1427
1428 if ((sync_flag == SYNC_BEFORE_WMIFLAG) ||
1429 (sync_flag == SYNC_BOTH_WMIFLAG)) {
1430 /*
1431 * Make sure all data currently queued is transmitted before
1432 * the cmd execution. Establish a new sync point.
1433 */
1434 ath6kl_wmi_sync_point(wmi);
1435 }
1436
1437 skb_push(skb, sizeof(struct wmi_cmd_hdr));
1438
1439 cmd_hdr = (struct wmi_cmd_hdr *) skb->data;
1440 cmd_hdr->cmd_id = cpu_to_le16(cmd_id);
1441 cmd_hdr->info1 = 0; /* added for virtual interface */
1442
1443 /* Only for OPT_TX_CMD, use BE endpoint. */
1444 if (cmd_id == WMI_OPT_TX_FRAME_CMDID) {
1445 ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE,
1446 false, false, 0, NULL);
1447 if (ret) {
1448 dev_kfree_skb(skb);
1449 return ret;
1450 }
1451 ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE);
1452 }
1453
1454 ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
1455
1456 if ((sync_flag == SYNC_AFTER_WMIFLAG) ||
1457 (sync_flag == SYNC_BOTH_WMIFLAG)) {
1458 /*
1459 * Make sure all new data queued waits for the command to
1460 * execute. Establish a new sync point.
1461 */
1462 ath6kl_wmi_sync_point(wmi);
1463 }
1464
1465 return 0;
1466}
1467
1468int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type,
1469 enum dot11_auth_mode dot11_auth_mode,
1470 enum auth_mode auth_mode,
1471 enum crypto_type pairwise_crypto,
1472 u8 pairwise_crypto_len,
1473 enum crypto_type group_crypto,
1474 u8 group_crypto_len, int ssid_len, u8 *ssid,
1475 u8 *bssid, u16 channel, u32 ctrl_flags)
1476{
1477 struct sk_buff *skb;
1478 struct wmi_connect_cmd *cc;
1479 int ret;
1480
1481 wmi->traffic_class = 100;
1482
1483 if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT))
1484 return -EINVAL;
1485
1486 if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT))
1487 return -EINVAL;
1488
1489 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd));
1490 if (!skb)
1491 return -ENOMEM;
1492
1493 cc = (struct wmi_connect_cmd *) skb->data;
1494
1495 if (ssid_len)
1496 memcpy(cc->ssid, ssid, ssid_len);
1497
1498 cc->ssid_len = ssid_len;
1499 cc->nw_type = nw_type;
1500 cc->dot11_auth_mode = dot11_auth_mode;
1501 cc->auth_mode = auth_mode;
1502 cc->prwise_crypto_type = pairwise_crypto;
1503 cc->prwise_crypto_len = pairwise_crypto_len;
1504 cc->grp_crypto_type = group_crypto;
1505 cc->grp_crypto_len = group_crypto_len;
1506 cc->ch = cpu_to_le16(channel);
1507 cc->ctrl_flags = cpu_to_le32(ctrl_flags);
1508
1509 if (bssid != NULL)
1510 memcpy(cc->bssid, bssid, ETH_ALEN);
1511
1512 wmi->pair_crypto_type = pairwise_crypto;
1513 wmi->grp_crypto_type = group_crypto;
1514
1515 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CONNECT_CMDID, NO_SYNC_WMIFLAG);
1516
1517 return ret;
1518}
1519
1520int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel)
1521{
1522 struct sk_buff *skb;
1523 struct wmi_reconnect_cmd *cc;
1524 int ret;
1525
1526 wmi->traffic_class = 100;
1527
1528 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd));
1529 if (!skb)
1530 return -ENOMEM;
1531
1532 cc = (struct wmi_reconnect_cmd *) skb->data;
1533 cc->channel = cpu_to_le16(channel);
1534
1535 if (bssid != NULL)
1536 memcpy(cc->bssid, bssid, ETH_ALEN);
1537
1538 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RECONNECT_CMDID,
1539 NO_SYNC_WMIFLAG);
1540
1541 return ret;
1542}
1543
1544int ath6kl_wmi_disconnect_cmd(struct wmi *wmi)
1545{
1546 int ret;
1547
1548 wmi->traffic_class = 100;
1549
1550 /* Disconnect command does not need to do a SYNC before. */
1551 ret = ath6kl_wmi_simple_cmd(wmi, WMI_DISCONNECT_CMDID);
1552
1553 return ret;
1554}
1555
1556int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type,
1557 u32 force_fgscan, u32 is_legacy,
1558 u32 home_dwell_time, u32 force_scan_interval,
1559 s8 num_chan, u16 *ch_list)
1560{
1561 struct sk_buff *skb;
1562 struct wmi_start_scan_cmd *sc;
1563 s8 size;
1564 int ret;
1565
1566 size = sizeof(struct wmi_start_scan_cmd);
1567
1568 if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
1569 return -EINVAL;
1570
1571 if (num_chan > WMI_MAX_CHANNELS)
1572 return -EINVAL;
1573
1574 if (num_chan)
1575 size += sizeof(u16) * (num_chan - 1);
1576
1577 skb = ath6kl_wmi_get_new_buf(size);
1578 if (!skb)
1579 return -ENOMEM;
1580
1581 sc = (struct wmi_start_scan_cmd *) skb->data;
1582 sc->scan_type = scan_type;
1583 sc->force_fg_scan = cpu_to_le32(force_fgscan);
1584 sc->is_legacy = cpu_to_le32(is_legacy);
1585 sc->home_dwell_time = cpu_to_le32(home_dwell_time);
1586 sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
1587 sc->num_ch = num_chan;
1588
1589 if (num_chan)
1590 memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16));
1591
1592 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID,
1593 NO_SYNC_WMIFLAG);
1594
1595 return ret;
1596}
1597
1598int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec,
1599 u16 fg_end_sec, u16 bg_sec,
1600 u16 minact_chdw_msec, u16 maxact_chdw_msec,
1601 u16 pas_chdw_msec, u8 short_scan_ratio,
1602 u8 scan_ctrl_flag, u32 max_dfsch_act_time,
1603 u16 maxact_scan_per_ssid)
1604{
1605 struct sk_buff *skb;
1606 struct wmi_scan_params_cmd *sc;
1607 int ret;
1608
1609 skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
1610 if (!skb)
1611 return -ENOMEM;
1612
1613 sc = (struct wmi_scan_params_cmd *) skb->data;
1614 sc->fg_start_period = cpu_to_le16(fg_start_sec);
1615 sc->fg_end_period = cpu_to_le16(fg_end_sec);
1616 sc->bg_period = cpu_to_le16(bg_sec);
1617 sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec);
1618 sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec);
1619 sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec);
1620 sc->short_scan_ratio = short_scan_ratio;
1621 sc->scan_ctrl_flags = scan_ctrl_flag;
1622 sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time);
1623 sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid);
1624
1625 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_SCAN_PARAMS_CMDID,
1626 NO_SYNC_WMIFLAG);
1627 return ret;
1628}
1629
1630int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask)
1631{
1632 struct sk_buff *skb;
1633 struct wmi_bss_filter_cmd *cmd;
1634 int ret;
1635
1636 if (filter >= LAST_BSS_FILTER)
1637 return -EINVAL;
1638
1639 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1640 if (!skb)
1641 return -ENOMEM;
1642
1643 cmd = (struct wmi_bss_filter_cmd *) skb->data;
1644 cmd->bss_filter = filter;
1645 cmd->ie_mask = cpu_to_le32(ie_mask);
1646
1647 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_BSS_FILTER_CMDID,
1648 NO_SYNC_WMIFLAG);
1649 return ret;
1650}
1651
1652int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag,
1653 u8 ssid_len, u8 *ssid)
1654{
1655 struct sk_buff *skb;
1656 struct wmi_probed_ssid_cmd *cmd;
1657 int ret;
1658
1659 if (index > MAX_PROBED_SSID_INDEX)
1660 return -EINVAL;
1661
1662 if (ssid_len > sizeof(cmd->ssid))
1663 return -EINVAL;
1664
1665 if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0))
1666 return -EINVAL;
1667
1668 if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len)
1669 return -EINVAL;
1670
1671 if (flag & SPECIFIC_SSID_FLAG)
1672 wmi->is_probe_ssid = true;
1673
1674 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1675 if (!skb)
1676 return -ENOMEM;
1677
1678 cmd = (struct wmi_probed_ssid_cmd *) skb->data;
1679 cmd->entry_index = index;
1680 cmd->flag = flag;
1681 cmd->ssid_len = ssid_len;
1682 memcpy(cmd->ssid, ssid, ssid_len);
1683
1684 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PROBED_SSID_CMDID,
1685 NO_SYNC_WMIFLAG);
1686 return ret;
1687}
1688
1689int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval,
1690 u16 listen_beacons)
1691{
1692 struct sk_buff *skb;
1693 struct wmi_listen_int_cmd *cmd;
1694 int ret;
1695
1696 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1697 if (!skb)
1698 return -ENOMEM;
1699
1700 cmd = (struct wmi_listen_int_cmd *) skb->data;
1701 cmd->listen_intvl = cpu_to_le16(listen_interval);
1702 cmd->num_beacons = cpu_to_le16(listen_beacons);
1703
1704 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LISTEN_INT_CMDID,
1705 NO_SYNC_WMIFLAG);
1706 return ret;
1707}
1708
1709int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode)
1710{
1711 struct sk_buff *skb;
1712 struct wmi_power_mode_cmd *cmd;
1713 int ret;
1714
1715 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1716 if (!skb)
1717 return -ENOMEM;
1718
1719 cmd = (struct wmi_power_mode_cmd *) skb->data;
1720 cmd->pwr_mode = pwr_mode;
1721 wmi->pwr_mode = pwr_mode;
1722
1723 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_MODE_CMDID,
1724 NO_SYNC_WMIFLAG);
1725 return ret;
1726}
1727
1728int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period,
1729 u16 ps_poll_num, u16 dtim_policy,
1730 u16 tx_wakeup_policy, u16 num_tx_to_wakeup,
1731 u16 ps_fail_event_policy)
1732{
1733 struct sk_buff *skb;
1734 struct wmi_power_params_cmd *pm;
1735 int ret;
1736
1737 skb = ath6kl_wmi_get_new_buf(sizeof(*pm));
1738 if (!skb)
1739 return -ENOMEM;
1740
1741 pm = (struct wmi_power_params_cmd *)skb->data;
1742 pm->idle_period = cpu_to_le16(idle_period);
1743 pm->pspoll_number = cpu_to_le16(ps_poll_num);
1744 pm->dtim_policy = cpu_to_le16(dtim_policy);
1745 pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy);
1746 pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup);
1747 pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy);
1748
1749 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_PARAMS_CMDID,
1750 NO_SYNC_WMIFLAG);
1751 return ret;
1752}
1753
1754int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout)
1755{
1756 struct sk_buff *skb;
1757 struct wmi_disc_timeout_cmd *cmd;
1758 int ret;
1759
1760 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1761 if (!skb)
1762 return -ENOMEM;
1763
1764 cmd = (struct wmi_disc_timeout_cmd *) skb->data;
1765 cmd->discon_timeout = timeout;
1766
1767 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_DISC_TIMEOUT_CMDID,
1768 NO_SYNC_WMIFLAG);
1769 return ret;
1770}
1771
1772int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index,
1773 enum crypto_type key_type,
1774 u8 key_usage, u8 key_len,
1775 u8 *key_rsc, u8 *key_material,
1776 u8 key_op_ctrl, u8 *mac_addr,
1777 enum wmi_sync_flag sync_flag)
1778{
1779 struct sk_buff *skb;
1780 struct wmi_add_cipher_key_cmd *cmd;
1781 int ret;
1782
1783 if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
1784 (key_material == NULL))
1785 return -EINVAL;
1786
1787 if ((WEP_CRYPT != key_type) && (NULL == key_rsc))
1788 return -EINVAL;
1789
1790 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1791 if (!skb)
1792 return -ENOMEM;
1793
1794 cmd = (struct wmi_add_cipher_key_cmd *) skb->data;
1795 cmd->key_index = key_index;
1796 cmd->key_type = key_type;
1797 cmd->key_usage = key_usage;
1798 cmd->key_len = key_len;
1799 memcpy(cmd->key, key_material, key_len);
1800
1801 if (key_rsc != NULL)
1802 memcpy(cmd->key_rsc, key_rsc, sizeof(cmd->key_rsc));
1803
1804 cmd->key_op_ctrl = key_op_ctrl;
1805
1806 if (mac_addr)
1807 memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN);
1808
1809 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_CIPHER_KEY_CMDID,
1810 sync_flag);
1811
1812 return ret;
1813}
1814
1815int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk)
1816{
1817 struct sk_buff *skb;
1818 struct wmi_add_krk_cmd *cmd;
1819 int ret;
1820
1821 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1822 if (!skb)
1823 return -ENOMEM;
1824
1825 cmd = (struct wmi_add_krk_cmd *) skb->data;
1826 memcpy(cmd->krk, krk, WMI_KRK_LEN);
1827
1828 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_KRK_CMDID, NO_SYNC_WMIFLAG);
1829
1830 return ret;
1831}
1832
1833int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index)
1834{
1835 struct sk_buff *skb;
1836 struct wmi_delete_cipher_key_cmd *cmd;
1837 int ret;
1838
1839 if (key_index > WMI_MAX_KEY_INDEX)
1840 return -EINVAL;
1841
1842 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1843 if (!skb)
1844 return -ENOMEM;
1845
1846 cmd = (struct wmi_delete_cipher_key_cmd *) skb->data;
1847 cmd->key_index = key_index;
1848
1849 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_CIPHER_KEY_CMDID,
1850 NO_SYNC_WMIFLAG);
1851
1852 return ret;
1853}
1854
1855int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid,
1856 const u8 *pmkid, bool set)
1857{
1858 struct sk_buff *skb;
1859 struct wmi_setpmkid_cmd *cmd;
1860 int ret;
1861
1862 if (bssid == NULL)
1863 return -EINVAL;
1864
1865 if (set && pmkid == NULL)
1866 return -EINVAL;
1867
1868 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1869 if (!skb)
1870 return -ENOMEM;
1871
1872 cmd = (struct wmi_setpmkid_cmd *) skb->data;
1873 memcpy(cmd->bssid, bssid, ETH_ALEN);
1874 if (set) {
1875 memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid));
1876 cmd->enable = PMKID_ENABLE;
1877 } else {
1878 memset(cmd->pmkid, 0, sizeof(cmd->pmkid));
1879 cmd->enable = PMKID_DISABLE;
1880 }
1881
1882 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PMKID_CMDID,
1883 NO_SYNC_WMIFLAG);
1884
1885 return ret;
1886}
1887
1888static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
1889 enum htc_endpoint_id ep_id)
1890{
1891 struct wmi_data_hdr *data_hdr;
1892 int ret;
1893
1894 if (WARN_ON(skb == NULL || ep_id == wmi->ep_id))
1895 return -EINVAL;
1896
1897 skb_push(skb, sizeof(struct wmi_data_hdr));
1898
1899 data_hdr = (struct wmi_data_hdr *) skb->data;
1900 data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT;
1901 data_hdr->info3 = 0;
1902
1903 ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
1904
1905 return ret;
1906}
1907
1908static int ath6kl_wmi_sync_point(struct wmi *wmi)
1909{
1910 struct sk_buff *skb;
1911 struct wmi_sync_cmd *cmd;
1912 struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC];
1913 enum htc_endpoint_id ep_id;
1914 u8 index, num_pri_streams = 0;
1915 int ret = 0;
1916
1917 memset(data_sync_bufs, 0, sizeof(data_sync_bufs));
1918
1919 spin_lock_bh(&wmi->lock);
1920
1921 for (index = 0; index < WMM_NUM_AC; index++) {
1922 if (wmi->fat_pipe_exist & (1 << index)) {
1923 num_pri_streams++;
1924 data_sync_bufs[num_pri_streams - 1].traffic_class =
1925 index;
1926 }
1927 }
1928
1929 spin_unlock_bh(&wmi->lock);
1930
1931 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1932 if (!skb) {
1933 ret = -ENOMEM;
1934 goto free_skb;
1935 }
1936
1937 cmd = (struct wmi_sync_cmd *) skb->data;
1938
1939 /*
1940 * In the SYNC cmd sent on the control Ep, send a bitmap
1941 * of the data eps on which the Data Sync will be sent
1942 */
1943 cmd->data_sync_map = wmi->fat_pipe_exist;
1944
1945 for (index = 0; index < num_pri_streams; index++) {
1946 data_sync_bufs[index].skb = ath6kl_buf_alloc(0);
1947 if (data_sync_bufs[index].skb == NULL) {
1948 ret = -ENOMEM;
1949 break;
1950 }
1951 }
1952
1953 /*
1954 * If buffer allocation for any of the dataSync fails,
1955 * then do not send the Synchronize cmd on the control ep
1956 */
1957 if (ret)
1958 goto free_skb;
1959
1960 /*
1961 * Send sync cmd followed by sync data messages on all
1962 * endpoints being used
1963 */
1964 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SYNCHRONIZE_CMDID,
1965 NO_SYNC_WMIFLAG);
1966
1967 if (ret)
1968 goto free_skb;
1969
1970 /* cmd buffer sent, we no longer own it */
1971 skb = NULL;
1972
1973 for (index = 0; index < num_pri_streams; index++) {
1974
1975 if (WARN_ON(!data_sync_bufs[index].skb))
1976 break;
1977
1978 ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
1979 data_sync_bufs[index].
1980 traffic_class);
1981 ret =
1982 ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
1983 ep_id);
1984
1985 if (ret)
1986 break;
1987
1988 data_sync_bufs[index].skb = NULL;
1989 }
1990
1991free_skb:
1992 /* free up any resources left over (possibly due to an error) */
1993 if (skb)
1994 dev_kfree_skb(skb);
1995
1996 for (index = 0; index < num_pri_streams; index++) {
1997 if (data_sync_bufs[index].skb != NULL) {
1998 dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
1999 skb);
2000 }
2001 }
2002
2003 return ret;
2004}
2005
2006int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi,
2007 struct wmi_create_pstream_cmd *params)
2008{
2009 struct sk_buff *skb;
2010 struct wmi_create_pstream_cmd *cmd;
2011 u8 fatpipe_exist_for_ac = 0;
2012 s32 min_phy = 0;
2013 s32 nominal_phy = 0;
2014 int ret;
2015
2016 if (!((params->user_pri < 8) &&
2017 (params->user_pri <= 0x7) &&
2018 (up_to_ac[params->user_pri & 0x7] == params->traffic_class) &&
2019 (params->traffic_direc == UPLINK_TRAFFIC ||
2020 params->traffic_direc == DNLINK_TRAFFIC ||
2021 params->traffic_direc == BIDIR_TRAFFIC) &&
2022 (params->traffic_type == TRAFFIC_TYPE_APERIODIC ||
2023 params->traffic_type == TRAFFIC_TYPE_PERIODIC) &&
2024 (params->voice_psc_cap == DISABLE_FOR_THIS_AC ||
2025 params->voice_psc_cap == ENABLE_FOR_THIS_AC ||
2026 params->voice_psc_cap == ENABLE_FOR_ALL_AC) &&
2027 (params->tsid == WMI_IMPLICIT_PSTREAM ||
2028 params->tsid <= WMI_MAX_THINSTREAM))) {
2029 return -EINVAL;
2030 }
2031
2032 /*
2033 * Check nominal PHY rate is >= minimalPHY,
2034 * so that DUT can allow TSRS IE
2035 */
2036
2037 /* Get the physical rate (units of bps) */
2038 min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000);
2039
2040 /* Check minimal phy < nominal phy rate */
2041 if (params->nominal_phy >= min_phy) {
2042 /* unit of 500 kbps */
2043 nominal_phy = (params->nominal_phy * 1000) / 500;
2044 ath6kl_dbg(ATH6KL_DBG_WMI,
2045 "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n",
2046 min_phy, nominal_phy);
2047
2048 params->nominal_phy = nominal_phy;
2049 } else {
2050 params->nominal_phy = 0;
2051 }
2052
2053 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2054 if (!skb)
2055 return -ENOMEM;
2056
2057 ath6kl_dbg(ATH6KL_DBG_WMI,
2058 "sending create_pstream_cmd: ac=%d tsid:%d\n",
2059 params->traffic_class, params->tsid);
2060
2061 cmd = (struct wmi_create_pstream_cmd *) skb->data;
2062 memcpy(cmd, params, sizeof(*cmd));
2063
2064 /* This is an implicitly created Fat pipe */
2065 if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) {
2066 spin_lock_bh(&wmi->lock);
2067 fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
2068 (1 << params->traffic_class));
2069 wmi->fat_pipe_exist |= (1 << params->traffic_class);
2070 spin_unlock_bh(&wmi->lock);
2071 } else {
2072 /* explicitly created thin stream within a fat pipe */
2073 spin_lock_bh(&wmi->lock);
2074 fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
2075 (1 << params->traffic_class));
2076 wmi->stream_exist_for_ac[params->traffic_class] |=
2077 (1 << params->tsid);
2078 /*
2079 * If a thinstream becomes active, the fat pipe automatically
2080 * becomes active
2081 */
2082 wmi->fat_pipe_exist |= (1 << params->traffic_class);
2083 spin_unlock_bh(&wmi->lock);
2084 }
2085
2086 /*
2087 * Indicate activty change to driver layer only if this is the
2088 * first TSID to get created in this AC explicitly or an implicit
2089 * fat pipe is getting created.
2090 */
2091 if (!fatpipe_exist_for_ac)
2092 ath6kl_indicate_tx_activity(wmi->parent_dev,
2093 params->traffic_class, true);
2094
2095 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CREATE_PSTREAM_CMDID,
2096 NO_SYNC_WMIFLAG);
2097 return ret;
2098}
2099
2100int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid)
2101{
2102 struct sk_buff *skb;
2103 struct wmi_delete_pstream_cmd *cmd;
2104 u16 active_tsids = 0;
2105 int ret;
2106
2107 if (traffic_class > 3) {
2108 ath6kl_err("invalid traffic class: %d\n", traffic_class);
2109 return -EINVAL;
2110 }
2111
2112 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2113 if (!skb)
2114 return -ENOMEM;
2115
2116 cmd = (struct wmi_delete_pstream_cmd *) skb->data;
2117 cmd->traffic_class = traffic_class;
2118 cmd->tsid = tsid;
2119
2120 spin_lock_bh(&wmi->lock);
2121 active_tsids = wmi->stream_exist_for_ac[traffic_class];
2122 spin_unlock_bh(&wmi->lock);
2123
2124 if (!(active_tsids & (1 << tsid))) {
2125 dev_kfree_skb(skb);
2126 ath6kl_dbg(ATH6KL_DBG_WMI,
2127 "TSID %d doesn't exist for traffic class: %d\n",
2128 tsid, traffic_class);
2129 return -ENODATA;
2130 }
2131
2132 ath6kl_dbg(ATH6KL_DBG_WMI,
2133 "sending delete_pstream_cmd: traffic class: %d tsid=%d\n",
2134 traffic_class, tsid);
2135
2136 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_PSTREAM_CMDID,
2137 SYNC_BEFORE_WMIFLAG);
2138
2139 spin_lock_bh(&wmi->lock);
2140 wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid);
2141 active_tsids = wmi->stream_exist_for_ac[traffic_class];
2142 spin_unlock_bh(&wmi->lock);
2143
2144 /*
2145 * Indicate stream inactivity to driver layer only if all tsids
2146 * within this AC are deleted.
2147 */
2148 if (!active_tsids) {
2149 ath6kl_indicate_tx_activity(wmi->parent_dev,
2150 traffic_class, false);
2151 wmi->fat_pipe_exist &= ~(1 << traffic_class);
2152 }
2153
2154 return ret;
2155}
2156
2157int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
2158{
2159 struct sk_buff *skb;
2160 struct wmi_set_ip_cmd *cmd;
2161 int ret;
2162
2163 /* Multicast address are not valid */
2164 if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) ||
2165 (*((u8 *) &ip_cmd->ips[1]) >= 0xE0))
2166 return -EINVAL;
2167
2168 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));
2169 if (!skb)
2170 return -ENOMEM;
2171
2172 cmd = (struct wmi_set_ip_cmd *) skb->data;
2173 memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd));
2174
2175 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_IP_CMDID, NO_SYNC_WMIFLAG);
2176 return ret;
2177}
2178
2179static int ath6kl_wmi_get_wow_list_event_rx(struct wmi *wmi, u8 * datap,
2180 int len)
2181{
2182 if (len < sizeof(struct wmi_get_wow_list_reply))
2183 return -EINVAL;
2184
2185 return 0;
2186}
2187
2188static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,
2189 enum wmix_command_id cmd_id,
2190 enum wmi_sync_flag sync_flag)
2191{
2192 struct wmix_cmd_hdr *cmd_hdr;
2193 int ret;
2194
2195 skb_push(skb, sizeof(struct wmix_cmd_hdr));
2196
2197 cmd_hdr = (struct wmix_cmd_hdr *) skb->data;
2198 cmd_hdr->cmd_id = cpu_to_le32(cmd_id);
2199
2200 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_EXTENSION_CMDID, sync_flag);
2201
2202 return ret;
2203}
2204
2205int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source)
2206{
2207 struct sk_buff *skb;
2208 struct wmix_hb_challenge_resp_cmd *cmd;
2209 int ret;
2210
2211 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2212 if (!skb)
2213 return -ENOMEM;
2214
2215 cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data;
2216 cmd->cookie = cpu_to_le32(cookie);
2217 cmd->source = cpu_to_le32(source);
2218
2219 ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID,
2220 NO_SYNC_WMIFLAG);
2221 return ret;
2222}
2223
2224int ath6kl_wmi_get_stats_cmd(struct wmi *wmi)
2225{
2226 return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID);
2227}
2228
2229int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM)
2230{
2231 struct sk_buff *skb;
2232 struct wmi_set_tx_pwr_cmd *cmd;
2233 int ret;
2234
2235 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd));
2236 if (!skb)
2237 return -ENOMEM;
2238
2239 cmd = (struct wmi_set_tx_pwr_cmd *) skb->data;
2240 cmd->dbM = dbM;
2241
2242 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_TX_PWR_CMDID,
2243 NO_SYNC_WMIFLAG);
2244
2245 return ret;
2246}
2247
2248int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi)
2249{
2250 return ath6kl_wmi_simple_cmd(wmi, WMI_GET_TX_PWR_CMDID);
2251}
2252
2253void ath6kl_wmi_get_current_bssid(struct wmi *wmi, u8 *bssid)
2254{
2255 if (bssid)
2256 memcpy(bssid, wmi->bssid, ETH_ALEN);
2257}
2258
2259int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy)
2260{
2261 struct sk_buff *skb;
2262 struct wmi_set_lpreamble_cmd *cmd;
2263 int ret;
2264
2265 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd));
2266 if (!skb)
2267 return -ENOMEM;
2268
2269 cmd = (struct wmi_set_lpreamble_cmd *) skb->data;
2270 cmd->status = status;
2271 cmd->preamble_policy = preamble_policy;
2272
2273 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LPREAMBLE_CMDID,
2274 NO_SYNC_WMIFLAG);
2275 return ret;
2276}
2277
2278int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold)
2279{
2280 struct sk_buff *skb;
2281 struct wmi_set_rts_cmd *cmd;
2282 int ret;
2283
2284 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd));
2285 if (!skb)
2286 return -ENOMEM;
2287
2288 cmd = (struct wmi_set_rts_cmd *) skb->data;
2289 cmd->threshold = cpu_to_le16(threshold);
2290
2291 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_RTS_CMDID, NO_SYNC_WMIFLAG);
2292 return ret;
2293}
2294
2295int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg)
2296{
2297 struct sk_buff *skb;
2298 struct wmi_set_wmm_txop_cmd *cmd;
2299 int ret;
2300
2301 if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)))
2302 return -EINVAL;
2303
2304 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd));
2305 if (!skb)
2306 return -ENOMEM;
2307
2308 cmd = (struct wmi_set_wmm_txop_cmd *) skb->data;
2309 cmd->txop_enable = cfg;
2310
2311 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_WMM_TXOP_CMDID,
2312 NO_SYNC_WMIFLAG);
2313 return ret;
2314}
2315
2316int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl)
2317{
2318 struct sk_buff *skb;
2319 struct wmi_set_keepalive_cmd *cmd;
2320 int ret;
2321
2322 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2323 if (!skb)
2324 return -ENOMEM;
2325
2326 cmd = (struct wmi_set_keepalive_cmd *) skb->data;
2327 cmd->keep_alive_intvl = keep_alive_intvl;
2328 wmi->keep_alive_intvl = keep_alive_intvl;
2329
2330 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_KEEPALIVE_CMDID,
2331 NO_SYNC_WMIFLAG);
2332 return ret;
2333}
2334
2335s32 ath6kl_wmi_get_rate(s8 rate_index)
2336{
2337 if (rate_index == RATE_AUTO)
2338 return 0;
2339
2340 return wmi_rate_tbl[(u32) rate_index][0];
2341}
2342
2343void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss)
2344{
2345 if (bss)
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +05302346 wlan_node_return(&wmi->parent_dev->scan_table, bss);
Kalle Valobdcd8172011-07-18 00:22:30 +03002347}
2348
2349struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 * ssid,
2350 u32 ssid_len, bool is_wpa2,
2351 bool match_ssid)
2352{
2353 struct bss *node = NULL;
2354
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +05302355 node = wlan_find_ssid_node(&wmi->parent_dev->scan_table, ssid,
Kalle Valobdcd8172011-07-18 00:22:30 +03002356 ssid_len, is_wpa2, match_ssid);
2357 return node;
2358}
2359
2360struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 * mac_addr)
2361{
2362 struct bss *ni = NULL;
2363
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +05302364 ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr);
Kalle Valobdcd8172011-07-18 00:22:30 +03002365
2366 return ni;
2367}
2368
2369void ath6kl_wmi_node_free(struct wmi *wmi, const u8 * mac_addr)
2370{
2371 struct bss *ni = NULL;
2372
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +05302373 ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr);
Kalle Valobdcd8172011-07-18 00:22:30 +03002374 if (ni != NULL)
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +05302375 wlan_node_reclaim(&wmi->parent_dev->scan_table, ni);
Kalle Valobdcd8172011-07-18 00:22:30 +03002376
2377 return;
2378}
2379
2380static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
2381 u32 len)
2382{
2383 struct wmi_pmkid_list_reply *reply;
2384 u32 expected_len;
2385
2386 if (len < sizeof(struct wmi_pmkid_list_reply))
2387 return -EINVAL;
2388
2389 reply = (struct wmi_pmkid_list_reply *)datap;
2390 expected_len = sizeof(reply->num_pmkid) +
2391 le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN;
2392
2393 if (len < expected_len)
2394 return -EINVAL;
2395
2396 return 0;
2397}
2398
2399static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
2400{
2401 struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap;
2402
2403 aggr_recv_addba_req_evt(wmi->parent_dev, cmd->tid,
2404 le16_to_cpu(cmd->st_seq_no), cmd->win_sz);
2405
2406 return 0;
2407}
2408
2409static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len)
2410{
2411 struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap;
2412
2413 aggr_recv_delba_req_evt(wmi->parent_dev, cmd->tid);
2414
2415 return 0;
2416}
2417
2418/* AP mode functions */
2419static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len)
2420{
2421 struct wmi_pspoll_event *ev;
2422
2423 if (len < sizeof(struct wmi_pspoll_event))
2424 return -EINVAL;
2425
2426 ev = (struct wmi_pspoll_event *) datap;
2427
2428 ath6kl_pspoll_event(wmi->parent_dev, le16_to_cpu(ev->aid));
2429
2430 return 0;
2431}
2432
2433static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len)
2434{
2435 ath6kl_dtimexpiry_event(wmi->parent_dev);
2436
2437 return 0;
2438}
2439
2440int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag)
2441{
2442 struct sk_buff *skb;
2443 struct wmi_ap_set_pvb_cmd *cmd;
2444 int ret;
2445
2446 skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd));
2447 if (!skb)
2448 return -ENOMEM;
2449
2450 cmd = (struct wmi_ap_set_pvb_cmd *) skb->data;
2451 cmd->aid = cpu_to_le16(aid);
2452 cmd->flag = cpu_to_le32(flag);
2453
2454 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID,
2455 NO_SYNC_WMIFLAG);
2456
2457 return 0;
2458}
2459
2460int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver,
2461 bool rx_dot11_hdr, bool defrag_on_host)
2462{
2463 struct sk_buff *skb;
2464 struct wmi_rx_frame_format_cmd *cmd;
2465 int ret;
2466
2467 skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2468 if (!skb)
2469 return -ENOMEM;
2470
2471 cmd = (struct wmi_rx_frame_format_cmd *) skb->data;
2472 cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0;
2473 cmd->defrag_on_host = defrag_on_host ? 1 : 0;
2474 cmd->meta_ver = rx_meta_ver;
2475
2476 /* Delete the local aggr state, on host */
2477 ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RX_FRAME_FORMAT_CMDID,
2478 NO_SYNC_WMIFLAG);
2479
2480 return ret;
2481}
2482
2483static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
2484{
2485 struct wmix_cmd_hdr *cmd;
2486 u32 len;
2487 u16 id;
2488 u8 *datap;
2489 int ret = 0;
2490
2491 if (skb->len < sizeof(struct wmix_cmd_hdr)) {
2492 ath6kl_err("bad packet 1\n");
2493 wmi->stat.cmd_len_err++;
2494 return -EINVAL;
2495 }
2496
2497 cmd = (struct wmix_cmd_hdr *) skb->data;
2498 id = le32_to_cpu(cmd->cmd_id);
2499
2500 skb_pull(skb, sizeof(struct wmix_cmd_hdr));
2501
2502 datap = skb->data;
2503 len = skb->len;
2504
2505 switch (id) {
2506 case WMIX_HB_CHALLENGE_RESP_EVENTID:
2507 break;
2508 case WMIX_DBGLOG_EVENTID:
2509 break;
2510 default:
2511 ath6kl_err("unknown cmd id 0x%x\n", id);
2512 wmi->stat.cmd_id_err++;
2513 ret = -EINVAL;
2514 break;
2515 }
2516
2517 return ret;
2518}
2519
2520/* Control Path */
2521int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
2522{
2523 struct wmi_cmd_hdr *cmd;
2524 u32 len;
2525 u16 id;
2526 u8 *datap;
2527 int ret = 0;
2528
2529 if (WARN_ON(skb == NULL))
2530 return -EINVAL;
2531
2532 if (skb->len < sizeof(struct wmi_cmd_hdr)) {
2533 ath6kl_err("bad packet 1\n");
2534 dev_kfree_skb(skb);
2535 wmi->stat.cmd_len_err++;
2536 return -EINVAL;
2537 }
2538
2539 cmd = (struct wmi_cmd_hdr *) skb->data;
2540 id = le16_to_cpu(cmd->cmd_id);
2541
2542 skb_pull(skb, sizeof(struct wmi_cmd_hdr));
2543
2544 datap = skb->data;
2545 len = skb->len;
2546
2547 ath6kl_dbg(ATH6KL_DBG_WMI, "%s: wmi id: %d\n", __func__, id);
2548 ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "msg payload ", datap, len);
2549
2550 switch (id) {
2551 case WMI_GET_BITRATE_CMDID:
2552 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
2553 ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len);
2554 break;
2555 case WMI_GET_CHANNEL_LIST_CMDID:
2556 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n");
2557 ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len);
2558 break;
2559 case WMI_GET_TX_PWR_CMDID:
2560 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n");
2561 ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len);
2562 break;
2563 case WMI_READY_EVENTID:
2564 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
2565 ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
2566 break;
2567 case WMI_CONNECT_EVENTID:
2568 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
2569 ret = ath6kl_wmi_connect_event_rx(wmi, datap, len);
2570 break;
2571 case WMI_DISCONNECT_EVENTID:
2572 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
2573 ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len);
2574 break;
2575 case WMI_PEER_NODE_EVENTID:
2576 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
2577 ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
2578 break;
2579 case WMI_TKIP_MICERR_EVENTID:
2580 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
2581 ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len);
2582 break;
2583 case WMI_BSSINFO_EVENTID:
2584 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
2585 ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(skb, datap);
2586 ret = ath6kl_wmi_bssinfo_event_rx(wmi, skb->data, skb->len);
2587 break;
2588 case WMI_REGDOMAIN_EVENTID:
2589 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
2590 break;
2591 case WMI_PSTREAM_TIMEOUT_EVENTID:
2592 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
2593 ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
2594 break;
2595 case WMI_NEIGHBOR_REPORT_EVENTID:
2596 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
2597 break;
2598 case WMI_SCAN_COMPLETE_EVENTID:
2599 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
2600 ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len);
2601 break;
2602 case WMI_CMDERROR_EVENTID:
2603 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
2604 ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
2605 break;
2606 case WMI_REPORT_STATISTICS_EVENTID:
2607 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
2608 ret = ath6kl_wmi_stats_event_rx(wmi, datap, len);
2609 break;
2610 case WMI_RSSI_THRESHOLD_EVENTID:
2611 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
2612 ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
2613 break;
2614 case WMI_ERROR_REPORT_EVENTID:
2615 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n");
2616 break;
2617 case WMI_OPT_RX_FRAME_EVENTID:
2618 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n");
2619 ret = ath6kl_wmi_opt_frame_event_rx(wmi, datap, len);
2620 break;
2621 case WMI_REPORT_ROAM_TBL_EVENTID:
2622 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n");
2623 break;
2624 case WMI_EXTENSION_EVENTID:
2625 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
2626 ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
2627 break;
2628 case WMI_CAC_EVENTID:
2629 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
2630 ret = ath6kl_wmi_cac_event_rx(wmi, datap, len);
2631 break;
2632 case WMI_CHANNEL_CHANGE_EVENTID:
2633 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
2634 break;
2635 case WMI_REPORT_ROAM_DATA_EVENTID:
2636 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n");
2637 break;
2638 case WMI_GET_FIXRATES_CMDID:
2639 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");
2640 ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len);
2641 break;
2642 case WMI_TX_RETRY_ERR_EVENTID:
2643 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n");
2644 break;
2645 case WMI_SNR_THRESHOLD_EVENTID:
2646 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n");
2647 ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len);
2648 break;
2649 case WMI_LQ_THRESHOLD_EVENTID:
2650 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n");
2651 break;
2652 case WMI_APLIST_EVENTID:
2653 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n");
2654 ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len);
2655 break;
2656 case WMI_GET_KEEPALIVE_CMDID:
2657 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n");
2658 ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len);
2659 break;
2660 case WMI_GET_WOW_LIST_EVENTID:
2661 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n");
2662 ret = ath6kl_wmi_get_wow_list_event_rx(wmi, datap, len);
2663 break;
2664 case WMI_GET_PMKID_LIST_EVENTID:
2665 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
2666 ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
2667 break;
2668 case WMI_PSPOLL_EVENTID:
2669 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
2670 ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len);
2671 break;
2672 case WMI_DTIMEXPIRY_EVENTID:
2673 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
2674 ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len);
2675 break;
2676 case WMI_SET_PARAMS_REPLY_EVENTID:
2677 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
2678 break;
2679 case WMI_ADDBA_REQ_EVENTID:
2680 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
2681 ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len);
2682 break;
2683 case WMI_ADDBA_RESP_EVENTID:
2684 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
2685 break;
2686 case WMI_DELBA_REQ_EVENTID:
2687 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
2688 ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len);
2689 break;
2690 case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
2691 ath6kl_dbg(ATH6KL_DBG_WMI,
2692 "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
2693 break;
2694 case WMI_REPORT_BTCOEX_STATS_EVENTID:
2695 ath6kl_dbg(ATH6KL_DBG_WMI,
2696 "WMI_REPORT_BTCOEX_STATS_EVENTID\n");
2697 break;
2698 case WMI_TX_COMPLETE_EVENTID:
2699 ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
2700 ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
2701 break;
2702 default:
2703 ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id);
2704 wmi->stat.cmd_id_err++;
2705 ret = -EINVAL;
2706 break;
2707 }
2708
2709 dev_kfree_skb(skb);
2710
2711 return ret;
2712}
2713
2714static void ath6kl_wmi_qos_state_init(struct wmi *wmi)
2715{
2716 if (!wmi)
2717 return;
2718
2719 spin_lock_bh(&wmi->lock);
2720
2721 wmi->fat_pipe_exist = 0;
2722 memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac));
2723
2724 spin_unlock_bh(&wmi->lock);
2725}
2726
Vasanthakumar Thiagarajan28657852011-07-21 12:00:49 +05302727void *ath6kl_wmi_init(struct ath6kl *dev)
Kalle Valobdcd8172011-07-18 00:22:30 +03002728{
2729 struct wmi *wmi;
2730
2731 wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);
2732 if (!wmi)
2733 return NULL;
2734
2735 spin_lock_init(&wmi->lock);
2736
2737 wmi->parent_dev = dev;
2738
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +05302739 wlan_node_table_init(wmi, &dev->scan_table);
Kalle Valobdcd8172011-07-18 00:22:30 +03002740 ath6kl_wmi_qos_state_init(wmi);
2741
2742 wmi->pwr_mode = REC_POWER;
2743 wmi->phy_mode = WMI_11G_MODE;
2744
2745 wmi->pair_crypto_type = NONE_CRYPT;
2746 wmi->grp_crypto_type = NONE_CRYPT;
2747
2748 wmi->ht_allowed[A_BAND_24GHZ] = 1;
2749 wmi->ht_allowed[A_BAND_5GHZ] = 1;
2750
2751 return wmi;
2752}
2753
2754void ath6kl_wmi_shutdown(struct wmi *wmi)
2755{
2756 if (!wmi)
2757 return;
2758
Vasanthakumar Thiagarajan7c3075e2011-07-21 13:38:33 +05302759 wlan_node_table_cleanup(&wmi->parent_dev->scan_table);
Kalle Valobdcd8172011-07-18 00:22:30 +03002760 kfree(wmi);
2761}