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