linux/drivers/staging/wilc1000/wilc_hif.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
   4 * All rights reserved.
   5 */
   6
   7#include "wilc_wfi_netdevice.h"
   8
   9#define WILC_HIF_SCAN_TIMEOUT_MS                5000
  10#define WILC_HIF_CONNECT_TIMEOUT_MS             9500
  11
  12#define WILC_FALSE_FRMWR_CHANNEL                100
  13#define WILC_MAX_RATES_SUPPORTED                12
  14
  15struct wilc_rcvd_mac_info {
  16        u8 status;
  17};
  18
  19struct wilc_set_multicast {
  20        u32 enabled;
  21        u32 cnt;
  22        u8 *mc_list;
  23};
  24
  25struct wilc_del_all_sta {
  26        u8 assoc_sta;
  27        u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];
  28};
  29
  30struct wilc_op_mode {
  31        __le32 mode;
  32};
  33
  34struct wilc_reg_frame {
  35        bool reg;
  36        u8 reg_id;
  37        __le16 frame_type;
  38} __packed;
  39
  40struct wilc_drv_handler {
  41        __le32 handler;
  42        u8 mode;
  43} __packed;
  44
  45struct wilc_wep_key {
  46        u8 index;
  47        u8 key_len;
  48        u8 key[0];
  49} __packed;
  50
  51struct wilc_sta_wpa_ptk {
  52        u8 mac_addr[ETH_ALEN];
  53        u8 key_len;
  54        u8 key[0];
  55} __packed;
  56
  57struct wilc_ap_wpa_ptk {
  58        u8 mac_addr[ETH_ALEN];
  59        u8 index;
  60        u8 key_len;
  61        u8 key[0];
  62} __packed;
  63
  64struct wilc_gtk_key {
  65        u8 mac_addr[ETH_ALEN];
  66        u8 rsc[8];
  67        u8 index;
  68        u8 key_len;
  69        u8 key[0];
  70} __packed;
  71
  72union wilc_message_body {
  73        struct wilc_rcvd_net_info net_info;
  74        struct wilc_rcvd_mac_info mac_info;
  75        struct wilc_set_multicast mc_info;
  76        struct wilc_remain_ch remain_on_ch;
  77        char *data;
  78};
  79
  80struct host_if_msg {
  81        union wilc_message_body body;
  82        struct wilc_vif *vif;
  83        struct work_struct work;
  84        void (*fn)(struct work_struct *ws);
  85        struct completion work_comp;
  86        bool is_sync;
  87};
  88
  89struct wilc_noa_opp_enable {
  90        u8 ct_window;
  91        u8 cnt;
  92        __le32 duration;
  93        __le32 interval;
  94        __le32 start_time;
  95} __packed;
  96
  97struct wilc_noa_opp_disable {
  98        u8 cnt;
  99        __le32 duration;
 100        __le32 interval;
 101        __le32 start_time;
 102} __packed;
 103
 104struct wilc_join_bss_param {
 105        char ssid[IEEE80211_MAX_SSID_LEN];
 106        u8 ssid_terminator;
 107        u8 bss_type;
 108        u8 ch;
 109        __le16 cap_info;
 110        u8 sa[ETH_ALEN];
 111        u8 bssid[ETH_ALEN];
 112        __le16 beacon_period;
 113        u8 dtim_period;
 114        u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1];
 115        u8 wmm_cap;
 116        u8 uapsd_cap;
 117        u8 ht_capable;
 118        u8 rsn_found;
 119        u8 rsn_grp_policy;
 120        u8 mode_802_11i;
 121        u8 p_suites[3];
 122        u8 akm_suites[3];
 123        u8 rsn_cap[2];
 124        u8 noa_enabled;
 125        __le32 tsf_lo;
 126        u8 idx;
 127        u8 opp_enabled;
 128        union {
 129                struct wilc_noa_opp_disable opp_dis;
 130                struct wilc_noa_opp_enable opp_en;
 131        };
 132} __packed;
 133
 134/* 'msg' should be free by the caller for syc */
 135static struct host_if_msg*
 136wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),
 137                bool is_sync)
 138{
 139        struct host_if_msg *msg;
 140
 141        if (!work_fun)
 142                return ERR_PTR(-EINVAL);
 143
 144        msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
 145        if (!msg)
 146                return ERR_PTR(-ENOMEM);
 147        msg->fn = work_fun;
 148        msg->vif = vif;
 149        msg->is_sync = is_sync;
 150        if (is_sync)
 151                init_completion(&msg->work_comp);
 152
 153        return msg;
 154}
 155
 156static int wilc_enqueue_work(struct host_if_msg *msg)
 157{
 158        INIT_WORK(&msg->work, msg->fn);
 159
 160        if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)
 161                return -EINVAL;
 162
 163        if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))
 164                return -EINVAL;
 165
 166        return 0;
 167}
 168
 169/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as
 170 * special purpose in wilc device, so we add 1 to the index to starts from 1.
 171 * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.
 172 */
 173int wilc_get_vif_idx(struct wilc_vif *vif)
 174{
 175        return vif->idx + 1;
 176}
 177
 178/* We need to minus 1 from idx which is from wilc device to get real index
 179 * of wilc->vif[], because we add 1 when pass to wilc device in the function
 180 * wilc_get_vif_idx.
 181 * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1).
 182 */
 183static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)
 184{
 185        int index = idx - 1;
 186
 187        if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)
 188                return NULL;
 189
 190        return wilc->vif[index];
 191}
 192
 193static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
 194{
 195        int result = 0;
 196        u8 abort_running_scan;
 197        struct wid wid;
 198        struct host_if_drv *hif_drv = vif->hif_drv;
 199        struct wilc_user_scan_req *scan_req;
 200
 201        if (evt == SCAN_EVENT_ABORTED) {
 202                abort_running_scan = 1;
 203                wid.id = WID_ABORT_RUNNING_SCAN;
 204                wid.type = WID_CHAR;
 205                wid.val = (s8 *)&abort_running_scan;
 206                wid.size = sizeof(char);
 207
 208                result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
 209                if (result) {
 210                        netdev_err(vif->ndev, "Failed to set abort running\n");
 211                        result = -EFAULT;
 212                }
 213        }
 214
 215        if (!hif_drv) {
 216                netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
 217                return result;
 218        }
 219
 220        scan_req = &hif_drv->usr_scan_req;
 221        if (scan_req->scan_result) {
 222                scan_req->scan_result(evt, NULL, scan_req->arg);
 223                scan_req->scan_result = NULL;
 224        }
 225
 226        return result;
 227}
 228
 229int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
 230              u8 *ch_freq_list, u8 ch_list_len,
 231              void (*scan_result_fn)(enum scan_event,
 232                                     struct wilc_rcvd_net_info *, void *),
 233              void *user_arg, struct cfg80211_scan_request *request)
 234{
 235        int result = 0;
 236        struct wid wid_list[5];
 237        u32 index = 0;
 238        u32 i, scan_timeout;
 239        u8 *buffer;
 240        u8 valuesize = 0;
 241        u8 *search_ssid_vals = NULL;
 242        struct host_if_drv *hif_drv = vif->hif_drv;
 243
 244        if (hif_drv->hif_state >= HOST_IF_SCANNING &&
 245            hif_drv->hif_state < HOST_IF_CONNECTED) {
 246                netdev_err(vif->ndev, "Already scan\n");
 247                result = -EBUSY;
 248                goto error;
 249        }
 250
 251        if (vif->obtaining_ip || vif->connecting) {
 252                netdev_err(vif->ndev, "Don't do obss scan\n");
 253                result = -EBUSY;
 254                goto error;
 255        }
 256
 257        hif_drv->usr_scan_req.ch_cnt = 0;
 258
 259        if (request->n_ssids) {
 260                for (i = 0; i < request->n_ssids; i++)
 261                        valuesize += ((request->ssids[i].ssid_len) + 1);
 262                search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);
 263                if (search_ssid_vals) {
 264                        wid_list[index].id = WID_SSID_PROBE_REQ;
 265                        wid_list[index].type = WID_STR;
 266                        wid_list[index].val = search_ssid_vals;
 267                        buffer = wid_list[index].val;
 268
 269                        *buffer++ = request->n_ssids;
 270
 271                        for (i = 0; i < request->n_ssids; i++) {
 272                                *buffer++ = request->ssids[i].ssid_len;
 273                                memcpy(buffer, request->ssids[i].ssid,
 274                                       request->ssids[i].ssid_len);
 275                                buffer += request->ssids[i].ssid_len;
 276                        }
 277                        wid_list[index].size = (s32)(valuesize + 1);
 278                        index++;
 279                }
 280        }
 281
 282        wid_list[index].id = WID_INFO_ELEMENT_PROBE;
 283        wid_list[index].type = WID_BIN_DATA;
 284        wid_list[index].val = (s8 *)request->ie;
 285        wid_list[index].size = request->ie_len;
 286        index++;
 287
 288        wid_list[index].id = WID_SCAN_TYPE;
 289        wid_list[index].type = WID_CHAR;
 290        wid_list[index].size = sizeof(char);
 291        wid_list[index].val = (s8 *)&scan_type;
 292        index++;
 293
 294        if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {
 295                wid_list[index].id = WID_PASSIVE_SCAN_TIME;
 296                wid_list[index].type = WID_SHORT;
 297                wid_list[index].size = sizeof(u16);
 298                wid_list[index].val = (s8 *)&request->duration;
 299                index++;
 300
 301                scan_timeout = (request->duration * ch_list_len) + 500;
 302        } else {
 303                scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;
 304        }
 305
 306        wid_list[index].id = WID_SCAN_CHANNEL_LIST;
 307        wid_list[index].type = WID_BIN_DATA;
 308
 309        if (ch_freq_list && ch_list_len > 0) {
 310                for (i = 0; i < ch_list_len; i++) {
 311                        if (ch_freq_list[i] > 0)
 312                                ch_freq_list[i] -= 1;
 313                }
 314        }
 315
 316        wid_list[index].val = ch_freq_list;
 317        wid_list[index].size = ch_list_len;
 318        index++;
 319
 320        wid_list[index].id = WID_START_SCAN_REQ;
 321        wid_list[index].type = WID_CHAR;
 322        wid_list[index].size = sizeof(char);
 323        wid_list[index].val = (s8 *)&scan_source;
 324        index++;
 325
 326        hif_drv->usr_scan_req.scan_result = scan_result_fn;
 327        hif_drv->usr_scan_req.arg = user_arg;
 328
 329        result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);
 330        if (result) {
 331                netdev_err(vif->ndev, "Failed to send scan parameters\n");
 332                goto error;
 333        }
 334
 335        hif_drv->scan_timer_vif = vif;
 336        mod_timer(&hif_drv->scan_timer,
 337                  jiffies + msecs_to_jiffies(scan_timeout));
 338
 339error:
 340
 341        kfree(search_ssid_vals);
 342
 343        return result;
 344}
 345
 346static int wilc_send_connect_wid(struct wilc_vif *vif)
 347{
 348        int result = 0;
 349        struct wid wid_list[4];
 350        u32 wid_cnt = 0;
 351        struct host_if_drv *hif_drv = vif->hif_drv;
 352        struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
 353        struct wilc_join_bss_param *bss_param = conn_attr->param;
 354
 355        wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
 356        wid_list[wid_cnt].type = WID_BIN_DATA;
 357        wid_list[wid_cnt].val = conn_attr->req_ies;
 358        wid_list[wid_cnt].size = conn_attr->req_ies_len;
 359        wid_cnt++;
 360
 361        wid_list[wid_cnt].id = WID_11I_MODE;
 362        wid_list[wid_cnt].type = WID_CHAR;
 363        wid_list[wid_cnt].size = sizeof(char);
 364        wid_list[wid_cnt].val = (s8 *)&conn_attr->security;
 365        wid_cnt++;
 366
 367        wid_list[wid_cnt].id = WID_AUTH_TYPE;
 368        wid_list[wid_cnt].type = WID_CHAR;
 369        wid_list[wid_cnt].size = sizeof(char);
 370        wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type;
 371        wid_cnt++;
 372
 373        wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;
 374        wid_list[wid_cnt].type = WID_STR;
 375        wid_list[wid_cnt].size = sizeof(*bss_param);
 376        wid_list[wid_cnt].val = (u8 *)bss_param;
 377        wid_cnt++;
 378
 379        result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);
 380        if (result) {
 381                netdev_err(vif->ndev, "failed to send config packet\n");
 382                goto error;
 383        } else {
 384                hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
 385        }
 386
 387        return 0;
 388
 389error:
 390
 391        kfree(conn_attr->req_ies);
 392        conn_attr->req_ies = NULL;
 393
 394        return result;
 395}
 396
 397static void handle_connect_timeout(struct work_struct *work)
 398{
 399        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
 400        struct wilc_vif *vif = msg->vif;
 401        int result;
 402        struct wid wid;
 403        u16 dummy_reason_code = 0;
 404        struct host_if_drv *hif_drv = vif->hif_drv;
 405
 406        if (!hif_drv) {
 407                netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
 408                goto out;
 409        }
 410
 411        hif_drv->hif_state = HOST_IF_IDLE;
 412
 413        if (hif_drv->conn_info.conn_result) {
 414                hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
 415                                               WILC_MAC_STATUS_DISCONNECTED,
 416                                               hif_drv->conn_info.arg);
 417
 418        } else {
 419                netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
 420        }
 421
 422        wid.id = WID_DISCONNECT;
 423        wid.type = WID_CHAR;
 424        wid.val = (s8 *)&dummy_reason_code;
 425        wid.size = sizeof(char);
 426
 427        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
 428        if (result)
 429                netdev_err(vif->ndev, "Failed to send disconnect\n");
 430
 431        hif_drv->conn_info.req_ies_len = 0;
 432        kfree(hif_drv->conn_info.req_ies);
 433        hif_drv->conn_info.req_ies = NULL;
 434
 435out:
 436        kfree(msg);
 437}
 438
 439void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
 440                                struct cfg80211_crypto_settings *crypto)
 441{
 442        struct wilc_join_bss_param *param;
 443        struct ieee80211_p2p_noa_attr noa_attr;
 444        u8 rates_len = 0;
 445        const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;
 446        const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;
 447        int ret;
 448        const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies);
 449
 450        param = kzalloc(sizeof(*param), GFP_KERNEL);
 451        if (!param)
 452                return NULL;
 453
 454        param->beacon_period = cpu_to_le16(bss->beacon_interval);
 455        param->cap_info = cpu_to_le16(bss->capability);
 456        param->bss_type = WILC_FW_BSS_TYPE_INFRA;
 457        param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
 458        ether_addr_copy(param->bssid, bss->bssid);
 459
 460        ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
 461        if (ssid_elm) {
 462                if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)
 463                        memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);
 464        }
 465
 466        tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len);
 467        if (tim_elm && tim_elm[1] >= 2)
 468                param->dtim_period = tim_elm[3];
 469
 470        memset(param->p_suites, 0xFF, 3);
 471        memset(param->akm_suites, 0xFF, 3);
 472
 473        rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len);
 474        if (rates_ie) {
 475                rates_len = rates_ie[1];
 476                param->supp_rates[0] = rates_len;
 477                memcpy(&param->supp_rates[1], rates_ie + 2, rates_len);
 478        }
 479
 480        supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data,
 481                                         ies->len);
 482        if (supp_rates_ie) {
 483                if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len))
 484                        param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;
 485                else
 486                        param->supp_rates[0] += supp_rates_ie[1];
 487
 488                memcpy(&param->supp_rates[rates_len + 1], supp_rates_ie + 2,
 489                       (param->supp_rates[0] - rates_len));
 490        }
 491
 492        ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len);
 493        if (ht_ie)
 494                param->ht_capable = true;
 495
 496        ret = cfg80211_get_p2p_attr(ies->data, ies->len,
 497                                    IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
 498                                    (u8 *)&noa_attr, sizeof(noa_attr));
 499        if (ret > 0) {
 500                param->tsf_lo = cpu_to_le32(ies->tsf);
 501                param->noa_enabled = 1;
 502                param->idx = noa_attr.index;
 503                if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {
 504                        param->opp_enabled = 1;
 505                        param->opp_en.ct_window = noa_attr.oppps_ctwindow;
 506                        param->opp_en.cnt = noa_attr.desc[0].count;
 507                        param->opp_en.duration = noa_attr.desc[0].duration;
 508                        param->opp_en.interval = noa_attr.desc[0].interval;
 509                        param->opp_en.start_time = noa_attr.desc[0].start_time;
 510                } else {
 511                        param->opp_enabled = 0;
 512                        param->opp_dis.cnt = noa_attr.desc[0].count;
 513                        param->opp_dis.duration = noa_attr.desc[0].duration;
 514                        param->opp_dis.interval = noa_attr.desc[0].interval;
 515                        param->opp_dis.start_time = noa_attr.desc[0].start_time;
 516                }
 517        }
 518        wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
 519                                         WLAN_OUI_TYPE_MICROSOFT_WMM,
 520                                         ies->data, ies->len);
 521        if (wmm_ie) {
 522                struct ieee80211_wmm_param_ie *ie;
 523
 524                ie = (struct ieee80211_wmm_param_ie *)wmm_ie;
 525                if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) &&
 526                    ie->version == 1) {
 527                        param->wmm_cap = true;
 528                        if (ie->qos_info & BIT(7))
 529                                param->uapsd_cap = true;
 530                }
 531        }
 532
 533        wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
 534                                         WLAN_OUI_TYPE_MICROSOFT_WPA,
 535                                         ies->data, ies->len);
 536        if (wpa_ie) {
 537                param->mode_802_11i = 1;
 538                param->rsn_found = true;
 539        }
 540
 541        rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len);
 542        if (rsn_ie) {
 543                int offset = 8;
 544
 545                param->mode_802_11i = 2;
 546                param->rsn_found = true;
 547                //extract RSN capabilities
 548                offset += (rsn_ie[offset] * 4) + 2;
 549                offset += (rsn_ie[offset] * 4) + 2;
 550                memcpy(param->rsn_cap, &rsn_ie[offset], 2);
 551        }
 552
 553        if (param->rsn_found) {
 554                int i;
 555
 556                param->rsn_grp_policy = crypto->cipher_group & 0xFF;
 557                for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++)
 558                        param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF;
 559
 560                for (i = 0; i < crypto->n_akm_suites && i < 3; i++)
 561                        param->akm_suites[i] = crypto->akm_suites[i] & 0xFF;
 562        }
 563
 564        return (void *)param;
 565}
 566
 567static void handle_rcvd_ntwrk_info(struct work_struct *work)
 568{
 569        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
 570        struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info;
 571        struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req;
 572        const u8 *ch_elm;
 573        u8 *ies;
 574        int ies_len;
 575        size_t offset;
 576
 577        if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control))
 578                offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
 579        else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control))
 580                offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
 581        else
 582                goto done;
 583
 584        ies = rcvd_info->mgmt->u.beacon.variable;
 585        ies_len = rcvd_info->frame_len - offset;
 586        if (ies_len <= 0)
 587                goto done;
 588
 589        ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);
 590        if (ch_elm && ch_elm[1] > 0)
 591                rcvd_info->ch = ch_elm[2];
 592
 593        if (scan_req->scan_result)
 594                scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,
 595                                      scan_req->arg);
 596
 597done:
 598        kfree(rcvd_info->mgmt);
 599        kfree(msg);
 600}
 601
 602static void host_int_get_assoc_res_info(struct wilc_vif *vif,
 603                                        u8 *assoc_resp_info,
 604                                        u32 max_assoc_resp_info_len,
 605                                        u32 *rcvd_assoc_resp_info_len)
 606{
 607        int result;
 608        struct wid wid;
 609
 610        wid.id = WID_ASSOC_RES_INFO;
 611        wid.type = WID_STR;
 612        wid.val = assoc_resp_info;
 613        wid.size = max_assoc_resp_info_len;
 614
 615        result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
 616        if (result) {
 617                *rcvd_assoc_resp_info_len = 0;
 618                netdev_err(vif->ndev, "Failed to send association response\n");
 619                return;
 620        }
 621
 622        *rcvd_assoc_resp_info_len = wid.size;
 623}
 624
 625static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
 626                                      struct wilc_conn_info *ret_conn_info)
 627{
 628        u8 *ies;
 629        u16 ies_len;
 630        struct assoc_resp *res = (struct assoc_resp *)buffer;
 631
 632        ret_conn_info->status = le16_to_cpu(res->status_code);
 633        if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
 634                ies = &buffer[sizeof(*res)];
 635                ies_len = buffer_len - sizeof(*res);
 636
 637                ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL);
 638                if (!ret_conn_info->resp_ies)
 639                        return -ENOMEM;
 640
 641                ret_conn_info->resp_ies_len = ies_len;
 642        }
 643
 644        return 0;
 645}
 646
 647static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
 648                                                  u8 mac_status)
 649{
 650        struct host_if_drv *hif_drv = vif->hif_drv;
 651        struct wilc_conn_info *conn_info = &hif_drv->conn_info;
 652
 653        if (mac_status == WILC_MAC_STATUS_CONNECTED) {
 654                u32 assoc_resp_info_len;
 655
 656                memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);
 657
 658                host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,
 659                                            WILC_MAX_ASSOC_RESP_FRAME_SIZE,
 660                                            &assoc_resp_info_len);
 661
 662                if (assoc_resp_info_len != 0) {
 663                        s32 err = 0;
 664
 665                        err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,
 666                                                         assoc_resp_info_len,
 667                                                         conn_info);
 668                        if (err)
 669                                netdev_err(vif->ndev,
 670                                           "wilc_parse_assoc_resp_info() returned error %d\n",
 671                                           err);
 672                }
 673        }
 674
 675        del_timer(&hif_drv->connect_timer);
 676        conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
 677                               hif_drv->conn_info.arg);
 678
 679        if (mac_status == WILC_MAC_STATUS_CONNECTED &&
 680            conn_info->status == WLAN_STATUS_SUCCESS) {
 681                ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);
 682                wilc_set_power_mgmt(vif, 0, 0);
 683
 684                hif_drv->hif_state = HOST_IF_CONNECTED;
 685
 686                vif->obtaining_ip = true;
 687                mod_timer(&vif->during_ip_timer,
 688                          jiffies + msecs_to_jiffies(10000));
 689        } else {
 690                hif_drv->hif_state = HOST_IF_IDLE;
 691        }
 692
 693        kfree(conn_info->resp_ies);
 694        conn_info->resp_ies = NULL;
 695        conn_info->resp_ies_len = 0;
 696
 697        kfree(conn_info->req_ies);
 698        conn_info->req_ies = NULL;
 699        conn_info->req_ies_len = 0;
 700}
 701
 702static inline void host_int_handle_disconnect(struct wilc_vif *vif)
 703{
 704        struct host_if_drv *hif_drv = vif->hif_drv;
 705
 706        if (hif_drv->usr_scan_req.scan_result) {
 707                del_timer(&hif_drv->scan_timer);
 708                handle_scan_done(vif, SCAN_EVENT_ABORTED);
 709        }
 710
 711        if (hif_drv->conn_info.conn_result) {
 712                vif->obtaining_ip = false;
 713                wilc_set_power_mgmt(vif, 0, 0);
 714
 715                hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
 716                                               0, hif_drv->conn_info.arg);
 717        } else {
 718                netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
 719        }
 720
 721        eth_zero_addr(hif_drv->assoc_bssid);
 722
 723        hif_drv->conn_info.req_ies_len = 0;
 724        kfree(hif_drv->conn_info.req_ies);
 725        hif_drv->conn_info.req_ies = NULL;
 726        hif_drv->hif_state = HOST_IF_IDLE;
 727}
 728
 729static void handle_rcvd_gnrl_async_info(struct work_struct *work)
 730{
 731        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
 732        struct wilc_vif *vif = msg->vif;
 733        struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;
 734        struct host_if_drv *hif_drv = vif->hif_drv;
 735
 736        if (!hif_drv) {
 737                netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);
 738                goto free_msg;
 739        }
 740
 741        if (!hif_drv->conn_info.conn_result) {
 742                netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
 743                goto free_msg;
 744        }
 745
 746        if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
 747                host_int_parse_assoc_resp_info(vif, mac_info->status);
 748        } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {
 749                if (hif_drv->hif_state == HOST_IF_CONNECTED) {
 750                        host_int_handle_disconnect(vif);
 751                } else if (hif_drv->usr_scan_req.scan_result) {
 752                        del_timer(&hif_drv->scan_timer);
 753                        handle_scan_done(vif, SCAN_EVENT_ABORTED);
 754                }
 755        }
 756
 757free_msg:
 758        kfree(msg);
 759}
 760
 761int wilc_disconnect(struct wilc_vif *vif)
 762{
 763        struct wid wid;
 764        struct host_if_drv *hif_drv = vif->hif_drv;
 765        struct wilc_user_scan_req *scan_req;
 766        struct wilc_conn_info *conn_info;
 767        int result;
 768        u16 dummy_reason_code = 0;
 769
 770        wid.id = WID_DISCONNECT;
 771        wid.type = WID_CHAR;
 772        wid.val = (s8 *)&dummy_reason_code;
 773        wid.size = sizeof(char);
 774
 775        vif->obtaining_ip = false;
 776        wilc_set_power_mgmt(vif, 0, 0);
 777
 778        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
 779        if (result) {
 780                netdev_err(vif->ndev, "Failed to send disconnect\n");
 781                return result;
 782        }
 783
 784        scan_req = &hif_drv->usr_scan_req;
 785        conn_info = &hif_drv->conn_info;
 786
 787        if (scan_req->scan_result) {
 788                del_timer(&hif_drv->scan_timer);
 789                scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg);
 790                scan_req->scan_result = NULL;
 791        }
 792
 793        if (conn_info->conn_result) {
 794                if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
 795                        del_timer(&hif_drv->connect_timer);
 796
 797                conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
 798                                       conn_info->arg);
 799        } else {
 800                netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
 801        }
 802
 803        hif_drv->hif_state = HOST_IF_IDLE;
 804
 805        eth_zero_addr(hif_drv->assoc_bssid);
 806
 807        conn_info->req_ies_len = 0;
 808        kfree(conn_info->req_ies);
 809        conn_info->req_ies = NULL;
 810
 811        return 0;
 812}
 813
 814void wilc_resolve_disconnect_aberration(struct wilc_vif *vif)
 815{
 816        if (!vif->hif_drv)
 817                return;
 818        if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
 819            vif->hif_drv->hif_state == HOST_IF_CONNECTING)
 820                wilc_disconnect(vif);
 821}
 822
 823int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)
 824{
 825        struct wid wid_list[5];
 826        u32 wid_cnt = 0, result;
 827
 828        wid_list[wid_cnt].id = WID_LINKSPEED;
 829        wid_list[wid_cnt].type = WID_CHAR;
 830        wid_list[wid_cnt].size = sizeof(char);
 831        wid_list[wid_cnt].val = (s8 *)&stats->link_speed;
 832        wid_cnt++;
 833
 834        wid_list[wid_cnt].id = WID_RSSI;
 835        wid_list[wid_cnt].type = WID_CHAR;
 836        wid_list[wid_cnt].size = sizeof(char);
 837        wid_list[wid_cnt].val = (s8 *)&stats->rssi;
 838        wid_cnt++;
 839
 840        wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;
 841        wid_list[wid_cnt].type = WID_INT;
 842        wid_list[wid_cnt].size = sizeof(u32);
 843        wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;
 844        wid_cnt++;
 845
 846        wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;
 847        wid_list[wid_cnt].type = WID_INT;
 848        wid_list[wid_cnt].size = sizeof(u32);
 849        wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;
 850        wid_cnt++;
 851
 852        wid_list[wid_cnt].id = WID_FAILED_COUNT;
 853        wid_list[wid_cnt].type = WID_INT;
 854        wid_list[wid_cnt].size = sizeof(u32);
 855        wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;
 856        wid_cnt++;
 857
 858        result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt);
 859        if (result) {
 860                netdev_err(vif->ndev, "Failed to send scan parameters\n");
 861                return result;
 862        }
 863
 864        if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
 865            stats->link_speed != DEFAULT_LINK_SPEED)
 866                wilc_enable_tcp_ack_filter(vif, true);
 867        else if (stats->link_speed != DEFAULT_LINK_SPEED)
 868                wilc_enable_tcp_ack_filter(vif, false);
 869
 870        return result;
 871}
 872
 873static void handle_get_statistics(struct work_struct *work)
 874{
 875        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
 876        struct wilc_vif *vif = msg->vif;
 877        struct rf_info *stats = (struct rf_info *)msg->body.data;
 878
 879        wilc_get_statistics(vif, stats);
 880
 881        kfree(msg);
 882}
 883
 884static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
 885                                    struct station_parameters *params)
 886{
 887        ether_addr_copy(cur_byte, mac);
 888        cur_byte += ETH_ALEN;
 889
 890        put_unaligned_le16(params->aid, cur_byte);
 891        cur_byte += 2;
 892
 893        *cur_byte++ = params->supported_rates_len;
 894        if (params->supported_rates_len > 0)
 895                memcpy(cur_byte, params->supported_rates,
 896                       params->supported_rates_len);
 897        cur_byte += params->supported_rates_len;
 898
 899        if (params->ht_capa) {
 900                *cur_byte++ = true;
 901                memcpy(cur_byte, &params->ht_capa,
 902                       sizeof(struct ieee80211_ht_cap));
 903        } else {
 904                *cur_byte++ = false;
 905        }
 906        cur_byte += sizeof(struct ieee80211_ht_cap);
 907
 908        put_unaligned_le16(params->sta_flags_mask, cur_byte);
 909        cur_byte += 2;
 910        put_unaligned_le16(params->sta_flags_set, cur_byte);
 911}
 912
 913static int handle_remain_on_chan(struct wilc_vif *vif,
 914                                 struct wilc_remain_ch *hif_remain_ch)
 915{
 916        int result;
 917        u8 remain_on_chan_flag;
 918        struct wid wid;
 919        struct host_if_drv *hif_drv = vif->hif_drv;
 920
 921        if (hif_drv->usr_scan_req.scan_result)
 922                return -EBUSY;
 923
 924        if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
 925                return -EBUSY;
 926
 927        if (vif->obtaining_ip || vif->connecting)
 928                return -EBUSY;
 929
 930        remain_on_chan_flag = true;
 931        wid.id = WID_REMAIN_ON_CHAN;
 932        wid.type = WID_STR;
 933        wid.size = 2;
 934        wid.val = kmalloc(wid.size, GFP_KERNEL);
 935        if (!wid.val)
 936                return -ENOMEM;
 937
 938        wid.val[0] = remain_on_chan_flag;
 939        wid.val[1] = (s8)hif_remain_ch->ch;
 940
 941        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
 942        kfree(wid.val);
 943        if (result)
 944                return -EBUSY;
 945
 946        hif_drv->remain_on_ch.arg = hif_remain_ch->arg;
 947        hif_drv->remain_on_ch.expired = hif_remain_ch->expired;
 948        hif_drv->remain_on_ch.ch = hif_remain_ch->ch;
 949        hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;
 950        hif_drv->remain_on_ch_timer_vif = vif;
 951
 952        return 0;
 953}
 954
 955static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
 956{
 957        u8 remain_on_chan_flag;
 958        struct wid wid;
 959        int result;
 960        struct host_if_drv *hif_drv = vif->hif_drv;
 961        struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
 962
 963        if (priv->p2p_listen_state) {
 964                remain_on_chan_flag = false;
 965                wid.id = WID_REMAIN_ON_CHAN;
 966                wid.type = WID_STR;
 967                wid.size = 2;
 968
 969                wid.val = kmalloc(wid.size, GFP_KERNEL);
 970                if (!wid.val)
 971                        return -ENOMEM;
 972
 973                wid.val[0] = remain_on_chan_flag;
 974                wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;
 975
 976                result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
 977                kfree(wid.val);
 978                if (result != 0) {
 979                        netdev_err(vif->ndev, "Failed to set remain channel\n");
 980                        return -EINVAL;
 981                }
 982
 983                if (hif_drv->remain_on_ch.expired) {
 984                        hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
 985                                                      cookie);
 986                }
 987        } else {
 988                netdev_dbg(vif->ndev, "Not in listen state\n");
 989        }
 990
 991        return 0;
 992}
 993
 994static void wilc_handle_listen_state_expired(struct work_struct *work)
 995{
 996        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
 997
 998        wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);
 999        kfree(msg);
1000}
1001
1002static void listen_timer_cb(struct timer_list *t)
1003{
1004        struct host_if_drv *hif_drv = from_timer(hif_drv, t,
1005                                                      remain_on_ch_timer);
1006        struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;
1007        int result;
1008        struct host_if_msg *msg;
1009
1010        del_timer(&vif->hif_drv->remain_on_ch_timer);
1011
1012        msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false);
1013        if (IS_ERR(msg))
1014                return;
1015
1016        msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;
1017
1018        result = wilc_enqueue_work(msg);
1019        if (result) {
1020                netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
1021                kfree(msg);
1022        }
1023}
1024
1025static void handle_set_mcast_filter(struct work_struct *work)
1026{
1027        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
1028        struct wilc_vif *vif = msg->vif;
1029        struct wilc_set_multicast *set_mc = &msg->body.mc_info;
1030        int result;
1031        struct wid wid;
1032        u8 *cur_byte;
1033
1034        wid.id = WID_SETUP_MULTICAST_FILTER;
1035        wid.type = WID_BIN;
1036        wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);
1037        wid.val = kmalloc(wid.size, GFP_KERNEL);
1038        if (!wid.val)
1039                goto error;
1040
1041        cur_byte = wid.val;
1042        put_unaligned_le32(set_mc->enabled, cur_byte);
1043        cur_byte += 4;
1044
1045        put_unaligned_le32(set_mc->cnt, cur_byte);
1046        cur_byte += 4;
1047
1048        if (set_mc->cnt > 0 && set_mc->mc_list)
1049                memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);
1050
1051        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1052        if (result)
1053                netdev_err(vif->ndev, "Failed to send setup multicast\n");
1054
1055error:
1056        kfree(set_mc->mc_list);
1057        kfree(wid.val);
1058        kfree(msg);
1059}
1060
1061static void handle_scan_timer(struct work_struct *work)
1062{
1063        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
1064
1065        handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);
1066        kfree(msg);
1067}
1068
1069static void handle_scan_complete(struct work_struct *work)
1070{
1071        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
1072        struct wilc *wilc = msg->vif->wilc;
1073
1074        del_timer(&msg->vif->hif_drv->scan_timer);
1075
1076        if (!wilc_wlan_get_num_conn_ifcs(wilc))
1077                wilc_chip_sleep_manually(wilc);
1078
1079        handle_scan_done(msg->vif, SCAN_EVENT_DONE);
1080
1081        kfree(msg);
1082}
1083
1084static void timer_scan_cb(struct timer_list *t)
1085{
1086        struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);
1087        struct wilc_vif *vif = hif_drv->scan_timer_vif;
1088        struct host_if_msg *msg;
1089        int result;
1090
1091        msg = wilc_alloc_work(vif, handle_scan_timer, false);
1092        if (IS_ERR(msg))
1093                return;
1094
1095        result = wilc_enqueue_work(msg);
1096        if (result)
1097                kfree(msg);
1098}
1099
1100static void timer_connect_cb(struct timer_list *t)
1101{
1102        struct host_if_drv *hif_drv = from_timer(hif_drv, t,
1103                                                      connect_timer);
1104        struct wilc_vif *vif = hif_drv->connect_timer_vif;
1105        struct host_if_msg *msg;
1106        int result;
1107
1108        msg = wilc_alloc_work(vif, handle_connect_timeout, false);
1109        if (IS_ERR(msg))
1110                return;
1111
1112        result = wilc_enqueue_work(msg);
1113        if (result)
1114                kfree(msg);
1115}
1116
1117int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
1118{
1119        struct wid wid;
1120        int result;
1121
1122        wid.id = WID_REMOVE_WEP_KEY;
1123        wid.type = WID_STR;
1124        wid.size = sizeof(char);
1125        wid.val = &index;
1126
1127        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1128        if (result)
1129                netdev_err(vif->ndev,
1130                           "Failed to send remove wep key config packet\n");
1131        return result;
1132}
1133
1134int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
1135{
1136        struct wid wid;
1137        int result;
1138
1139        wid.id = WID_KEY_ID;
1140        wid.type = WID_CHAR;
1141        wid.size = sizeof(char);
1142        wid.val = &index;
1143        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1144        if (result)
1145                netdev_err(vif->ndev,
1146                           "Failed to send wep default key config packet\n");
1147
1148        return result;
1149}
1150
1151int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
1152                             u8 index)
1153{
1154        struct wid wid;
1155        int result;
1156        struct wilc_wep_key *wep_key;
1157
1158        wid.id = WID_ADD_WEP_KEY;
1159        wid.type = WID_STR;
1160        wid.size = sizeof(*wep_key) + len;
1161        wep_key = kzalloc(wid.size, GFP_KERNEL);
1162        if (!wep_key)
1163                return -ENOMEM;
1164
1165        wid.val = (u8 *)wep_key;
1166
1167        wep_key->index = index;
1168        wep_key->key_len = len;
1169        memcpy(wep_key->key, key, len);
1170
1171        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1172        if (result)
1173                netdev_err(vif->ndev,
1174                           "Failed to add wep key config packet\n");
1175
1176        kfree(wep_key);
1177        return result;
1178}
1179
1180int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
1181                            u8 index, u8 mode, enum authtype auth_type)
1182{
1183        struct wid wid_list[3];
1184        int result;
1185        struct wilc_wep_key *wep_key;
1186
1187        wid_list[0].id = WID_11I_MODE;
1188        wid_list[0].type = WID_CHAR;
1189        wid_list[0].size = sizeof(char);
1190        wid_list[0].val = &mode;
1191
1192        wid_list[1].id = WID_AUTH_TYPE;
1193        wid_list[1].type = WID_CHAR;
1194        wid_list[1].size = sizeof(char);
1195        wid_list[1].val = (s8 *)&auth_type;
1196
1197        wid_list[2].id = WID_WEP_KEY_VALUE;
1198        wid_list[2].type = WID_STR;
1199        wid_list[2].size = sizeof(*wep_key) + len;
1200        wep_key = kzalloc(wid_list[2].size, GFP_KERNEL);
1201        if (!wep_key)
1202                return -ENOMEM;
1203
1204        wid_list[2].val = (u8 *)wep_key;
1205
1206        wep_key->index = index;
1207        wep_key->key_len = len;
1208        memcpy(wep_key->key, key, len);
1209        result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
1210                                      ARRAY_SIZE(wid_list));
1211        if (result)
1212                netdev_err(vif->ndev,
1213                           "Failed to add wep ap key config packet\n");
1214
1215        kfree(wep_key);
1216        return result;
1217}
1218
1219int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
1220                 const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
1221                 u8 mode, u8 cipher_mode, u8 index)
1222{
1223        int result = 0;
1224        u8 t_key_len  = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
1225
1226        if (mode == WILC_AP_MODE) {
1227                struct wid wid_list[2];
1228                struct wilc_ap_wpa_ptk *key_buf;
1229
1230                wid_list[0].id = WID_11I_MODE;
1231                wid_list[0].type = WID_CHAR;
1232                wid_list[0].size = sizeof(char);
1233                wid_list[0].val = (s8 *)&cipher_mode;
1234
1235                key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
1236                if (!key_buf)
1237                        return -ENOMEM;
1238
1239                ether_addr_copy(key_buf->mac_addr, mac_addr);
1240                key_buf->index = index;
1241                key_buf->key_len = t_key_len;
1242                memcpy(&key_buf->key[0], ptk, ptk_key_len);
1243
1244                if (rx_mic)
1245                        memcpy(&key_buf->key[ptk_key_len], rx_mic,
1246                               WILC_RX_MIC_KEY_LEN);
1247
1248                if (tx_mic)
1249                        memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
1250                               tx_mic, WILC_TX_MIC_KEY_LEN);
1251
1252                wid_list[1].id = WID_ADD_PTK;
1253                wid_list[1].type = WID_STR;
1254                wid_list[1].size = sizeof(*key_buf) + t_key_len;
1255                wid_list[1].val = (u8 *)key_buf;
1256                result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
1257                                              ARRAY_SIZE(wid_list));
1258                kfree(key_buf);
1259        } else if (mode == WILC_STATION_MODE) {
1260                struct wid wid;
1261                struct wilc_sta_wpa_ptk *key_buf;
1262
1263                key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
1264                if (!key_buf)
1265                        return -ENOMEM;
1266
1267                ether_addr_copy(key_buf->mac_addr, mac_addr);
1268                key_buf->key_len = t_key_len;
1269                memcpy(&key_buf->key[0], ptk, ptk_key_len);
1270
1271                if (rx_mic)
1272                        memcpy(&key_buf->key[ptk_key_len], rx_mic,
1273                               WILC_RX_MIC_KEY_LEN);
1274
1275                if (tx_mic)
1276                        memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],
1277                               tx_mic, WILC_TX_MIC_KEY_LEN);
1278
1279                wid.id = WID_ADD_PTK;
1280                wid.type = WID_STR;
1281                wid.size = sizeof(*key_buf) + t_key_len;
1282                wid.val = (s8 *)key_buf;
1283                result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1284                kfree(key_buf);
1285        }
1286
1287        return result;
1288}
1289
1290int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
1291                    u8 index, u32 key_rsc_len, const u8 *key_rsc,
1292                    const u8 *rx_mic, const u8 *tx_mic, u8 mode,
1293                    u8 cipher_mode)
1294{
1295        int result = 0;
1296        struct wilc_gtk_key *gtk_key;
1297        int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
1298
1299        gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);
1300        if (!gtk_key)
1301                return -ENOMEM;
1302
1303        /* fill bssid value only in station mode */
1304        if (mode == WILC_STATION_MODE &&
1305            vif->hif_drv->hif_state == HOST_IF_CONNECTED)
1306                memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);
1307
1308        if (key_rsc)
1309                memcpy(gtk_key->rsc, key_rsc, 8);
1310        gtk_key->index = index;
1311        gtk_key->key_len = t_key_len;
1312        memcpy(&gtk_key->key[0], rx_gtk, gtk_key_len);
1313
1314        if (rx_mic)
1315                memcpy(&gtk_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
1316
1317        if (tx_mic)
1318                memcpy(&gtk_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN],
1319                       tx_mic, WILC_TX_MIC_KEY_LEN);
1320
1321        if (mode == WILC_AP_MODE) {
1322                struct wid wid_list[2];
1323
1324                wid_list[0].id = WID_11I_MODE;
1325                wid_list[0].type = WID_CHAR;
1326                wid_list[0].size = sizeof(char);
1327                wid_list[0].val = (s8 *)&cipher_mode;
1328
1329                wid_list[1].id = WID_ADD_RX_GTK;
1330                wid_list[1].type = WID_STR;
1331                wid_list[1].size = sizeof(*gtk_key) + t_key_len;
1332                wid_list[1].val = (u8 *)gtk_key;
1333
1334                result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
1335                                              ARRAY_SIZE(wid_list));
1336        } else if (mode == WILC_STATION_MODE) {
1337                struct wid wid;
1338
1339                wid.id = WID_ADD_RX_GTK;
1340                wid.type = WID_STR;
1341                wid.size = sizeof(*gtk_key) + t_key_len;
1342                wid.val = (u8 *)gtk_key;
1343                result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1344        }
1345
1346        kfree(gtk_key);
1347        return result;
1348}
1349
1350int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)
1351{
1352        struct wid wid;
1353
1354        wid.id = WID_PMKID_INFO;
1355        wid.type = WID_STR;
1356        wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;
1357        wid.val = (u8 *)pmkid;
1358
1359        return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1360}
1361
1362int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)
1363{
1364        int result;
1365        struct wid wid;
1366
1367        wid.id = WID_MAC_ADDR;
1368        wid.type = WID_STR;
1369        wid.size = ETH_ALEN;
1370        wid.val = mac_addr;
1371
1372        result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
1373        if (result)
1374                netdev_err(vif->ndev, "Failed to get mac address\n");
1375
1376        return result;
1377}
1378
1379int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
1380                      size_t ies_len)
1381{
1382        int result;
1383        struct host_if_drv *hif_drv = vif->hif_drv;
1384        struct wilc_conn_info *conn_info = &hif_drv->conn_info;
1385
1386        if (bssid)
1387                ether_addr_copy(conn_info->bssid, bssid);
1388
1389        if (ies) {
1390                conn_info->req_ies_len = ies_len;
1391                conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL);
1392                if (!conn_info->req_ies)
1393                        return -ENOMEM;
1394        }
1395
1396        result = wilc_send_connect_wid(vif);
1397        if (result)
1398                goto free_ies;
1399
1400        hif_drv->connect_timer_vif = vif;
1401        mod_timer(&hif_drv->connect_timer,
1402                  jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS));
1403
1404        return 0;
1405
1406free_ies:
1407        kfree(conn_info->req_ies);
1408
1409        return result;
1410}
1411
1412int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)
1413{
1414        struct wid wid;
1415        int result;
1416
1417        wid.id = WID_CURRENT_CHANNEL;
1418        wid.type = WID_CHAR;
1419        wid.size = sizeof(char);
1420        wid.val = &channel;
1421
1422        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1423        if (result)
1424                netdev_err(vif->ndev, "Failed to set channel\n");
1425
1426        return result;
1427}
1428
1429int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode,
1430                             u8 ifc_id)
1431{
1432        struct wid wid;
1433        struct host_if_drv *hif_drv = vif->hif_drv;
1434        int result;
1435        struct wilc_drv_handler drv;
1436
1437        if (!hif_drv)
1438                return -EFAULT;
1439
1440        wid.id = WID_SET_DRV_HANDLER;
1441        wid.type = WID_STR;
1442        wid.size = sizeof(drv);
1443        wid.val = (u8 *)&drv;
1444
1445        drv.handler = cpu_to_le32(index);
1446        drv.mode = (ifc_id | (mode << 1));
1447
1448        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1449        if (result)
1450                netdev_err(vif->ndev, "Failed to set driver handler\n");
1451
1452        return result;
1453}
1454
1455int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode)
1456{
1457        struct wid wid;
1458        struct wilc_op_mode op_mode;
1459        int result;
1460
1461        wid.id = WID_SET_OPERATION_MODE;
1462        wid.type = WID_INT;
1463        wid.size = sizeof(op_mode);
1464        wid.val = (u8 *)&op_mode;
1465
1466        op_mode.mode = cpu_to_le32(mode);
1467
1468        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1469        if (result)
1470                netdev_err(vif->ndev, "Failed to set operation mode\n");
1471
1472        return result;
1473}
1474
1475s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)
1476{
1477        struct wid wid;
1478        s32 result;
1479
1480        wid.id = WID_SET_STA_MAC_INACTIVE_TIME;
1481        wid.type = WID_STR;
1482        wid.size = ETH_ALEN;
1483        wid.val = kzalloc(wid.size, GFP_KERNEL);
1484        if (!wid.val)
1485                return -ENOMEM;
1486
1487        ether_addr_copy(wid.val, mac);
1488        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1489        kfree(wid.val);
1490        if (result) {
1491                netdev_err(vif->ndev, "Failed to set inactive mac\n");
1492                return result;
1493        }
1494
1495        wid.id = WID_GET_INACTIVE_TIME;
1496        wid.type = WID_INT;
1497        wid.val = (s8 *)out_val;
1498        wid.size = sizeof(u32);
1499        result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
1500        if (result)
1501                netdev_err(vif->ndev, "Failed to get inactive time\n");
1502
1503        return result;
1504}
1505
1506int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)
1507{
1508        struct wid wid;
1509        int result;
1510
1511        if (!rssi_level) {
1512                netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);
1513                return -EFAULT;
1514        }
1515
1516        wid.id = WID_RSSI;
1517        wid.type = WID_CHAR;
1518        wid.size = sizeof(char);
1519        wid.val = rssi_level;
1520        result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
1521        if (result)
1522                netdev_err(vif->ndev, "Failed to get RSSI value\n");
1523
1524        return result;
1525}
1526
1527static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats)
1528{
1529        int result;
1530        struct host_if_msg *msg;
1531
1532        msg = wilc_alloc_work(vif, handle_get_statistics, false);
1533        if (IS_ERR(msg))
1534                return PTR_ERR(msg);
1535
1536        msg->body.data = (char *)stats;
1537
1538        result = wilc_enqueue_work(msg);
1539        if (result) {
1540                netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
1541                kfree(msg);
1542                return result;
1543        }
1544
1545        return result;
1546}
1547
1548int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)
1549{
1550        struct wid wid_list[4];
1551        int i = 0;
1552
1553        if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) {
1554                wid_list[i].id = WID_SHORT_RETRY_LIMIT;
1555                wid_list[i].val = (s8 *)&param->short_retry_limit;
1556                wid_list[i].type = WID_SHORT;
1557                wid_list[i].size = sizeof(u16);
1558                i++;
1559        }
1560        if (param->flag & WILC_CFG_PARAM_RETRY_LONG) {
1561                wid_list[i].id = WID_LONG_RETRY_LIMIT;
1562                wid_list[i].val = (s8 *)&param->long_retry_limit;
1563                wid_list[i].type = WID_SHORT;
1564                wid_list[i].size = sizeof(u16);
1565                i++;
1566        }
1567        if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) {
1568                wid_list[i].id = WID_FRAG_THRESHOLD;
1569                wid_list[i].val = (s8 *)&param->frag_threshold;
1570                wid_list[i].type = WID_SHORT;
1571                wid_list[i].size = sizeof(u16);
1572                i++;
1573        }
1574        if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) {
1575                wid_list[i].id = WID_RTS_THRESHOLD;
1576                wid_list[i].val = (s8 *)&param->rts_threshold;
1577                wid_list[i].type = WID_SHORT;
1578                wid_list[i].size = sizeof(u16);
1579                i++;
1580        }
1581
1582        return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i);
1583}
1584
1585static void get_periodic_rssi(struct timer_list *t)
1586{
1587        struct wilc_vif *vif = from_timer(vif, t, periodic_rssi);
1588
1589        if (!vif->hif_drv) {
1590                netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
1591                return;
1592        }
1593
1594        if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)
1595                wilc_get_stats_async(vif, &vif->periodic_stat);
1596
1597        mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
1598}
1599
1600int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)
1601{
1602        struct host_if_drv *hif_drv;
1603        struct wilc_vif *vif = netdev_priv(dev);
1604        struct wilc *wilc = vif->wilc;
1605
1606        hif_drv  = kzalloc(sizeof(*hif_drv), GFP_KERNEL);
1607        if (!hif_drv)
1608                return -ENOMEM;
1609
1610        *hif_drv_handler = hif_drv;
1611
1612        vif->hif_drv = hif_drv;
1613        vif->obtaining_ip = false;
1614
1615        if (wilc->clients_count == 0)
1616                mutex_init(&wilc->deinit_lock);
1617
1618        timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0);
1619        mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));
1620
1621        timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);
1622        timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);
1623        timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0);
1624
1625        hif_drv->hif_state = HOST_IF_IDLE;
1626
1627        hif_drv->p2p_timeout = 0;
1628
1629        wilc->clients_count++;
1630
1631        return 0;
1632}
1633
1634int wilc_deinit(struct wilc_vif *vif)
1635{
1636        int result = 0;
1637        struct host_if_drv *hif_drv = vif->hif_drv;
1638
1639        if (!hif_drv) {
1640                netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
1641                return -EFAULT;
1642        }
1643
1644        mutex_lock(&vif->wilc->deinit_lock);
1645
1646        del_timer_sync(&hif_drv->scan_timer);
1647        del_timer_sync(&hif_drv->connect_timer);
1648        del_timer_sync(&vif->periodic_rssi);
1649        del_timer_sync(&hif_drv->remain_on_ch_timer);
1650
1651        wilc_set_wfi_drv_handler(vif, 0, 0, 0);
1652
1653        if (hif_drv->usr_scan_req.scan_result) {
1654                hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
1655                                                  hif_drv->usr_scan_req.arg);
1656                hif_drv->usr_scan_req.scan_result = NULL;
1657        }
1658
1659        hif_drv->hif_state = HOST_IF_IDLE;
1660
1661        kfree(hif_drv);
1662        vif->hif_drv = NULL;
1663        vif->wilc->clients_count--;
1664        mutex_unlock(&vif->wilc->deinit_lock);
1665        return result;
1666}
1667
1668void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)
1669{
1670        int result;
1671        struct host_if_msg *msg;
1672        int id;
1673        struct host_if_drv *hif_drv;
1674        struct wilc_vif *vif;
1675
1676        id = get_unaligned_le32(&buffer[length - 4]);
1677        vif = wilc_get_vif_from_idx(wilc, id);
1678        if (!vif)
1679                return;
1680        hif_drv = vif->hif_drv;
1681
1682        if (!hif_drv) {
1683                netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv);
1684                return;
1685        }
1686
1687        msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false);
1688        if (IS_ERR(msg))
1689                return;
1690
1691        msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1;
1692        msg->body.net_info.rssi = buffer[8];
1693        msg->body.net_info.mgmt = kmemdup(&buffer[9],
1694                                          msg->body.net_info.frame_len,
1695                                          GFP_KERNEL);
1696        if (!msg->body.net_info.mgmt) {
1697                kfree(msg);
1698                return;
1699        }
1700
1701        result = wilc_enqueue_work(msg);
1702        if (result) {
1703                netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
1704                kfree(msg->body.net_info.mgmt);
1705                kfree(msg);
1706        }
1707}
1708
1709void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)
1710{
1711        int result;
1712        struct host_if_msg *msg;
1713        int id;
1714        struct host_if_drv *hif_drv;
1715        struct wilc_vif *vif;
1716
1717        mutex_lock(&wilc->deinit_lock);
1718
1719        id = get_unaligned_le32(&buffer[length - 4]);
1720        vif = wilc_get_vif_from_idx(wilc, id);
1721        if (!vif) {
1722                mutex_unlock(&wilc->deinit_lock);
1723                return;
1724        }
1725
1726        hif_drv = vif->hif_drv;
1727
1728        if (!hif_drv) {
1729                mutex_unlock(&wilc->deinit_lock);
1730                return;
1731        }
1732
1733        if (!hif_drv->conn_info.conn_result) {
1734                netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
1735                mutex_unlock(&wilc->deinit_lock);
1736                return;
1737        }
1738
1739        msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);
1740        if (IS_ERR(msg)) {
1741                mutex_unlock(&wilc->deinit_lock);
1742                return;
1743        }
1744
1745        msg->body.mac_info.status = buffer[7];
1746        result = wilc_enqueue_work(msg);
1747        if (result) {
1748                netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
1749                kfree(msg);
1750        }
1751
1752        mutex_unlock(&wilc->deinit_lock);
1753}
1754
1755void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)
1756{
1757        int result;
1758        int id;
1759        struct host_if_drv *hif_drv;
1760        struct wilc_vif *vif;
1761
1762        id = get_unaligned_le32(&buffer[length - 4]);
1763        vif = wilc_get_vif_from_idx(wilc, id);
1764        if (!vif)
1765                return;
1766        hif_drv = vif->hif_drv;
1767
1768        if (!hif_drv)
1769                return;
1770
1771        if (hif_drv->usr_scan_req.scan_result) {
1772                struct host_if_msg *msg;
1773
1774                msg = wilc_alloc_work(vif, handle_scan_complete, false);
1775                if (IS_ERR(msg))
1776                        return;
1777
1778                result = wilc_enqueue_work(msg);
1779                if (result) {
1780                        netdev_err(vif->ndev, "%s: enqueue work failed\n",
1781                                   __func__);
1782                        kfree(msg);
1783                }
1784        }
1785}
1786
1787int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
1788                           u32 duration, u16 chan,
1789                           void (*expired)(void *, u64),
1790                           void *user_arg)
1791{
1792        struct wilc_remain_ch roc;
1793        int result;
1794
1795        roc.ch = chan;
1796        roc.expired = expired;
1797        roc.arg = user_arg;
1798        roc.duration = duration;
1799        roc.cookie = cookie;
1800        result = handle_remain_on_chan(vif, &roc);
1801        if (result)
1802                netdev_err(vif->ndev, "%s: failed to set remain on channel\n",
1803                           __func__);
1804
1805        return result;
1806}
1807
1808int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)
1809{
1810        if (!vif->hif_drv) {
1811                netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);
1812                return -EFAULT;
1813        }
1814
1815        del_timer(&vif->hif_drv->remain_on_ch_timer);
1816
1817        return wilc_handle_roc_expired(vif, cookie);
1818}
1819
1820void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
1821{
1822        struct wid wid;
1823        int result;
1824        struct wilc_reg_frame reg_frame;
1825
1826        wid.id = WID_REGISTER_FRAME;
1827        wid.type = WID_STR;
1828        wid.size = sizeof(reg_frame);
1829        wid.val = (u8 *)&reg_frame;
1830
1831        memset(&reg_frame, 0x0, sizeof(reg_frame));
1832        reg_frame.reg = reg;
1833
1834        switch (frame_type) {
1835        case IEEE80211_STYPE_ACTION:
1836                reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX;
1837                break;
1838
1839        case IEEE80211_STYPE_PROBE_REQ:
1840                reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;
1841                break;
1842
1843        default:
1844                break;
1845        }
1846        reg_frame.frame_type = cpu_to_le16(frame_type);
1847        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1848        if (result)
1849                netdev_err(vif->ndev, "Failed to frame register\n");
1850}
1851
1852int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,
1853                    struct cfg80211_beacon_data *params)
1854{
1855        struct wid wid;
1856        int result;
1857        u8 *cur_byte;
1858
1859        wid.id = WID_ADD_BEACON;
1860        wid.type = WID_BIN;
1861        wid.size = params->head_len + params->tail_len + 16;
1862        wid.val = kzalloc(wid.size, GFP_KERNEL);
1863        if (!wid.val)
1864                return -ENOMEM;
1865
1866        cur_byte = wid.val;
1867        put_unaligned_le32(interval, cur_byte);
1868        cur_byte += 4;
1869        put_unaligned_le32(dtim_period, cur_byte);
1870        cur_byte += 4;
1871        put_unaligned_le32(params->head_len, cur_byte);
1872        cur_byte += 4;
1873
1874        if (params->head_len > 0)
1875                memcpy(cur_byte, params->head, params->head_len);
1876        cur_byte += params->head_len;
1877
1878        put_unaligned_le32(params->tail_len, cur_byte);
1879        cur_byte += 4;
1880
1881        if (params->tail_len > 0)
1882                memcpy(cur_byte, params->tail, params->tail_len);
1883
1884        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1885        if (result)
1886                netdev_err(vif->ndev, "Failed to send add beacon\n");
1887
1888        kfree(wid.val);
1889
1890        return result;
1891}
1892
1893int wilc_del_beacon(struct wilc_vif *vif)
1894{
1895        int result;
1896        struct wid wid;
1897        u8 del_beacon = 0;
1898
1899        wid.id = WID_DEL_BEACON;
1900        wid.type = WID_CHAR;
1901        wid.size = sizeof(char);
1902        wid.val = &del_beacon;
1903
1904        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1905        if (result)
1906                netdev_err(vif->ndev, "Failed to send delete beacon\n");
1907
1908        return result;
1909}
1910
1911int wilc_add_station(struct wilc_vif *vif, const u8 *mac,
1912                     struct station_parameters *params)
1913{
1914        struct wid wid;
1915        int result;
1916        u8 *cur_byte;
1917
1918        wid.id = WID_ADD_STA;
1919        wid.type = WID_BIN;
1920        wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
1921        wid.val = kmalloc(wid.size, GFP_KERNEL);
1922        if (!wid.val)
1923                return -ENOMEM;
1924
1925        cur_byte = wid.val;
1926        wilc_hif_pack_sta_param(cur_byte, mac, params);
1927
1928        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1929        if (result != 0)
1930                netdev_err(vif->ndev, "Failed to send add station\n");
1931
1932        kfree(wid.val);
1933
1934        return result;
1935}
1936
1937int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)
1938{
1939        struct wid wid;
1940        int result;
1941
1942        wid.id = WID_REMOVE_STA;
1943        wid.type = WID_BIN;
1944        wid.size = ETH_ALEN;
1945        wid.val = kzalloc(wid.size, GFP_KERNEL);
1946        if (!wid.val)
1947                return -ENOMEM;
1948
1949        if (!mac_addr)
1950                eth_broadcast_addr(wid.val);
1951        else
1952                ether_addr_copy(wid.val, mac_addr);
1953
1954        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1955        if (result)
1956                netdev_err(vif->ndev, "Failed to del station\n");
1957
1958        kfree(wid.val);
1959
1960        return result;
1961}
1962
1963int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])
1964{
1965        struct wid wid;
1966        int result;
1967        int i;
1968        u8 assoc_sta = 0;
1969        struct wilc_del_all_sta del_sta;
1970
1971        memset(&del_sta, 0x0, sizeof(del_sta));
1972        for (i = 0; i < WILC_MAX_NUM_STA; i++) {
1973                if (!is_zero_ether_addr(mac_addr[i])) {
1974                        assoc_sta++;
1975                        ether_addr_copy(del_sta.mac[i], mac_addr[i]);
1976                }
1977        }
1978
1979        if (!assoc_sta)
1980                return 0;
1981
1982        del_sta.assoc_sta = assoc_sta;
1983
1984        wid.id = WID_DEL_ALL_STA;
1985        wid.type = WID_STR;
1986        wid.size = (assoc_sta * ETH_ALEN) + 1;
1987        wid.val = (u8 *)&del_sta;
1988
1989        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
1990        if (result)
1991                netdev_err(vif->ndev, "Failed to send delete all station\n");
1992
1993        return result;
1994}
1995
1996int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
1997                      struct station_parameters *params)
1998{
1999        struct wid wid;
2000        int result;
2001        u8 *cur_byte;
2002
2003        wid.id = WID_EDIT_STA;
2004        wid.type = WID_BIN;
2005        wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len;
2006        wid.val = kmalloc(wid.size, GFP_KERNEL);
2007        if (!wid.val)
2008                return -ENOMEM;
2009
2010        cur_byte = wid.val;
2011        wilc_hif_pack_sta_param(cur_byte, mac, params);
2012
2013        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
2014        if (result)
2015                netdev_err(vif->ndev, "Failed to send edit station\n");
2016
2017        kfree(wid.val);
2018        return result;
2019}
2020
2021int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)
2022{
2023        struct wid wid;
2024        int result;
2025        s8 power_mode;
2026
2027        if (wilc_wlan_get_num_conn_ifcs(vif->wilc) == 2 && enabled)
2028                return 0;
2029
2030        if (enabled)
2031                power_mode = WILC_FW_MIN_FAST_PS;
2032        else
2033                power_mode = WILC_FW_NO_POWERSAVE;
2034
2035        wid.id = WID_POWER_MANAGEMENT;
2036        wid.val = &power_mode;
2037        wid.size = sizeof(char);
2038        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
2039        if (result)
2040                netdev_err(vif->ndev, "Failed to send power management\n");
2041
2042        return result;
2043}
2044
2045int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
2046                                u8 *mc_list)
2047{
2048        int result;
2049        struct host_if_msg *msg;
2050
2051        msg = wilc_alloc_work(vif, handle_set_mcast_filter, false);
2052        if (IS_ERR(msg))
2053                return PTR_ERR(msg);
2054
2055        msg->body.mc_info.enabled = enabled;
2056        msg->body.mc_info.cnt = count;
2057        msg->body.mc_info.mc_list = mc_list;
2058
2059        result = wilc_enqueue_work(msg);
2060        if (result) {
2061                netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);
2062                kfree(msg);
2063        }
2064        return result;
2065}
2066
2067int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)
2068{
2069        struct wid wid;
2070
2071        wid.id = WID_TX_POWER;
2072        wid.type = WID_CHAR;
2073        wid.val = &tx_power;
2074        wid.size = sizeof(char);
2075
2076        return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
2077}
2078
2079int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
2080{
2081        struct wid wid;
2082
2083        wid.id = WID_TX_POWER;
2084        wid.type = WID_CHAR;
2085        wid.val = tx_power;
2086        wid.size = sizeof(char);
2087
2088        return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
2089}
2090