ath6kl: logical continuations should be on the previous line
[cascardo/linux.git] / drivers / net / wireless / ath / ath6kl / wmi.c
index f6f2aa2..79aa90b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2004-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -126,7 +127,7 @@ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)
 
        if (!is_ethertype(be16_to_cpu(type))) {
                ath6kl_dbg(ATH6KL_DBG_WMI,
-                       "%s: pkt is already in 802.3 format\n", __func__);
+                          "%s: pkt is already in 802.3 format\n", __func__);
                return 0;
        }
 
@@ -180,7 +181,7 @@ static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,
 }
 
 int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
-                           u8 msg_type, bool more_data,
+                           u8 msg_type, u32 flags,
                            enum wmi_data_hdr_data_type data_type,
                            u8 meta_ver, void *tx_meta_info, u8 if_idx)
 {
@@ -204,17 +205,19 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
        data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;
        data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;
 
-       if (more_data)
-               data_hdr->info |=
-                   WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT;
+       if (flags & WMI_DATA_HDR_FLAGS_MORE)
+               data_hdr->info |= WMI_DATA_HDR_MORE;
 
-       data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
-       data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
+       if (flags & WMI_DATA_HDR_FLAGS_EOSP)
+               data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP);
+
+       data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);
+       data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);
 
        return 0;
 }
 
-static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
+u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
 {
        struct iphdr *ip_hdr = (struct iphdr *) pkt;
        u8 ip_pri;
@@ -236,6 +239,11 @@ static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)
                return ip_pri;
 }
 
+u8 ath6kl_wmi_get_traffic_class(u8 user_priority)
+{
+       return  up_to_ac[user_priority & 0x7];
+}
+
 int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
                                       struct sk_buff *skb,
                                       u32 layer2_priority, bool wmm_enabled,
@@ -419,9 +427,6 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
        ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
                   evt->num_msg, evt->msg_len, evt->msg_type);
 
-       if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI))
-               return 0;
-
        for (index = 0; index < evt->num_msg; index++) {
                size = sizeof(struct wmi_tx_complete_event) +
                    (index * sizeof(struct tx_complete_msg_v1));
@@ -786,12 +791,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
                                   ev->u.ap_sta.keymgmt,
                                   le16_to_cpu(ev->u.ap_sta.cipher),
                                   ev->u.ap_sta.apsd_info);
+
                        ath6kl_connect_ap_mode_sta(
                                vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,
                                ev->u.ap_sta.keymgmt,
                                le16_to_cpu(ev->u.ap_sta.cipher),
                                ev->u.ap_sta.auth, ev->assoc_req_len,
-                               ev->assoc_info + ev->beacon_ie_len);
+                               ev->assoc_info + ev->beacon_ie_len,
+                               ev->u.ap_sta.apsd_info);
                }
                return 0;
        }
@@ -819,8 +826,8 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
                        if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&
                            pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {
                                /* WMM OUT (00:50:F2) */
-                               if (pie[1] > 5
-                                   && pie[6] == WMM_PARAM_OUI_SUBTYPE)
+                               if (pie[1] > 5 &&
+                                   pie[6] == WMM_PARAM_OUI_SUBTYPE)
                                        wmi->is_wmm_enabled = true;
                        }
                        break;
@@ -904,17 +911,17 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
                regpair = ath6kl_get_regpair((u16) reg_code);
                country = ath6kl_regd_find_country_by_rd((u16) reg_code);
                ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
-                               regpair->regDmnEnum);
+                          regpair->regDmnEnum);
        }
 
-       if (country) {
+       if (country && wmi->parent_dev->wiphy_registered) {
                alpha2[0] = country->isoName[0];
                alpha2[1] = country->isoName[1];
 
                regulatory_hint(wmi->parent_dev->wiphy, alpha2);
 
                ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",
-                               alpha2[0], alpha2[1]);
+                          alpha2[0], alpha2[1]);
        }
 }
 
@@ -1025,8 +1032,9 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
        if (len < 8 + 2 + 2)
                return -EINVAL;
 
-       if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &vif->flags)
-           && memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
+       if (bih->frame_type == BEACON_FTYPE &&
+           test_bit(CONNECTED, &vif->flags) &&
+           memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {
                const u8 *tim;
                tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,
                                       len - 8 - 2 - 2);
@@ -1145,9 +1153,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
        return 0;
 }
 
-static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len)
+static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len)
 {
-       ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len);
+       ath6kl_tm_rx_event(wmi->parent_dev, datap, len);
 
        return 0;
 }
@@ -1358,8 +1366,8 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Upper threshold breached */
                if (rssi < sq_thresh->upper_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious upper rssi threshold event: %d\n",
-                               rssi);
+                                  "spurious upper rssi threshold event: %d\n",
+                                  rssi);
                } else if ((rssi < sq_thresh->upper_threshold[1]) &&
                           (rssi >= sq_thresh->upper_threshold[0])) {
                        new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;
@@ -1382,7 +1390,7 @@ static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Lower threshold breached */
                if (rssi > sq_thresh->lower_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious lower rssi threshold event: %d %d\n",
+                                  "spurious lower rssi threshold event: %d %d\n",
                                rssi, sq_thresh->lower_threshold[0]);
                } else if ((rssi > sq_thresh->lower_threshold[1]) &&
                           (rssi <= sq_thresh->lower_threshold[0])) {
@@ -1543,8 +1551,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Upper threshold breached */
                if (snr < sq_thresh->upper_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious upper snr threshold event: %d\n",
-                               snr);
+                                  "spurious upper snr threshold event: %d\n",
+                                  snr);
                } else if ((snr < sq_thresh->upper_threshold[1]) &&
                           (snr >= sq_thresh->upper_threshold[0])) {
                        new_threshold = WMI_SNR_THRESHOLD1_ABOVE;
@@ -1561,8 +1569,8 @@ static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,
                /* Lower threshold breached */
                if (snr > sq_thresh->lower_threshold[0]) {
                        ath6kl_dbg(ATH6KL_DBG_WMI,
-                               "spurious lower snr threshold event: %d\n",
-                               sq_thresh->lower_threshold[0]);
+                                  "spurious lower snr threshold event: %d\n",
+                                  sq_thresh->lower_threshold[0]);
                } else if ((snr > sq_thresh->lower_threshold[1]) &&
                           (snr <= sq_thresh->lower_threshold[0])) {
                        new_threshold = WMI_SNR_THRESHOLD4_BELOW;
@@ -2020,6 +2028,26 @@ int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,
        return ret;
 }
 
+int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,
+                            u16 bmiss_time, u16 num_beacons)
+{
+       struct sk_buff *skb;
+       struct wmi_bmiss_time_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_bmiss_time_cmd *) skb->data;
+       cmd->bmiss_time = cpu_to_le16(bmiss_time);
+       cmd->num_beacons = cpu_to_le16(num_beacons);
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
 int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode)
 {
        struct sk_buff *skb;
@@ -2479,15 +2507,16 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
        return ret;
 }
 
-int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
+int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,
+                         __be32 ips0, __be32 ips1)
 {
        struct sk_buff *skb;
        struct wmi_set_ip_cmd *cmd;
        int ret;
 
        /* Multicast address are not valid */
-       if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) ||
-           (*((u8 *) &ip_cmd->ips[1]) >= 0xE0))
+       if (ipv4_is_multicast(ips0) ||
+           ipv4_is_multicast(ips1))
                return -EINVAL;
 
        skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));
@@ -2495,9 +2524,10 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
                return -ENOMEM;
 
        cmd = (struct wmi_set_ip_cmd *) skb->data;
-       memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd));
+       cmd->ips[0] = ips0;
+       cmd->ips[1] = ips1;
 
-       ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_IP_CMDID,
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IP_CMDID,
                                  NO_SYNC_WMIFLAG);
        return ret;
 }
@@ -2582,6 +2612,18 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
        return ret;
 }
 
+/* This command has zero length payload */
+static int ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(struct wmi *wmi,
+                                                     struct ath6kl_vif *vif)
+{
+       struct ath6kl *ar = wmi->parent_dev;
+
+       set_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
+       wake_up(&ar->event_wq);
+
+       return 0;
+}
+
 int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
                                enum ath6kl_wow_mode wow_mode,
                                u32 filter, u16 host_req_delay)
@@ -2591,7 +2633,7 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
        int ret;
 
        if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) &&
-            wow_mode != ATH6KL_WOW_MODE_DISABLE) {
+           wow_mode != ATH6KL_WOW_MODE_DISABLE) {
                ath6kl_err("invalid wow mode: %d\n", wow_mode);
                return -EINVAL;
        }
@@ -2612,7 +2654,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
 
 int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
                                   u8 list_id, u8 filter_size,
-                                  u8 filter_offset, u8 *filter, u8 *mask)
+                                  u8 filter_offset, const u8 *filter,
+                                  const u8 *mask)
 {
        struct sk_buff *skb;
        struct wmi_add_wow_pattern_cmd *cmd;
@@ -2853,6 +2896,51 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)
        return ret;
 }
 
+int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on)
+{
+       struct sk_buff *skb;
+       struct wmi_mcast_filter_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_mcast_filter_cmd *) skb->data;
+       cmd->mcast_all_enable = mc_all_on;
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_MCAST_FILTER_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
+int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
+                                       u8 *filter, bool add_filter)
+{
+       struct sk_buff *skb;
+       struct wmi_mcast_filter_add_del_cmd *cmd;
+       int ret;
+
+       if ((filter[0] != 0x33 || filter[1] != 0x33) &&
+           (filter[0] != 0x01 || filter[1] != 0x00 ||
+           filter[2] != 0x5e || filter[3] > 0x7f)) {
+               ath6kl_warn("invalid multicast filter address\n");
+               return -EINVAL;
+       }
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_mcast_filter_add_del_cmd *) skb->data;
+       memcpy(cmd->mcast_mac, filter, ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 add_filter ? WMI_SET_MCAST_FILTER_CMDID :
+                                 WMI_DEL_MCAST_FILTER_CMDID,
+                                 NO_SYNC_WMIFLAG);
+
+       return ret;
+}
 
 s32 ath6kl_wmi_get_rate(s8 rate_index)
 {
@@ -2946,6 +3034,59 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable)
+{
+       struct sk_buff *skb;
+       struct wmi_ap_hidden_ssid_cmd *cmd;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data;
+       cmd->hidden_ssid = enable ? 1 : 0;
+
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
+/* This command will be used to enable/disable AP uAPSD feature */
+int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable)
+{
+       struct wmi_ap_set_apsd_cmd *cmd;
+       struct sk_buff *skb;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_ap_set_apsd_cmd *)skb->data;
+       cmd->enable = enable;
+
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx,
+                                            u16 aid, u16 bitmap, u32 flags)
+{
+       struct wmi_ap_apsd_buffered_traffic_cmd *cmd;
+       struct sk_buff *skb;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data;
+       cmd->aid = cpu_to_le16(aid);
+       cmd->bitmap = cpu_to_le16(bitmap);
+       cmd->flags = cpu_to_le32(flags);
+
+       return ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                  WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
 static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len,
                                      struct ath6kl_vif *vif)
 {
@@ -3078,8 +3219,9 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
  * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
  * mgmt operations using station interface.
  */
-int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
-                              u32 wait, const u8 *data, u16 data_len)
+static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
+                                     u32 freq, u32 wait, const u8 *data,
+                                     u16 data_len)
 {
        struct sk_buff *skb;
        struct wmi_send_action_cmd *p;
@@ -3115,9 +3257,9 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
                                   NO_SYNC_WMIFLAG);
 }
 
-int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
-                              u32 wait, const u8 *data, u16 data_len,
-                              u32 no_cck)
+static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
+                                     u32 freq, u32 wait, const u8 *data,
+                                     u16 data_len, u32 no_cck)
 {
        struct sk_buff *skb;
        struct wmi_send_mgmt_cmd *p;
@@ -3154,6 +3296,32 @@ int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
                                   NO_SYNC_WMIFLAG);
 }
 
+int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
+                               u32 wait, const u8 *data, u16 data_len,
+                               u32 no_cck)
+{
+       int status;
+       struct ath6kl *ar = wmi->parent_dev;
+
+       if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
+                    ar->fw_capabilities)) {
+               /*
+                * If capable of doing P2P mgmt operations using
+                * station interface, send additional information like
+                * supported rates to advertise and xmit rates for
+                * probe requests
+                */
+               status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq,
+                                                   wait, data, data_len,
+                                                   no_cck);
+       } else {
+               status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq,
+                                                   wait, data, data_len);
+       }
+
+       return status;
+}
+
 int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
                                       const u8 *dst, const u8 *data,
                                       u16 data_len)
@@ -3265,32 +3433,101 @@ static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)
        return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len);
 }
 
-/* Control Path */
-int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
+/* Process interface specific wmi events, caller would free the datap */
+static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
+                                       u8 *datap, u32 len)
 {
-       struct wmi_cmd_hdr *cmd;
        struct ath6kl_vif *vif;
-       u32 len;
-       u16 id;
-       u8 if_idx;
-       u8 *datap;
-       int ret = 0;
 
-       if (WARN_ON(skb == NULL))
+       vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
+       if (!vif) {
+               ath6kl_dbg(ATH6KL_DBG_WMI,
+                          "Wmi event for unavailable vif, vif_index:%d\n",
+                           if_idx);
                return -EINVAL;
+       }
 
-       if (skb->len < sizeof(struct wmi_cmd_hdr)) {
-               ath6kl_err("bad packet 1\n");
-               dev_kfree_skb(skb);
+       switch (cmd_id) {
+       case WMI_CONNECT_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
+               return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
+       case WMI_DISCONNECT_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
+               return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
+       case WMI_TKIP_MICERR_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
+               return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
+       case WMI_BSSINFO_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
+               return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
+       case WMI_NEIGHBOR_REPORT_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
+               return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
+                                                          vif);
+       case WMI_SCAN_COMPLETE_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
+               return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
+       case WMI_REPORT_STATISTICS_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
+               return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
+       case WMI_CAC_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
+               return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
+       case WMI_PSPOLL_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
+               return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
+       case WMI_DTIMEXPIRY_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
+               return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
+       case WMI_ADDBA_REQ_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
+               return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
+       case WMI_DELBA_REQ_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
+               return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
+       case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI,
+                          "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
+               return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
+       case WMI_REMAIN_ON_CHNL_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
+               return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
+       case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI,
+                          "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
+               return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
+                                                                len, vif);
+       case WMI_TX_STATUS_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
+               return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
+       case WMI_RX_PROBE_REQ_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
+               return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
+       case WMI_RX_ACTION_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
+               return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
+       default:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
                return -EINVAL;
        }
 
+       return 0;
+}
+
+static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb)
+{
+       struct wmi_cmd_hdr *cmd;
+       int ret = 0;
+       u32 len;
+       u16 id;
+       u8 if_idx;
+       u8 *datap;
+
        cmd = (struct wmi_cmd_hdr *) skb->data;
        id = le16_to_cpu(cmd->cmd_id);
        if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK;
 
        skb_pull(skb, sizeof(struct wmi_cmd_hdr));
-
        datap = skb->data;
        len = skb->len;
 
@@ -3298,15 +3535,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
        ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ",
                        datap, len);
 
-       vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);
-       if (!vif) {
-               ath6kl_dbg(ATH6KL_DBG_WMI,
-                          "Wmi event for unavailable vif, vif_index:%d\n",
-                           if_idx);
-               dev_kfree_skb(skb);
-               return -EINVAL;
-       }
-
        switch (id) {
        case WMI_GET_BITRATE_CMDID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");
@@ -3324,26 +3552,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");
                ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);
                break;
-       case WMI_CONNECT_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");
-               ret = ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_DISCONNECT_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");
-               ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_PEER_NODE_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");
                ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);
                break;
-       case WMI_TKIP_MICERR_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");
-               ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_BSSINFO_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");
-               ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_REGDOMAIN_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");
                ath6kl_wmi_regdomain_event(wmi, datap, len);
@@ -3352,23 +3564,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");
                ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);
                break;
-       case WMI_NEIGHBOR_REPORT_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");
-               ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,
-                                                         vif);
-               break;
-       case WMI_SCAN_COMPLETE_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");
-               ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);
-               break;
        case WMI_CMDERROR_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");
                ret = ath6kl_wmi_error_event_rx(wmi, datap, len);
                break;
-       case WMI_REPORT_STATISTICS_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");
-               ret = ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_RSSI_THRESHOLD_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");
                ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);
@@ -3388,10 +3587,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");
                ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);
                break;
-       case WMI_CAC_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");
-               ret = ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_CHANNEL_CHANGE_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");
                break;
@@ -3400,7 +3595,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                break;
        case WMI_TEST_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n");
-               ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len);
+               ret = ath6kl_wmi_test_rx(wmi, datap, len);
                break;
        case WMI_GET_FIXRATES_CMDID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");
@@ -3431,28 +3626,12 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
                ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);
                break;
-       case WMI_PSPOLL_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");
-               ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_DTIMEXPIRY_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");
-               ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_SET_PARAMS_REPLY_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");
                break;
-       case WMI_ADDBA_REQ_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");
-               ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_ADDBA_RESP_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");
                break;
-       case WMI_DELBA_REQ_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");
-               ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_REPORT_BTCOEX_CONFIG_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI,
                           "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");
@@ -3465,47 +3644,39 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
                ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
                break;
-       case WMI_REMAIN_ON_CHNL_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
-               ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI,
-                          "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");
-               ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,
-                                                               len, vif);
-               break;
-       case WMI_TX_STATUS_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");
-               ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);
-               break;
-       case WMI_RX_PROBE_REQ_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");
-               ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_P2P_CAPABILITIES_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");
                ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);
                break;
-       case WMI_RX_ACTION_EVENTID:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
-               ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
-               break;
        case WMI_P2P_INFO_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");
                ret = ath6kl_wmi_p2p_info_event_rx(datap, len);
                break;
        default:
-               ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id);
-               ret = -EINVAL;
+               /* may be the event is interface specific */
+               ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len);
                break;
        }
 
        dev_kfree_skb(skb);
-
        return ret;
 }
 
+/* Control Path */
+int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
+{
+       if (WARN_ON(skb == NULL))
+               return -EINVAL;
+
+       if (skb->len < sizeof(struct wmi_cmd_hdr)) {
+               ath6kl_err("bad packet 1\n");
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       return ath6kl_wmi_proc_events(wmi, skb);
+}
+
 void ath6kl_wmi_reset(struct wmi *wmi)
 {
        spin_lock_bh(&wmi->lock);