Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2004-2011 Atheros Communications Inc.
0003  * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
0004  *
0005  * Permission to use, copy, modify, and/or distribute this software for any
0006  * purpose with or without fee is hereby granted, provided that the above
0007  * copyright notice and this permission notice appear in all copies.
0008  *
0009  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0010  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0011  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0012  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0015  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0016  */
0017 
0018 #include <linux/ip.h>
0019 #include <linux/in.h>
0020 #include "core.h"
0021 #include "debug.h"
0022 #include "testmode.h"
0023 #include "trace.h"
0024 #include "../regd.h"
0025 #include "../regd_common.h"
0026 
0027 static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx);
0028 
0029 static const s32 wmi_rate_tbl[][2] = {
0030     /* {W/O SGI, with SGI} */
0031     {1000, 1000},
0032     {2000, 2000},
0033     {5500, 5500},
0034     {11000, 11000},
0035     {6000, 6000},
0036     {9000, 9000},
0037     {12000, 12000},
0038     {18000, 18000},
0039     {24000, 24000},
0040     {36000, 36000},
0041     {48000, 48000},
0042     {54000, 54000},
0043     {6500, 7200},
0044     {13000, 14400},
0045     {19500, 21700},
0046     {26000, 28900},
0047     {39000, 43300},
0048     {52000, 57800},
0049     {58500, 65000},
0050     {65000, 72200},
0051     {13500, 15000},
0052     {27000, 30000},
0053     {40500, 45000},
0054     {54000, 60000},
0055     {81000, 90000},
0056     {108000, 120000},
0057     {121500, 135000},
0058     {135000, 150000},
0059     {0, 0}
0060 };
0061 
0062 static const s32 wmi_rate_tbl_mcs15[][2] = {
0063     /* {W/O SGI, with SGI} */
0064     {1000, 1000},
0065     {2000, 2000},
0066     {5500, 5500},
0067     {11000, 11000},
0068     {6000, 6000},
0069     {9000, 9000},
0070     {12000, 12000},
0071     {18000, 18000},
0072     {24000, 24000},
0073     {36000, 36000},
0074     {48000, 48000},
0075     {54000, 54000},
0076     {6500, 7200},     /* HT 20, MCS 0 */
0077     {13000, 14400},
0078     {19500, 21700},
0079     {26000, 28900},
0080     {39000, 43300},
0081     {52000, 57800},
0082     {58500, 65000},
0083     {65000, 72200},
0084     {13000, 14400},   /* HT 20, MCS 8 */
0085     {26000, 28900},
0086     {39000, 43300},
0087     {52000, 57800},
0088     {78000, 86700},
0089     {104000, 115600},
0090     {117000, 130000},
0091     {130000, 144400}, /* HT 20, MCS 15 */
0092     {13500, 15000},   /*HT 40, MCS 0 */
0093     {27000, 30000},
0094     {40500, 45000},
0095     {54000, 60000},
0096     {81000, 90000},
0097     {108000, 120000},
0098     {121500, 135000},
0099     {135000, 150000},
0100     {27000, 30000},   /*HT 40, MCS 8 */
0101     {54000, 60000},
0102     {81000, 90000},
0103     {108000, 120000},
0104     {162000, 180000},
0105     {216000, 240000},
0106     {243000, 270000},
0107     {270000, 300000}, /*HT 40, MCS 15 */
0108     {0, 0}
0109 };
0110 
0111 /* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */
0112 static const u8 up_to_ac[] = {
0113     WMM_AC_BE,
0114     WMM_AC_BK,
0115     WMM_AC_BK,
0116     WMM_AC_BE,
0117     WMM_AC_VI,
0118     WMM_AC_VI,
0119     WMM_AC_VO,
0120     WMM_AC_VO,
0121 };
0122 
0123 void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id)
0124 {
0125     if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX))
0126         return;
0127 
0128     wmi->ep_id = ep_id;
0129 }
0130 
0131 enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)
0132 {
0133     return wmi->ep_id;
0134 }
0135 
0136 struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
0137 {
0138     struct ath6kl_vif *vif, *found = NULL;
0139 
0140     if (WARN_ON(if_idx > (ar->vif_max - 1)))
0141         return NULL;
0142 
0143     /* FIXME: Locking */
0144     spin_lock_bh(&ar->list_lock);
0145     list_for_each_entry(vif, &ar->vif_list, list) {
0146         if (vif->fw_vif_idx == if_idx) {
0147             found = vif;
0148             break;
0149         }
0150     }
0151     spin_unlock_bh(&ar->list_lock);
0152 
0153     return found;
0154 }
0155 
0156 /*  Performs DIX to 802.3 encapsulation for transmit packets.
0157  *  Assumes the entire DIX header is contiguous and that there is
0158  *  enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.
0159  */
0160 int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
0161 {
0162     struct ath6kl_llc_snap_hdr *llc_hdr;
0163     struct ethhdr *eth_hdr;
0164     size_t new_len;
0165     __be16 type;
0166     u8 *datap;
0167     u16 size;
0168 
0169     if (WARN_ON(skb == NULL))
0170         return -EINVAL;
0171 
0172     size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr);
0173     if (skb_headroom(skb) < size)
0174         return -ENOMEM;
0175 
0176     eth_hdr = (struct ethhdr *) skb->data;
0177     type = eth_hdr->h_proto;
0178 
0179     if (!is_ethertype(be16_to_cpu(type))) {
0180         ath6kl_dbg(ATH6KL_DBG_WMI,
0181                "%s: pkt is already in 802.3 format\n", __func__);
0182         return 0;
0183     }
0184 
0185     new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr);
0186 
0187     skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr));
0188     datap = skb->data;
0189 
0190     eth_hdr->h_proto = cpu_to_be16(new_len);
0191 
0192     memcpy(datap, eth_hdr, sizeof(*eth_hdr));
0193 
0194     llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr));
0195     llc_hdr->dsap = 0xAA;
0196     llc_hdr->ssap = 0xAA;
0197     llc_hdr->cntl = 0x03;
0198     llc_hdr->org_code[0] = 0x0;
0199     llc_hdr->org_code[1] = 0x0;
0200     llc_hdr->org_code[2] = 0x0;
0201     llc_hdr->eth_type = type;
0202 
0203     return 0;
0204 }
0205 
0206 static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
0207                    u8 *version, void *tx_meta_info)
0208 {
0209     struct wmi_tx_meta_v1 *v1;
0210     struct wmi_tx_meta_v2 *v2;
0211 
0212     if (WARN_ON(skb == NULL || version == NULL))
0213         return -EINVAL;
0214 
0215     switch (*version) {
0216     case WMI_META_VERSION_1:
0217         skb_push(skb, WMI_MAX_TX_META_SZ);
0218         v1 = (struct wmi_tx_meta_v1 *) skb->data;
0219         v1->pkt_id = 0;
0220         v1->rate_plcy_id = 0;
0221         *version = WMI_META_VERSION_1;
0222         break;
0223     case WMI_META_VERSION_2:
0224         skb_push(skb, WMI_MAX_TX_META_SZ);
0225         v2 = (struct wmi_tx_meta_v2 *) skb->data;
0226         memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info,
0227                sizeof(struct wmi_tx_meta_v2));
0228         break;
0229     }
0230 
0231     return 0;
0232 }
0233 
0234 int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
0235                 u8 msg_type, u32 flags,
0236                 enum wmi_data_hdr_data_type data_type,
0237                 u8 meta_ver, void *tx_meta_info, u8 if_idx)
0238 {
0239     struct wmi_data_hdr *data_hdr;
0240     int ret;
0241 
0242     if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))
0243         return -EINVAL;
0244 
0245     if (tx_meta_info) {
0246         ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info);
0247         if (ret)
0248             return ret;
0249     }
0250 
0251     skb_push(skb, sizeof(struct wmi_data_hdr));
0252 
0253     data_hdr = (struct wmi_data_hdr *)skb->data;
0254     memset(data_hdr, 0, sizeof(struct wmi_data_hdr));
0255 
0256     data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
0257     data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
0258 
0259     if (flags & WMI_DATA_HDR_FLAGS_MORE)
0260         data_hdr->info |= WMI_DATA_HDR_MORE;
0261 
0262     if (flags & WMI_DATA_HDR_FLAGS_EOSP)
0263         data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP);
0264 
0265     data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
0266     data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
0267 
0268     return 0;
0269 }
0270 
0271 u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
0272 {
0273     struct iphdr *ip_hdr = (struct iphdr *) pkt;
0274     u8 ip_pri;
0275 
0276     /*
0277      * Determine IPTOS priority
0278      *
0279      * IP-TOS - 8bits
0280      *          : DSCP(6-bits) ECN(2-bits)
0281      *          : DSCP - P2 P1 P0 X X X
0282      * where (P2 P1 P0) form 802.1D
0283      */
0284     ip_pri = ip_hdr->tos >> 5;
0285     ip_pri &= 0x7;
0286 
0287     if ((layer2_pri & 0x7) > ip_pri)
0288         return (u8) layer2_pri & 0x7;
0289     else
0290         return ip_pri;
0291 }
0292 
0293 u8 ath6kl_wmi_get_traffic_class(u8 user_priority)
0294 {
0295     return  up_to_ac[user_priority & 0x7];
0296 }
0297 
0298 int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
0299                        struct sk_buff *skb,
0300                        u32 layer2_priority, bool wmm_enabled,
0301                        u8 *ac)
0302 {
0303     struct wmi_data_hdr *data_hdr;
0304     struct ath6kl_llc_snap_hdr *llc_hdr;
0305     struct wmi_create_pstream_cmd cmd;
0306     u32 meta_size, hdr_size;
0307     u16 ip_type = IP_ETHERTYPE;
0308     u8 stream_exist, usr_pri;
0309     u8 traffic_class = WMM_AC_BE;
0310     u8 *datap;
0311 
0312     if (WARN_ON(skb == NULL))
0313         return -EINVAL;
0314 
0315     datap = skb->data;
0316     data_hdr = (struct wmi_data_hdr *) datap;
0317 
0318     meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) &
0319              WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0;
0320 
0321     if (!wmm_enabled) {
0322         /* If WMM is disabled all traffic goes as BE traffic */
0323         usr_pri = 0;
0324     } else {
0325         hdr_size = sizeof(struct ethhdr);
0326 
0327         llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap +
0328                              sizeof(struct
0329                                 wmi_data_hdr) +
0330                              meta_size + hdr_size);
0331 
0332         if (llc_hdr->eth_type == htons(ip_type)) {
0333             /*
0334              * Extract the endpoint info from the TOS field
0335              * in the IP header.
0336              */
0337             usr_pri =
0338                ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +
0339                     sizeof(struct ath6kl_llc_snap_hdr),
0340                     layer2_priority);
0341         } else {
0342             usr_pri = layer2_priority & 0x7;
0343         }
0344 
0345         /*
0346          * Queue the EAPOL frames in the same WMM_AC_VO queue
0347          * as that of management frames.
0348          */
0349         if (skb->protocol == cpu_to_be16(ETH_P_PAE))
0350             usr_pri = WMI_VOICE_USER_PRIORITY;
0351     }
0352 
0353     /*
0354      * workaround for WMM S5
0355      *
0356      * FIXME: wmi->traffic_class is always 100 so this test doesn't
0357      * make sense
0358      */
0359     if ((wmi->traffic_class == WMM_AC_VI) &&
0360         ((usr_pri == 5) || (usr_pri == 4)))
0361         usr_pri = 1;
0362 
0363     /* Convert user priority to traffic class */
0364     traffic_class = up_to_ac[usr_pri & 0x7];
0365 
0366     wmi_data_hdr_set_up(data_hdr, usr_pri);
0367 
0368     spin_lock_bh(&wmi->lock);
0369     stream_exist = wmi->fat_pipe_exist;
0370     spin_unlock_bh(&wmi->lock);
0371 
0372     if (!(stream_exist & (1 << traffic_class))) {
0373         memset(&cmd, 0, sizeof(cmd));
0374         cmd.traffic_class = traffic_class;
0375         cmd.user_pri = usr_pri;
0376         cmd.inactivity_int =
0377             cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT);
0378         /* Implicit streams are created with TSID 0xFF */
0379         cmd.tsid = WMI_IMPLICIT_PSTREAM;
0380         ath6kl_wmi_create_pstream_cmd(wmi, if_idx, &cmd);
0381     }
0382 
0383     *ac = traffic_class;
0384 
0385     return 0;
0386 }
0387 
0388 int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)
0389 {
0390     struct ieee80211_hdr_3addr *pwh, wh;
0391     struct ath6kl_llc_snap_hdr *llc_hdr;
0392     struct ethhdr eth_hdr;
0393     u32 hdr_size;
0394     u8 *datap;
0395     __le16 sub_type;
0396 
0397     if (WARN_ON(skb == NULL))
0398         return -EINVAL;
0399 
0400     datap = skb->data;
0401     pwh = (struct ieee80211_hdr_3addr *) datap;
0402 
0403     sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
0404 
0405     memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr));
0406 
0407     /* Strip off the 802.11 header */
0408     if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
0409         hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),
0410                    sizeof(u32));
0411         skb_pull(skb, hdr_size);
0412     } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) {
0413         skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));
0414     }
0415 
0416     datap = skb->data;
0417     llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);
0418 
0419     memset(&eth_hdr, 0, sizeof(eth_hdr));
0420     eth_hdr.h_proto = llc_hdr->eth_type;
0421 
0422     switch ((le16_to_cpu(wh.frame_control)) &
0423         (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
0424     case IEEE80211_FCTL_TODS:
0425         memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN);
0426         memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
0427         break;
0428     case IEEE80211_FCTL_FROMDS:
0429         memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
0430         memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN);
0431         break;
0432     case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
0433         break;
0434     default:
0435         memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);
0436         memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);
0437         break;
0438     }
0439 
0440     skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
0441     skb_push(skb, sizeof(eth_hdr));
0442 
0443     datap = skb->data;
0444 
0445     memcpy(datap, &eth_hdr, sizeof(eth_hdr));
0446 
0447     return 0;
0448 }
0449 
0450 /*
0451  * Performs 802.3 to DIX encapsulation for received packets.
0452  * Assumes the entire 802.3 header is contiguous.
0453  */
0454 int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)
0455 {
0456     struct ath6kl_llc_snap_hdr *llc_hdr;
0457     struct ethhdr eth_hdr;
0458     u8 *datap;
0459 
0460     if (WARN_ON(skb == NULL))
0461         return -EINVAL;
0462 
0463     datap = skb->data;
0464 
0465     memcpy(&eth_hdr, datap, sizeof(eth_hdr));
0466 
0467     llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr));
0468     eth_hdr.h_proto = llc_hdr->eth_type;
0469 
0470     skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));
0471     datap = skb->data;
0472 
0473     memcpy(datap, &eth_hdr, sizeof(eth_hdr));
0474 
0475     return 0;
0476 }
0477 
0478 static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
0479 {
0480     struct tx_complete_msg_v1 *msg_v1;
0481     struct wmi_tx_complete_event *evt;
0482     int index;
0483     u16 size;
0484 
0485     evt = (struct wmi_tx_complete_event *) datap;
0486 
0487     ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
0488            evt->num_msg, evt->msg_len, evt->msg_type);
0489 
0490     for (index = 0; index < evt->num_msg; index++) {
0491         size = sizeof(struct wmi_tx_complete_event) +
0492             (index * sizeof(struct tx_complete_msg_v1));
0493         msg_v1 = (struct tx_complete_msg_v1 *)(datap + size);
0494 
0495         ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n",
0496                msg_v1->status, msg_v1->pkt_id,
0497                msg_v1->rate_idx, msg_v1->ack_failures);
0498     }
0499 
0500     return 0;
0501 }
0502 
0503 static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
0504                           int len, struct ath6kl_vif *vif)
0505 {
0506     struct wmi_remain_on_chnl_event *ev;
0507     u32 freq;
0508     u32 dur;
0509     struct ieee80211_channel *chan;
0510     struct ath6kl *ar = wmi->parent_dev;
0511     u32 id;
0512 
0513     if (len < sizeof(*ev))
0514         return -EINVAL;
0515 
0516     ev = (struct wmi_remain_on_chnl_event *) datap;
0517     freq = le32_to_cpu(ev->freq);
0518     dur = le32_to_cpu(ev->duration);
0519     ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n",
0520            freq, dur);
0521     chan = ieee80211_get_channel(ar->wiphy, freq);
0522     if (!chan) {
0523         ath6kl_dbg(ATH6KL_DBG_WMI,
0524                "remain_on_chnl: Unknown channel (freq=%u)\n",
0525                freq);
0526         return -EINVAL;
0527     }
0528     id = vif->last_roc_id;
0529     cfg80211_ready_on_channel(&vif->wdev, id, chan,
0530                   dur, GFP_ATOMIC);
0531 
0532     return 0;
0533 }
0534 
0535 static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
0536                              u8 *datap, int len,
0537                              struct ath6kl_vif *vif)
0538 {
0539     struct wmi_cancel_remain_on_chnl_event *ev;
0540     u32 freq;
0541     u32 dur;
0542     struct ieee80211_channel *chan;
0543     struct ath6kl *ar = wmi->parent_dev;
0544     u32 id;
0545 
0546     if (len < sizeof(*ev))
0547         return -EINVAL;
0548 
0549     ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
0550     freq = le32_to_cpu(ev->freq);
0551     dur = le32_to_cpu(ev->duration);
0552     ath6kl_dbg(ATH6KL_DBG_WMI,
0553            "cancel_remain_on_chnl: freq=%u dur=%u status=%u\n",
0554            freq, dur, ev->status);
0555     chan = ieee80211_get_channel(ar->wiphy, freq);
0556     if (!chan) {
0557         ath6kl_dbg(ATH6KL_DBG_WMI,
0558                "cancel_remain_on_chnl: Unknown channel (freq=%u)\n",
0559                freq);
0560         return -EINVAL;
0561     }
0562     if (vif->last_cancel_roc_id &&
0563         vif->last_cancel_roc_id + 1 == vif->last_roc_id)
0564         id = vif->last_cancel_roc_id; /* event for cancel command */
0565     else
0566         id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
0567     vif->last_cancel_roc_id = 0;
0568     cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC);
0569 
0570     return 0;
0571 }
0572 
0573 static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len,
0574                      struct ath6kl_vif *vif)
0575 {
0576     struct wmi_tx_status_event *ev;
0577     u32 id;
0578 
0579     if (len < sizeof(*ev))
0580         return -EINVAL;
0581 
0582     ev = (struct wmi_tx_status_event *) datap;
0583     id = le32_to_cpu(ev->id);
0584     ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
0585            id, ev->ack_status);
0586     if (wmi->last_mgmt_tx_frame) {
0587         cfg80211_mgmt_tx_status(&vif->wdev, id,
0588                     wmi->last_mgmt_tx_frame,
0589                     wmi->last_mgmt_tx_frame_len,
0590                     !!ev->ack_status, GFP_ATOMIC);
0591         kfree(wmi->last_mgmt_tx_frame);
0592         wmi->last_mgmt_tx_frame = NULL;
0593         wmi->last_mgmt_tx_frame_len = 0;
0594     }
0595 
0596     return 0;
0597 }
0598 
0599 static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
0600                         struct ath6kl_vif *vif)
0601 {
0602     struct wmi_p2p_rx_probe_req_event *ev;
0603     u32 freq;
0604     u16 dlen;
0605 
0606     if (len < sizeof(*ev))
0607         return -EINVAL;
0608 
0609     ev = (struct wmi_p2p_rx_probe_req_event *) datap;
0610     freq = le32_to_cpu(ev->freq);
0611     dlen = le16_to_cpu(ev->len);
0612     if (datap + len < ev->data + dlen) {
0613         ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n",
0614                len, dlen);
0615         return -EINVAL;
0616     }
0617     ath6kl_dbg(ATH6KL_DBG_WMI,
0618            "rx_probe_req: len=%u freq=%u probe_req_report=%d\n",
0619            dlen, freq, vif->probe_req_report);
0620 
0621     if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
0622         cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
0623 
0624     return 0;
0625 }
0626 
0627 static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)
0628 {
0629     struct wmi_p2p_capabilities_event *ev;
0630     u16 dlen;
0631 
0632     if (len < sizeof(*ev))
0633         return -EINVAL;
0634 
0635     ev = (struct wmi_p2p_capabilities_event *) datap;
0636     dlen = le16_to_cpu(ev->len);
0637     ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen);
0638 
0639     return 0;
0640 }
0641 
0642 static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
0643                      struct ath6kl_vif *vif)
0644 {
0645     struct wmi_rx_action_event *ev;
0646     u32 freq;
0647     u16 dlen;
0648 
0649     if (len < sizeof(*ev))
0650         return -EINVAL;
0651 
0652     ev = (struct wmi_rx_action_event *) datap;
0653     freq = le32_to_cpu(ev->freq);
0654     dlen = le16_to_cpu(ev->len);
0655     if (datap + len < ev->data + dlen) {
0656         ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n",
0657                len, dlen);
0658         return -EINVAL;
0659     }
0660     ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
0661     cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
0662 
0663     return 0;
0664 }
0665 
0666 static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len)
0667 {
0668     struct wmi_p2p_info_event *ev;
0669     u32 flags;
0670     u16 dlen;
0671 
0672     if (len < sizeof(*ev))
0673         return -EINVAL;
0674 
0675     ev = (struct wmi_p2p_info_event *) datap;
0676     flags = le32_to_cpu(ev->info_req_flags);
0677     dlen = le16_to_cpu(ev->len);
0678     ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen);
0679 
0680     if (flags & P2P_FLAG_CAPABILITIES_REQ) {
0681         struct wmi_p2p_capabilities *cap;
0682         if (dlen < sizeof(*cap))
0683             return -EINVAL;
0684         cap = (struct wmi_p2p_capabilities *) ev->data;
0685         ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n",
0686                cap->go_power_save);
0687     }
0688 
0689     if (flags & P2P_FLAG_MACADDR_REQ) {
0690         struct wmi_p2p_macaddr *mac;
0691         if (dlen < sizeof(*mac))
0692             return -EINVAL;
0693         mac = (struct wmi_p2p_macaddr *) ev->data;
0694         ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n",
0695                mac->mac_addr);
0696     }
0697 
0698     if (flags & P2P_FLAG_HMODEL_REQ) {
0699         struct wmi_p2p_hmodel *mod;
0700         if (dlen < sizeof(*mod))
0701             return -EINVAL;
0702         mod = (struct wmi_p2p_hmodel *) ev->data;
0703         ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n",
0704                mod->p2p_model,
0705                mod->p2p_model ? "host" : "firmware");
0706     }
0707     return 0;
0708 }
0709 
0710 static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)
0711 {
0712     struct sk_buff *skb;
0713 
0714     skb = ath6kl_buf_alloc(size);
0715     if (!skb)
0716         return NULL;
0717 
0718     skb_put(skb, size);
0719     if (size)
0720         memset(skb->data, 0, size);
0721 
0722     return skb;
0723 }
0724 
0725 /* Send a "simple" wmi command -- one with no arguments */
0726 static int ath6kl_wmi_simple_cmd(struct wmi *wmi, u8 if_idx,
0727                  enum wmi_cmd_id cmd_id)
0728 {
0729     struct sk_buff *skb;
0730     int ret;
0731 
0732     skb = ath6kl_wmi_get_new_buf(0);
0733     if (!skb)
0734         return -ENOMEM;
0735 
0736     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, cmd_id, NO_SYNC_WMIFLAG);
0737 
0738     return ret;
0739 }
0740 
0741 static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
0742 {
0743     struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap;
0744 
0745     if (len < sizeof(struct wmi_ready_event_2))
0746         return -EINVAL;
0747 
0748     ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
0749                le32_to_cpu(ev->sw_version),
0750                le32_to_cpu(ev->abi_version), ev->phy_cap);
0751 
0752     return 0;
0753 }
0754 
0755 /*
0756  * Mechanism to modify the roaming behavior in the firmware. The lower rssi
0757  * at which the station has to roam can be passed with
0758  * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level
0759  * in dBm.
0760  */
0761 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi)
0762 {
0763     struct sk_buff *skb;
0764     struct roam_ctrl_cmd *cmd;
0765 
0766     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
0767     if (!skb)
0768         return -ENOMEM;
0769 
0770     cmd = (struct roam_ctrl_cmd *) skb->data;
0771 
0772     cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD);
0773     cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi +
0774                                DEF_SCAN_FOR_ROAM_INTVL);
0775     cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi);
0776     cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR;
0777     cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS;
0778 
0779     return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
0780                 NO_SYNC_WMIFLAG);
0781 }
0782 
0783 int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)
0784 {
0785     struct sk_buff *skb;
0786     struct roam_ctrl_cmd *cmd;
0787 
0788     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
0789     if (!skb)
0790         return -ENOMEM;
0791 
0792     cmd = (struct roam_ctrl_cmd *) skb->data;
0793 
0794     memcpy(cmd->info.bssid, bssid, ETH_ALEN);
0795     cmd->roam_ctrl = WMI_FORCE_ROAM;
0796 
0797     ath6kl_dbg(ATH6KL_DBG_WMI, "force roam to %pM\n", bssid);
0798     return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
0799                    NO_SYNC_WMIFLAG);
0800 }
0801 
0802 int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,
0803                        u32 beacon_intvl)
0804 {
0805     struct sk_buff *skb;
0806     struct set_beacon_int_cmd *cmd;
0807 
0808     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
0809     if (!skb)
0810         return -ENOMEM;
0811 
0812     cmd = (struct set_beacon_int_cmd *) skb->data;
0813 
0814     cmd->beacon_intvl = cpu_to_le32(beacon_intvl);
0815     return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
0816                    WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG);
0817 }
0818 
0819 int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)
0820 {
0821     struct sk_buff *skb;
0822     struct set_dtim_cmd *cmd;
0823 
0824     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
0825     if (!skb)
0826         return -ENOMEM;
0827 
0828     cmd = (struct set_dtim_cmd *) skb->data;
0829 
0830     cmd->dtim_period = cpu_to_le32(dtim_period);
0831     return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
0832                    WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);
0833 }
0834 
0835 int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)
0836 {
0837     struct sk_buff *skb;
0838     struct roam_ctrl_cmd *cmd;
0839 
0840     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
0841     if (!skb)
0842         return -ENOMEM;
0843 
0844     cmd = (struct roam_ctrl_cmd *) skb->data;
0845 
0846     cmd->info.roam_mode = mode;
0847     cmd->roam_ctrl = WMI_SET_ROAM_MODE;
0848 
0849     ath6kl_dbg(ATH6KL_DBG_WMI, "set roam mode %d\n", mode);
0850     return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,
0851                    NO_SYNC_WMIFLAG);
0852 }
0853 
0854 static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
0855                        struct ath6kl_vif *vif)
0856 {
0857     struct wmi_connect_event *ev;
0858     u8 *pie, *peie;
0859 
0860     if (len < sizeof(struct wmi_connect_event))
0861         return -EINVAL;
0862 
0863     ev = (struct wmi_connect_event *) datap;
0864 
0865     if (vif->nw_type == AP_NETWORK) {
0866         /* AP mode start/STA connected event */
0867         struct net_device *dev = vif->ndev;
0868         if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {
0869             ath6kl_dbg(ATH6KL_DBG_WMI,
0870                    "%s: freq %d bssid %pM (AP started)\n",
0871                    __func__, le16_to_cpu(ev->u.ap_bss.ch),
0872                    ev->u.ap_bss.bssid);
0873             ath6kl_connect_ap_mode_bss(
0874                 vif, le16_to_cpu(ev->u.ap_bss.ch));
0875         } else {
0876             ath6kl_dbg(ATH6KL_DBG_WMI,
0877                    "%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n",
0878                    __func__, ev->u.ap_sta.aid,
0879                    ev->u.ap_sta.mac_addr,
0880                    ev->u.ap_sta.auth,
0881                    ev->u.ap_sta.keymgmt,
0882                    le16_to_cpu(ev->u.ap_sta.cipher),
0883                    ev->u.ap_sta.apsd_info);
0884 
0885             ath6kl_connect_ap_mode_sta(
0886                 vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,
0887                 ev->u.ap_sta.keymgmt,
0888                 le16_to_cpu(ev->u.ap_sta.cipher),
0889                 ev->u.ap_sta.auth, ev->assoc_req_len,
0890                 ev->assoc_info + ev->beacon_ie_len,
0891                 ev->u.ap_sta.apsd_info);
0892         }
0893         return 0;
0894     }
0895 
0896     /* STA/IBSS mode connection event */
0897 
0898     ath6kl_dbg(ATH6KL_DBG_WMI,
0899            "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n",
0900            le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid,
0901            le16_to_cpu(ev->u.sta.listen_intvl),
0902            le16_to_cpu(ev->u.sta.beacon_intvl),
0903            le32_to_cpu(ev->u.sta.nw_type));
0904 
0905     /* Start of assoc rsp IEs */
0906     pie = ev->assoc_info + ev->beacon_ie_len +
0907           ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */
0908 
0909     /* End of assoc rsp IEs */
0910     peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len +
0911         ev->assoc_resp_len;
0912 
0913     while (pie < peie) {
0914         switch (*pie) {
0915         case WLAN_EID_VENDOR_SPECIFIC:
0916             if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
0917                 pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
0918                 /* WMM OUT (00:50:F2) */
0919                 if (pie[1] > 5 &&
0920                     pie[6] == WMM_PARAM_OUI_SUBTYPE)
0921                     wmi->is_wmm_enabled = true;
0922             }
0923             break;
0924         }
0925 
0926         if (wmi->is_wmm_enabled)
0927             break;
0928 
0929         pie += pie[1] + 2;
0930     }
0931 
0932     ath6kl_connect_event(vif, le16_to_cpu(ev->u.sta.ch),
0933                  ev->u.sta.bssid,
0934                  le16_to_cpu(ev->u.sta.listen_intvl),
0935                  le16_to_cpu(ev->u.sta.beacon_intvl),
0936                  le32_to_cpu(ev->u.sta.nw_type),
0937                  ev->beacon_ie_len, ev->assoc_req_len,
0938                  ev->assoc_resp_len, ev->assoc_info);
0939 
0940     return 0;
0941 }
0942 
0943 static struct country_code_to_enum_rd *
0944 ath6kl_regd_find_country(u16 countryCode)
0945 {
0946     int i;
0947 
0948     for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
0949         if (allCountries[i].countryCode == countryCode)
0950             return &allCountries[i];
0951     }
0952 
0953     return NULL;
0954 }
0955 
0956 static struct reg_dmn_pair_mapping *
0957 ath6kl_get_regpair(u16 regdmn)
0958 {
0959     int i;
0960 
0961     if (regdmn == NO_ENUMRD)
0962         return NULL;
0963 
0964     for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
0965         if (regDomainPairs[i].reg_domain == regdmn)
0966             return &regDomainPairs[i];
0967     }
0968 
0969     return NULL;
0970 }
0971 
0972 static struct country_code_to_enum_rd *
0973 ath6kl_regd_find_country_by_rd(u16 regdmn)
0974 {
0975     int i;
0976 
0977     for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
0978         if (allCountries[i].regDmnEnum == regdmn)
0979             return &allCountries[i];
0980     }
0981 
0982     return NULL;
0983 }
0984 
0985 static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
0986 {
0987     struct ath6kl_wmi_regdomain *ev;
0988     struct country_code_to_enum_rd *country = NULL;
0989     struct reg_dmn_pair_mapping *regpair = NULL;
0990     char alpha2[2];
0991     u32 reg_code;
0992 
0993     ev = (struct ath6kl_wmi_regdomain *) datap;
0994     reg_code = le32_to_cpu(ev->reg_code);
0995 
0996     if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) {
0997         country = ath6kl_regd_find_country((u16) reg_code);
0998     } else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {
0999         regpair = ath6kl_get_regpair((u16) reg_code);
1000         country = ath6kl_regd_find_country_by_rd((u16) reg_code);
1001         if (regpair)
1002             ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
1003                    regpair->reg_domain);
1004         else
1005             ath6kl_warn("Regpair not found reg_code 0x%0x\n",
1006                     reg_code);
1007     }
1008 
1009     if (country && wmi->parent_dev->wiphy_registered) {
1010         alpha2[0] = country->isoName[0];
1011         alpha2[1] = country->isoName[1];
1012 
1013         regulatory_hint(wmi->parent_dev->wiphy, alpha2);
1014 
1015         ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",
1016                alpha2[0], alpha2[1]);
1017     }
1018 }
1019 
1020 static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len,
1021                       struct ath6kl_vif *vif)
1022 {
1023     struct wmi_disconnect_event *ev;
1024     wmi->traffic_class = 100;
1025 
1026     if (len < sizeof(struct wmi_disconnect_event))
1027         return -EINVAL;
1028 
1029     ev = (struct wmi_disconnect_event *) datap;
1030 
1031     ath6kl_dbg(ATH6KL_DBG_WMI,
1032            "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n",
1033            le16_to_cpu(ev->proto_reason_status), ev->bssid,
1034            ev->disconn_reason, ev->assoc_resp_len);
1035 
1036     wmi->is_wmm_enabled = false;
1037 
1038     ath6kl_disconnect_event(vif, ev->disconn_reason,
1039                 ev->bssid, ev->assoc_resp_len, ev->assoc_info,
1040                 le16_to_cpu(ev->proto_reason_status));
1041 
1042     return 0;
1043 }
1044 
1045 static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)
1046 {
1047     struct wmi_peer_node_event *ev;
1048 
1049     if (len < sizeof(struct wmi_peer_node_event))
1050         return -EINVAL;
1051 
1052     ev = (struct wmi_peer_node_event *) datap;
1053 
1054     if (ev->event_code == PEER_NODE_JOIN_EVENT)
1055         ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n",
1056                ev->peer_mac_addr);
1057     else if (ev->event_code == PEER_NODE_LEAVE_EVENT)
1058         ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n",
1059                ev->peer_mac_addr);
1060 
1061     return 0;
1062 }
1063 
1064 static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
1065                        struct ath6kl_vif *vif)
1066 {
1067     struct wmi_tkip_micerr_event *ev;
1068 
1069     if (len < sizeof(struct wmi_tkip_micerr_event))
1070         return -EINVAL;
1071 
1072     ev = (struct wmi_tkip_micerr_event *) datap;
1073 
1074     ath6kl_tkip_micerr_event(vif, ev->key_id, ev->is_mcast);
1075 
1076     return 0;
1077 }
1078 
1079 void ath6kl_wmi_sscan_timer(struct timer_list *t)
1080 {
1081     struct ath6kl_vif *vif = from_timer(vif, t, sched_scan_timer);
1082 
1083     cfg80211_sched_scan_results(vif->ar->wiphy, 0);
1084 }
1085 
1086 static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
1087                        struct ath6kl_vif *vif)
1088 {
1089     struct wmi_bss_info_hdr2 *bih;
1090     u8 *buf;
1091     struct ieee80211_channel *channel;
1092     struct ath6kl *ar = wmi->parent_dev;
1093     struct cfg80211_bss *bss;
1094 
1095     if (len <= sizeof(struct wmi_bss_info_hdr2))
1096         return -EINVAL;
1097 
1098     bih = (struct wmi_bss_info_hdr2 *) datap;
1099     buf = datap + sizeof(struct wmi_bss_info_hdr2);
1100     len -= sizeof(struct wmi_bss_info_hdr2);
1101 
1102     ath6kl_dbg(ATH6KL_DBG_WMI,
1103            "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" "
1104            "frame_type=%d\n",
1105            bih->ch, bih->snr, bih->snr - 95, bih->bssid,
1106            bih->frame_type);
1107 
1108     if (bih->frame_type != BEACON_FTYPE &&
1109         bih->frame_type != PROBERESP_FTYPE)
1110         return 0; /* Only update BSS table for now */
1111 
1112     if (bih->frame_type == BEACON_FTYPE &&
1113         test_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags)) {
1114         clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
1115         ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
1116                      NONE_BSS_FILTER, 0);
1117     }
1118 
1119     channel = ieee80211_get_channel(ar->wiphy, le16_to_cpu(bih->ch));
1120     if (channel == NULL)
1121         return -EINVAL;
1122 
1123     if (len < 8 + 2 + 2)
1124         return -EINVAL;
1125 
1126     if (bih->frame_type == BEACON_FTYPE &&
1127         test_bit(CONNECTED, &vif->flags) &&
1128         memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
1129         const u8 *tim;
1130         tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,
1131                        len - 8 - 2 - 2);
1132         if (tim && tim[1] >= 2) {
1133             vif->assoc_bss_dtim_period = tim[3];
1134             set_bit(DTIM_PERIOD_AVAIL, &vif->flags);
1135         }
1136     }
1137 
1138     bss = cfg80211_inform_bss(ar->wiphy, channel,
1139                   bih->frame_type == BEACON_FTYPE ?
1140                     CFG80211_BSS_FTYPE_BEACON :
1141                     CFG80211_BSS_FTYPE_PRESP,
1142                   bih->bssid, get_unaligned_le64((__le64 *)buf),
1143                   get_unaligned_le16(((__le16 *)buf) + 5),
1144                   get_unaligned_le16(((__le16 *)buf) + 4),
1145                   buf + 8 + 2 + 2, len - 8 - 2 - 2,
1146                   (bih->snr - 95) * 100, GFP_ATOMIC);
1147     if (bss == NULL)
1148         return -ENOMEM;
1149     cfg80211_put_bss(ar->wiphy, bss);
1150 
1151     /*
1152      * Firmware doesn't return any event when scheduled scan has
1153      * finished, so we need to use a timer to find out when there are
1154      * no more results.
1155      *
1156      * The timer is started from the first bss info received, otherwise
1157      * the timer would not ever fire if the scan interval is short
1158      * enough.
1159      */
1160     if (test_bit(SCHED_SCANNING, &vif->flags) &&
1161         !timer_pending(&vif->sched_scan_timer)) {
1162         mod_timer(&vif->sched_scan_timer, jiffies +
1163               msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
1164     }
1165 
1166     return 0;
1167 }
1168 
1169 /* Inactivity timeout of a fatpipe(pstream) at the target */
1170 static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
1171                            int len)
1172 {
1173     struct wmi_pstream_timeout_event *ev;
1174 
1175     if (len < sizeof(struct wmi_pstream_timeout_event))
1176         return -EINVAL;
1177 
1178     ev = (struct wmi_pstream_timeout_event *) datap;
1179     if (ev->traffic_class >= WMM_NUM_AC) {
1180         ath6kl_err("invalid traffic class: %d\n", ev->traffic_class);
1181         return -EINVAL;
1182     }
1183 
1184     /*
1185      * When the pstream (fat pipe == AC) timesout, it means there were
1186      * no thinStreams within this pstream & it got implicitly created
1187      * due to data flow on this AC. We start the inactivity timer only
1188      * for implicitly created pstream. Just reset the host state.
1189      */
1190     spin_lock_bh(&wmi->lock);
1191     wmi->stream_exist_for_ac[ev->traffic_class] = 0;
1192     wmi->fat_pipe_exist &= ~(1 << ev->traffic_class);
1193     spin_unlock_bh(&wmi->lock);
1194 
1195     /* Indicate inactivity to driver layer for this fatpipe (pstream) */
1196     ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false);
1197 
1198     return 0;
1199 }
1200 
1201 static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
1202 {
1203     struct wmi_bit_rate_reply *reply;
1204     u32 index;
1205 
1206     if (len < sizeof(struct wmi_bit_rate_reply))
1207         return -EINVAL;
1208 
1209     reply = (struct wmi_bit_rate_reply *) datap;
1210 
1211     ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index);
1212 
1213     if (reply->rate_index != (s8) RATE_AUTO) {
1214         index = reply->rate_index & 0x7f;
1215         if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1)))
1216             return -EINVAL;
1217     }
1218 
1219     ath6kl_wakeup_event(wmi->parent_dev);
1220 
1221     return 0;
1222 }
1223 
1224 static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len)
1225 {
1226     ath6kl_tm_rx_event(wmi->parent_dev, datap, len);
1227 
1228     return 0;
1229 }
1230 
1231 static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len)
1232 {
1233     if (len < sizeof(struct wmi_fix_rates_reply))
1234         return -EINVAL;
1235 
1236     ath6kl_wakeup_event(wmi->parent_dev);
1237 
1238     return 0;
1239 }
1240 
1241 static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len)
1242 {
1243     if (len < sizeof(struct wmi_channel_list_reply))
1244         return -EINVAL;
1245 
1246     ath6kl_wakeup_event(wmi->parent_dev);
1247 
1248     return 0;
1249 }
1250 
1251 static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len)
1252 {
1253     struct wmi_tx_pwr_reply *reply;
1254 
1255     if (len < sizeof(struct wmi_tx_pwr_reply))
1256         return -EINVAL;
1257 
1258     reply = (struct wmi_tx_pwr_reply *) datap;
1259     ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM);
1260 
1261     return 0;
1262 }
1263 
1264 static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)
1265 {
1266     if (len < sizeof(struct wmi_get_keepalive_cmd))
1267         return -EINVAL;
1268 
1269     ath6kl_wakeup_event(wmi->parent_dev);
1270 
1271     return 0;
1272 }
1273 
1274 static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len,
1275                        struct ath6kl_vif *vif)
1276 {
1277     struct wmi_scan_complete_event *ev;
1278 
1279     ev = (struct wmi_scan_complete_event *) datap;
1280 
1281     ath6kl_scan_complete_evt(vif, a_sle32_to_cpu(ev->status));
1282     wmi->is_probe_ssid = false;
1283 
1284     return 0;
1285 }
1286 
1287 static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
1288                            int len, struct ath6kl_vif *vif)
1289 {
1290     struct wmi_neighbor_report_event *ev;
1291     u8 i;
1292 
1293     if (len < sizeof(*ev))
1294         return -EINVAL;
1295     ev = (struct wmi_neighbor_report_event *) datap;
1296     if (struct_size(ev, neighbor, ev->num_neighbors) > len) {
1297         ath6kl_dbg(ATH6KL_DBG_WMI,
1298                "truncated neighbor event (num=%d len=%d)\n",
1299                ev->num_neighbors, len);
1300         return -EINVAL;
1301     }
1302     for (i = 0; i < ev->num_neighbors; i++) {
1303         ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n",
1304                i + 1, ev->num_neighbors, ev->neighbor[i].bssid,
1305                ev->neighbor[i].bss_flags);
1306         cfg80211_pmksa_candidate_notify(vif->ndev, i,
1307                         ev->neighbor[i].bssid,
1308                         !!(ev->neighbor[i].bss_flags &
1309                            WMI_PREAUTH_CAPABLE_BSS),
1310                         GFP_ATOMIC);
1311     }
1312 
1313     return 0;
1314 }
1315 
1316 /*
1317  * Target is reporting a programming error.  This is for
1318  * developer aid only.  Target only checks a few common violations
1319  * and it is responsibility of host to do all error checking.
1320  * Behavior of target after wmi error event is undefined.
1321  * A reset is recommended.
1322  */
1323 static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)
1324 {
1325     const char *type = "unknown error";
1326     struct wmi_cmd_error_event *ev;
1327     ev = (struct wmi_cmd_error_event *) datap;
1328 
1329     switch (ev->err_code) {
1330     case INVALID_PARAM:
1331         type = "invalid parameter";
1332         break;
1333     case ILLEGAL_STATE:
1334         type = "invalid state";
1335         break;
1336     case INTERNAL_ERROR:
1337         type = "internal error";
1338         break;
1339     }
1340 
1341     ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n",
1342            ev->cmd_id, type);
1343 
1344     return 0;
1345 }
1346 
1347 static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len,
1348                      struct ath6kl_vif *vif)
1349 {
1350     ath6kl_tgt_stats_event(vif, datap, len);
1351 
1352     return 0;
1353 }
1354 
1355 static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,
1356                      struct sq_threshold_params *sq_thresh,
1357                      u32 size)
1358 {
1359     u32 index;
1360     u8 threshold = (u8) sq_thresh->upper_threshold[size - 1];
1361 
1362     /* The list is already in sorted order. Get the next lower value */
1363     for (index = 0; index < size; index++) {
1364         if (rssi < sq_thresh->upper_threshold[index]) {
1365             threshold = (u8) sq_thresh->upper_threshold[index];
1366             break;
1367         }
1368     }
1369 
1370     return threshold;
1371 }
1372 
1373 static u8 ath6kl_wmi_get_lower_threshold(s16 rssi,
1374                      struct sq_threshold_params *sq_thresh,
1375                      u32 size)
1376 {
1377     u32 index;
1378     u8 threshold = (u8) sq_thresh->lower_threshold[size - 1];
1379 
1380     /* The list is already in sorted order. Get the next lower value */
1381     for (index = 0; index < size; index++) {
1382         if (rssi > sq_thresh->lower_threshold[index]) {
1383             threshold = (u8) sq_thresh->lower_threshold[index];
1384             break;
1385         }
1386     }
1387 
1388     return threshold;
1389 }
1390 
1391 static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,
1392             struct wmi_rssi_threshold_params_cmd *rssi_cmd)
1393 {
1394     struct sk_buff *skb;
1395     struct wmi_rssi_threshold_params_cmd *cmd;
1396 
1397     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1398     if (!skb)
1399         return -ENOMEM;
1400 
1401     cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data;
1402     memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd));
1403 
1404     return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID,
1405                    NO_SYNC_WMIFLAG);
1406 }
1407 
1408 static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
1409                           int len)
1410 {
1411     struct wmi_rssi_threshold_event *reply;
1412     struct wmi_rssi_threshold_params_cmd cmd;
1413     struct sq_threshold_params *sq_thresh;
1414     enum wmi_rssi_threshold_val new_threshold;
1415     u8 upper_rssi_threshold, lower_rssi_threshold;
1416     s16 rssi;
1417     int ret;
1418 
1419     if (len < sizeof(struct wmi_rssi_threshold_event))
1420         return -EINVAL;
1421 
1422     reply = (struct wmi_rssi_threshold_event *) datap;
1423     new_threshold = (enum wmi_rssi_threshold_val) reply->range;
1424     rssi = a_sle16_to_cpu(reply->rssi);
1425 
1426     sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI];
1427 
1428     /*
1429      * Identify the threshold breached and communicate that to the app.
1430      * After that install a new set of thresholds based on the signal
1431      * quality reported by the target
1432      */
1433     if (new_threshold) {
1434         /* Upper threshold breached */
1435         if (rssi < sq_thresh->upper_threshold[0]) {
1436             ath6kl_dbg(ATH6KL_DBG_WMI,
1437                    "spurious upper rssi threshold event: %d\n",
1438                    rssi);
1439         } else if ((rssi < sq_thresh->upper_threshold[1]) &&
1440                (rssi >= sq_thresh->upper_threshold[0])) {
1441             new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
1442         } else if ((rssi < sq_thresh->upper_threshold[2]) &&
1443                (rssi >= sq_thresh->upper_threshold[1])) {
1444             new_threshold = WMI_RSSI_THRESHOLD2_ABOVE;
1445         } else if ((rssi < sq_thresh->upper_threshold[3]) &&
1446                (rssi >= sq_thresh->upper_threshold[2])) {
1447             new_threshold = WMI_RSSI_THRESHOLD3_ABOVE;
1448         } else if ((rssi < sq_thresh->upper_threshold[4]) &&
1449                (rssi >= sq_thresh->upper_threshold[3])) {
1450             new_threshold = WMI_RSSI_THRESHOLD4_ABOVE;
1451         } else if ((rssi < sq_thresh->upper_threshold[5]) &&
1452                (rssi >= sq_thresh->upper_threshold[4])) {
1453             new_threshold = WMI_RSSI_THRESHOLD5_ABOVE;
1454         } else if (rssi >= sq_thresh->upper_threshold[5]) {
1455             new_threshold = WMI_RSSI_THRESHOLD6_ABOVE;
1456         }
1457     } else {
1458         /* Lower threshold breached */
1459         if (rssi > sq_thresh->lower_threshold[0]) {
1460             ath6kl_dbg(ATH6KL_DBG_WMI,
1461                    "spurious lower rssi threshold event: %d %d\n",
1462                 rssi, sq_thresh->lower_threshold[0]);
1463         } else if ((rssi > sq_thresh->lower_threshold[1]) &&
1464                (rssi <= sq_thresh->lower_threshold[0])) {
1465             new_threshold = WMI_RSSI_THRESHOLD6_BELOW;
1466         } else if ((rssi > sq_thresh->lower_threshold[2]) &&
1467                (rssi <= sq_thresh->lower_threshold[1])) {
1468             new_threshold = WMI_RSSI_THRESHOLD5_BELOW;
1469         } else if ((rssi > sq_thresh->lower_threshold[3]) &&
1470                (rssi <= sq_thresh->lower_threshold[2])) {
1471             new_threshold = WMI_RSSI_THRESHOLD4_BELOW;
1472         } else if ((rssi > sq_thresh->lower_threshold[4]) &&
1473                (rssi <= sq_thresh->lower_threshold[3])) {
1474             new_threshold = WMI_RSSI_THRESHOLD3_BELOW;
1475         } else if ((rssi > sq_thresh->lower_threshold[5]) &&
1476                (rssi <= sq_thresh->lower_threshold[4])) {
1477             new_threshold = WMI_RSSI_THRESHOLD2_BELOW;
1478         } else if (rssi <= sq_thresh->lower_threshold[5]) {
1479             new_threshold = WMI_RSSI_THRESHOLD1_BELOW;
1480         }
1481     }
1482 
1483     /* Calculate and install the next set of thresholds */
1484     lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh,
1485                        sq_thresh->lower_threshold_valid_count);
1486     upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh,
1487                        sq_thresh->upper_threshold_valid_count);
1488 
1489     /* Issue a wmi command to install the thresholds */
1490     cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold);
1491     cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold);
1492     cmd.weight = sq_thresh->weight;
1493     cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1494 
1495     ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd);
1496     if (ret) {
1497         ath6kl_err("unable to configure rssi thresholds\n");
1498         return -EIO;
1499     }
1500 
1501     return 0;
1502 }
1503 
1504 static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
1505                    struct ath6kl_vif *vif)
1506 {
1507     struct wmi_cac_event *reply;
1508     struct ieee80211_tspec_ie *ts;
1509     u16 active_tsids, tsinfo;
1510     u8 tsid, index;
1511     u8 ts_id;
1512 
1513     if (len < sizeof(struct wmi_cac_event))
1514         return -EINVAL;
1515 
1516     reply = (struct wmi_cac_event *) datap;
1517     if (reply->ac >= WMM_NUM_AC) {
1518         ath6kl_err("invalid AC: %d\n", reply->ac);
1519         return -EINVAL;
1520     }
1521 
1522     if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
1523         (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
1524         ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1525         tsinfo = le16_to_cpu(ts->tsinfo);
1526         tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1527             IEEE80211_WMM_IE_TSPEC_TID_MASK;
1528 
1529         ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,
1530                           reply->ac, tsid);
1531     } else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {
1532         /*
1533          * Following assumes that there is only one outstanding
1534          * ADDTS request when this event is received
1535          */
1536         spin_lock_bh(&wmi->lock);
1537         active_tsids = wmi->stream_exist_for_ac[reply->ac];
1538         spin_unlock_bh(&wmi->lock);
1539 
1540         for (index = 0; index < sizeof(active_tsids) * 8; index++) {
1541             if ((active_tsids >> index) & 1)
1542                 break;
1543         }
1544         if (index < (sizeof(active_tsids) * 8))
1545             ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,
1546                               reply->ac, index);
1547     }
1548 
1549     /*
1550      * Clear active tsids and Add missing handling
1551      * for delete qos stream from AP
1552      */
1553     else if (reply->cac_indication == CAC_INDICATION_DELETE) {
1554         ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);
1555         tsinfo = le16_to_cpu(ts->tsinfo);
1556         ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &
1557              IEEE80211_WMM_IE_TSPEC_TID_MASK);
1558 
1559         spin_lock_bh(&wmi->lock);
1560         wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id);
1561         active_tsids = wmi->stream_exist_for_ac[reply->ac];
1562         spin_unlock_bh(&wmi->lock);
1563 
1564         /* Indicate stream inactivity to driver layer only if all tsids
1565          * within this AC are deleted.
1566          */
1567         if (!active_tsids) {
1568             ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac,
1569                             false);
1570             wmi->fat_pipe_exist &= ~(1 << reply->ac);
1571         }
1572     }
1573 
1574     return 0;
1575 }
1576 
1577 static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,
1578                       struct ath6kl_vif *vif)
1579 {
1580     struct wmi_txe_notify_event *ev;
1581     u32 rate, pkts;
1582 
1583     if (len < sizeof(*ev))
1584         return -EINVAL;
1585 
1586     if (vif->nw_type != INFRA_NETWORK ||
1587         !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,
1588               vif->ar->fw_capabilities))
1589         return -EOPNOTSUPP;
1590 
1591     if (vif->sme_state != SME_CONNECTED)
1592         return -ENOTCONN;
1593 
1594     ev = (struct wmi_txe_notify_event *) datap;
1595     rate = le32_to_cpu(ev->rate);
1596     pkts = le32_to_cpu(ev->pkts);
1597 
1598     ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d%% pkts %d intvl %ds\n",
1599            vif->bssid, rate, pkts, vif->txe_intvl);
1600 
1601     cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts,
1602                 rate, vif->txe_intvl, GFP_KERNEL);
1603 
1604     return 0;
1605 }
1606 
1607 int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
1608                   u32 rate, u32 pkts, u32 intvl)
1609 {
1610     struct sk_buff *skb;
1611     struct wmi_txe_notify_cmd *cmd;
1612 
1613     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1614     if (!skb)
1615         return -ENOMEM;
1616 
1617     cmd = (struct wmi_txe_notify_cmd *) skb->data;
1618     cmd->rate = cpu_to_le32(rate);
1619     cmd->pkts = cpu_to_le32(pkts);
1620     cmd->intvl = cpu_to_le32(intvl);
1621 
1622     return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID,
1623                    NO_SYNC_WMIFLAG);
1624 }
1625 
1626 int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi)
1627 {
1628     struct sk_buff *skb;
1629     struct wmi_set_rssi_filter_cmd *cmd;
1630     int ret;
1631 
1632     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1633     if (!skb)
1634         return -ENOMEM;
1635 
1636     cmd = (struct wmi_set_rssi_filter_cmd *) skb->data;
1637     cmd->rssi = rssi;
1638 
1639     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID,
1640                   NO_SYNC_WMIFLAG);
1641     return ret;
1642 }
1643 
1644 static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
1645             struct wmi_snr_threshold_params_cmd *snr_cmd)
1646 {
1647     struct sk_buff *skb;
1648     struct wmi_snr_threshold_params_cmd *cmd;
1649 
1650     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
1651     if (!skb)
1652         return -ENOMEM;
1653 
1654     cmd = (struct wmi_snr_threshold_params_cmd *) skb->data;
1655     memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd));
1656 
1657     return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID,
1658                    NO_SYNC_WMIFLAG);
1659 }
1660 
1661 static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
1662                          int len)
1663 {
1664     struct wmi_snr_threshold_event *reply;
1665     struct sq_threshold_params *sq_thresh;
1666     struct wmi_snr_threshold_params_cmd cmd;
1667     enum wmi_snr_threshold_val new_threshold;
1668     u8 upper_snr_threshold, lower_snr_threshold;
1669     s16 snr;
1670     int ret;
1671 
1672     if (len < sizeof(struct wmi_snr_threshold_event))
1673         return -EINVAL;
1674 
1675     reply = (struct wmi_snr_threshold_event *) datap;
1676 
1677     new_threshold = (enum wmi_snr_threshold_val) reply->range;
1678     snr = reply->snr;
1679 
1680     sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR];
1681 
1682     /*
1683      * Identify the threshold breached and communicate that to the app.
1684      * After that install a new set of thresholds based on the signal
1685      * quality reported by the target.
1686      */
1687     if (new_threshold) {
1688         /* Upper threshold breached */
1689         if (snr < sq_thresh->upper_threshold[0]) {
1690             ath6kl_dbg(ATH6KL_DBG_WMI,
1691                    "spurious upper snr threshold event: %d\n",
1692                    snr);
1693         } else if ((snr < sq_thresh->upper_threshold[1]) &&
1694                (snr >= sq_thresh->upper_threshold[0])) {
1695             new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
1696         } else if ((snr < sq_thresh->upper_threshold[2]) &&
1697                (snr >= sq_thresh->upper_threshold[1])) {
1698             new_threshold = WMI_SNR_THRESHOLD2_ABOVE;
1699         } else if ((snr < sq_thresh->upper_threshold[3]) &&
1700                (snr >= sq_thresh->upper_threshold[2])) {
1701             new_threshold = WMI_SNR_THRESHOLD3_ABOVE;
1702         } else if (snr >= sq_thresh->upper_threshold[3]) {
1703             new_threshold = WMI_SNR_THRESHOLD4_ABOVE;
1704         }
1705     } else {
1706         /* Lower threshold breached */
1707         if (snr > sq_thresh->lower_threshold[0]) {
1708             ath6kl_dbg(ATH6KL_DBG_WMI,
1709                    "spurious lower snr threshold event: %d\n",
1710                    sq_thresh->lower_threshold[0]);
1711         } else if ((snr > sq_thresh->lower_threshold[1]) &&
1712                (snr <= sq_thresh->lower_threshold[0])) {
1713             new_threshold = WMI_SNR_THRESHOLD4_BELOW;
1714         } else if ((snr > sq_thresh->lower_threshold[2]) &&
1715                (snr <= sq_thresh->lower_threshold[1])) {
1716             new_threshold = WMI_SNR_THRESHOLD3_BELOW;
1717         } else if ((snr > sq_thresh->lower_threshold[3]) &&
1718                (snr <= sq_thresh->lower_threshold[2])) {
1719             new_threshold = WMI_SNR_THRESHOLD2_BELOW;
1720         } else if (snr <= sq_thresh->lower_threshold[3]) {
1721             new_threshold = WMI_SNR_THRESHOLD1_BELOW;
1722         }
1723     }
1724 
1725     /* Calculate and install the next set of thresholds */
1726     lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh,
1727                        sq_thresh->lower_threshold_valid_count);
1728     upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh,
1729                        sq_thresh->upper_threshold_valid_count);
1730 
1731     /* Issue a wmi command to install the thresholds */
1732     cmd.thresh_above1_val = upper_snr_threshold;
1733     cmd.thresh_below1_val = lower_snr_threshold;
1734     cmd.weight = sq_thresh->weight;
1735     cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);
1736 
1737     ath6kl_dbg(ATH6KL_DBG_WMI,
1738            "snr: %d, threshold: %d, lower: %d, upper: %d\n",
1739            snr, new_threshold,
1740            lower_snr_threshold, upper_snr_threshold);
1741 
1742     ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd);
1743     if (ret) {
1744         ath6kl_err("unable to configure snr threshold\n");
1745         return -EIO;
1746     }
1747 
1748     return 0;
1749 }
1750 
1751 static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)
1752 {
1753     struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap;
1754     struct wmi_ap_info_v1 *ap_info_v1;
1755     u8 index;
1756 
1757     if (len < sizeof(struct wmi_aplist_event) ||
1758         ev->ap_list_ver != APLIST_VER1)
1759         return -EINVAL;
1760 
1761     ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list;
1762 
1763     ath6kl_dbg(ATH6KL_DBG_WMI,
1764            "number of APs in aplist event: %d\n", ev->num_ap);
1765 
1766     if (len < struct_size(ev, ap_list, ev->num_ap))
1767         return -EINVAL;
1768 
1769     /* AP list version 1 contents */
1770     for (index = 0; index < ev->num_ap; index++) {
1771         ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n",
1772                index, ap_info_v1->bssid, ap_info_v1->channel);
1773         ap_info_v1++;
1774     }
1775 
1776     return 0;
1777 }
1778 
1779 int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
1780             enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag)
1781 {
1782     struct wmi_cmd_hdr *cmd_hdr;
1783     enum htc_endpoint_id ep_id = wmi->ep_id;
1784     int ret;
1785     u16 info1;
1786 
1787     if (WARN_ON(skb == NULL ||
1788             (if_idx > (wmi->parent_dev->vif_max - 1)))) {
1789         dev_kfree_skb(skb);
1790         return -EINVAL;
1791     }
1792 
1793     ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
1794            cmd_id, skb->len, sync_flag);
1795     ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ",
1796             skb->data, skb->len);
1797 
1798     if (sync_flag >= END_WMIFLAG) {
1799         dev_kfree_skb(skb);
1800         return -EINVAL;
1801     }
1802 
1803     if ((sync_flag == SYNC_BEFORE_WMIFLAG) ||
1804         (sync_flag == SYNC_BOTH_WMIFLAG)) {
1805         /*
1806          * Make sure all data currently queued is transmitted before
1807          * the cmd execution.  Establish a new sync point.
1808          */
1809         ath6kl_wmi_sync_point(wmi, if_idx);
1810     }
1811 
1812     skb_push(skb, sizeof(struct wmi_cmd_hdr));
1813 
1814     cmd_hdr = (struct wmi_cmd_hdr *) skb->data;
1815     cmd_hdr->cmd_id = cpu_to_le16(cmd_id);
1816     info1 = if_idx & WMI_CMD_HDR_IF_ID_MASK;
1817     cmd_hdr->info1 = cpu_to_le16(info1);
1818 
1819     /* Only for OPT_TX_CMD, use BE endpoint. */
1820     if (cmd_id == WMI_OPT_TX_FRAME_CMDID) {
1821         ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE, false,
1822                 WMI_DATA_HDR_DATA_TYPE_802_3, 0, NULL, if_idx);
1823         if (ret) {
1824             dev_kfree_skb(skb);
1825             return ret;
1826         }
1827         ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE);
1828     }
1829 
1830     ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
1831 
1832     if ((sync_flag == SYNC_AFTER_WMIFLAG) ||
1833         (sync_flag == SYNC_BOTH_WMIFLAG)) {
1834         /*
1835          * Make sure all new data queued waits for the command to
1836          * execute. Establish a new sync point.
1837          */
1838         ath6kl_wmi_sync_point(wmi, if_idx);
1839     }
1840 
1841     return 0;
1842 }
1843 
1844 int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
1845                enum network_type nw_type,
1846                enum dot11_auth_mode dot11_auth_mode,
1847                enum auth_mode auth_mode,
1848                enum ath6kl_crypto_type pairwise_crypto,
1849                u8 pairwise_crypto_len,
1850                enum ath6kl_crypto_type group_crypto,
1851                u8 group_crypto_len, int ssid_len, u8 *ssid,
1852                u8 *bssid, u16 channel, u32 ctrl_flags,
1853                u8 nw_subtype)
1854 {
1855     struct sk_buff *skb;
1856     struct wmi_connect_cmd *cc;
1857     int ret;
1858 
1859     ath6kl_dbg(ATH6KL_DBG_WMI,
1860            "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d "
1861            "type %d dot11_auth %d auth %d pairwise %d group %d\n",
1862            bssid, channel, ctrl_flags, ssid_len, nw_type,
1863            dot11_auth_mode, auth_mode, pairwise_crypto, group_crypto);
1864     ath6kl_dbg_dump(ATH6KL_DBG_WMI, NULL, "ssid ", ssid, ssid_len);
1865 
1866     wmi->traffic_class = 100;
1867 
1868     if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT))
1869         return -EINVAL;
1870 
1871     if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT))
1872         return -EINVAL;
1873 
1874     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd));
1875     if (!skb)
1876         return -ENOMEM;
1877 
1878     cc = (struct wmi_connect_cmd *) skb->data;
1879 
1880     if (ssid_len)
1881         memcpy(cc->ssid, ssid, ssid_len);
1882 
1883     cc->ssid_len = ssid_len;
1884     cc->nw_type = nw_type;
1885     cc->dot11_auth_mode = dot11_auth_mode;
1886     cc->auth_mode = auth_mode;
1887     cc->prwise_crypto_type = pairwise_crypto;
1888     cc->prwise_crypto_len = pairwise_crypto_len;
1889     cc->grp_crypto_type = group_crypto;
1890     cc->grp_crypto_len = group_crypto_len;
1891     cc->ch = cpu_to_le16(channel);
1892     cc->ctrl_flags = cpu_to_le32(ctrl_flags);
1893     cc->nw_subtype = nw_subtype;
1894 
1895     if (bssid != NULL)
1896         memcpy(cc->bssid, bssid, ETH_ALEN);
1897 
1898     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_CONNECT_CMDID,
1899                   NO_SYNC_WMIFLAG);
1900 
1901     return ret;
1902 }
1903 
1904 int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
1905                  u16 channel)
1906 {
1907     struct sk_buff *skb;
1908     struct wmi_reconnect_cmd *cc;
1909     int ret;
1910 
1911     ath6kl_dbg(ATH6KL_DBG_WMI, "wmi reconnect bssid %pM freq %d\n",
1912            bssid, channel);
1913 
1914     wmi->traffic_class = 100;
1915 
1916     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd));
1917     if (!skb)
1918         return -ENOMEM;
1919 
1920     cc = (struct wmi_reconnect_cmd *) skb->data;
1921     cc->channel = cpu_to_le16(channel);
1922 
1923     if (bssid != NULL)
1924         memcpy(cc->bssid, bssid, ETH_ALEN);
1925 
1926     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_RECONNECT_CMDID,
1927                   NO_SYNC_WMIFLAG);
1928 
1929     return ret;
1930 }
1931 
1932 int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
1933 {
1934     int ret;
1935 
1936     ath6kl_dbg(ATH6KL_DBG_WMI, "wmi disconnect\n");
1937 
1938     wmi->traffic_class = 100;
1939 
1940     /* Disconnect command does not need to do a SYNC before. */
1941     ret = ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_DISCONNECT_CMDID);
1942 
1943     return ret;
1944 }
1945 
1946 /* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
1947  * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
1948  * mgmt operations using station interface.
1949  */
1950 static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
1951                     enum wmi_scan_type scan_type,
1952                     u32 force_fgscan, u32 is_legacy,
1953                     u32 home_dwell_time,
1954                     u32 force_scan_interval,
1955                     s8 num_chan, u16 *ch_list)
1956 {
1957     struct sk_buff *skb;
1958     struct wmi_start_scan_cmd *sc;
1959     int i, ret;
1960 
1961     if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
1962         return -EINVAL;
1963 
1964     if (num_chan > WMI_MAX_CHANNELS)
1965         return -EINVAL;
1966 
1967     skb = ath6kl_wmi_get_new_buf(struct_size(sc, ch_list, num_chan));
1968     if (!skb)
1969         return -ENOMEM;
1970 
1971     sc = (struct wmi_start_scan_cmd *) skb->data;
1972     sc->scan_type = scan_type;
1973     sc->force_fg_scan = cpu_to_le32(force_fgscan);
1974     sc->is_legacy = cpu_to_le32(is_legacy);
1975     sc->home_dwell_time = cpu_to_le32(home_dwell_time);
1976     sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
1977     sc->num_ch = num_chan;
1978 
1979     for (i = 0; i < num_chan; i++)
1980         sc->ch_list[i] = cpu_to_le16(ch_list[i]);
1981 
1982     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
1983                   NO_SYNC_WMIFLAG);
1984 
1985     return ret;
1986 }
1987 
1988 /*
1989  * beginscan supports (compared to old startscan) P2P mgmt operations using
1990  * station interface, send additional information like supported rates to
1991  * advertise and xmit rates for probe requests
1992  */
1993 int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
1994                  enum wmi_scan_type scan_type,
1995                  u32 force_fgscan, u32 is_legacy,
1996                  u32 home_dwell_time, u32 force_scan_interval,
1997                  s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
1998 {
1999     struct ieee80211_supported_band *sband;
2000     struct sk_buff *skb;
2001     struct wmi_begin_scan_cmd *sc;
2002     s8 *supp_rates;
2003     int i, band, ret;
2004     struct ath6kl *ar = wmi->parent_dev;
2005     int num_rates;
2006     u32 ratemask;
2007 
2008     if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
2009               ar->fw_capabilities)) {
2010         return ath6kl_wmi_startscan_cmd(wmi, if_idx,
2011                         scan_type, force_fgscan,
2012                         is_legacy, home_dwell_time,
2013                         force_scan_interval,
2014                         num_chan, ch_list);
2015     }
2016 
2017     if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
2018         return -EINVAL;
2019 
2020     if (num_chan > WMI_MAX_CHANNELS)
2021         return -EINVAL;
2022 
2023     skb = ath6kl_wmi_get_new_buf(struct_size(sc, ch_list, num_chan));
2024     if (!skb)
2025         return -ENOMEM;
2026 
2027     sc = (struct wmi_begin_scan_cmd *) skb->data;
2028     sc->scan_type = scan_type;
2029     sc->force_fg_scan = cpu_to_le32(force_fgscan);
2030     sc->is_legacy = cpu_to_le32(is_legacy);
2031     sc->home_dwell_time = cpu_to_le32(home_dwell_time);
2032     sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
2033     sc->no_cck = cpu_to_le32(no_cck);
2034     sc->num_ch = num_chan;
2035 
2036     for (band = 0; band < NUM_NL80211_BANDS; band++) {
2037         sband = ar->wiphy->bands[band];
2038 
2039         if (!sband)
2040             continue;
2041 
2042         if (WARN_ON(band >= ATH6KL_NUM_BANDS))
2043             break;
2044 
2045         ratemask = rates[band];
2046         supp_rates = sc->supp_rates[band].rates;
2047         num_rates = 0;
2048 
2049         for (i = 0; i < sband->n_bitrates; i++) {
2050             if ((BIT(i) & ratemask) == 0)
2051                 continue; /* skip rate */
2052             supp_rates[num_rates++] =
2053                 (u8) (sband->bitrates[i].bitrate / 5);
2054         }
2055         sc->supp_rates[band].nrates = num_rates;
2056     }
2057 
2058     for (i = 0; i < num_chan; i++)
2059         sc->ch_list[i] = cpu_to_le16(ch_list[i]);
2060 
2061     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID,
2062                   NO_SYNC_WMIFLAG);
2063 
2064     return ret;
2065 }
2066 
2067 int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)
2068 {
2069     struct sk_buff *skb;
2070     struct wmi_enable_sched_scan_cmd *sc;
2071     int ret;
2072 
2073     skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
2074     if (!skb)
2075         return -ENOMEM;
2076 
2077     ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n",
2078            enable ? "enabling" : "disabling", if_idx);
2079     sc = (struct wmi_enable_sched_scan_cmd *) skb->data;
2080     sc->enable = enable ? 1 : 0;
2081 
2082     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2083                   WMI_ENABLE_SCHED_SCAN_CMDID,
2084                   NO_SYNC_WMIFLAG);
2085     return ret;
2086 }
2087 
2088 int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx,
2089                   u16 fg_start_sec,
2090                   u16 fg_end_sec, u16 bg_sec,
2091                   u16 minact_chdw_msec, u16 maxact_chdw_msec,
2092                   u16 pas_chdw_msec, u8 short_scan_ratio,
2093                   u8 scan_ctrl_flag, u32 max_dfsch_act_time,
2094                   u16 maxact_scan_per_ssid)
2095 {
2096     struct sk_buff *skb;
2097     struct wmi_scan_params_cmd *sc;
2098     int ret;
2099 
2100     skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
2101     if (!skb)
2102         return -ENOMEM;
2103 
2104     sc = (struct wmi_scan_params_cmd *) skb->data;
2105     sc->fg_start_period = cpu_to_le16(fg_start_sec);
2106     sc->fg_end_period = cpu_to_le16(fg_end_sec);
2107     sc->bg_period = cpu_to_le16(bg_sec);
2108     sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec);
2109     sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec);
2110     sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec);
2111     sc->short_scan_ratio = short_scan_ratio;
2112     sc->scan_ctrl_flags = scan_ctrl_flag;
2113     sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time);
2114     sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid);
2115 
2116     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_SCAN_PARAMS_CMDID,
2117                   NO_SYNC_WMIFLAG);
2118     return ret;
2119 }
2120 
2121 int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 if_idx, u8 filter, u32 ie_mask)
2122 {
2123     struct sk_buff *skb;
2124     struct wmi_bss_filter_cmd *cmd;
2125     int ret;
2126 
2127     if (filter >= LAST_BSS_FILTER)
2128         return -EINVAL;
2129 
2130     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2131     if (!skb)
2132         return -ENOMEM;
2133 
2134     cmd = (struct wmi_bss_filter_cmd *) skb->data;
2135     cmd->bss_filter = filter;
2136     cmd->ie_mask = cpu_to_le32(ie_mask);
2137 
2138     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BSS_FILTER_CMDID,
2139                   NO_SYNC_WMIFLAG);
2140     return ret;
2141 }
2142 
2143 int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,
2144                   u8 ssid_len, u8 *ssid)
2145 {
2146     struct sk_buff *skb;
2147     struct wmi_probed_ssid_cmd *cmd;
2148     int ret;
2149 
2150     if (index >= MAX_PROBED_SSIDS)
2151         return -EINVAL;
2152 
2153     if (ssid_len > sizeof(cmd->ssid))
2154         return -EINVAL;
2155 
2156     if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0))
2157         return -EINVAL;
2158 
2159     if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len)
2160         return -EINVAL;
2161 
2162     if (flag & SPECIFIC_SSID_FLAG)
2163         wmi->is_probe_ssid = true;
2164 
2165     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2166     if (!skb)
2167         return -ENOMEM;
2168 
2169     cmd = (struct wmi_probed_ssid_cmd *) skb->data;
2170     cmd->entry_index = index;
2171     cmd->flag = flag;
2172     cmd->ssid_len = ssid_len;
2173     memcpy(cmd->ssid, ssid, ssid_len);
2174 
2175     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_PROBED_SSID_CMDID,
2176                   NO_SYNC_WMIFLAG);
2177     return ret;
2178 }
2179 
2180 int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,
2181                   u16 listen_interval,
2182                   u16 listen_beacons)
2183 {
2184     struct sk_buff *skb;
2185     struct wmi_listen_int_cmd *cmd;
2186     int ret;
2187 
2188     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2189     if (!skb)
2190         return -ENOMEM;
2191 
2192     cmd = (struct wmi_listen_int_cmd *) skb->data;
2193     cmd->listen_intvl = cpu_to_le16(listen_interval);
2194     cmd->num_beacons = cpu_to_le16(listen_beacons);
2195 
2196     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_LISTEN_INT_CMDID,
2197                   NO_SYNC_WMIFLAG);
2198     return ret;
2199 }
2200 
2201 int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
2202                  u16 bmiss_time, u16 num_beacons)
2203 {
2204     struct sk_buff *skb;
2205     struct wmi_bmiss_time_cmd *cmd;
2206     int ret;
2207 
2208     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2209     if (!skb)
2210         return -ENOMEM;
2211 
2212     cmd = (struct wmi_bmiss_time_cmd *) skb->data;
2213     cmd->bmiss_time = cpu_to_le16(bmiss_time);
2214     cmd->num_beacons = cpu_to_le16(num_beacons);
2215 
2216     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID,
2217                   NO_SYNC_WMIFLAG);
2218     return ret;
2219 }
2220 
2221 int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode)
2222 {
2223     struct sk_buff *skb;
2224     struct wmi_power_mode_cmd *cmd;
2225     int ret;
2226 
2227     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2228     if (!skb)
2229         return -ENOMEM;
2230 
2231     cmd = (struct wmi_power_mode_cmd *) skb->data;
2232     cmd->pwr_mode = pwr_mode;
2233     wmi->pwr_mode = pwr_mode;
2234 
2235     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_POWER_MODE_CMDID,
2236                   NO_SYNC_WMIFLAG);
2237     return ret;
2238 }
2239 
2240 int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period,
2241                 u16 ps_poll_num, u16 dtim_policy,
2242                 u16 tx_wakeup_policy, u16 num_tx_to_wakeup,
2243                 u16 ps_fail_event_policy)
2244 {
2245     struct sk_buff *skb;
2246     struct wmi_power_params_cmd *pm;
2247     int ret;
2248 
2249     skb = ath6kl_wmi_get_new_buf(sizeof(*pm));
2250     if (!skb)
2251         return -ENOMEM;
2252 
2253     pm = (struct wmi_power_params_cmd *)skb->data;
2254     pm->idle_period = cpu_to_le16(idle_period);
2255     pm->pspoll_number = cpu_to_le16(ps_poll_num);
2256     pm->dtim_policy = cpu_to_le16(dtim_policy);
2257     pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy);
2258     pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup);
2259     pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy);
2260 
2261     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_POWER_PARAMS_CMDID,
2262                   NO_SYNC_WMIFLAG);
2263     return ret;
2264 }
2265 
2266 int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 if_idx, u8 timeout)
2267 {
2268     struct sk_buff *skb;
2269     struct wmi_disc_timeout_cmd *cmd;
2270     int ret;
2271 
2272     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2273     if (!skb)
2274         return -ENOMEM;
2275 
2276     cmd = (struct wmi_disc_timeout_cmd *) skb->data;
2277     cmd->discon_timeout = timeout;
2278 
2279     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_DISC_TIMEOUT_CMDID,
2280                   NO_SYNC_WMIFLAG);
2281 
2282     if (ret == 0)
2283         ath6kl_debug_set_disconnect_timeout(wmi->parent_dev, timeout);
2284 
2285     return ret;
2286 }
2287 
2288 int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
2289               enum ath6kl_crypto_type key_type,
2290               u8 key_usage, u8 key_len,
2291               u8 *key_rsc, unsigned int key_rsc_len,
2292               u8 *key_material,
2293               u8 key_op_ctrl, u8 *mac_addr,
2294               enum wmi_sync_flag sync_flag)
2295 {
2296     struct sk_buff *skb;
2297     struct wmi_add_cipher_key_cmd *cmd;
2298     int ret;
2299 
2300     ath6kl_dbg(ATH6KL_DBG_WMI,
2301            "addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n",
2302            key_index, key_type, key_usage, key_len, key_op_ctrl);
2303 
2304     if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
2305         (key_material == NULL) || key_rsc_len > 8)
2306         return -EINVAL;
2307 
2308     if ((WEP_CRYPT != key_type) && (NULL == key_rsc))
2309         return -EINVAL;
2310 
2311     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2312     if (!skb)
2313         return -ENOMEM;
2314 
2315     cmd = (struct wmi_add_cipher_key_cmd *) skb->data;
2316     cmd->key_index = key_index;
2317     cmd->key_type = key_type;
2318     cmd->key_usage = key_usage;
2319     cmd->key_len = key_len;
2320     memcpy(cmd->key, key_material, key_len);
2321 
2322     if (key_rsc != NULL)
2323         memcpy(cmd->key_rsc, key_rsc, key_rsc_len);
2324 
2325     cmd->key_op_ctrl = key_op_ctrl;
2326 
2327     if (mac_addr)
2328         memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN);
2329 
2330     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_CIPHER_KEY_CMDID,
2331                   sync_flag);
2332 
2333     return ret;
2334 }
2335 
2336 int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk)
2337 {
2338     struct sk_buff *skb;
2339     struct wmi_add_krk_cmd *cmd;
2340     int ret;
2341 
2342     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2343     if (!skb)
2344         return -ENOMEM;
2345 
2346     cmd = (struct wmi_add_krk_cmd *) skb->data;
2347     memcpy(cmd->krk, krk, WMI_KRK_LEN);
2348 
2349     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_KRK_CMDID,
2350                   NO_SYNC_WMIFLAG);
2351 
2352     return ret;
2353 }
2354 
2355 int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index)
2356 {
2357     struct sk_buff *skb;
2358     struct wmi_delete_cipher_key_cmd *cmd;
2359     int ret;
2360 
2361     if (key_index > WMI_MAX_KEY_INDEX)
2362         return -EINVAL;
2363 
2364     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2365     if (!skb)
2366         return -ENOMEM;
2367 
2368     cmd = (struct wmi_delete_cipher_key_cmd *) skb->data;
2369     cmd->key_index = key_index;
2370 
2371     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DELETE_CIPHER_KEY_CMDID,
2372                   NO_SYNC_WMIFLAG);
2373 
2374     return ret;
2375 }
2376 
2377 int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, u8 if_idx, const u8 *bssid,
2378                 const u8 *pmkid, bool set)
2379 {
2380     struct sk_buff *skb;
2381     struct wmi_setpmkid_cmd *cmd;
2382     int ret;
2383 
2384     if (bssid == NULL)
2385         return -EINVAL;
2386 
2387     if (set && pmkid == NULL)
2388         return -EINVAL;
2389 
2390     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2391     if (!skb)
2392         return -ENOMEM;
2393 
2394     cmd = (struct wmi_setpmkid_cmd *) skb->data;
2395     memcpy(cmd->bssid, bssid, ETH_ALEN);
2396     if (set) {
2397         memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid));
2398         cmd->enable = PMKID_ENABLE;
2399     } else {
2400         memset(cmd->pmkid, 0, sizeof(cmd->pmkid));
2401         cmd->enable = PMKID_DISABLE;
2402     }
2403 
2404     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_PMKID_CMDID,
2405                   NO_SYNC_WMIFLAG);
2406 
2407     return ret;
2408 }
2409 
2410 static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
2411                   enum htc_endpoint_id ep_id, u8 if_idx)
2412 {
2413     struct wmi_data_hdr *data_hdr;
2414     int ret;
2415 
2416     if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) {
2417         dev_kfree_skb(skb);
2418         return -EINVAL;
2419     }
2420 
2421     skb_push(skb, sizeof(struct wmi_data_hdr));
2422 
2423     data_hdr = (struct wmi_data_hdr *) skb->data;
2424     data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT;
2425     data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
2426 
2427     ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id);
2428 
2429     return ret;
2430 }
2431 
2432 static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
2433 {
2434     struct sk_buff *skb;
2435     struct wmi_sync_cmd *cmd;
2436     struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC];
2437     enum htc_endpoint_id ep_id;
2438     u8 index, num_pri_streams = 0;
2439     int ret = 0;
2440 
2441     memset(data_sync_bufs, 0, sizeof(data_sync_bufs));
2442 
2443     spin_lock_bh(&wmi->lock);
2444 
2445     for (index = 0; index < WMM_NUM_AC; index++) {
2446         if (wmi->fat_pipe_exist & (1 << index)) {
2447             num_pri_streams++;
2448             data_sync_bufs[num_pri_streams - 1].traffic_class =
2449                 index;
2450         }
2451     }
2452 
2453     spin_unlock_bh(&wmi->lock);
2454 
2455     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2456     if (!skb)
2457         return -ENOMEM;
2458 
2459     cmd = (struct wmi_sync_cmd *) skb->data;
2460 
2461     /*
2462      * In the SYNC cmd sent on the control Ep, send a bitmap
2463      * of the data eps on which the Data Sync will be sent
2464      */
2465     cmd->data_sync_map = wmi->fat_pipe_exist;
2466 
2467     for (index = 0; index < num_pri_streams; index++) {
2468         data_sync_bufs[index].skb = ath6kl_buf_alloc(0);
2469         if (data_sync_bufs[index].skb == NULL) {
2470             ret = -ENOMEM;
2471             break;
2472         }
2473     }
2474 
2475     /*
2476      * If buffer allocation for any of the dataSync fails,
2477      * then do not send the Synchronize cmd on the control ep
2478      */
2479     if (ret)
2480         goto free_cmd_skb;
2481 
2482     /*
2483      * Send sync cmd followed by sync data messages on all
2484      * endpoints being used
2485      */
2486     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SYNCHRONIZE_CMDID,
2487                   NO_SYNC_WMIFLAG);
2488 
2489     if (ret)
2490         goto free_data_skb;
2491 
2492     for (index = 0; index < num_pri_streams; index++) {
2493         if (WARN_ON(!data_sync_bufs[index].skb)) {
2494             ret = -ENOMEM;
2495             goto free_data_skb;
2496         }
2497 
2498         ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
2499                            data_sync_bufs[index].
2500                            traffic_class);
2501         ret =
2502             ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
2503                           ep_id, if_idx);
2504 
2505         data_sync_bufs[index].skb = NULL;
2506 
2507         if (ret)
2508             goto free_data_skb;
2509     }
2510 
2511     return 0;
2512 
2513 free_cmd_skb:
2514     /* free up any resources left over (possibly due to an error) */
2515     dev_kfree_skb(skb);
2516 
2517 free_data_skb:
2518     for (index = 0; index < num_pri_streams; index++)
2519         dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].skb);
2520 
2521     return ret;
2522 }
2523 
2524 int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, u8 if_idx,
2525                   struct wmi_create_pstream_cmd *params)
2526 {
2527     struct sk_buff *skb;
2528     struct wmi_create_pstream_cmd *cmd;
2529     u8 fatpipe_exist_for_ac = 0;
2530     s32 min_phy = 0;
2531     s32 nominal_phy = 0;
2532     int ret;
2533 
2534     if (!((params->user_pri <= 0x7) &&
2535           (up_to_ac[params->user_pri & 0x7] == params->traffic_class) &&
2536           (params->traffic_direc == UPLINK_TRAFFIC ||
2537            params->traffic_direc == DNLINK_TRAFFIC ||
2538            params->traffic_direc == BIDIR_TRAFFIC) &&
2539           (params->traffic_type == TRAFFIC_TYPE_APERIODIC ||
2540            params->traffic_type == TRAFFIC_TYPE_PERIODIC) &&
2541           (params->voice_psc_cap == DISABLE_FOR_THIS_AC ||
2542            params->voice_psc_cap == ENABLE_FOR_THIS_AC ||
2543            params->voice_psc_cap == ENABLE_FOR_ALL_AC) &&
2544           (params->tsid == WMI_IMPLICIT_PSTREAM ||
2545            params->tsid <= WMI_MAX_THINSTREAM))) {
2546         return -EINVAL;
2547     }
2548 
2549     /*
2550      * Check nominal PHY rate is >= minimalPHY,
2551      * so that DUT can allow TSRS IE
2552      */
2553 
2554     /* Get the physical rate (units of bps) */
2555     min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000);
2556 
2557     /* Check minimal phy < nominal phy rate */
2558     if (params->nominal_phy >= min_phy) {
2559         /* unit of 500 kbps */
2560         nominal_phy = (params->nominal_phy * 1000) / 500;
2561         ath6kl_dbg(ATH6KL_DBG_WMI,
2562                "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n",
2563                min_phy, nominal_phy);
2564 
2565         params->nominal_phy = nominal_phy;
2566     } else {
2567         params->nominal_phy = 0;
2568     }
2569 
2570     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2571     if (!skb)
2572         return -ENOMEM;
2573 
2574     ath6kl_dbg(ATH6KL_DBG_WMI,
2575            "sending create_pstream_cmd: ac=%d  tsid:%d\n",
2576            params->traffic_class, params->tsid);
2577 
2578     cmd = (struct wmi_create_pstream_cmd *) skb->data;
2579     memcpy(cmd, params, sizeof(*cmd));
2580 
2581     /* This is an implicitly created Fat pipe */
2582     if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) {
2583         spin_lock_bh(&wmi->lock);
2584         fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
2585                     (1 << params->traffic_class));
2586         wmi->fat_pipe_exist |= (1 << params->traffic_class);
2587         spin_unlock_bh(&wmi->lock);
2588     } else {
2589         /* explicitly created thin stream within a fat pipe */
2590         spin_lock_bh(&wmi->lock);
2591         fatpipe_exist_for_ac = (wmi->fat_pipe_exist &
2592                     (1 << params->traffic_class));
2593         wmi->stream_exist_for_ac[params->traffic_class] |=
2594             (1 << params->tsid);
2595         /*
2596          * If a thinstream becomes active, the fat pipe automatically
2597          * becomes active
2598          */
2599         wmi->fat_pipe_exist |= (1 << params->traffic_class);
2600         spin_unlock_bh(&wmi->lock);
2601     }
2602 
2603     /*
2604      * Indicate activty change to driver layer only if this is the
2605      * first TSID to get created in this AC explicitly or an implicit
2606      * fat pipe is getting created.
2607      */
2608     if (!fatpipe_exist_for_ac)
2609         ath6kl_indicate_tx_activity(wmi->parent_dev,
2610                         params->traffic_class, true);
2611 
2612     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_CREATE_PSTREAM_CMDID,
2613                   NO_SYNC_WMIFLAG);
2614     return ret;
2615 }
2616 
2617 int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
2618                   u8 tsid)
2619 {
2620     struct sk_buff *skb;
2621     struct wmi_delete_pstream_cmd *cmd;
2622     u16 active_tsids = 0;
2623     int ret;
2624 
2625     if (traffic_class >= WMM_NUM_AC) {
2626         ath6kl_err("invalid traffic class: %d\n", traffic_class);
2627         return -EINVAL;
2628     }
2629 
2630     if (tsid >= 16) {
2631         ath6kl_err("invalid tsid: %d\n", tsid);
2632         return -EINVAL;
2633     }
2634 
2635     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2636     if (!skb)
2637         return -ENOMEM;
2638 
2639     cmd = (struct wmi_delete_pstream_cmd *) skb->data;
2640     cmd->traffic_class = traffic_class;
2641     cmd->tsid = tsid;
2642 
2643     spin_lock_bh(&wmi->lock);
2644     active_tsids = wmi->stream_exist_for_ac[traffic_class];
2645     spin_unlock_bh(&wmi->lock);
2646 
2647     if (!(active_tsids & (1 << tsid))) {
2648         dev_kfree_skb(skb);
2649         ath6kl_dbg(ATH6KL_DBG_WMI,
2650                "TSID %d doesn't exist for traffic class: %d\n",
2651                tsid, traffic_class);
2652         return -ENODATA;
2653     }
2654 
2655     ath6kl_dbg(ATH6KL_DBG_WMI,
2656            "sending delete_pstream_cmd: traffic class: %d tsid=%d\n",
2657            traffic_class, tsid);
2658 
2659     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DELETE_PSTREAM_CMDID,
2660                   SYNC_BEFORE_WMIFLAG);
2661 
2662     spin_lock_bh(&wmi->lock);
2663     wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid);
2664     active_tsids = wmi->stream_exist_for_ac[traffic_class];
2665     spin_unlock_bh(&wmi->lock);
2666 
2667     /*
2668      * Indicate stream inactivity to driver layer only if all tsids
2669      * within this AC are deleted.
2670      */
2671     if (!active_tsids) {
2672         ath6kl_indicate_tx_activity(wmi->parent_dev,
2673                         traffic_class, false);
2674         wmi->fat_pipe_exist &= ~(1 << traffic_class);
2675     }
2676 
2677     return ret;
2678 }
2679 
2680 int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
2681               __be32 ips0, __be32 ips1)
2682 {
2683     struct sk_buff *skb;
2684     struct wmi_set_ip_cmd *cmd;
2685     int ret;
2686 
2687     /* Multicast address are not valid */
2688     if (ipv4_is_multicast(ips0) ||
2689         ipv4_is_multicast(ips1))
2690         return -EINVAL;
2691 
2692     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));
2693     if (!skb)
2694         return -ENOMEM;
2695 
2696     cmd = (struct wmi_set_ip_cmd *) skb->data;
2697     cmd->ips[0] = ips0;
2698     cmd->ips[1] = ips1;
2699 
2700     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IP_CMDID,
2701                   NO_SYNC_WMIFLAG);
2702     return ret;
2703 }
2704 
2705 static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
2706 {
2707     u16 active_tsids;
2708     u8 stream_exist;
2709     int i;
2710 
2711     /*
2712      * Relinquish credits from all implicitly created pstreams
2713      * since when we go to sleep. If user created explicit
2714      * thinstreams exists with in a fatpipe leave them intact
2715      * for the user to delete.
2716      */
2717     spin_lock_bh(&wmi->lock);
2718     stream_exist = wmi->fat_pipe_exist;
2719     spin_unlock_bh(&wmi->lock);
2720 
2721     for (i = 0; i < WMM_NUM_AC; i++) {
2722         if (stream_exist & (1 << i)) {
2723             /*
2724              * FIXME: Is this lock & unlock inside
2725              * for loop correct? may need rework.
2726              */
2727             spin_lock_bh(&wmi->lock);
2728             active_tsids = wmi->stream_exist_for_ac[i];
2729             spin_unlock_bh(&wmi->lock);
2730 
2731             /*
2732              * If there are no user created thin streams
2733              * delete the fatpipe
2734              */
2735             if (!active_tsids) {
2736                 stream_exist &= ~(1 << i);
2737                 /*
2738                  * Indicate inactivity to driver layer for
2739                  * this fatpipe (pstream)
2740                  */
2741                 ath6kl_indicate_tx_activity(wmi->parent_dev,
2742                                 i, false);
2743             }
2744         }
2745     }
2746 
2747     /* FIXME: Can we do this assignment without locking ? */
2748     spin_lock_bh(&wmi->lock);
2749     wmi->fat_pipe_exist = stream_exist;
2750     spin_unlock_bh(&wmi->lock);
2751 }
2752 
2753 static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
2754                      const struct cfg80211_bitrate_mask *mask)
2755 {
2756     struct sk_buff *skb;
2757     int ret, mode, band;
2758     u64 mcsrate, ratemask[ATH6KL_NUM_BANDS];
2759     struct wmi_set_tx_select_rates64_cmd *cmd;
2760 
2761     memset(&ratemask, 0, sizeof(ratemask));
2762 
2763     /* only check 2.4 and 5 GHz bands, skip the rest */
2764     for (band = 0; band <= NL80211_BAND_5GHZ; band++) {
2765         /* copy legacy rate mask */
2766         ratemask[band] = mask->control[band].legacy;
2767         if (band == NL80211_BAND_5GHZ)
2768             ratemask[band] =
2769                 mask->control[band].legacy << 4;
2770 
2771         /* copy mcs rate mask */
2772         mcsrate = mask->control[band].ht_mcs[1];
2773         mcsrate <<= 8;
2774         mcsrate |= mask->control[band].ht_mcs[0];
2775         ratemask[band] |= mcsrate << 12;
2776         ratemask[band] |= mcsrate << 28;
2777     }
2778 
2779     ath6kl_dbg(ATH6KL_DBG_WMI,
2780            "Ratemask 64 bit: 2.4:%llx 5:%llx\n",
2781            ratemask[0], ratemask[1]);
2782 
2783     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
2784     if (!skb)
2785         return -ENOMEM;
2786 
2787     cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;
2788     for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
2789         /* A mode operate in 5GHZ band */
2790         if (mode == WMI_RATES_MODE_11A ||
2791             mode == WMI_RATES_MODE_11A_HT20 ||
2792             mode == WMI_RATES_MODE_11A_HT40)
2793             band = NL80211_BAND_5GHZ;
2794         else
2795             band = NL80211_BAND_2GHZ;
2796         cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);
2797     }
2798 
2799     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2800                   WMI_SET_TX_SELECT_RATES_CMDID,
2801                   NO_SYNC_WMIFLAG);
2802     return ret;
2803 }
2804 
2805 static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
2806                      const struct cfg80211_bitrate_mask *mask)
2807 {
2808     struct sk_buff *skb;
2809     int ret, mode, band;
2810     u32 mcsrate, ratemask[ATH6KL_NUM_BANDS];
2811     struct wmi_set_tx_select_rates32_cmd *cmd;
2812 
2813     memset(&ratemask, 0, sizeof(ratemask));
2814 
2815     /* only check 2.4 and 5 GHz bands, skip the rest */
2816     for (band = 0; band <= NL80211_BAND_5GHZ; band++) {
2817         /* copy legacy rate mask */
2818         ratemask[band] = mask->control[band].legacy;
2819         if (band == NL80211_BAND_5GHZ)
2820             ratemask[band] =
2821                 mask->control[band].legacy << 4;
2822 
2823         /* copy mcs rate mask */
2824         mcsrate = mask->control[band].ht_mcs[0];
2825         ratemask[band] |= mcsrate << 12;
2826         ratemask[band] |= mcsrate << 20;
2827     }
2828 
2829     ath6kl_dbg(ATH6KL_DBG_WMI,
2830            "Ratemask 32 bit: 2.4:%x 5:%x\n",
2831            ratemask[0], ratemask[1]);
2832 
2833     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
2834     if (!skb)
2835         return -ENOMEM;
2836 
2837     cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;
2838     for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
2839         /* A mode operate in 5GHZ band */
2840         if (mode == WMI_RATES_MODE_11A ||
2841             mode == WMI_RATES_MODE_11A_HT20 ||
2842             mode == WMI_RATES_MODE_11A_HT40)
2843             band = NL80211_BAND_5GHZ;
2844         else
2845             band = NL80211_BAND_2GHZ;
2846         cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);
2847     }
2848 
2849     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2850                   WMI_SET_TX_SELECT_RATES_CMDID,
2851                   NO_SYNC_WMIFLAG);
2852     return ret;
2853 }
2854 
2855 int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
2856                 const struct cfg80211_bitrate_mask *mask)
2857 {
2858     struct ath6kl *ar = wmi->parent_dev;
2859 
2860     if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,
2861              ar->fw_capabilities))
2862         return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
2863     else
2864         return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
2865 }
2866 
2867 int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
2868                        enum ath6kl_host_mode host_mode)
2869 {
2870     struct sk_buff *skb;
2871     struct wmi_set_host_sleep_mode_cmd *cmd;
2872     int ret;
2873 
2874     if ((host_mode != ATH6KL_HOST_MODE_ASLEEP) &&
2875         (host_mode != ATH6KL_HOST_MODE_AWAKE)) {
2876         ath6kl_err("invalid host sleep mode: %d\n", host_mode);
2877         return -EINVAL;
2878     }
2879 
2880     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2881     if (!skb)
2882         return -ENOMEM;
2883 
2884     cmd = (struct wmi_set_host_sleep_mode_cmd *) skb->data;
2885 
2886     if (host_mode == ATH6KL_HOST_MODE_ASLEEP) {
2887         ath6kl_wmi_relinquish_implicit_pstream_credits(wmi);
2888         cmd->asleep = cpu_to_le32(1);
2889     } else {
2890         cmd->awake = cpu_to_le32(1);
2891     }
2892 
2893     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
2894                   WMI_SET_HOST_SLEEP_MODE_CMDID,
2895                   NO_SYNC_WMIFLAG);
2896     return ret;
2897 }
2898 
2899 /* This command has zero length payload */
2900 static int ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(struct wmi *wmi,
2901                               struct ath6kl_vif *vif)
2902 {
2903     struct ath6kl *ar = wmi->parent_dev;
2904 
2905     set_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
2906     wake_up(&ar->event_wq);
2907 
2908     return 0;
2909 }
2910 
2911 int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
2912                 enum ath6kl_wow_mode wow_mode,
2913                 u32 filter, u16 host_req_delay)
2914 {
2915     struct sk_buff *skb;
2916     struct wmi_set_wow_mode_cmd *cmd;
2917     int ret;
2918 
2919     if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) &&
2920         wow_mode != ATH6KL_WOW_MODE_DISABLE) {
2921         ath6kl_err("invalid wow mode: %d\n", wow_mode);
2922         return -EINVAL;
2923     }
2924 
2925     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2926     if (!skb)
2927         return -ENOMEM;
2928 
2929     cmd = (struct wmi_set_wow_mode_cmd *) skb->data;
2930     cmd->enable_wow = cpu_to_le32(wow_mode);
2931     cmd->filter = cpu_to_le32(filter);
2932     cmd->host_req_delay = cpu_to_le16(host_req_delay);
2933 
2934     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_WOW_MODE_CMDID,
2935                   NO_SYNC_WMIFLAG);
2936     return ret;
2937 }
2938 
2939 int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
2940                    u8 list_id, u8 filter_size,
2941                    u8 filter_offset, const u8 *filter,
2942                    const u8 *mask)
2943 {
2944     struct sk_buff *skb;
2945     struct wmi_add_wow_pattern_cmd *cmd;
2946     u16 size;
2947     u8 *filter_mask;
2948     int ret;
2949 
2950     /*
2951      * Allocate additional memory in the buffer to hold
2952      * filter and mask value, which is twice of filter_size.
2953      */
2954     size = sizeof(*cmd) + (2 * filter_size);
2955 
2956     skb = ath6kl_wmi_get_new_buf(size);
2957     if (!skb)
2958         return -ENOMEM;
2959 
2960     cmd = (struct wmi_add_wow_pattern_cmd *) skb->data;
2961     cmd->filter_list_id = list_id;
2962     cmd->filter_size = filter_size;
2963     cmd->filter_offset = filter_offset;
2964 
2965     memcpy(cmd->filter, filter, filter_size);
2966 
2967     filter_mask = (u8 *) (cmd->filter + filter_size);
2968     memcpy(filter_mask, mask, filter_size);
2969 
2970     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_WOW_PATTERN_CMDID,
2971                   NO_SYNC_WMIFLAG);
2972 
2973     return ret;
2974 }
2975 
2976 int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
2977                    u16 list_id, u16 filter_id)
2978 {
2979     struct sk_buff *skb;
2980     struct wmi_del_wow_pattern_cmd *cmd;
2981     int ret;
2982 
2983     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
2984     if (!skb)
2985         return -ENOMEM;
2986 
2987     cmd = (struct wmi_del_wow_pattern_cmd *) skb->data;
2988     cmd->filter_list_id = cpu_to_le16(list_id);
2989     cmd->filter_id = cpu_to_le16(filter_id);
2990 
2991     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DEL_WOW_PATTERN_CMDID,
2992                   NO_SYNC_WMIFLAG);
2993     return ret;
2994 }
2995 
2996 static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,
2997                     enum wmix_command_id cmd_id,
2998                     enum wmi_sync_flag sync_flag)
2999 {
3000     struct wmix_cmd_hdr *cmd_hdr;
3001     int ret;
3002 
3003     skb_push(skb, sizeof(struct wmix_cmd_hdr));
3004 
3005     cmd_hdr = (struct wmix_cmd_hdr *) skb->data;
3006     cmd_hdr->cmd_id = cpu_to_le32(cmd_id);
3007 
3008     ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_EXTENSION_CMDID, sync_flag);
3009 
3010     return ret;
3011 }
3012 
3013 int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source)
3014 {
3015     struct sk_buff *skb;
3016     struct wmix_hb_challenge_resp_cmd *cmd;
3017     int ret;
3018 
3019     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3020     if (!skb)
3021         return -ENOMEM;
3022 
3023     cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data;
3024     cmd->cookie = cpu_to_le32(cookie);
3025     cmd->source = cpu_to_le32(source);
3026 
3027     ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID,
3028                        NO_SYNC_WMIFLAG);
3029     return ret;
3030 }
3031 
3032 int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config)
3033 {
3034     struct ath6kl_wmix_dbglog_cfg_module_cmd *cmd;
3035     struct sk_buff *skb;
3036     int ret;
3037 
3038     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3039     if (!skb)
3040         return -ENOMEM;
3041 
3042     cmd = (struct ath6kl_wmix_dbglog_cfg_module_cmd *) skb->data;
3043     cmd->valid = cpu_to_le32(valid);
3044     cmd->config = cpu_to_le32(config);
3045 
3046     ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_DBGLOG_CFG_MODULE_CMDID,
3047                        NO_SYNC_WMIFLAG);
3048     return ret;
3049 }
3050 
3051 int ath6kl_wmi_get_stats_cmd(struct wmi *wmi, u8 if_idx)
3052 {
3053     return ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_GET_STATISTICS_CMDID);
3054 }
3055 
3056 int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 if_idx, u8 dbM)
3057 {
3058     struct sk_buff *skb;
3059     struct wmi_set_tx_pwr_cmd *cmd;
3060     int ret;
3061 
3062     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd));
3063     if (!skb)
3064         return -ENOMEM;
3065 
3066     cmd = (struct wmi_set_tx_pwr_cmd *) skb->data;
3067     cmd->dbM = dbM;
3068 
3069     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_TX_PWR_CMDID,
3070                   NO_SYNC_WMIFLAG);
3071 
3072     return ret;
3073 }
3074 
3075 int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi, u8 if_idx)
3076 {
3077     return ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_GET_TX_PWR_CMDID);
3078 }
3079 
3080 int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi)
3081 {
3082     return ath6kl_wmi_simple_cmd(wmi, 0, WMI_GET_ROAM_TBL_CMDID);
3083 }
3084 
3085 int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 if_idx, u8 status,
3086                  u8 preamble_policy)
3087 {
3088     struct sk_buff *skb;
3089     struct wmi_set_lpreamble_cmd *cmd;
3090     int ret;
3091 
3092     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd));
3093     if (!skb)
3094         return -ENOMEM;
3095 
3096     cmd = (struct wmi_set_lpreamble_cmd *) skb->data;
3097     cmd->status = status;
3098     cmd->preamble_policy = preamble_policy;
3099 
3100     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_LPREAMBLE_CMDID,
3101                   NO_SYNC_WMIFLAG);
3102     return ret;
3103 }
3104 
3105 int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold)
3106 {
3107     struct sk_buff *skb;
3108     struct wmi_set_rts_cmd *cmd;
3109     int ret;
3110 
3111     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd));
3112     if (!skb)
3113         return -ENOMEM;
3114 
3115     cmd = (struct wmi_set_rts_cmd *) skb->data;
3116     cmd->threshold = cpu_to_le16(threshold);
3117 
3118     ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_RTS_CMDID,
3119                   NO_SYNC_WMIFLAG);
3120     return ret;
3121 }
3122 
3123 int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg)
3124 {
3125     struct sk_buff *skb;
3126     struct wmi_set_wmm_txop_cmd *cmd;
3127     int ret;
3128 
3129     if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)))
3130         return -EINVAL;
3131 
3132     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd));
3133     if (!skb)
3134         return -ENOMEM;
3135 
3136     cmd = (struct wmi_set_wmm_txop_cmd *) skb->data;
3137     cmd->txop_enable = cfg;
3138 
3139     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_WMM_TXOP_CMDID,
3140                   NO_SYNC_WMIFLAG);
3141     return ret;
3142 }
3143 
3144 int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,
3145                  u8 keep_alive_intvl)
3146 {
3147     struct sk_buff *skb;
3148     struct wmi_set_keepalive_cmd *cmd;
3149     int ret;
3150 
3151     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3152     if (!skb)
3153         return -ENOMEM;
3154 
3155     cmd = (struct wmi_set_keepalive_cmd *) skb->data;
3156     cmd->keep_alive_intvl = keep_alive_intvl;
3157 
3158     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_KEEPALIVE_CMDID,
3159                   NO_SYNC_WMIFLAG);
3160 
3161     if (ret == 0)
3162         ath6kl_debug_set_keepalive(wmi->parent_dev, keep_alive_intvl);
3163 
3164     return ret;
3165 }
3166 
3167 int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,
3168                  enum nl80211_band band,
3169                  struct ath6kl_htcap *htcap)
3170 {
3171     struct sk_buff *skb;
3172     struct wmi_set_htcap_cmd *cmd;
3173 
3174     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3175     if (!skb)
3176         return -ENOMEM;
3177 
3178     cmd = (struct wmi_set_htcap_cmd *) skb->data;
3179 
3180     /*
3181      * NOTE: Band in firmware matches enum nl80211_band, it is unlikely
3182      * this will be changed in firmware. If at all there is any change in
3183      * band value, the host needs to be fixed.
3184      */
3185     cmd->band = band;
3186     cmd->ht_enable = !!htcap->ht_enable;
3187     cmd->ht20_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_20);
3188     cmd->ht40_supported =
3189         !!(htcap->cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
3190     cmd->ht40_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_40);
3191     cmd->intolerant_40mhz =
3192         !!(htcap->cap_info & IEEE80211_HT_CAP_40MHZ_INTOLERANT);
3193     cmd->max_ampdu_len_exp = htcap->ampdu_factor;
3194 
3195     ath6kl_dbg(ATH6KL_DBG_WMI,
3196            "Set htcap: band:%d ht_enable:%d 40mhz:%d sgi_20mhz:%d sgi_40mhz:%d 40mhz_intolerant:%d ampdu_len_exp:%d\n",
3197            cmd->band, cmd->ht_enable, cmd->ht40_supported,
3198            cmd->ht20_sgi, cmd->ht40_sgi, cmd->intolerant_40mhz,
3199            cmd->max_ampdu_len_exp);
3200     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HT_CAP_CMDID,
3201                    NO_SYNC_WMIFLAG);
3202 }
3203 
3204 int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
3205 {
3206     struct sk_buff *skb;
3207     int ret;
3208 
3209     skb = ath6kl_wmi_get_new_buf(len);
3210     if (!skb)
3211         return -ENOMEM;
3212 
3213     memcpy(skb->data, buf, len);
3214 
3215     ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_TEST_CMDID, NO_SYNC_WMIFLAG);
3216 
3217     return ret;
3218 }
3219 
3220 int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on)
3221 {
3222     struct sk_buff *skb;
3223     struct wmi_mcast_filter_cmd *cmd;
3224     int ret;
3225 
3226     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3227     if (!skb)
3228         return -ENOMEM;
3229 
3230     cmd = (struct wmi_mcast_filter_cmd *) skb->data;
3231     cmd->mcast_all_enable = mc_all_on;
3232 
3233     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_MCAST_FILTER_CMDID,
3234                   NO_SYNC_WMIFLAG);
3235     return ret;
3236 }
3237 
3238 int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
3239                     u8 *filter, bool add_filter)
3240 {
3241     struct sk_buff *skb;
3242     struct wmi_mcast_filter_add_del_cmd *cmd;
3243     int ret;
3244 
3245     if ((filter[0] != 0x33 || filter[1] != 0x33) &&
3246         (filter[0] != 0x01 || filter[1] != 0x00 ||
3247         filter[2] != 0x5e || filter[3] > 0x7f)) {
3248         ath6kl_warn("invalid multicast filter address\n");
3249         return -EINVAL;
3250     }
3251 
3252     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3253     if (!skb)
3254         return -ENOMEM;
3255 
3256     cmd = (struct wmi_mcast_filter_add_del_cmd *) skb->data;
3257     memcpy(cmd->mcast_mac, filter, ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);
3258     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3259                   add_filter ? WMI_SET_MCAST_FILTER_CMDID :
3260                   WMI_DEL_MCAST_FILTER_CMDID,
3261                   NO_SYNC_WMIFLAG);
3262 
3263     return ret;
3264 }
3265 
3266 int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
3267 {
3268     struct sk_buff *skb;
3269     struct wmi_sta_bmiss_enhance_cmd *cmd;
3270     int ret;
3271 
3272     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3273     if (!skb)
3274         return -ENOMEM;
3275 
3276     cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data;
3277     cmd->enable = enhance ? 1 : 0;
3278 
3279     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3280                   WMI_STA_BMISS_ENHANCE_CMDID,
3281                   NO_SYNC_WMIFLAG);
3282     return ret;
3283 }
3284 
3285 int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2)
3286 {
3287     struct sk_buff *skb;
3288     struct wmi_set_regdomain_cmd *cmd;
3289 
3290     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3291     if (!skb)
3292         return -ENOMEM;
3293 
3294     cmd = (struct wmi_set_regdomain_cmd *) skb->data;
3295     memcpy(cmd->iso_name, alpha2, 2);
3296 
3297     return ath6kl_wmi_cmd_send(wmi, 0, skb,
3298                    WMI_SET_REGDOMAIN_CMDID,
3299                    NO_SYNC_WMIFLAG);
3300 }
3301 
3302 s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index)
3303 {
3304     struct ath6kl *ar = wmi->parent_dev;
3305     u8 sgi = 0;
3306     s32 ret;
3307 
3308     if (rate_index == RATE_AUTO)
3309         return 0;
3310 
3311     /* SGI is stored as the MSB of the rate_index */
3312     if (rate_index & RATE_INDEX_MSB) {
3313         rate_index &= RATE_INDEX_WITHOUT_SGI_MASK;
3314         sgi = 1;
3315     }
3316 
3317     if (test_bit(ATH6KL_FW_CAPABILITY_RATETABLE_MCS15,
3318              ar->fw_capabilities)) {
3319         if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl_mcs15)))
3320             return 0;
3321 
3322         ret = wmi_rate_tbl_mcs15[(u32) rate_index][sgi];
3323     } else {
3324         if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl)))
3325             return 0;
3326 
3327         ret = wmi_rate_tbl[(u32) rate_index][sgi];
3328     }
3329 
3330     return ret;
3331 }
3332 
3333 static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
3334                           u32 len)
3335 {
3336     struct wmi_pmkid_list_reply *reply;
3337     u32 expected_len;
3338 
3339     if (len < sizeof(struct wmi_pmkid_list_reply))
3340         return -EINVAL;
3341 
3342     reply = (struct wmi_pmkid_list_reply *)datap;
3343     expected_len = sizeof(reply->num_pmkid) +
3344         le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN;
3345 
3346     if (len < expected_len)
3347         return -EINVAL;
3348 
3349     return 0;
3350 }
3351 
3352 static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len,
3353                      struct ath6kl_vif *vif)
3354 {
3355     struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap;
3356 
3357     aggr_recv_addba_req_evt(vif, cmd->tid,
3358                 le16_to_cpu(cmd->st_seq_no), cmd->win_sz);
3359 
3360     return 0;
3361 }
3362 
3363 static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len,
3364                      struct ath6kl_vif *vif)
3365 {
3366     struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap;
3367 
3368     aggr_recv_delba_req_evt(vif, cmd->tid);
3369 
3370     return 0;
3371 }
3372 
3373 /*  AP mode functions */
3374 
3375 int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
3376                  struct wmi_connect_cmd *p)
3377 {
3378     struct sk_buff *skb;
3379     struct wmi_connect_cmd *cm;
3380     int res;
3381 
3382     skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
3383     if (!skb)
3384         return -ENOMEM;
3385 
3386     cm = (struct wmi_connect_cmd *) skb->data;
3387     memcpy(cm, p, sizeof(*cm));
3388 
3389     res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID,
3390                   NO_SYNC_WMIFLAG);
3391     ath6kl_dbg(ATH6KL_DBG_WMI,
3392            "%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n",
3393            __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),
3394            le32_to_cpu(p->ctrl_flags), res);
3395     return res;
3396 }
3397 
3398 int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
3399                u16 reason)
3400 {
3401     struct sk_buff *skb;
3402     struct wmi_ap_set_mlme_cmd *cm;
3403 
3404     skb = ath6kl_wmi_get_new_buf(sizeof(*cm));
3405     if (!skb)
3406         return -ENOMEM;
3407 
3408     cm = (struct wmi_ap_set_mlme_cmd *) skb->data;
3409     memcpy(cm->mac, mac, ETH_ALEN);
3410     cm->reason = cpu_to_le16(reason);
3411     cm->cmd = cmd;
3412 
3413     ath6kl_dbg(ATH6KL_DBG_WMI, "ap_set_mlme: cmd=%d reason=%d\n", cm->cmd,
3414            cm->reason);
3415 
3416     return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID,
3417                    NO_SYNC_WMIFLAG);
3418 }
3419 
3420 int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable)
3421 {
3422     struct sk_buff *skb;
3423     struct wmi_ap_hidden_ssid_cmd *cmd;
3424 
3425     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3426     if (!skb)
3427         return -ENOMEM;
3428 
3429     cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data;
3430     cmd->hidden_ssid = enable ? 1 : 0;
3431 
3432     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID,
3433                    NO_SYNC_WMIFLAG);
3434 }
3435 
3436 /* This command will be used to enable/disable AP uAPSD feature */
3437 int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable)
3438 {
3439     struct wmi_ap_set_apsd_cmd *cmd;
3440     struct sk_buff *skb;
3441 
3442     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3443     if (!skb)
3444         return -ENOMEM;
3445 
3446     cmd = (struct wmi_ap_set_apsd_cmd *)skb->data;
3447     cmd->enable = enable;
3448 
3449     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID,
3450                    NO_SYNC_WMIFLAG);
3451 }
3452 
3453 int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx,
3454                          u16 aid, u16 bitmap, u32 flags)
3455 {
3456     struct wmi_ap_apsd_buffered_traffic_cmd *cmd;
3457     struct sk_buff *skb;
3458 
3459     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3460     if (!skb)
3461         return -ENOMEM;
3462 
3463     cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data;
3464     cmd->aid = cpu_to_le16(aid);
3465     cmd->bitmap = cpu_to_le16(bitmap);
3466     cmd->flags = cpu_to_le32(flags);
3467 
3468     return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3469                    WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
3470                    NO_SYNC_WMIFLAG);
3471 }
3472 
3473 static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len,
3474                       struct ath6kl_vif *vif)
3475 {
3476     struct wmi_pspoll_event *ev;
3477 
3478     if (len < sizeof(struct wmi_pspoll_event))
3479         return -EINVAL;
3480 
3481     ev = (struct wmi_pspoll_event *) datap;
3482 
3483     ath6kl_pspoll_event(vif, le16_to_cpu(ev->aid));
3484 
3485     return 0;
3486 }
3487 
3488 static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len,
3489                       struct ath6kl_vif *vif)
3490 {
3491     ath6kl_dtimexpiry_event(vif);
3492 
3493     return 0;
3494 }
3495 
3496 int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u8 if_idx, u16 aid,
3497                bool flag)
3498 {
3499     struct sk_buff *skb;
3500     struct wmi_ap_set_pvb_cmd *cmd;
3501     int ret;
3502 
3503     skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd));
3504     if (!skb)
3505         return -ENOMEM;
3506 
3507     cmd = (struct wmi_ap_set_pvb_cmd *) skb->data;
3508     cmd->aid = cpu_to_le16(aid);
3509     cmd->rsvd = cpu_to_le16(0);
3510     cmd->flag = cpu_to_le32(flag);
3511 
3512     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_PVB_CMDID,
3513                   NO_SYNC_WMIFLAG);
3514 
3515     return ret;
3516 }
3517 
3518 int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx,
3519                        u8 rx_meta_ver,
3520                        bool rx_dot11_hdr, bool defrag_on_host)
3521 {
3522     struct sk_buff *skb;
3523     struct wmi_rx_frame_format_cmd *cmd;
3524     int ret;
3525 
3526     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3527     if (!skb)
3528         return -ENOMEM;
3529 
3530     cmd = (struct wmi_rx_frame_format_cmd *) skb->data;
3531     cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0;
3532     cmd->defrag_on_host = defrag_on_host ? 1 : 0;
3533     cmd->meta_ver = rx_meta_ver;
3534 
3535     /* Delete the local aggr state, on host */
3536     ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_RX_FRAME_FORMAT_CMDID,
3537                   NO_SYNC_WMIFLAG);
3538 
3539     return ret;
3540 }
3541 
3542 int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
3543                  const u8 *ie, u8 ie_len)
3544 {
3545     struct sk_buff *skb;
3546     struct wmi_set_appie_cmd *p;
3547 
3548     skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
3549     if (!skb)
3550         return -ENOMEM;
3551 
3552     ath6kl_dbg(ATH6KL_DBG_WMI,
3553            "set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n",
3554            mgmt_frm_type, ie_len);
3555     p = (struct wmi_set_appie_cmd *) skb->data;
3556     p->mgmt_frm_type = mgmt_frm_type;
3557     p->ie_len = ie_len;
3558 
3559     if (ie != NULL && ie_len > 0)
3560         memcpy(p->ie_info, ie, ie_len);
3561 
3562     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,
3563                    NO_SYNC_WMIFLAG);
3564 }
3565 
3566 int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,
3567               const u8 *ie_info, u8 ie_len)
3568 {
3569     struct sk_buff *skb;
3570     struct wmi_set_ie_cmd *p;
3571 
3572     skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);
3573     if (!skb)
3574         return -ENOMEM;
3575 
3576     ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n",
3577            ie_id, ie_field, ie_len);
3578     p = (struct wmi_set_ie_cmd *) skb->data;
3579     p->ie_id = ie_id;
3580     p->ie_field = ie_field;
3581     p->ie_len = ie_len;
3582     if (ie_info && ie_len > 0)
3583         memcpy(p->ie_info, ie_info, ie_len);
3584 
3585     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID,
3586                    NO_SYNC_WMIFLAG);
3587 }
3588 
3589 int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)
3590 {
3591     struct sk_buff *skb;
3592     struct wmi_disable_11b_rates_cmd *cmd;
3593 
3594     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3595     if (!skb)
3596         return -ENOMEM;
3597 
3598     ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n",
3599            disable);
3600     cmd = (struct wmi_disable_11b_rates_cmd *) skb->data;
3601     cmd->disable = disable ? 1 : 0;
3602 
3603     return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_DISABLE_11B_RATES_CMDID,
3604                    NO_SYNC_WMIFLAG);
3605 }
3606 
3607 int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
3608 {
3609     struct sk_buff *skb;
3610     struct wmi_remain_on_chnl_cmd *p;
3611 
3612     skb = ath6kl_wmi_get_new_buf(sizeof(*p));
3613     if (!skb)
3614         return -ENOMEM;
3615 
3616     ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n",
3617            freq, dur);
3618     p = (struct wmi_remain_on_chnl_cmd *) skb->data;
3619     p->freq = cpu_to_le32(freq);
3620     p->duration = cpu_to_le32(dur);
3621     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_REMAIN_ON_CHNL_CMDID,
3622                    NO_SYNC_WMIFLAG);
3623 }
3624 
3625 /* ath6kl_wmi_send_action_cmd is to be deprecated. Use
3626  * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
3627  * mgmt operations using station interface.
3628  */
3629 static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
3630                       u32 freq, u32 wait, const u8 *data,
3631                       u16 data_len)
3632 {
3633     struct sk_buff *skb;
3634     struct wmi_send_action_cmd *p;
3635     u8 *buf;
3636 
3637     if (wait)
3638         return -EINVAL; /* Offload for wait not supported */
3639 
3640     buf = kmemdup(data, data_len, GFP_KERNEL);
3641     if (!buf)
3642         return -ENOMEM;
3643 
3644     skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
3645     if (!skb) {
3646         kfree(buf);
3647         return -ENOMEM;
3648     }
3649 
3650     kfree(wmi->last_mgmt_tx_frame);
3651     wmi->last_mgmt_tx_frame = buf;
3652     wmi->last_mgmt_tx_frame_len = data_len;
3653 
3654     ath6kl_dbg(ATH6KL_DBG_WMI,
3655            "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
3656            id, freq, wait, data_len);
3657     p = (struct wmi_send_action_cmd *) skb->data;
3658     p->id = cpu_to_le32(id);
3659     p->freq = cpu_to_le32(freq);
3660     p->wait = cpu_to_le32(wait);
3661     p->len = cpu_to_le16(data_len);
3662     memcpy(p->data, data, data_len);
3663     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_ACTION_CMDID,
3664                    NO_SYNC_WMIFLAG);
3665 }
3666 
3667 static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
3668                       u32 freq, u32 wait, const u8 *data,
3669                       u16 data_len, u32 no_cck)
3670 {
3671     struct sk_buff *skb;
3672     struct wmi_send_mgmt_cmd *p;
3673     u8 *buf;
3674 
3675     if (wait)
3676         return -EINVAL; /* Offload for wait not supported */
3677 
3678     buf = kmemdup(data, data_len, GFP_KERNEL);
3679     if (!buf)
3680         return -ENOMEM;
3681 
3682     skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
3683     if (!skb) {
3684         kfree(buf);
3685         return -ENOMEM;
3686     }
3687 
3688     kfree(wmi->last_mgmt_tx_frame);
3689     wmi->last_mgmt_tx_frame = buf;
3690     wmi->last_mgmt_tx_frame_len = data_len;
3691 
3692     ath6kl_dbg(ATH6KL_DBG_WMI,
3693            "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
3694            id, freq, wait, data_len);
3695     p = (struct wmi_send_mgmt_cmd *) skb->data;
3696     p->id = cpu_to_le32(id);
3697     p->freq = cpu_to_le32(freq);
3698     p->wait = cpu_to_le32(wait);
3699     p->no_cck = cpu_to_le32(no_cck);
3700     p->len = cpu_to_le16(data_len);
3701     memcpy(p->data, data, data_len);
3702     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_MGMT_CMDID,
3703                    NO_SYNC_WMIFLAG);
3704 }
3705 
3706 int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
3707                 u32 wait, const u8 *data, u16 data_len,
3708                 u32 no_cck)
3709 {
3710     int status;
3711     struct ath6kl *ar = wmi->parent_dev;
3712 
3713     if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
3714              ar->fw_capabilities)) {
3715         /*
3716          * If capable of doing P2P mgmt operations using
3717          * station interface, send additional information like
3718          * supported rates to advertise and xmit rates for
3719          * probe requests
3720          */
3721         status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq,
3722                             wait, data, data_len,
3723                             no_cck);
3724     } else {
3725         status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq,
3726                             wait, data, data_len);
3727     }
3728 
3729     return status;
3730 }
3731 
3732 int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
3733                        const u8 *dst, const u8 *data,
3734                        u16 data_len)
3735 {
3736     struct sk_buff *skb;
3737     struct wmi_p2p_probe_response_cmd *p;
3738     size_t cmd_len = sizeof(*p) + data_len;
3739 
3740     if (data_len == 0)
3741         cmd_len++; /* work around target minimum length requirement */
3742 
3743     skb = ath6kl_wmi_get_new_buf(cmd_len);
3744     if (!skb)
3745         return -ENOMEM;
3746 
3747     ath6kl_dbg(ATH6KL_DBG_WMI,
3748            "send_probe_response_cmd: freq=%u dst=%pM len=%u\n",
3749            freq, dst, data_len);
3750     p = (struct wmi_p2p_probe_response_cmd *) skb->data;
3751     p->freq = cpu_to_le32(freq);
3752     memcpy(p->destination_addr, dst, ETH_ALEN);
3753     p->len = cpu_to_le16(data_len);
3754     memcpy(p->data, data, data_len);
3755     return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
3756                    WMI_SEND_PROBE_RESPONSE_CMDID,
3757                    NO_SYNC_WMIFLAG);
3758 }
3759 
3760 int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, u8 if_idx, bool enable)
3761 {
3762     struct sk_buff *skb;
3763     struct wmi_probe_req_report_cmd *p;
3764 
3765     skb = ath6kl_wmi_get_new_buf(sizeof(*p));
3766     if (!skb)
3767         return -ENOMEM;
3768 
3769     ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n",
3770            enable);
3771     p = (struct wmi_probe_req_report_cmd *) skb->data;
3772     p->enable = enable ? 1 : 0;
3773     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_PROBE_REQ_REPORT_CMDID,
3774                    NO_SYNC_WMIFLAG);
3775 }
3776 
3777 int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u8 if_idx, u32 info_req_flags)
3778 {
3779     struct sk_buff *skb;
3780     struct wmi_get_p2p_info *p;
3781 
3782     skb = ath6kl_wmi_get_new_buf(sizeof(*p));
3783     if (!skb)
3784         return -ENOMEM;
3785 
3786     ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n",
3787            info_req_flags);
3788     p = (struct wmi_get_p2p_info *) skb->data;
3789     p->info_req_flags = cpu_to_le32(info_req_flags);
3790     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_GET_P2P_INFO_CMDID,
3791                    NO_SYNC_WMIFLAG);
3792 }
3793 
3794 int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx)
3795 {
3796     ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n");
3797     return ath6kl_wmi_simple_cmd(wmi, if_idx,
3798                      WMI_CANCEL_REMAIN_ON_CHNL_CMDID);
3799 }
3800 
3801 int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)
3802 {
3803     struct sk_buff *skb;
3804     struct wmi_set_inact_period_cmd *cmd;
3805 
3806     skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
3807     if (!skb)
3808         return -ENOMEM;
3809 
3810     cmd = (struct wmi_set_inact_period_cmd *) skb->data;
3811     cmd->inact_period = cpu_to_le32(inact_timeout);
3812     cmd->num_null_func = 0;
3813 
3814     return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_CONN_INACT_CMDID,
3815                    NO_SYNC_WMIFLAG);
3816 }
3817 
3818 static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap,
3819                            int len)
3820 {
3821     struct wmix_hb_challenge_resp_cmd *cmd;
3822 
3823     if (len < sizeof(struct wmix_hb_challenge_resp_cmd))
3824         return;
3825 
3826     cmd = (struct wmix_hb_challenge_resp_cmd *) datap;
3827     ath6kl_recovery_hb_event(wmi->parent_dev,
3828                  le32_to_cpu(cmd->cookie));
3829 }
3830 
3831 static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
3832 {
3833     struct wmix_cmd_hdr *cmd;
3834     u32 len;
3835     u16 id;
3836     u8 *datap;
3837     int ret = 0;
3838 
3839     if (skb->len < sizeof(struct wmix_cmd_hdr)) {
3840         ath6kl_err("bad packet 1\n");
3841         return -EINVAL;
3842     }
3843 
3844     cmd = (struct wmix_cmd_hdr *) skb->data;
3845     id = le32_to_cpu(cmd->cmd_id);
3846 
3847     skb_pull(skb, sizeof(struct wmix_cmd_hdr));
3848 
3849     datap = skb->data;
3850     len = skb->len;
3851 
3852     switch (id) {
3853     case WMIX_HB_CHALLENGE_RESP_EVENTID:
3854         ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n");
3855         ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len);
3856         break;
3857     case WMIX_DBGLOG_EVENTID:
3858         ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len);
3859         ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len);
3860         break;
3861     default:
3862         ath6kl_warn("unknown cmd id 0x%x\n", id);
3863         ret = -EINVAL;
3864         break;
3865     }
3866 
3867     return ret;
3868 }
3869 
3870 static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)
3871 {
3872     return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len);
3873 }
3874 
3875 /* Process interface specific wmi events, caller would free the datap */
3876 static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
3877                     u8 *datap, u32 len)
3878 {
3879     struct ath6kl_vif *vif;
3880 
3881     vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
3882     if (!vif) {
3883         ath6kl_dbg(ATH6KL_DBG_WMI,
3884                "Wmi event for unavailable vif, vif_index:%d\n",
3885                 if_idx);
3886         return -EINVAL;
3887     }
3888 
3889     switch (cmd_id) {
3890     case WMI_CONNECT_EVENTID:
3891         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
3892         return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
3893     case WMI_DISCONNECT_EVENTID:
3894         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
3895         return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
3896     case WMI_TKIP_MICERR_EVENTID:
3897         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
3898         return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
3899     case WMI_BSSINFO_EVENTID:
3900         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
3901         return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
3902     case WMI_NEIGHBOR_REPORT_EVENTID:
3903         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
3904         return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
3905                                vif);
3906     case WMI_SCAN_COMPLETE_EVENTID:
3907         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
3908         return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
3909     case WMI_REPORT_STATISTICS_EVENTID:
3910         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
3911         return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
3912     case WMI_CAC_EVENTID:
3913         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
3914         return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
3915     case WMI_PSPOLL_EVENTID:
3916         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
3917         return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
3918     case WMI_DTIMEXPIRY_EVENTID:
3919         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
3920         return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
3921     case WMI_ADDBA_REQ_EVENTID:
3922         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
3923         return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
3924     case WMI_DELBA_REQ_EVENTID:
3925         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
3926         return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
3927     case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
3928         ath6kl_dbg(ATH6KL_DBG_WMI,
3929                "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
3930         return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
3931     case WMI_REMAIN_ON_CHNL_EVENTID:
3932         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
3933         return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
3934     case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
3935         ath6kl_dbg(ATH6KL_DBG_WMI,
3936                "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
3937         return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
3938                                  len, vif);
3939     case WMI_TX_STATUS_EVENTID:
3940         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
3941         return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
3942     case WMI_RX_PROBE_REQ_EVENTID:
3943         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
3944         return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
3945     case WMI_RX_ACTION_EVENTID:
3946         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
3947         return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
3948     case WMI_TXE_NOTIFY_EVENTID:
3949         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n");
3950         return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif);
3951     default:
3952         ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
3953         return -EINVAL;
3954     }
3955 
3956     return 0;
3957 }
3958 
3959 static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb)
3960 {
3961     struct wmi_cmd_hdr *cmd;
3962     int ret = 0;
3963     u32 len;
3964     u16 id;
3965     u8 if_idx;
3966     u8 *datap;
3967 
3968     cmd = (struct wmi_cmd_hdr *) skb->data;
3969     id = le16_to_cpu(cmd->cmd_id);
3970     if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK;
3971 
3972     skb_pull(skb, sizeof(struct wmi_cmd_hdr));
3973     datap = skb->data;
3974     len = skb->len;
3975 
3976     ath6kl_dbg(ATH6KL_DBG_WMI, "wmi rx id %d len %d\n", id, len);
3977     ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ",
3978             datap, len);
3979 
3980     switch (id) {
3981     case WMI_GET_BITRATE_CMDID:
3982         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
3983         ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len);
3984         break;
3985     case WMI_GET_CHANNEL_LIST_CMDID:
3986         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n");
3987         ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len);
3988         break;
3989     case WMI_GET_TX_PWR_CMDID:
3990         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n");
3991         ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len);
3992         break;
3993     case WMI_READY_EVENTID:
3994         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
3995         ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
3996         break;
3997     case WMI_PEER_NODE_EVENTID:
3998         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
3999         ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
4000         break;
4001     case WMI_REGDOMAIN_EVENTID:
4002         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
4003         ath6kl_wmi_regdomain_event(wmi, datap, len);
4004         break;
4005     case WMI_PSTREAM_TIMEOUT_EVENTID:
4006         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
4007         ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
4008         break;
4009     case WMI_CMDERROR_EVENTID:
4010         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
4011         ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
4012         break;
4013     case WMI_RSSI_THRESHOLD_EVENTID:
4014         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
4015         ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
4016         break;
4017     case WMI_ERROR_REPORT_EVENTID:
4018         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n");
4019         break;
4020     case WMI_OPT_RX_FRAME_EVENTID:
4021         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n");
4022         /* this event has been deprecated */
4023         break;
4024     case WMI_REPORT_ROAM_TBL_EVENTID:
4025         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n");
4026         ret = ath6kl_wmi_roam_tbl_event_rx(wmi, datap, len);
4027         break;
4028     case WMI_EXTENSION_EVENTID:
4029         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
4030         ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
4031         break;
4032     case WMI_CHANNEL_CHANGE_EVENTID:
4033         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
4034         break;
4035     case WMI_REPORT_ROAM_DATA_EVENTID:
4036         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n");
4037         break;
4038     case WMI_TEST_EVENTID:
4039         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n");
4040         ret = ath6kl_wmi_test_rx(wmi, datap, len);
4041         break;
4042     case WMI_GET_FIXRATES_CMDID:
4043         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");
4044         ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len);
4045         break;
4046     case WMI_TX_RETRY_ERR_EVENTID:
4047         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n");
4048         break;
4049     case WMI_SNR_THRESHOLD_EVENTID:
4050         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n");
4051         ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len);
4052         break;
4053     case WMI_LQ_THRESHOLD_EVENTID:
4054         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n");
4055         break;
4056     case WMI_APLIST_EVENTID:
4057         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n");
4058         ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len);
4059         break;
4060     case WMI_GET_KEEPALIVE_CMDID:
4061         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n");
4062         ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len);
4063         break;
4064     case WMI_GET_WOW_LIST_EVENTID:
4065         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n");
4066         break;
4067     case WMI_GET_PMKID_LIST_EVENTID:
4068         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
4069         ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
4070         break;
4071     case WMI_SET_PARAMS_REPLY_EVENTID:
4072         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
4073         break;
4074     case WMI_ADDBA_RESP_EVENTID:
4075         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
4076         break;
4077     case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
4078         ath6kl_dbg(ATH6KL_DBG_WMI,
4079                "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
4080         break;
4081     case WMI_REPORT_BTCOEX_STATS_EVENTID:
4082         ath6kl_dbg(ATH6KL_DBG_WMI,
4083                "WMI_REPORT_BTCOEX_STATS_EVENTID\n");
4084         break;
4085     case WMI_TX_COMPLETE_EVENTID:
4086         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
4087         ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
4088         break;
4089     case WMI_P2P_CAPABILITIES_EVENTID:
4090         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
4091         ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);
4092         break;
4093     case WMI_P2P_INFO_EVENTID:
4094         ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
4095         ret = ath6kl_wmi_p2p_info_event_rx(datap, len);
4096         break;
4097     default:
4098         /* may be the event is interface specific */
4099         ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len);
4100         break;
4101     }
4102 
4103     dev_kfree_skb(skb);
4104     return ret;
4105 }
4106 
4107 /* Control Path */
4108 int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
4109 {
4110     if (WARN_ON(skb == NULL))
4111         return -EINVAL;
4112 
4113     if (skb->len < sizeof(struct wmi_cmd_hdr)) {
4114         ath6kl_err("bad packet 1\n");
4115         dev_kfree_skb(skb);
4116         return -EINVAL;
4117     }
4118 
4119     trace_ath6kl_wmi_event(skb->data, skb->len);
4120 
4121     return ath6kl_wmi_proc_events(wmi, skb);
4122 }
4123 
4124 void ath6kl_wmi_reset(struct wmi *wmi)
4125 {
4126     spin_lock_bh(&wmi->lock);
4127 
4128     wmi->fat_pipe_exist = 0;
4129     memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac));
4130 
4131     spin_unlock_bh(&wmi->lock);
4132 }
4133 
4134 void *ath6kl_wmi_init(struct ath6kl *dev)
4135 {
4136     struct wmi *wmi;
4137 
4138     wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);
4139     if (!wmi)
4140         return NULL;
4141 
4142     spin_lock_init(&wmi->lock);
4143 
4144     wmi->parent_dev = dev;
4145 
4146     wmi->pwr_mode = REC_POWER;
4147 
4148     ath6kl_wmi_reset(wmi);
4149 
4150     return wmi;
4151 }
4152 
4153 void ath6kl_wmi_shutdown(struct wmi *wmi)
4154 {
4155     if (!wmi)
4156         return;
4157 
4158     kfree(wmi->last_mgmt_tx_frame);
4159     kfree(wmi);
4160 }