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