xref: /openbmc/linux/drivers/net/wireless/microchip/wilc1000/cfg80211.c (revision 5ee9cd065836e5934710ca35653bce7905add20b)
15625f965SAjay Singh // SPDX-License-Identifier: GPL-2.0
25625f965SAjay Singh /*
35625f965SAjay Singh  * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
45625f965SAjay Singh  * All rights reserved.
55625f965SAjay Singh  */
65625f965SAjay Singh 
75625f965SAjay Singh #include "cfg80211.h"
85625f965SAjay Singh 
95625f965SAjay Singh #define GO_NEG_REQ			0x00
105625f965SAjay Singh #define GO_NEG_RSP			0x01
115625f965SAjay Singh #define GO_NEG_CONF			0x02
125625f965SAjay Singh #define P2P_INV_REQ			0x03
135625f965SAjay Singh #define P2P_INV_RSP			0x04
145625f965SAjay Singh 
155625f965SAjay Singh #define WILC_INVALID_CHANNEL		0
165625f965SAjay Singh 
175625f965SAjay Singh /* Operation at 2.4 GHz with channels 1-13 */
185625f965SAjay Singh #define WILC_WLAN_OPERATING_CLASS_2_4GHZ		0x51
195625f965SAjay Singh 
205625f965SAjay Singh static const struct ieee80211_txrx_stypes
215625f965SAjay Singh 	wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
225625f965SAjay Singh 	[NL80211_IFTYPE_STATION] = {
23c5b331d4SAjay Singh 		.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
24c5b331d4SAjay Singh 			BIT(IEEE80211_STYPE_AUTH >> 4),
255625f965SAjay Singh 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
26c5b331d4SAjay Singh 			BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
27c5b331d4SAjay Singh 			BIT(IEEE80211_STYPE_AUTH >> 4)
285625f965SAjay Singh 	},
295625f965SAjay Singh 	[NL80211_IFTYPE_AP] = {
305625f965SAjay Singh 		.tx = 0xffff,
315625f965SAjay Singh 		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
325625f965SAjay Singh 			BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
335625f965SAjay Singh 			BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
345625f965SAjay Singh 			BIT(IEEE80211_STYPE_DISASSOC >> 4) |
355625f965SAjay Singh 			BIT(IEEE80211_STYPE_AUTH >> 4) |
365625f965SAjay Singh 			BIT(IEEE80211_STYPE_DEAUTH >> 4) |
375625f965SAjay Singh 			BIT(IEEE80211_STYPE_ACTION >> 4)
385625f965SAjay Singh 	},
395625f965SAjay Singh 	[NL80211_IFTYPE_P2P_CLIENT] = {
405625f965SAjay Singh 		.tx = 0xffff,
415625f965SAjay Singh 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
425625f965SAjay Singh 			BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
435625f965SAjay Singh 			BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
445625f965SAjay Singh 			BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
455625f965SAjay Singh 			BIT(IEEE80211_STYPE_DISASSOC >> 4) |
465625f965SAjay Singh 			BIT(IEEE80211_STYPE_AUTH >> 4) |
475625f965SAjay Singh 			BIT(IEEE80211_STYPE_DEAUTH >> 4)
485625f965SAjay Singh 	}
495625f965SAjay Singh };
505625f965SAjay Singh 
519bdcbdafSAjay Singh #ifdef CONFIG_PM
525625f965SAjay Singh static const struct wiphy_wowlan_support wowlan_support = {
535625f965SAjay Singh 	.flags = WIPHY_WOWLAN_ANY
545625f965SAjay Singh };
559bdcbdafSAjay Singh #endif
565625f965SAjay Singh 
575625f965SAjay Singh struct wilc_p2p_mgmt_data {
585625f965SAjay Singh 	int size;
595625f965SAjay Singh 	u8 *buff;
605625f965SAjay Singh };
615625f965SAjay Singh 
625625f965SAjay Singh struct wilc_p2p_pub_act_frame {
635625f965SAjay Singh 	u8 category;
645625f965SAjay Singh 	u8 action;
655625f965SAjay Singh 	u8 oui[3];
665625f965SAjay Singh 	u8 oui_type;
675625f965SAjay Singh 	u8 oui_subtype;
685625f965SAjay Singh 	u8 dialog_token;
695625f965SAjay Singh 	u8 elem[];
705625f965SAjay Singh } __packed;
715625f965SAjay Singh 
725625f965SAjay Singh struct wilc_vendor_specific_ie {
735625f965SAjay Singh 	u8 tag_number;
745625f965SAjay Singh 	u8 tag_len;
755625f965SAjay Singh 	u8 oui[3];
765625f965SAjay Singh 	u8 oui_type;
775625f965SAjay Singh 	u8 attr[];
785625f965SAjay Singh } __packed;
795625f965SAjay Singh 
805625f965SAjay Singh struct wilc_attr_entry {
815625f965SAjay Singh 	u8  attr_type;
825625f965SAjay Singh 	__le16 attr_len;
835625f965SAjay Singh 	u8 val[];
845625f965SAjay Singh } __packed;
855625f965SAjay Singh 
865625f965SAjay Singh struct wilc_attr_oper_ch {
875625f965SAjay Singh 	u8 attr_type;
885625f965SAjay Singh 	__le16 attr_len;
895625f965SAjay Singh 	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
905625f965SAjay Singh 	u8 op_class;
915625f965SAjay Singh 	u8 op_channel;
925625f965SAjay Singh } __packed;
935625f965SAjay Singh 
945625f965SAjay Singh struct wilc_attr_ch_list {
955625f965SAjay Singh 	u8 attr_type;
965625f965SAjay Singh 	__le16 attr_len;
975625f965SAjay Singh 	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
985625f965SAjay Singh 	u8 elem[];
995625f965SAjay Singh } __packed;
1005625f965SAjay Singh 
1015625f965SAjay Singh struct wilc_ch_list_elem {
1025625f965SAjay Singh 	u8 op_class;
1035625f965SAjay Singh 	u8 no_of_channels;
1045625f965SAjay Singh 	u8 ch_list[];
1055625f965SAjay Singh } __packed;
1065625f965SAjay Singh 
cfg_scan_result(enum scan_event scan_event,struct wilc_rcvd_net_info * info,void * user_void)1075625f965SAjay Singh static void cfg_scan_result(enum scan_event scan_event,
1085625f965SAjay Singh 			    struct wilc_rcvd_net_info *info, void *user_void)
1095625f965SAjay Singh {
1105625f965SAjay Singh 	struct wilc_priv *priv = user_void;
1115625f965SAjay Singh 
1125625f965SAjay Singh 	if (!priv->cfg_scanning)
1135625f965SAjay Singh 		return;
1145625f965SAjay Singh 
1155625f965SAjay Singh 	if (scan_event == SCAN_EVENT_NETWORK_FOUND) {
1165625f965SAjay Singh 		s32 freq;
1175625f965SAjay Singh 		struct ieee80211_channel *channel;
1185625f965SAjay Singh 		struct cfg80211_bss *bss;
1195625f965SAjay Singh 		struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy;
1205625f965SAjay Singh 
1215625f965SAjay Singh 		if (!wiphy || !info)
1225625f965SAjay Singh 			return;
1235625f965SAjay Singh 
1245625f965SAjay Singh 		freq = ieee80211_channel_to_frequency((s32)info->ch,
1255625f965SAjay Singh 						      NL80211_BAND_2GHZ);
1265625f965SAjay Singh 		channel = ieee80211_get_channel(wiphy, freq);
1275625f965SAjay Singh 		if (!channel)
1285625f965SAjay Singh 			return;
1295625f965SAjay Singh 
1305625f965SAjay Singh 		bss = cfg80211_inform_bss_frame(wiphy, channel, info->mgmt,
1315625f965SAjay Singh 						info->frame_len,
1325625f965SAjay Singh 						(s32)info->rssi * 100,
1335625f965SAjay Singh 						GFP_KERNEL);
1345625f965SAjay Singh 		cfg80211_put_bss(wiphy, bss);
1355625f965SAjay Singh 	} else if (scan_event == SCAN_EVENT_DONE) {
1365625f965SAjay Singh 		mutex_lock(&priv->scan_req_lock);
1375625f965SAjay Singh 
1385625f965SAjay Singh 		if (priv->scan_req) {
1395625f965SAjay Singh 			struct cfg80211_scan_info info = {
1405625f965SAjay Singh 				.aborted = false,
1415625f965SAjay Singh 			};
1425625f965SAjay Singh 
1435625f965SAjay Singh 			cfg80211_scan_done(priv->scan_req, &info);
1445625f965SAjay Singh 			priv->cfg_scanning = false;
1455625f965SAjay Singh 			priv->scan_req = NULL;
1465625f965SAjay Singh 		}
1475625f965SAjay Singh 		mutex_unlock(&priv->scan_req_lock);
1485625f965SAjay Singh 	} else if (scan_event == SCAN_EVENT_ABORTED) {
1495625f965SAjay Singh 		mutex_lock(&priv->scan_req_lock);
1505625f965SAjay Singh 
1515625f965SAjay Singh 		if (priv->scan_req) {
1525625f965SAjay Singh 			struct cfg80211_scan_info info = {
1535625f965SAjay Singh 				.aborted = false,
1545625f965SAjay Singh 			};
1555625f965SAjay Singh 
1565625f965SAjay Singh 			cfg80211_scan_done(priv->scan_req, &info);
1575625f965SAjay Singh 			priv->cfg_scanning = false;
1585625f965SAjay Singh 			priv->scan_req = NULL;
1595625f965SAjay Singh 		}
1605625f965SAjay Singh 		mutex_unlock(&priv->scan_req_lock);
1615625f965SAjay Singh 	}
1625625f965SAjay Singh }
1635625f965SAjay Singh 
cfg_connect_result(enum conn_event conn_disconn_evt,u8 mac_status,void * priv_data)1645625f965SAjay Singh static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
1655625f965SAjay Singh 			       void *priv_data)
1665625f965SAjay Singh {
1675625f965SAjay Singh 	struct wilc_priv *priv = priv_data;
1685625f965SAjay Singh 	struct net_device *dev = priv->dev;
1695625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
1705625f965SAjay Singh 	struct wilc *wl = vif->wilc;
1715625f965SAjay Singh 	struct host_if_drv *wfi_drv = priv->hif_drv;
1725625f965SAjay Singh 	struct wilc_conn_info *conn_info = &wfi_drv->conn_info;
1735625f965SAjay Singh 	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
1745625f965SAjay Singh 
1755625f965SAjay Singh 	vif->connecting = false;
1765625f965SAjay Singh 
1775625f965SAjay Singh 	if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) {
1785625f965SAjay Singh 		u16 connect_status = conn_info->status;
1795625f965SAjay Singh 
1805625f965SAjay Singh 		if (mac_status == WILC_MAC_STATUS_DISCONNECTED &&
1815625f965SAjay Singh 		    connect_status == WLAN_STATUS_SUCCESS) {
1825625f965SAjay Singh 			connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1835625f965SAjay Singh 			wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
1845625f965SAjay Singh 
1855625f965SAjay Singh 			if (vif->iftype != WILC_CLIENT_MODE)
1865625f965SAjay Singh 				wl->sta_ch = WILC_INVALID_CHANNEL;
1875625f965SAjay Singh 
1885625f965SAjay Singh 			netdev_err(dev, "Unspecified failure\n");
1895625f965SAjay Singh 		}
1905625f965SAjay Singh 
1915625f965SAjay Singh 		if (connect_status == WLAN_STATUS_SUCCESS)
1925625f965SAjay Singh 			memcpy(priv->associated_bss, conn_info->bssid,
1935625f965SAjay Singh 			       ETH_ALEN);
1945625f965SAjay Singh 
1955625f965SAjay Singh 		cfg80211_ref_bss(wiphy, vif->bss);
1965625f965SAjay Singh 		cfg80211_connect_bss(dev, conn_info->bssid, vif->bss,
1975625f965SAjay Singh 				     conn_info->req_ies,
1985625f965SAjay Singh 				     conn_info->req_ies_len,
1995625f965SAjay Singh 				     conn_info->resp_ies,
2005625f965SAjay Singh 				     conn_info->resp_ies_len,
2015625f965SAjay Singh 				     connect_status, GFP_KERNEL,
2025625f965SAjay Singh 				     NL80211_TIMEOUT_UNSPECIFIED);
2035625f965SAjay Singh 
2045625f965SAjay Singh 		vif->bss = NULL;
2055625f965SAjay Singh 	} else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
2065625f965SAjay Singh 		u16 reason = 0;
2075625f965SAjay Singh 
2085625f965SAjay Singh 		eth_zero_addr(priv->associated_bss);
2095625f965SAjay Singh 		wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
2105625f965SAjay Singh 
2115625f965SAjay Singh 		if (vif->iftype != WILC_CLIENT_MODE) {
2125625f965SAjay Singh 			wl->sta_ch = WILC_INVALID_CHANNEL;
2135625f965SAjay Singh 		} else {
2145625f965SAjay Singh 			if (wfi_drv->ifc_up)
2155625f965SAjay Singh 				reason = 3;
2165625f965SAjay Singh 			else
2175625f965SAjay Singh 				reason = 1;
2185625f965SAjay Singh 		}
2195625f965SAjay Singh 
2205625f965SAjay Singh 		cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL);
2215625f965SAjay Singh 	}
2225625f965SAjay Singh }
2235625f965SAjay Singh 
wilc_get_wl_to_vif(struct wilc * wl)2245625f965SAjay Singh struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
2255625f965SAjay Singh {
2265625f965SAjay Singh 	struct wilc_vif *vif;
2275625f965SAjay Singh 
2285625f965SAjay Singh 	vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list);
2295625f965SAjay Singh 	if (!vif)
2305625f965SAjay Singh 		return ERR_PTR(-EINVAL);
2315625f965SAjay Singh 
2325625f965SAjay Singh 	return vif;
2335625f965SAjay Singh }
2345625f965SAjay Singh 
set_channel(struct wiphy * wiphy,struct cfg80211_chan_def * chandef)2355625f965SAjay Singh static int set_channel(struct wiphy *wiphy,
2365625f965SAjay Singh 		       struct cfg80211_chan_def *chandef)
2375625f965SAjay Singh {
2385625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
2395625f965SAjay Singh 	struct wilc_vif *vif;
2405625f965SAjay Singh 	u32 channelnum;
2415625f965SAjay Singh 	int result;
2425625f965SAjay Singh 	int srcu_idx;
2435625f965SAjay Singh 
2445625f965SAjay Singh 	srcu_idx = srcu_read_lock(&wl->srcu);
2455625f965SAjay Singh 	vif = wilc_get_wl_to_vif(wl);
2465625f965SAjay Singh 	if (IS_ERR(vif)) {
2475625f965SAjay Singh 		srcu_read_unlock(&wl->srcu, srcu_idx);
2485625f965SAjay Singh 		return PTR_ERR(vif);
2495625f965SAjay Singh 	}
2505625f965SAjay Singh 
2515625f965SAjay Singh 	channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq);
2525625f965SAjay Singh 
2535625f965SAjay Singh 	wl->op_ch = channelnum;
2545625f965SAjay Singh 	result = wilc_set_mac_chnl_num(vif, channelnum);
2555625f965SAjay Singh 	if (result)
2565625f965SAjay Singh 		netdev_err(vif->ndev, "Error in setting channel\n");
2575625f965SAjay Singh 
2585625f965SAjay Singh 	srcu_read_unlock(&wl->srcu, srcu_idx);
2595625f965SAjay Singh 	return result;
2605625f965SAjay Singh }
2615625f965SAjay Singh 
scan(struct wiphy * wiphy,struct cfg80211_scan_request * request)2625625f965SAjay Singh static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
2635625f965SAjay Singh {
2645625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(request->wdev->netdev);
2655625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
2665625f965SAjay Singh 	u32 i;
2675625f965SAjay Singh 	int ret = 0;
2685625f965SAjay Singh 	u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH];
2695625f965SAjay Singh 	u8 scan_type;
2705625f965SAjay Singh 
2715625f965SAjay Singh 	if (request->n_channels > WILC_MAX_NUM_SCANNED_CH) {
2725625f965SAjay Singh 		netdev_err(vif->ndev, "Requested scanned channels over\n");
2735625f965SAjay Singh 		return -EINVAL;
2745625f965SAjay Singh 	}
2755625f965SAjay Singh 
2765625f965SAjay Singh 	priv->scan_req = request;
2775625f965SAjay Singh 	priv->cfg_scanning = true;
2785625f965SAjay Singh 	for (i = 0; i < request->n_channels; i++) {
2795625f965SAjay Singh 		u16 freq = request->channels[i]->center_freq;
2805625f965SAjay Singh 
2815625f965SAjay Singh 		scan_ch_list[i] = ieee80211_frequency_to_channel(freq);
2825625f965SAjay Singh 	}
2835625f965SAjay Singh 
2845625f965SAjay Singh 	if (request->n_ssids)
2855625f965SAjay Singh 		scan_type = WILC_FW_ACTIVE_SCAN;
2865625f965SAjay Singh 	else
2875625f965SAjay Singh 		scan_type = WILC_FW_PASSIVE_SCAN;
2885625f965SAjay Singh 
2895625f965SAjay Singh 	ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list,
2905625f965SAjay Singh 			request->n_channels, cfg_scan_result, (void *)priv,
2915625f965SAjay Singh 			request);
2925625f965SAjay Singh 
2935625f965SAjay Singh 	if (ret) {
2945625f965SAjay Singh 		priv->scan_req = NULL;
2955625f965SAjay Singh 		priv->cfg_scanning = false;
2965625f965SAjay Singh 	}
2975625f965SAjay Singh 
2985625f965SAjay Singh 	return ret;
2995625f965SAjay Singh }
3005625f965SAjay Singh 
connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)3015625f965SAjay Singh static int connect(struct wiphy *wiphy, struct net_device *dev,
3025625f965SAjay Singh 		   struct cfg80211_connect_params *sme)
3035625f965SAjay Singh {
3045625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
3055625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
3065625f965SAjay Singh 	struct host_if_drv *wfi_drv = priv->hif_drv;
3075625f965SAjay Singh 	int ret;
3085625f965SAjay Singh 	u32 i;
3095625f965SAjay Singh 	u8 security = WILC_FW_SEC_NO;
3100e703de3SAjay Singh 	enum mfptype mfp_type = WILC_FW_MFP_NONE;
3115625f965SAjay Singh 	enum authtype auth_type = WILC_FW_AUTH_ANY;
3125625f965SAjay Singh 	u32 cipher_group;
3135625f965SAjay Singh 	struct cfg80211_bss *bss;
3145625f965SAjay Singh 	void *join_params;
3155625f965SAjay Singh 	u8 ch;
3165625f965SAjay Singh 
3175625f965SAjay Singh 	vif->connecting = true;
3185625f965SAjay Singh 
3195625f965SAjay Singh 	cipher_group = sme->crypto.cipher_group;
3205625f965SAjay Singh 	if (cipher_group != 0) {
3213c76ec88SAjay Singh 		if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
3225625f965SAjay Singh 			if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
3235625f965SAjay Singh 				security = WILC_FW_SEC_WPA2_TKIP;
3245625f965SAjay Singh 			else
3255625f965SAjay Singh 				security = WILC_FW_SEC_WPA2_AES;
3265625f965SAjay Singh 		} else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
3275625f965SAjay Singh 			if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
3285625f965SAjay Singh 				security = WILC_FW_SEC_WPA_TKIP;
3295625f965SAjay Singh 			else
3305625f965SAjay Singh 				security = WILC_FW_SEC_WPA_AES;
3315625f965SAjay Singh 		} else {
3325625f965SAjay Singh 			ret = -ENOTSUPP;
3335625f965SAjay Singh 			netdev_err(dev, "%s: Unsupported cipher\n",
3345625f965SAjay Singh 				   __func__);
3355625f965SAjay Singh 			goto out_error;
3365625f965SAjay Singh 		}
3375625f965SAjay Singh 	}
3385625f965SAjay Singh 
3395625f965SAjay Singh 	if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) ||
3405625f965SAjay Singh 	    (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
3415625f965SAjay Singh 		for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) {
3425625f965SAjay Singh 			u32 ciphers_pairwise = sme->crypto.ciphers_pairwise[i];
3435625f965SAjay Singh 
3445625f965SAjay Singh 			if (ciphers_pairwise == WLAN_CIPHER_SUITE_TKIP)
3455625f965SAjay Singh 				security |= WILC_FW_TKIP;
3465625f965SAjay Singh 			else
3475625f965SAjay Singh 				security |= WILC_FW_AES;
3485625f965SAjay Singh 		}
3495625f965SAjay Singh 	}
3505625f965SAjay Singh 
3515625f965SAjay Singh 	switch (sme->auth_type) {
3525625f965SAjay Singh 	case NL80211_AUTHTYPE_OPEN_SYSTEM:
3535625f965SAjay Singh 		auth_type = WILC_FW_AUTH_OPEN_SYSTEM;
3545625f965SAjay Singh 		break;
3555625f965SAjay Singh 
356c5b331d4SAjay Singh 	case NL80211_AUTHTYPE_SAE:
357c5b331d4SAjay Singh 		auth_type = WILC_FW_AUTH_SAE;
358c5b331d4SAjay Singh 		if (sme->ssid_len) {
359c5b331d4SAjay Singh 			memcpy(vif->auth.ssid.ssid, sme->ssid, sme->ssid_len);
360c5b331d4SAjay Singh 			vif->auth.ssid.ssid_len = sme->ssid_len;
361c5b331d4SAjay Singh 		}
362c5b331d4SAjay Singh 		vif->auth.key_mgmt_suite = cpu_to_be32(sme->crypto.akm_suites[0]);
363c5b331d4SAjay Singh 		ether_addr_copy(vif->auth.bssid, sme->bssid);
364c5b331d4SAjay Singh 		break;
365c5b331d4SAjay Singh 
3665625f965SAjay Singh 	default:
3675625f965SAjay Singh 		break;
3685625f965SAjay Singh 	}
3695625f965SAjay Singh 
3705625f965SAjay Singh 	if (sme->crypto.n_akm_suites) {
3715625f965SAjay Singh 		if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X)
3725625f965SAjay Singh 			auth_type = WILC_FW_AUTH_IEEE8021;
373c5b331d4SAjay Singh 		else if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_PSK_SHA256)
374c5b331d4SAjay Singh 			auth_type = WILC_FW_AUTH_OPEN_SYSTEM_SHA256;
375c5b331d4SAjay Singh 		else if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X_SHA256)
376c5b331d4SAjay Singh 			auth_type = WILC_FW_AUTH_IEE8021X_SHA256;
3775625f965SAjay Singh 	}
3785625f965SAjay Singh 
3795625f965SAjay Singh 	if (wfi_drv->usr_scan_req.scan_result) {
3805625f965SAjay Singh 		netdev_err(vif->ndev, "%s: Scan in progress\n", __func__);
3815625f965SAjay Singh 		ret = -EBUSY;
3825625f965SAjay Singh 		goto out_error;
3835625f965SAjay Singh 	}
3845625f965SAjay Singh 
3855625f965SAjay Singh 	bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid,
3865625f965SAjay Singh 			       sme->ssid_len, IEEE80211_BSS_TYPE_ANY,
3875625f965SAjay Singh 			       IEEE80211_PRIVACY(sme->privacy));
3885625f965SAjay Singh 	if (!bss) {
3895625f965SAjay Singh 		ret = -EINVAL;
3905625f965SAjay Singh 		goto out_error;
3915625f965SAjay Singh 	}
3925625f965SAjay Singh 
3935625f965SAjay Singh 	if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) {
3945625f965SAjay Singh 		ret = -EALREADY;
3955625f965SAjay Singh 		goto out_put_bss;
3965625f965SAjay Singh 	}
3975625f965SAjay Singh 
3985625f965SAjay Singh 	join_params = wilc_parse_join_bss_param(bss, &sme->crypto);
3995625f965SAjay Singh 	if (!join_params) {
4005625f965SAjay Singh 		netdev_err(dev, "%s: failed to construct join param\n",
4015625f965SAjay Singh 			   __func__);
4025625f965SAjay Singh 		ret = -EINVAL;
4035625f965SAjay Singh 		goto out_put_bss;
4045625f965SAjay Singh 	}
4055625f965SAjay Singh 
4065625f965SAjay Singh 	ch = ieee80211_frequency_to_channel(bss->channel->center_freq);
4075625f965SAjay Singh 	vif->wilc->op_ch = ch;
4085625f965SAjay Singh 	if (vif->iftype != WILC_CLIENT_MODE)
4095625f965SAjay Singh 		vif->wilc->sta_ch = ch;
4105625f965SAjay Singh 
4115625f965SAjay Singh 	wilc_wlan_set_bssid(dev, bss->bssid, WILC_STATION_MODE);
4125625f965SAjay Singh 
4135625f965SAjay Singh 	wfi_drv->conn_info.security = security;
4145625f965SAjay Singh 	wfi_drv->conn_info.auth_type = auth_type;
4155625f965SAjay Singh 	wfi_drv->conn_info.ch = ch;
4165625f965SAjay Singh 	wfi_drv->conn_info.conn_result = cfg_connect_result;
4175625f965SAjay Singh 	wfi_drv->conn_info.arg = priv;
4185625f965SAjay Singh 	wfi_drv->conn_info.param = join_params;
4195625f965SAjay Singh 
4200e703de3SAjay Singh 	if (sme->mfp == NL80211_MFP_OPTIONAL)
4210e703de3SAjay Singh 		mfp_type = WILC_FW_MFP_OPTIONAL;
4220e703de3SAjay Singh 	else if (sme->mfp == NL80211_MFP_REQUIRED)
4230e703de3SAjay Singh 		mfp_type = WILC_FW_MFP_REQUIRED;
4240e703de3SAjay Singh 
4250e703de3SAjay Singh 	wfi_drv->conn_info.mfp_type = mfp_type;
4260e703de3SAjay Singh 
4275625f965SAjay Singh 	ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len);
4285625f965SAjay Singh 	if (ret) {
4295625f965SAjay Singh 		netdev_err(dev, "wilc_set_join_req(): Error\n");
4305625f965SAjay Singh 		ret = -ENOENT;
4315625f965SAjay Singh 		if (vif->iftype != WILC_CLIENT_MODE)
4325625f965SAjay Singh 			vif->wilc->sta_ch = WILC_INVALID_CHANNEL;
4335625f965SAjay Singh 		wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE);
4345625f965SAjay Singh 		wfi_drv->conn_info.conn_result = NULL;
4355625f965SAjay Singh 		kfree(join_params);
4365625f965SAjay Singh 		goto out_put_bss;
4375625f965SAjay Singh 	}
4385625f965SAjay Singh 	kfree(join_params);
4395625f965SAjay Singh 	vif->bss = bss;
4405625f965SAjay Singh 	cfg80211_put_bss(wiphy, bss);
4415625f965SAjay Singh 	return 0;
4425625f965SAjay Singh 
4435625f965SAjay Singh out_put_bss:
4445625f965SAjay Singh 	cfg80211_put_bss(wiphy, bss);
4455625f965SAjay Singh 
4465625f965SAjay Singh out_error:
4475625f965SAjay Singh 	vif->connecting = false;
4485625f965SAjay Singh 	return ret;
4495625f965SAjay Singh }
4505625f965SAjay Singh 
disconnect(struct wiphy * wiphy,struct net_device * dev,u16 reason_code)4515625f965SAjay Singh static int disconnect(struct wiphy *wiphy, struct net_device *dev,
4525625f965SAjay Singh 		      u16 reason_code)
4535625f965SAjay Singh {
4545625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
4555625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
4565625f965SAjay Singh 	struct wilc *wilc = vif->wilc;
4575625f965SAjay Singh 	int ret;
4585625f965SAjay Singh 
4595625f965SAjay Singh 	vif->connecting = false;
4605625f965SAjay Singh 
4615625f965SAjay Singh 	if (!wilc)
4625625f965SAjay Singh 		return -EIO;
4635625f965SAjay Singh 
4645625f965SAjay Singh 	if (wilc->close) {
4655625f965SAjay Singh 		/* already disconnected done */
4665625f965SAjay Singh 		cfg80211_disconnected(dev, 0, NULL, 0, true, GFP_KERNEL);
4675625f965SAjay Singh 		return 0;
4685625f965SAjay Singh 	}
4695625f965SAjay Singh 
4705625f965SAjay Singh 	if (vif->iftype != WILC_CLIENT_MODE)
4715625f965SAjay Singh 		wilc->sta_ch = WILC_INVALID_CHANNEL;
4725625f965SAjay Singh 	wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
4735625f965SAjay Singh 
4745625f965SAjay Singh 	priv->hif_drv->p2p_timeout = 0;
4755625f965SAjay Singh 
4765625f965SAjay Singh 	ret = wilc_disconnect(vif);
4775625f965SAjay Singh 	if (ret != 0) {
4785625f965SAjay Singh 		netdev_err(priv->dev, "Error in disconnecting\n");
4795625f965SAjay Singh 		ret = -EINVAL;
4805625f965SAjay Singh 	}
4815625f965SAjay Singh 
4825625f965SAjay Singh 	vif->bss = NULL;
4835625f965SAjay Singh 
4845625f965SAjay Singh 	return ret;
4855625f965SAjay Singh }
4865625f965SAjay Singh 
wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv * priv,u8 idx)4875625f965SAjay Singh static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx)
4885625f965SAjay Singh {
4895625f965SAjay Singh 	if (!priv->wilc_gtk[idx]) {
4905625f965SAjay Singh 		priv->wilc_gtk[idx] = kzalloc(sizeof(*priv->wilc_gtk[idx]),
4915625f965SAjay Singh 					      GFP_KERNEL);
4925625f965SAjay Singh 		if (!priv->wilc_gtk[idx])
4935625f965SAjay Singh 			return -ENOMEM;
4945625f965SAjay Singh 	}
4955625f965SAjay Singh 
4965625f965SAjay Singh 	if (!priv->wilc_ptk[idx]) {
4975625f965SAjay Singh 		priv->wilc_ptk[idx] = kzalloc(sizeof(*priv->wilc_ptk[idx]),
4985625f965SAjay Singh 					      GFP_KERNEL);
4995625f965SAjay Singh 		if (!priv->wilc_ptk[idx])
5005625f965SAjay Singh 			return -ENOMEM;
5015625f965SAjay Singh 	}
5025625f965SAjay Singh 
5035625f965SAjay Singh 	return 0;
5045625f965SAjay Singh }
5055625f965SAjay Singh 
wilc_wfi_cfg_allocate_wpa_igtk_entry(struct wilc_priv * priv,u8 idx)5060e703de3SAjay Singh static int wilc_wfi_cfg_allocate_wpa_igtk_entry(struct wilc_priv *priv, u8 idx)
5070e703de3SAjay Singh {
5080e703de3SAjay Singh 	idx -= 4;
5090e703de3SAjay Singh 	if (!priv->wilc_igtk[idx]) {
5100e703de3SAjay Singh 		priv->wilc_igtk[idx] = kzalloc(sizeof(*priv->wilc_igtk[idx]),
5110e703de3SAjay Singh 					       GFP_KERNEL);
5120e703de3SAjay Singh 		if (!priv->wilc_igtk[idx])
5130e703de3SAjay Singh 			return -ENOMEM;
5140e703de3SAjay Singh 	}
5150e703de3SAjay Singh 	return 0;
5160e703de3SAjay Singh }
5170e703de3SAjay Singh 
wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key * key_info,struct key_params * params)5185625f965SAjay Singh static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
5195625f965SAjay Singh 				      struct key_params *params)
5205625f965SAjay Singh {
5215625f965SAjay Singh 	kfree(key_info->key);
5225625f965SAjay Singh 
5235625f965SAjay Singh 	key_info->key = kmemdup(params->key, params->key_len, GFP_KERNEL);
5245625f965SAjay Singh 	if (!key_info->key)
5255625f965SAjay Singh 		return -ENOMEM;
5265625f965SAjay Singh 
5275625f965SAjay Singh 	kfree(key_info->seq);
5285625f965SAjay Singh 
5295625f965SAjay Singh 	if (params->seq_len > 0) {
5305625f965SAjay Singh 		key_info->seq = kmemdup(params->seq, params->seq_len,
5315625f965SAjay Singh 					GFP_KERNEL);
5325625f965SAjay Singh 		if (!key_info->seq)
5335625f965SAjay Singh 			return -ENOMEM;
5345625f965SAjay Singh 	}
5355625f965SAjay Singh 
5365625f965SAjay Singh 	key_info->cipher = params->cipher;
5375625f965SAjay Singh 	key_info->key_len = params->key_len;
5385625f965SAjay Singh 	key_info->seq_len = params->seq_len;
5395625f965SAjay Singh 
5405625f965SAjay Singh 	return 0;
5415625f965SAjay Singh }
5425625f965SAjay Singh 
add_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,u8 key_index,bool pairwise,const u8 * mac_addr,struct key_params * params)543e7a7b84eSVeerendranath Jakkam static int add_key(struct wiphy *wiphy, struct net_device *netdev, int link_id,
544e7a7b84eSVeerendranath Jakkam 		   u8 key_index, bool pairwise, const u8 *mac_addr,
545e7a7b84eSVeerendranath Jakkam 		   struct key_params *params)
5465625f965SAjay Singh 
5475625f965SAjay Singh {
5485625f965SAjay Singh 	int ret = 0, keylen = params->key_len;
5495625f965SAjay Singh 	const u8 *rx_mic = NULL;
5505625f965SAjay Singh 	const u8 *tx_mic = NULL;
5515625f965SAjay Singh 	u8 mode = WILC_FW_SEC_NO;
5525625f965SAjay Singh 	u8 op_mode;
5535625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(netdev);
5545625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
5550e703de3SAjay Singh 	struct wilc_wfi_key *key;
5565625f965SAjay Singh 
5575625f965SAjay Singh 	switch (params->cipher) {
5585625f965SAjay Singh 	case WLAN_CIPHER_SUITE_TKIP:
5595625f965SAjay Singh 	case WLAN_CIPHER_SUITE_CCMP:
5605625f965SAjay Singh 		if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
5615625f965SAjay Singh 		    priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
5625625f965SAjay Singh 			struct wilc_wfi_key *key;
5635625f965SAjay Singh 
5645625f965SAjay Singh 			ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index);
5655625f965SAjay Singh 			if (ret)
5665625f965SAjay Singh 				return -ENOMEM;
5675625f965SAjay Singh 
5685625f965SAjay Singh 			if (params->key_len > 16 &&
5695625f965SAjay Singh 			    params->cipher == WLAN_CIPHER_SUITE_TKIP) {
5705625f965SAjay Singh 				tx_mic = params->key + 24;
5715625f965SAjay Singh 				rx_mic = params->key + 16;
5725625f965SAjay Singh 				keylen = params->key_len - 16;
5735625f965SAjay Singh 			}
5745625f965SAjay Singh 
5755625f965SAjay Singh 			if (!pairwise) {
5765625f965SAjay Singh 				if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
5775625f965SAjay Singh 					mode = WILC_FW_SEC_WPA_TKIP;
5785625f965SAjay Singh 				else
5795625f965SAjay Singh 					mode = WILC_FW_SEC_WPA2_AES;
5805625f965SAjay Singh 
5815625f965SAjay Singh 				priv->wilc_groupkey = mode;
5825625f965SAjay Singh 
5835625f965SAjay Singh 				key = priv->wilc_gtk[key_index];
5845625f965SAjay Singh 			} else {
5855625f965SAjay Singh 				if (params->cipher == WLAN_CIPHER_SUITE_TKIP)
5865625f965SAjay Singh 					mode = WILC_FW_SEC_WPA_TKIP;
5875625f965SAjay Singh 				else
5885625f965SAjay Singh 					mode = priv->wilc_groupkey | WILC_FW_AES;
5895625f965SAjay Singh 
5905625f965SAjay Singh 				key = priv->wilc_ptk[key_index];
5915625f965SAjay Singh 			}
5925625f965SAjay Singh 			ret = wilc_wfi_cfg_copy_wpa_info(key, params);
5935625f965SAjay Singh 			if (ret)
5945625f965SAjay Singh 				return -ENOMEM;
5955625f965SAjay Singh 
5965625f965SAjay Singh 			op_mode = WILC_AP_MODE;
5975625f965SAjay Singh 		} else {
5985625f965SAjay Singh 			if (params->key_len > 16 &&
5995625f965SAjay Singh 			    params->cipher == WLAN_CIPHER_SUITE_TKIP) {
6005625f965SAjay Singh 				rx_mic = params->key + 24;
6015625f965SAjay Singh 				tx_mic = params->key + 16;
6025625f965SAjay Singh 				keylen = params->key_len - 16;
6035625f965SAjay Singh 			}
6045625f965SAjay Singh 
6055625f965SAjay Singh 			op_mode = WILC_STATION_MODE;
6065625f965SAjay Singh 		}
6075625f965SAjay Singh 
6085625f965SAjay Singh 		if (!pairwise)
6095625f965SAjay Singh 			ret = wilc_add_rx_gtk(vif, params->key, keylen,
6105625f965SAjay Singh 					      key_index, params->seq_len,
6115625f965SAjay Singh 					      params->seq, rx_mic, tx_mic,
6125625f965SAjay Singh 					      op_mode, mode);
6135625f965SAjay Singh 		else
6145625f965SAjay Singh 			ret = wilc_add_ptk(vif, params->key, keylen, mac_addr,
6155625f965SAjay Singh 					   rx_mic, tx_mic, op_mode, mode,
6165625f965SAjay Singh 					   key_index);
6175625f965SAjay Singh 
6185625f965SAjay Singh 		break;
6190e703de3SAjay Singh 	case WLAN_CIPHER_SUITE_AES_CMAC:
6200e703de3SAjay Singh 		ret = wilc_wfi_cfg_allocate_wpa_igtk_entry(priv, key_index);
6210e703de3SAjay Singh 		if (ret)
6220e703de3SAjay Singh 			return -ENOMEM;
6230e703de3SAjay Singh 
6240e703de3SAjay Singh 		key = priv->wilc_igtk[key_index - 4];
6250e703de3SAjay Singh 		ret = wilc_wfi_cfg_copy_wpa_info(key, params);
6260e703de3SAjay Singh 		if (ret)
6270e703de3SAjay Singh 			return -ENOMEM;
6280e703de3SAjay Singh 
6290e703de3SAjay Singh 		if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
6300e703de3SAjay Singh 		    priv->wdev.iftype == NL80211_IFTYPE_P2P_GO)
6310e703de3SAjay Singh 			op_mode = WILC_AP_MODE;
6320e703de3SAjay Singh 		else
6330e703de3SAjay Singh 			op_mode = WILC_STATION_MODE;
6340e703de3SAjay Singh 
6350e703de3SAjay Singh 		ret = wilc_add_igtk(vif, params->key, keylen, params->seq,
6360e703de3SAjay Singh 				    params->seq_len, mac_addr, op_mode,
6370e703de3SAjay Singh 				    key_index);
6380e703de3SAjay Singh 		break;
6395625f965SAjay Singh 
6405625f965SAjay Singh 	default:
6415625f965SAjay Singh 		netdev_err(netdev, "%s: Unsupported cipher\n", __func__);
6425625f965SAjay Singh 		ret = -ENOTSUPP;
6435625f965SAjay Singh 	}
6445625f965SAjay Singh 
6455625f965SAjay Singh 	return ret;
6465625f965SAjay Singh }
6475625f965SAjay Singh 
del_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,u8 key_index,bool pairwise,const u8 * mac_addr)648e7a7b84eSVeerendranath Jakkam static int del_key(struct wiphy *wiphy, struct net_device *netdev, int link_id,
6495625f965SAjay Singh 		   u8 key_index,
6505625f965SAjay Singh 		   bool pairwise,
6515625f965SAjay Singh 		   const u8 *mac_addr)
6525625f965SAjay Singh {
6535625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(netdev);
6545625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
6555625f965SAjay Singh 
6560e703de3SAjay Singh 	if (!pairwise && (key_index == 4 || key_index == 5)) {
6570e703de3SAjay Singh 		key_index -= 4;
6580e703de3SAjay Singh 		if (priv->wilc_igtk[key_index]) {
6590e703de3SAjay Singh 			kfree(priv->wilc_igtk[key_index]->key);
6600e703de3SAjay Singh 			priv->wilc_igtk[key_index]->key = NULL;
6610e703de3SAjay Singh 			kfree(priv->wilc_igtk[key_index]->seq);
6620e703de3SAjay Singh 			priv->wilc_igtk[key_index]->seq = NULL;
6630e703de3SAjay Singh 			kfree(priv->wilc_igtk[key_index]);
6640e703de3SAjay Singh 			priv->wilc_igtk[key_index] = NULL;
6650e703de3SAjay Singh 		}
6660e703de3SAjay Singh 	} else {
6675625f965SAjay Singh 		if (priv->wilc_gtk[key_index]) {
6685625f965SAjay Singh 			kfree(priv->wilc_gtk[key_index]->key);
6695625f965SAjay Singh 			priv->wilc_gtk[key_index]->key = NULL;
6705625f965SAjay Singh 			kfree(priv->wilc_gtk[key_index]->seq);
6715625f965SAjay Singh 			priv->wilc_gtk[key_index]->seq = NULL;
6725625f965SAjay Singh 
6735625f965SAjay Singh 			kfree(priv->wilc_gtk[key_index]);
6745625f965SAjay Singh 			priv->wilc_gtk[key_index] = NULL;
6755625f965SAjay Singh 		}
6765625f965SAjay Singh 		if (priv->wilc_ptk[key_index]) {
6775625f965SAjay Singh 			kfree(priv->wilc_ptk[key_index]->key);
6785625f965SAjay Singh 			priv->wilc_ptk[key_index]->key = NULL;
6795625f965SAjay Singh 			kfree(priv->wilc_ptk[key_index]->seq);
6805625f965SAjay Singh 			priv->wilc_ptk[key_index]->seq = NULL;
6815625f965SAjay Singh 			kfree(priv->wilc_ptk[key_index]);
6825625f965SAjay Singh 			priv->wilc_ptk[key_index] = NULL;
6835625f965SAjay Singh 		}
6840e703de3SAjay Singh 	}
6855625f965SAjay Singh 
6865625f965SAjay Singh 	return 0;
6875625f965SAjay Singh }
6885625f965SAjay Singh 
get_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,u8 key_index,bool pairwise,const u8 * mac_addr,void * cookie,void (* callback)(void * cookie,struct key_params *))689e7a7b84eSVeerendranath Jakkam static int get_key(struct wiphy *wiphy, struct net_device *netdev, int link_id,
690e7a7b84eSVeerendranath Jakkam 		   u8 key_index, bool pairwise, const u8 *mac_addr,
691e7a7b84eSVeerendranath Jakkam 		   void *cookie,
6925625f965SAjay Singh 		   void (*callback)(void *cookie, struct key_params *))
6935625f965SAjay Singh {
6945625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(netdev);
6955625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
6965625f965SAjay Singh 	struct  key_params key_params;
6975625f965SAjay Singh 
6985625f965SAjay Singh 	if (!pairwise) {
6990e703de3SAjay Singh 		if (key_index == 4 || key_index == 5) {
7000e703de3SAjay Singh 			key_index -= 4;
7010e703de3SAjay Singh 			key_params.key = priv->wilc_igtk[key_index]->key;
7020e703de3SAjay Singh 			key_params.cipher = priv->wilc_igtk[key_index]->cipher;
7030e703de3SAjay Singh 			key_params.key_len = priv->wilc_igtk[key_index]->key_len;
7040e703de3SAjay Singh 			key_params.seq = priv->wilc_igtk[key_index]->seq;
7050e703de3SAjay Singh 			key_params.seq_len = priv->wilc_igtk[key_index]->seq_len;
7060e703de3SAjay Singh 		} else {
7075625f965SAjay Singh 			key_params.key = priv->wilc_gtk[key_index]->key;
7085625f965SAjay Singh 			key_params.cipher = priv->wilc_gtk[key_index]->cipher;
7095625f965SAjay Singh 			key_params.key_len = priv->wilc_gtk[key_index]->key_len;
7105625f965SAjay Singh 			key_params.seq = priv->wilc_gtk[key_index]->seq;
7115625f965SAjay Singh 			key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
7120e703de3SAjay Singh 		}
7135625f965SAjay Singh 	} else {
7145625f965SAjay Singh 		key_params.key = priv->wilc_ptk[key_index]->key;
7155625f965SAjay Singh 		key_params.cipher = priv->wilc_ptk[key_index]->cipher;
7165625f965SAjay Singh 		key_params.key_len = priv->wilc_ptk[key_index]->key_len;
7175625f965SAjay Singh 		key_params.seq = priv->wilc_ptk[key_index]->seq;
7185625f965SAjay Singh 		key_params.seq_len = priv->wilc_ptk[key_index]->seq_len;
7195625f965SAjay Singh 	}
7205625f965SAjay Singh 
7215625f965SAjay Singh 	callback(cookie, &key_params);
7225625f965SAjay Singh 
7235625f965SAjay Singh 	return 0;
7245625f965SAjay Singh }
7255625f965SAjay Singh 
7263c76ec88SAjay Singh /* wiphy_new_nm() will WARNON if not present */
set_default_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,u8 key_index,bool unicast,bool multicast)7275625f965SAjay Singh static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
728e7a7b84eSVeerendranath Jakkam 			   int link_id, u8 key_index, bool unicast,
729e7a7b84eSVeerendranath Jakkam 			   bool multicast)
7305625f965SAjay Singh {
7315625f965SAjay Singh 	return 0;
7325625f965SAjay Singh }
7335625f965SAjay Singh 
set_default_mgmt_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,u8 key_index)7340e703de3SAjay Singh static int set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev,
735e7a7b84eSVeerendranath Jakkam 				int link_id, u8 key_index)
7360e703de3SAjay Singh {
7370e703de3SAjay Singh 	struct wilc_vif *vif = netdev_priv(netdev);
7380e703de3SAjay Singh 
7390e703de3SAjay Singh 	return wilc_set_default_mgmt_key_index(vif, key_index);
7400e703de3SAjay Singh }
7410e703de3SAjay Singh 
get_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_info * sinfo)7425625f965SAjay Singh static int get_station(struct wiphy *wiphy, struct net_device *dev,
7435625f965SAjay Singh 		       const u8 *mac, struct station_info *sinfo)
7445625f965SAjay Singh {
7455625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
7465625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
747cd50248dSAjay Singh 	struct wilc *wilc = vif->wilc;
7485625f965SAjay Singh 	u32 i = 0;
7495625f965SAjay Singh 	u32 associatedsta = ~0;
7505625f965SAjay Singh 	u32 inactive_time = 0;
7515625f965SAjay Singh 
7525625f965SAjay Singh 	if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
7535625f965SAjay Singh 		for (i = 0; i < NUM_STA_ASSOCIATED; i++) {
7545625f965SAjay Singh 			if (!(memcmp(mac,
7555625f965SAjay Singh 				     priv->assoc_stainfo.sta_associated_bss[i],
7565625f965SAjay Singh 				     ETH_ALEN))) {
7575625f965SAjay Singh 				associatedsta = i;
7585625f965SAjay Singh 				break;
7595625f965SAjay Singh 			}
7605625f965SAjay Singh 		}
7615625f965SAjay Singh 
7625625f965SAjay Singh 		if (associatedsta == ~0) {
7635625f965SAjay Singh 			netdev_err(dev, "sta required is not associated\n");
7645625f965SAjay Singh 			return -ENOENT;
7655625f965SAjay Singh 		}
7665625f965SAjay Singh 
7675625f965SAjay Singh 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME);
7685625f965SAjay Singh 
7695625f965SAjay Singh 		wilc_get_inactive_time(vif, mac, &inactive_time);
7705625f965SAjay Singh 		sinfo->inactive_time = 1000 * inactive_time;
7715625f965SAjay Singh 	} else if (vif->iftype == WILC_STATION_MODE) {
7725625f965SAjay Singh 		struct rf_info stats;
7735625f965SAjay Singh 
774cd50248dSAjay Singh 		if (!wilc->initialized)
775cd50248dSAjay Singh 			return -EBUSY;
776cd50248dSAjay Singh 
7775625f965SAjay Singh 		wilc_get_statistics(vif, &stats);
7785625f965SAjay Singh 
7795625f965SAjay Singh 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL) |
7805625f965SAjay Singh 				 BIT_ULL(NL80211_STA_INFO_RX_PACKETS) |
7815625f965SAjay Singh 				 BIT_ULL(NL80211_STA_INFO_TX_PACKETS) |
7825625f965SAjay Singh 				 BIT_ULL(NL80211_STA_INFO_TX_FAILED) |
7835625f965SAjay Singh 				 BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
7845625f965SAjay Singh 
7855625f965SAjay Singh 		sinfo->signal = stats.rssi;
7865625f965SAjay Singh 		sinfo->rx_packets = stats.rx_cnt;
7875625f965SAjay Singh 		sinfo->tx_packets = stats.tx_cnt + stats.tx_fail_cnt;
7885625f965SAjay Singh 		sinfo->tx_failed = stats.tx_fail_cnt;
7895625f965SAjay Singh 		sinfo->txrate.legacy = stats.link_speed * 10;
7905625f965SAjay Singh 
7915625f965SAjay Singh 		if (stats.link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&
7925625f965SAjay Singh 		    stats.link_speed != DEFAULT_LINK_SPEED)
7935625f965SAjay Singh 			wilc_enable_tcp_ack_filter(vif, true);
7945625f965SAjay Singh 		else if (stats.link_speed != DEFAULT_LINK_SPEED)
7955625f965SAjay Singh 			wilc_enable_tcp_ack_filter(vif, false);
7965625f965SAjay Singh 	}
7975625f965SAjay Singh 	return 0;
7985625f965SAjay Singh }
7995625f965SAjay Singh 
change_bss(struct wiphy * wiphy,struct net_device * dev,struct bss_parameters * params)8005625f965SAjay Singh static int change_bss(struct wiphy *wiphy, struct net_device *dev,
8015625f965SAjay Singh 		      struct bss_parameters *params)
8025625f965SAjay Singh {
8035625f965SAjay Singh 	return 0;
8045625f965SAjay Singh }
8055625f965SAjay Singh 
set_wiphy_params(struct wiphy * wiphy,u32 changed)8065625f965SAjay Singh static int set_wiphy_params(struct wiphy *wiphy, u32 changed)
8075625f965SAjay Singh {
8085625f965SAjay Singh 	int ret = -EINVAL;
8095625f965SAjay Singh 	struct cfg_param_attr cfg_param_val;
8105625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
8115625f965SAjay Singh 	struct wilc_vif *vif;
8125625f965SAjay Singh 	struct wilc_priv *priv;
8135625f965SAjay Singh 	int srcu_idx;
8145625f965SAjay Singh 
8155625f965SAjay Singh 	srcu_idx = srcu_read_lock(&wl->srcu);
8165625f965SAjay Singh 	vif = wilc_get_wl_to_vif(wl);
8175625f965SAjay Singh 	if (IS_ERR(vif))
8185625f965SAjay Singh 		goto out;
8195625f965SAjay Singh 
8205625f965SAjay Singh 	priv = &vif->priv;
8215625f965SAjay Singh 	cfg_param_val.flag = 0;
8225625f965SAjay Singh 
8235625f965SAjay Singh 	if (changed & WIPHY_PARAM_RETRY_SHORT) {
8245625f965SAjay Singh 		netdev_dbg(vif->ndev,
8255625f965SAjay Singh 			   "Setting WIPHY_PARAM_RETRY_SHORT %d\n",
8265625f965SAjay Singh 			   wiphy->retry_short);
8275625f965SAjay Singh 		cfg_param_val.flag  |= WILC_CFG_PARAM_RETRY_SHORT;
8285625f965SAjay Singh 		cfg_param_val.short_retry_limit = wiphy->retry_short;
8295625f965SAjay Singh 	}
8305625f965SAjay Singh 	if (changed & WIPHY_PARAM_RETRY_LONG) {
8315625f965SAjay Singh 		netdev_dbg(vif->ndev,
8325625f965SAjay Singh 			   "Setting WIPHY_PARAM_RETRY_LONG %d\n",
8335625f965SAjay Singh 			   wiphy->retry_long);
8345625f965SAjay Singh 		cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_LONG;
8355625f965SAjay Singh 		cfg_param_val.long_retry_limit = wiphy->retry_long;
8365625f965SAjay Singh 	}
8375625f965SAjay Singh 	if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
8385625f965SAjay Singh 		if (wiphy->frag_threshold > 255 &&
8395625f965SAjay Singh 		    wiphy->frag_threshold < 7937) {
8405625f965SAjay Singh 			netdev_dbg(vif->ndev,
8415625f965SAjay Singh 				   "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n",
8425625f965SAjay Singh 				   wiphy->frag_threshold);
8435625f965SAjay Singh 			cfg_param_val.flag |= WILC_CFG_PARAM_FRAG_THRESHOLD;
8445625f965SAjay Singh 			cfg_param_val.frag_threshold = wiphy->frag_threshold;
8455625f965SAjay Singh 		} else {
8465625f965SAjay Singh 			netdev_err(vif->ndev,
8475625f965SAjay Singh 				   "Fragmentation threshold out of range\n");
8485625f965SAjay Singh 			goto out;
8495625f965SAjay Singh 		}
8505625f965SAjay Singh 	}
8515625f965SAjay Singh 
8525625f965SAjay Singh 	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
8535625f965SAjay Singh 		if (wiphy->rts_threshold > 255) {
8545625f965SAjay Singh 			netdev_dbg(vif->ndev,
8555625f965SAjay Singh 				   "Setting WIPHY_PARAM_RTS_THRESHOLD %d\n",
8565625f965SAjay Singh 				   wiphy->rts_threshold);
8575625f965SAjay Singh 			cfg_param_val.flag |= WILC_CFG_PARAM_RTS_THRESHOLD;
8585625f965SAjay Singh 			cfg_param_val.rts_threshold = wiphy->rts_threshold;
8595625f965SAjay Singh 		} else {
8605625f965SAjay Singh 			netdev_err(vif->ndev, "RTS threshold out of range\n");
8615625f965SAjay Singh 			goto out;
8625625f965SAjay Singh 		}
8635625f965SAjay Singh 	}
8645625f965SAjay Singh 
8655625f965SAjay Singh 	ret = wilc_hif_set_cfg(vif, &cfg_param_val);
8665625f965SAjay Singh 	if (ret)
8675625f965SAjay Singh 		netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n");
8685625f965SAjay Singh 
8695625f965SAjay Singh out:
8705625f965SAjay Singh 	srcu_read_unlock(&wl->srcu, srcu_idx);
8715625f965SAjay Singh 	return ret;
8725625f965SAjay Singh }
8735625f965SAjay Singh 
set_pmksa(struct wiphy * wiphy,struct net_device * netdev,struct cfg80211_pmksa * pmksa)8745625f965SAjay Singh static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
8755625f965SAjay Singh 		     struct cfg80211_pmksa *pmksa)
8765625f965SAjay Singh {
8775625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(netdev);
8785625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
8795625f965SAjay Singh 	u32 i;
8805625f965SAjay Singh 	int ret = 0;
8815625f965SAjay Singh 	u8 flag = 0;
8825625f965SAjay Singh 
8835625f965SAjay Singh 	for (i = 0; i < priv->pmkid_list.numpmkid; i++)	{
8845625f965SAjay Singh 		if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
8855625f965SAjay Singh 			    ETH_ALEN)) {
8865625f965SAjay Singh 			flag = PMKID_FOUND;
8875625f965SAjay Singh 			break;
8885625f965SAjay Singh 		}
8895625f965SAjay Singh 	}
8905625f965SAjay Singh 	if (i < WILC_MAX_NUM_PMKIDS) {
8915625f965SAjay Singh 		memcpy(priv->pmkid_list.pmkidlist[i].bssid, pmksa->bssid,
8925625f965SAjay Singh 		       ETH_ALEN);
8935625f965SAjay Singh 		memcpy(priv->pmkid_list.pmkidlist[i].pmkid, pmksa->pmkid,
8945625f965SAjay Singh 		       WLAN_PMKID_LEN);
8955625f965SAjay Singh 		if (!(flag == PMKID_FOUND))
8965625f965SAjay Singh 			priv->pmkid_list.numpmkid++;
8975625f965SAjay Singh 	} else {
8985625f965SAjay Singh 		netdev_err(netdev, "Invalid PMKID index\n");
8995625f965SAjay Singh 		ret = -EINVAL;
9005625f965SAjay Singh 	}
9015625f965SAjay Singh 
9025625f965SAjay Singh 	if (!ret)
9035625f965SAjay Singh 		ret = wilc_set_pmkid_info(vif, &priv->pmkid_list);
9045625f965SAjay Singh 
9055625f965SAjay Singh 	return ret;
9065625f965SAjay Singh }
9075625f965SAjay Singh 
del_pmksa(struct wiphy * wiphy,struct net_device * netdev,struct cfg80211_pmksa * pmksa)9085625f965SAjay Singh static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
9095625f965SAjay Singh 		     struct cfg80211_pmksa *pmksa)
9105625f965SAjay Singh {
9115625f965SAjay Singh 	u32 i;
9125625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(netdev);
9135625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
9145625f965SAjay Singh 
9155625f965SAjay Singh 	for (i = 0; i < priv->pmkid_list.numpmkid; i++)	{
9165625f965SAjay Singh 		if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid,
9175625f965SAjay Singh 			    ETH_ALEN)) {
9185625f965SAjay Singh 			memset(&priv->pmkid_list.pmkidlist[i], 0,
9195625f965SAjay Singh 			       sizeof(struct wilc_pmkid));
9205625f965SAjay Singh 			break;
9215625f965SAjay Singh 		}
9225625f965SAjay Singh 	}
9235625f965SAjay Singh 
9245625f965SAjay Singh 	if (i == priv->pmkid_list.numpmkid)
9255625f965SAjay Singh 		return -EINVAL;
9265625f965SAjay Singh 
9275625f965SAjay Singh 	for (; i < (priv->pmkid_list.numpmkid - 1); i++) {
9285625f965SAjay Singh 		memcpy(priv->pmkid_list.pmkidlist[i].bssid,
9295625f965SAjay Singh 		       priv->pmkid_list.pmkidlist[i + 1].bssid,
9305625f965SAjay Singh 		       ETH_ALEN);
9315625f965SAjay Singh 		memcpy(priv->pmkid_list.pmkidlist[i].pmkid,
9325625f965SAjay Singh 		       priv->pmkid_list.pmkidlist[i + 1].pmkid,
9335625f965SAjay Singh 		       WLAN_PMKID_LEN);
9345625f965SAjay Singh 	}
9355625f965SAjay Singh 	priv->pmkid_list.numpmkid--;
9365625f965SAjay Singh 
9375625f965SAjay Singh 	return 0;
9385625f965SAjay Singh }
9395625f965SAjay Singh 
flush_pmksa(struct wiphy * wiphy,struct net_device * netdev)9405625f965SAjay Singh static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
9415625f965SAjay Singh {
9425625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(netdev);
9435625f965SAjay Singh 
9445625f965SAjay Singh 	memset(&vif->priv.pmkid_list, 0, sizeof(struct wilc_pmkid_attr));
9455625f965SAjay Singh 
9465625f965SAjay Singh 	return 0;
9475625f965SAjay Singh }
9485625f965SAjay Singh 
wilc_wfi_cfg_parse_ch_attr(u8 * buf,u32 len,u8 sta_ch)9495625f965SAjay Singh static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
9505625f965SAjay Singh {
9515625f965SAjay Singh 	struct wilc_attr_entry *e;
9525625f965SAjay Singh 	struct wilc_attr_ch_list *ch_list;
9535625f965SAjay Singh 	struct wilc_attr_oper_ch *op_ch;
9545625f965SAjay Singh 	u32 index = 0;
9555625f965SAjay Singh 	u8 ch_list_idx = 0;
9565625f965SAjay Singh 	u8 op_ch_idx = 0;
9575625f965SAjay Singh 
9585625f965SAjay Singh 	if (sta_ch == WILC_INVALID_CHANNEL)
9595625f965SAjay Singh 		return;
9605625f965SAjay Singh 
9615625f965SAjay Singh 	while (index + sizeof(*e) <= len) {
962051ae669SPhil Turnbull 		u16 attr_size;
963051ae669SPhil Turnbull 
9645625f965SAjay Singh 		e = (struct wilc_attr_entry *)&buf[index];
965051ae669SPhil Turnbull 		attr_size = le16_to_cpu(e->attr_len);
966051ae669SPhil Turnbull 
967051ae669SPhil Turnbull 		if (index + sizeof(*e) + attr_size > len)
968051ae669SPhil Turnbull 			return;
969051ae669SPhil Turnbull 
970f9b62f98SPhil Turnbull 		if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST &&
971f9b62f98SPhil Turnbull 		    attr_size >= (sizeof(struct wilc_attr_ch_list) - sizeof(*e)))
9725625f965SAjay Singh 			ch_list_idx = index;
973051ae669SPhil Turnbull 		else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL &&
974051ae669SPhil Turnbull 			 attr_size == (sizeof(struct wilc_attr_oper_ch) - sizeof(*e)))
9755625f965SAjay Singh 			op_ch_idx = index;
976051ae669SPhil Turnbull 
9775625f965SAjay Singh 		if (ch_list_idx && op_ch_idx)
9785625f965SAjay Singh 			break;
979051ae669SPhil Turnbull 
980051ae669SPhil Turnbull 		index += sizeof(*e) + attr_size;
9815625f965SAjay Singh 	}
9825625f965SAjay Singh 
9835625f965SAjay Singh 	if (ch_list_idx) {
9840cdfa9e6SPhil Turnbull 		u16 elem_size;
9855625f965SAjay Singh 
9865625f965SAjay Singh 		ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx];
9870cdfa9e6SPhil Turnbull 		/* the number of bytes following the final 'elem' member */
9880cdfa9e6SPhil Turnbull 		elem_size = le16_to_cpu(ch_list->attr_len) -
9890cdfa9e6SPhil Turnbull 			(sizeof(*ch_list) - sizeof(struct wilc_attr_entry));
9900cdfa9e6SPhil Turnbull 		for (unsigned int i = 0; i < elem_size;) {
9910cdfa9e6SPhil Turnbull 			struct wilc_ch_list_elem *e;
9920cdfa9e6SPhil Turnbull 
9935625f965SAjay Singh 			e = (struct wilc_ch_list_elem *)(ch_list->elem + i);
9940cdfa9e6SPhil Turnbull 
9950cdfa9e6SPhil Turnbull 			i += sizeof(*e);
9960cdfa9e6SPhil Turnbull 			if (i > elem_size)
9970cdfa9e6SPhil Turnbull 				break;
9980cdfa9e6SPhil Turnbull 
9990cdfa9e6SPhil Turnbull 			i += e->no_of_channels;
10000cdfa9e6SPhil Turnbull 			if (i > elem_size)
10010cdfa9e6SPhil Turnbull 				break;
10020cdfa9e6SPhil Turnbull 
10035625f965SAjay Singh 			if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) {
10045625f965SAjay Singh 				memset(e->ch_list, sta_ch, e->no_of_channels);
10055625f965SAjay Singh 				break;
10065625f965SAjay Singh 			}
10075625f965SAjay Singh 		}
10085625f965SAjay Singh 	}
10095625f965SAjay Singh 
10105625f965SAjay Singh 	if (op_ch_idx) {
10115625f965SAjay Singh 		op_ch = (struct wilc_attr_oper_ch *)&buf[op_ch_idx];
10125625f965SAjay Singh 		op_ch->op_class = WILC_WLAN_OPERATING_CLASS_2_4GHZ;
10135625f965SAjay Singh 		op_ch->op_channel = sta_ch;
10145625f965SAjay Singh 	}
10155625f965SAjay Singh }
10165625f965SAjay Singh 
wilc_wfi_mgmt_frame_rx(struct wilc_vif * vif,u8 * buff,u32 size)1017c5b331d4SAjay Singh bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size)
1018c5b331d4SAjay Singh {
1019c5b331d4SAjay Singh 	struct wilc *wl = vif->wilc;
1020c5b331d4SAjay Singh 	struct wilc_priv *priv = &vif->priv;
10211dc13236SJinpeng Cui 	int freq;
1022c5b331d4SAjay Singh 
1023c5b331d4SAjay Singh 	freq = ieee80211_channel_to_frequency(wl->op_ch, NL80211_BAND_2GHZ);
1024c5b331d4SAjay Singh 
10251dc13236SJinpeng Cui 	return cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
1026c5b331d4SAjay Singh }
1027c5b331d4SAjay Singh 
wilc_wfi_p2p_rx(struct wilc_vif * vif,u8 * buff,u32 size)10285625f965SAjay Singh void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
10295625f965SAjay Singh {
10305625f965SAjay Singh 	struct wilc *wl = vif->wilc;
10315625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
10325625f965SAjay Singh 	struct host_if_drv *wfi_drv = priv->hif_drv;
10335625f965SAjay Singh 	struct ieee80211_mgmt *mgmt;
10345625f965SAjay Singh 	struct wilc_vendor_specific_ie *p;
10355625f965SAjay Singh 	struct wilc_p2p_pub_act_frame *d;
10365625f965SAjay Singh 	int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d);
10375625f965SAjay Singh 	const u8 *vendor_ie;
10385625f965SAjay Singh 	u32 header, pkt_offset;
10395625f965SAjay Singh 	s32 freq;
10405625f965SAjay Singh 
10415625f965SAjay Singh 	header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
10425625f965SAjay Singh 	pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);
10435625f965SAjay Singh 
10445625f965SAjay Singh 	if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
10455625f965SAjay Singh 		bool ack = false;
10465625f965SAjay Singh 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)buff;
10475625f965SAjay Singh 
10485625f965SAjay Singh 		if (ieee80211_is_probe_resp(hdr->frame_control) ||
10495625f965SAjay Singh 		    pkt_offset & IS_MGMT_STATUS_SUCCES)
10505625f965SAjay Singh 			ack = true;
10515625f965SAjay Singh 
10525625f965SAjay Singh 		cfg80211_mgmt_tx_status(&priv->wdev, priv->tx_cookie, buff,
10535625f965SAjay Singh 					size, ack, GFP_KERNEL);
10545625f965SAjay Singh 		return;
10555625f965SAjay Singh 	}
10565625f965SAjay Singh 
10575625f965SAjay Singh 	freq = ieee80211_channel_to_frequency(wl->op_ch, NL80211_BAND_2GHZ);
10585625f965SAjay Singh 
10595625f965SAjay Singh 	mgmt = (struct ieee80211_mgmt *)buff;
10605625f965SAjay Singh 	if (!ieee80211_is_action(mgmt->frame_control))
10615625f965SAjay Singh 		goto out_rx_mgmt;
10625625f965SAjay Singh 
10635625f965SAjay Singh 	if (priv->cfg_scanning &&
10645625f965SAjay Singh 	    time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) {
10655625f965SAjay Singh 		netdev_dbg(vif->ndev, "Receiving action wrong ch\n");
10665625f965SAjay Singh 		return;
10675625f965SAjay Singh 	}
10685625f965SAjay Singh 
10695625f965SAjay Singh 	if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size))
10705625f965SAjay Singh 		goto out_rx_mgmt;
10715625f965SAjay Singh 
10725625f965SAjay Singh 	d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
10735625f965SAjay Singh 	if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP &&
10745625f965SAjay Singh 	    d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
10755625f965SAjay Singh 		goto out_rx_mgmt;
10765625f965SAjay Singh 
10775625f965SAjay Singh 	vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
10785625f965SAjay Singh 					    buff + ie_offset, size - ie_offset);
10795625f965SAjay Singh 	if (!vendor_ie)
10805625f965SAjay Singh 		goto out_rx_mgmt;
10815625f965SAjay Singh 
10825625f965SAjay Singh 	p = (struct wilc_vendor_specific_ie *)vendor_ie;
10835625f965SAjay Singh 	wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch);
10845625f965SAjay Singh 
10855625f965SAjay Singh out_rx_mgmt:
10865625f965SAjay Singh 	cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
10875625f965SAjay Singh }
10885625f965SAjay Singh 
wilc_wfi_mgmt_tx_complete(void * priv,int status)10895625f965SAjay Singh static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
10905625f965SAjay Singh {
10915625f965SAjay Singh 	struct wilc_p2p_mgmt_data *pv_data = priv;
10925625f965SAjay Singh 
10935625f965SAjay Singh 	kfree(pv_data->buff);
10945625f965SAjay Singh 	kfree(pv_data);
10955625f965SAjay Singh }
10965625f965SAjay Singh 
wilc_wfi_remain_on_channel_expired(void * data,u64 cookie)10975625f965SAjay Singh static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
10985625f965SAjay Singh {
10995625f965SAjay Singh 	struct wilc_vif *vif = data;
11005625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
11015625f965SAjay Singh 	struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
11025625f965SAjay Singh 
11035625f965SAjay Singh 	if (cookie != params->listen_cookie)
11045625f965SAjay Singh 		return;
11055625f965SAjay Singh 
11065625f965SAjay Singh 	priv->p2p_listen_state = false;
11075625f965SAjay Singh 
11085625f965SAjay Singh 	cfg80211_remain_on_channel_expired(&priv->wdev, params->listen_cookie,
11095625f965SAjay Singh 					   params->listen_ch, GFP_KERNEL);
11105625f965SAjay Singh }
11115625f965SAjay Singh 
remain_on_channel(struct wiphy * wiphy,struct wireless_dev * wdev,struct ieee80211_channel * chan,unsigned int duration,u64 * cookie)11125625f965SAjay Singh static int remain_on_channel(struct wiphy *wiphy,
11135625f965SAjay Singh 			     struct wireless_dev *wdev,
11145625f965SAjay Singh 			     struct ieee80211_channel *chan,
11155625f965SAjay Singh 			     unsigned int duration, u64 *cookie)
11165625f965SAjay Singh {
11175625f965SAjay Singh 	int ret = 0;
11185625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(wdev->netdev);
11195625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
11205625f965SAjay Singh 	u64 id;
11215625f965SAjay Singh 
11225625f965SAjay Singh 	if (wdev->iftype == NL80211_IFTYPE_AP) {
11235625f965SAjay Singh 		netdev_dbg(vif->ndev, "Required while in AP mode\n");
11245625f965SAjay Singh 		return ret;
11255625f965SAjay Singh 	}
11265625f965SAjay Singh 
11275625f965SAjay Singh 	id = ++priv->inc_roc_cookie;
11285625f965SAjay Singh 	if (id == 0)
11295625f965SAjay Singh 		id = ++priv->inc_roc_cookie;
11305625f965SAjay Singh 
11315625f965SAjay Singh 	ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value,
11325625f965SAjay Singh 				     wilc_wfi_remain_on_channel_expired,
11335625f965SAjay Singh 				     (void *)vif);
11345625f965SAjay Singh 	if (ret)
11355625f965SAjay Singh 		return ret;
11365625f965SAjay Singh 
11375625f965SAjay Singh 	vif->wilc->op_ch = chan->hw_value;
11385625f965SAjay Singh 
11395625f965SAjay Singh 	priv->remain_on_ch_params.listen_ch = chan;
11405625f965SAjay Singh 	priv->remain_on_ch_params.listen_cookie = id;
11415625f965SAjay Singh 	*cookie = id;
11425625f965SAjay Singh 	priv->p2p_listen_state = true;
11435625f965SAjay Singh 	priv->remain_on_ch_params.listen_duration = duration;
11445625f965SAjay Singh 
11455625f965SAjay Singh 	cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL);
11465625f965SAjay Singh 	mod_timer(&vif->hif_drv->remain_on_ch_timer,
11475625f965SAjay Singh 		  jiffies + msecs_to_jiffies(duration + 1000));
11485625f965SAjay Singh 
11495625f965SAjay Singh 	return ret;
11505625f965SAjay Singh }
11515625f965SAjay Singh 
cancel_remain_on_channel(struct wiphy * wiphy,struct wireless_dev * wdev,u64 cookie)11525625f965SAjay Singh static int cancel_remain_on_channel(struct wiphy *wiphy,
11535625f965SAjay Singh 				    struct wireless_dev *wdev,
11545625f965SAjay Singh 				    u64 cookie)
11555625f965SAjay Singh {
11565625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(wdev->netdev);
11575625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
11585625f965SAjay Singh 
11595625f965SAjay Singh 	if (cookie != priv->remain_on_ch_params.listen_cookie)
11605625f965SAjay Singh 		return -ENOENT;
11615625f965SAjay Singh 
11625625f965SAjay Singh 	return wilc_listen_state_expired(vif, cookie);
11635625f965SAjay Singh }
11645625f965SAjay Singh 
mgmt_tx(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_mgmt_tx_params * params,u64 * cookie)11655625f965SAjay Singh static int mgmt_tx(struct wiphy *wiphy,
11665625f965SAjay Singh 		   struct wireless_dev *wdev,
11675625f965SAjay Singh 		   struct cfg80211_mgmt_tx_params *params,
11685625f965SAjay Singh 		   u64 *cookie)
11695625f965SAjay Singh {
11705625f965SAjay Singh 	struct ieee80211_channel *chan = params->chan;
11715625f965SAjay Singh 	unsigned int wait = params->wait;
11725625f965SAjay Singh 	const u8 *buf = params->buf;
11735625f965SAjay Singh 	size_t len = params->len;
11745625f965SAjay Singh 	const struct ieee80211_mgmt *mgmt;
11755625f965SAjay Singh 	struct wilc_p2p_mgmt_data *mgmt_tx;
11765625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(wdev->netdev);
11775625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
11785625f965SAjay Singh 	struct host_if_drv *wfi_drv = priv->hif_drv;
11795625f965SAjay Singh 	struct wilc_vendor_specific_ie *p;
11805625f965SAjay Singh 	struct wilc_p2p_pub_act_frame *d;
11815625f965SAjay Singh 	int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d);
11825625f965SAjay Singh 	const u8 *vendor_ie;
11835625f965SAjay Singh 	int ret = 0;
11845625f965SAjay Singh 
1185a251c17aSJason A. Donenfeld 	*cookie = get_random_u32();
11865625f965SAjay Singh 	priv->tx_cookie = *cookie;
11875625f965SAjay Singh 	mgmt = (const struct ieee80211_mgmt *)buf;
11885625f965SAjay Singh 
11895625f965SAjay Singh 	if (!ieee80211_is_mgmt(mgmt->frame_control))
11905625f965SAjay Singh 		goto out;
11915625f965SAjay Singh 
11925625f965SAjay Singh 	mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_KERNEL);
11935625f965SAjay Singh 	if (!mgmt_tx) {
11945625f965SAjay Singh 		ret = -ENOMEM;
11955625f965SAjay Singh 		goto out;
11965625f965SAjay Singh 	}
11975625f965SAjay Singh 
11985625f965SAjay Singh 	mgmt_tx->buff = kmemdup(buf, len, GFP_KERNEL);
11995625f965SAjay Singh 	if (!mgmt_tx->buff) {
12005625f965SAjay Singh 		ret = -ENOMEM;
12015625f965SAjay Singh 		kfree(mgmt_tx);
12025625f965SAjay Singh 		goto out;
12035625f965SAjay Singh 	}
12045625f965SAjay Singh 
12055625f965SAjay Singh 	mgmt_tx->size = len;
12065625f965SAjay Singh 
12075625f965SAjay Singh 	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
12085625f965SAjay Singh 		wilc_set_mac_chnl_num(vif, chan->hw_value);
12095625f965SAjay Singh 		vif->wilc->op_ch = chan->hw_value;
12105625f965SAjay Singh 		goto out_txq_add_pkt;
12115625f965SAjay Singh 	}
12125625f965SAjay Singh 
1213c5b331d4SAjay Singh 	if (!ieee80211_is_public_action((struct ieee80211_hdr *)buf, len)) {
1214c5b331d4SAjay Singh 		if (chan)
1215c5b331d4SAjay Singh 			wilc_set_mac_chnl_num(vif, chan->hw_value);
1216c5b331d4SAjay Singh 		else
1217c5b331d4SAjay Singh 			wilc_set_mac_chnl_num(vif, vif->wilc->op_ch);
1218c5b331d4SAjay Singh 
12195625f965SAjay Singh 		goto out_set_timeout;
1220c5b331d4SAjay Singh 	}
12215625f965SAjay Singh 
12225625f965SAjay Singh 	d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
12235625f965SAjay Singh 	if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P ||
12245625f965SAjay Singh 	    d->oui_subtype != GO_NEG_CONF) {
12255625f965SAjay Singh 		wilc_set_mac_chnl_num(vif, chan->hw_value);
12265625f965SAjay Singh 		vif->wilc->op_ch = chan->hw_value;
12275625f965SAjay Singh 	}
12285625f965SAjay Singh 
12295625f965SAjay Singh 	if (d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
12305625f965SAjay Singh 		goto out_set_timeout;
12315625f965SAjay Singh 
12325625f965SAjay Singh 	vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
12335625f965SAjay Singh 					    mgmt_tx->buff + ie_offset,
12345625f965SAjay Singh 					    len - ie_offset);
12355625f965SAjay Singh 	if (!vendor_ie)
12365625f965SAjay Singh 		goto out_set_timeout;
12375625f965SAjay Singh 
12385625f965SAjay Singh 	p = (struct wilc_vendor_specific_ie *)vendor_ie;
12395625f965SAjay Singh 	wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch);
12405625f965SAjay Singh 
12415625f965SAjay Singh out_set_timeout:
12425625f965SAjay Singh 	wfi_drv->p2p_timeout = (jiffies + msecs_to_jiffies(wait));
12435625f965SAjay Singh 
12445625f965SAjay Singh out_txq_add_pkt:
12455625f965SAjay Singh 
12465625f965SAjay Singh 	wilc_wlan_txq_add_mgmt_pkt(wdev->netdev, mgmt_tx,
12475625f965SAjay Singh 				   mgmt_tx->buff, mgmt_tx->size,
12485625f965SAjay Singh 				   wilc_wfi_mgmt_tx_complete);
12495625f965SAjay Singh 
12505625f965SAjay Singh out:
12515625f965SAjay Singh 
12525625f965SAjay Singh 	return ret;
12535625f965SAjay Singh }
12545625f965SAjay Singh 
mgmt_tx_cancel_wait(struct wiphy * wiphy,struct wireless_dev * wdev,u64 cookie)12555625f965SAjay Singh static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
12565625f965SAjay Singh 			       struct wireless_dev *wdev,
12575625f965SAjay Singh 			       u64 cookie)
12585625f965SAjay Singh {
12595625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(wdev->netdev);
12605625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
12615625f965SAjay Singh 	struct host_if_drv *wfi_drv = priv->hif_drv;
12625625f965SAjay Singh 
12635625f965SAjay Singh 	wfi_drv->p2p_timeout = jiffies;
12645625f965SAjay Singh 
12655625f965SAjay Singh 	if (!priv->p2p_listen_state) {
12665625f965SAjay Singh 		struct wilc_wfi_p2p_listen_params *params;
12675625f965SAjay Singh 
12685625f965SAjay Singh 		params = &priv->remain_on_ch_params;
12695625f965SAjay Singh 
12705625f965SAjay Singh 		cfg80211_remain_on_channel_expired(wdev,
12715625f965SAjay Singh 						   params->listen_cookie,
12725625f965SAjay Singh 						   params->listen_ch,
12735625f965SAjay Singh 						   GFP_KERNEL);
12745625f965SAjay Singh 	}
12755625f965SAjay Singh 
12765625f965SAjay Singh 	return 0;
12775625f965SAjay Singh }
12785625f965SAjay Singh 
wilc_update_mgmt_frame_registrations(struct wiphy * wiphy,struct wireless_dev * wdev,struct mgmt_frame_regs * upd)12795625f965SAjay Singh void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
12805625f965SAjay Singh 					  struct wireless_dev *wdev,
12815625f965SAjay Singh 					  struct mgmt_frame_regs *upd)
12825625f965SAjay Singh {
12835625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
12845625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(wdev->netdev);
12855625f965SAjay Singh 	u32 presp_bit = BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
12865625f965SAjay Singh 	u32 action_bit = BIT(IEEE80211_STYPE_ACTION >> 4);
1287c5b331d4SAjay Singh 	u32 pauth_bit = BIT(IEEE80211_STYPE_AUTH >> 4);
12885625f965SAjay Singh 
12895625f965SAjay Singh 	if (wl->initialized) {
12905625f965SAjay Singh 		bool prev = vif->mgmt_reg_stypes & presp_bit;
12915625f965SAjay Singh 		bool now = upd->interface_stypes & presp_bit;
12925625f965SAjay Singh 
12935625f965SAjay Singh 		if (now != prev)
12945625f965SAjay Singh 			wilc_frame_register(vif, IEEE80211_STYPE_PROBE_REQ, now);
12955625f965SAjay Singh 
12965625f965SAjay Singh 		prev = vif->mgmt_reg_stypes & action_bit;
12975625f965SAjay Singh 		now = upd->interface_stypes & action_bit;
12985625f965SAjay Singh 
12995625f965SAjay Singh 		if (now != prev)
13005625f965SAjay Singh 			wilc_frame_register(vif, IEEE80211_STYPE_ACTION, now);
1301c5b331d4SAjay Singh 
1302c5b331d4SAjay Singh 		prev = vif->mgmt_reg_stypes & pauth_bit;
1303c5b331d4SAjay Singh 		now = upd->interface_stypes & pauth_bit;
1304c5b331d4SAjay Singh 		if (now != prev)
1305c5b331d4SAjay Singh 			wilc_frame_register(vif, IEEE80211_STYPE_AUTH, now);
13065625f965SAjay Singh 	}
13075625f965SAjay Singh 
13085625f965SAjay Singh 	vif->mgmt_reg_stypes =
1309c5b331d4SAjay Singh 		upd->interface_stypes & (presp_bit | action_bit | pauth_bit);
1310c5b331d4SAjay Singh }
1311c5b331d4SAjay Singh 
external_auth(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_external_auth_params * auth)1312c5b331d4SAjay Singh static int external_auth(struct wiphy *wiphy, struct net_device *dev,
1313c5b331d4SAjay Singh 			 struct cfg80211_external_auth_params *auth)
1314c5b331d4SAjay Singh {
1315c5b331d4SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
1316c5b331d4SAjay Singh 
1317c5b331d4SAjay Singh 	if (auth->status == WLAN_STATUS_SUCCESS)
1318c5b331d4SAjay Singh 		wilc_set_external_auth_param(vif, auth);
1319c5b331d4SAjay Singh 
1320c5b331d4SAjay Singh 	return 0;
13215625f965SAjay Singh }
13225625f965SAjay Singh 
set_cqm_rssi_config(struct wiphy * wiphy,struct net_device * dev,s32 rssi_thold,u32 rssi_hyst)13235625f965SAjay Singh static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
13245625f965SAjay Singh 			       s32 rssi_thold, u32 rssi_hyst)
13255625f965SAjay Singh {
13265625f965SAjay Singh 	return 0;
13275625f965SAjay Singh }
13285625f965SAjay Singh 
dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,u8 * mac,struct station_info * sinfo)13295625f965SAjay Singh static int dump_station(struct wiphy *wiphy, struct net_device *dev,
13305625f965SAjay Singh 			int idx, u8 *mac, struct station_info *sinfo)
13315625f965SAjay Singh {
13325625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
13335625f965SAjay Singh 	int ret;
13345625f965SAjay Singh 
13355625f965SAjay Singh 	if (idx != 0)
13365625f965SAjay Singh 		return -ENOENT;
13375625f965SAjay Singh 
13385625f965SAjay Singh 	ret = wilc_get_rssi(vif, &sinfo->signal);
13395625f965SAjay Singh 	if (ret)
13405625f965SAjay Singh 		return ret;
13415625f965SAjay Singh 
134233d4a577SAjay Singh 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
13435625f965SAjay Singh 	memcpy(mac, vif->priv.associated_bss, ETH_ALEN);
13445625f965SAjay Singh 	return 0;
13455625f965SAjay Singh }
13465625f965SAjay Singh 
set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,int timeout)13475625f965SAjay Singh static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
13485625f965SAjay Singh 			  bool enabled, int timeout)
13495625f965SAjay Singh {
13505625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
13515625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
13525625f965SAjay Singh 
13535625f965SAjay Singh 	if (!priv->hif_drv)
13545625f965SAjay Singh 		return -EIO;
13555625f965SAjay Singh 
13565625f965SAjay Singh 	wilc_set_power_mgmt(vif, enabled, timeout);
13575625f965SAjay Singh 
13585625f965SAjay Singh 	return 0;
13595625f965SAjay Singh }
13605625f965SAjay Singh 
change_virtual_intf(struct wiphy * wiphy,struct net_device * dev,enum nl80211_iftype type,struct vif_params * params)13615625f965SAjay Singh static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
13625625f965SAjay Singh 			       enum nl80211_iftype type,
13635625f965SAjay Singh 			       struct vif_params *params)
13645625f965SAjay Singh {
13655625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
13665625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
13675625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
13685625f965SAjay Singh 
13695625f965SAjay Singh 	switch (type) {
13705625f965SAjay Singh 	case NL80211_IFTYPE_STATION:
13715625f965SAjay Singh 		vif->connecting = false;
13725625f965SAjay Singh 		dev->ieee80211_ptr->iftype = type;
13735625f965SAjay Singh 		priv->wdev.iftype = type;
13745625f965SAjay Singh 		vif->monitor_flag = 0;
13755625f965SAjay Singh 		if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)
13765625f965SAjay Singh 			wilc_wfi_deinit_mon_interface(wl, true);
13775625f965SAjay Singh 		vif->iftype = WILC_STATION_MODE;
13785625f965SAjay Singh 
13795625f965SAjay Singh 		if (wl->initialized)
13805625f965SAjay Singh 			wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
13815625f965SAjay Singh 						WILC_STATION_MODE, vif->idx);
13825625f965SAjay Singh 
13835625f965SAjay Singh 		memset(priv->assoc_stainfo.sta_associated_bss, 0,
13845625f965SAjay Singh 		       WILC_MAX_NUM_STA * ETH_ALEN);
13855625f965SAjay Singh 		break;
13865625f965SAjay Singh 
13875625f965SAjay Singh 	case NL80211_IFTYPE_P2P_CLIENT:
13885625f965SAjay Singh 		vif->connecting = false;
13895625f965SAjay Singh 		dev->ieee80211_ptr->iftype = type;
13905625f965SAjay Singh 		priv->wdev.iftype = type;
13915625f965SAjay Singh 		vif->monitor_flag = 0;
13925625f965SAjay Singh 		vif->iftype = WILC_CLIENT_MODE;
13935625f965SAjay Singh 
13945625f965SAjay Singh 		if (wl->initialized)
13955625f965SAjay Singh 			wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
13965625f965SAjay Singh 						WILC_STATION_MODE, vif->idx);
13975625f965SAjay Singh 		break;
13985625f965SAjay Singh 
13995625f965SAjay Singh 	case NL80211_IFTYPE_AP:
14005625f965SAjay Singh 		dev->ieee80211_ptr->iftype = type;
14015625f965SAjay Singh 		priv->wdev.iftype = type;
14025625f965SAjay Singh 		vif->iftype = WILC_AP_MODE;
14035625f965SAjay Singh 
14045625f965SAjay Singh 		if (wl->initialized)
14055625f965SAjay Singh 			wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
14065625f965SAjay Singh 						WILC_AP_MODE, vif->idx);
14075625f965SAjay Singh 		break;
14085625f965SAjay Singh 
14095625f965SAjay Singh 	case NL80211_IFTYPE_P2P_GO:
14105625f965SAjay Singh 		dev->ieee80211_ptr->iftype = type;
14115625f965SAjay Singh 		priv->wdev.iftype = type;
14125625f965SAjay Singh 		vif->iftype = WILC_GO_MODE;
14135625f965SAjay Singh 
14145625f965SAjay Singh 		if (wl->initialized)
14155625f965SAjay Singh 			wilc_set_operation_mode(vif, wilc_get_vif_idx(vif),
14165625f965SAjay Singh 						WILC_AP_MODE, vif->idx);
14175625f965SAjay Singh 		break;
14185625f965SAjay Singh 
14195625f965SAjay Singh 	default:
14205625f965SAjay Singh 		netdev_err(dev, "Unknown interface type= %d\n", type);
14215625f965SAjay Singh 		return -EINVAL;
14225625f965SAjay Singh 	}
14235625f965SAjay Singh 
14245625f965SAjay Singh 	return 0;
14255625f965SAjay Singh }
14265625f965SAjay Singh 
start_ap(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ap_settings * settings)14275625f965SAjay Singh static int start_ap(struct wiphy *wiphy, struct net_device *dev,
14285625f965SAjay Singh 		    struct cfg80211_ap_settings *settings)
14295625f965SAjay Singh {
14305625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
14315625f965SAjay Singh 	int ret;
14325625f965SAjay Singh 
14335625f965SAjay Singh 	ret = set_channel(wiphy, &settings->chandef);
14345625f965SAjay Singh 	if (ret != 0)
14355625f965SAjay Singh 		netdev_err(dev, "Error in setting channel\n");
14365625f965SAjay Singh 
14375625f965SAjay Singh 	wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE);
14385625f965SAjay Singh 
14395625f965SAjay Singh 	return wilc_add_beacon(vif, settings->beacon_interval,
14405625f965SAjay Singh 				   settings->dtim_period, &settings->beacon);
14415625f965SAjay Singh }
14425625f965SAjay Singh 
change_beacon(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_beacon_data * beacon)14435625f965SAjay Singh static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
14445625f965SAjay Singh 			 struct cfg80211_beacon_data *beacon)
14455625f965SAjay Singh {
14465625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
14475625f965SAjay Singh 
14485625f965SAjay Singh 	return wilc_add_beacon(vif, 0, 0, beacon);
14495625f965SAjay Singh }
14505625f965SAjay Singh 
stop_ap(struct wiphy * wiphy,struct net_device * dev,unsigned int link_id)14517b0a0e3cSJohannes Berg static int stop_ap(struct wiphy *wiphy, struct net_device *dev,
14527b0a0e3cSJohannes Berg 		   unsigned int link_id)
14535625f965SAjay Singh {
14545625f965SAjay Singh 	int ret;
14555625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
14565625f965SAjay Singh 
14575625f965SAjay Singh 	wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE);
14585625f965SAjay Singh 
14595625f965SAjay Singh 	ret = wilc_del_beacon(vif);
14605625f965SAjay Singh 
14615625f965SAjay Singh 	if (ret)
14625625f965SAjay Singh 		netdev_err(dev, "Host delete beacon fail\n");
14635625f965SAjay Singh 
14645625f965SAjay Singh 	return ret;
14655625f965SAjay Singh }
14665625f965SAjay Singh 
add_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)14675625f965SAjay Singh static int add_station(struct wiphy *wiphy, struct net_device *dev,
14685625f965SAjay Singh 		       const u8 *mac, struct station_parameters *params)
14695625f965SAjay Singh {
14705625f965SAjay Singh 	int ret = 0;
14715625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
14725625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
14735625f965SAjay Singh 
14745625f965SAjay Singh 	if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
14755625f965SAjay Singh 		memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac,
14765625f965SAjay Singh 		       ETH_ALEN);
14775625f965SAjay Singh 
14785625f965SAjay Singh 		ret = wilc_add_station(vif, mac, params);
14795625f965SAjay Singh 		if (ret)
14805625f965SAjay Singh 			netdev_err(dev, "Host add station fail\n");
14815625f965SAjay Singh 	}
14825625f965SAjay Singh 
14835625f965SAjay Singh 	return ret;
14845625f965SAjay Singh }
14855625f965SAjay Singh 
del_station(struct wiphy * wiphy,struct net_device * dev,struct station_del_parameters * params)14865625f965SAjay Singh static int del_station(struct wiphy *wiphy, struct net_device *dev,
14875625f965SAjay Singh 		       struct station_del_parameters *params)
14885625f965SAjay Singh {
14895625f965SAjay Singh 	const u8 *mac = params->mac;
14905625f965SAjay Singh 	int ret = 0;
14915625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
14925625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
14935625f965SAjay Singh 	struct sta_info *info;
14945625f965SAjay Singh 
14955625f965SAjay Singh 	if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE))
14965625f965SAjay Singh 		return ret;
14975625f965SAjay Singh 
14985625f965SAjay Singh 	info = &priv->assoc_stainfo;
14995625f965SAjay Singh 
15005625f965SAjay Singh 	if (!mac)
15015625f965SAjay Singh 		ret = wilc_del_allstation(vif, info->sta_associated_bss);
15025625f965SAjay Singh 
15035625f965SAjay Singh 	ret = wilc_del_station(vif, mac);
15045625f965SAjay Singh 	if (ret)
15055625f965SAjay Singh 		netdev_err(dev, "Host delete station fail\n");
15065625f965SAjay Singh 	return ret;
15075625f965SAjay Singh }
15085625f965SAjay Singh 
change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)15095625f965SAjay Singh static int change_station(struct wiphy *wiphy, struct net_device *dev,
15105625f965SAjay Singh 			  const u8 *mac, struct station_parameters *params)
15115625f965SAjay Singh {
15125625f965SAjay Singh 	int ret = 0;
15135625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(dev);
15145625f965SAjay Singh 
15155625f965SAjay Singh 	if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) {
15165625f965SAjay Singh 		ret = wilc_edit_station(vif, mac, params);
15175625f965SAjay Singh 		if (ret)
15185625f965SAjay Singh 			netdev_err(dev, "Host edit station fail\n");
15195625f965SAjay Singh 	}
15205625f965SAjay Singh 	return ret;
15215625f965SAjay Singh }
15225625f965SAjay Singh 
wilc_get_vif_from_type(struct wilc * wl,int type)15235625f965SAjay Singh static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type)
15245625f965SAjay Singh {
15255625f965SAjay Singh 	struct wilc_vif *vif;
15265625f965SAjay Singh 
15275625f965SAjay Singh 	list_for_each_entry_rcu(vif, &wl->vif_list, list) {
15285625f965SAjay Singh 		if (vif->iftype == type)
15295625f965SAjay Singh 			return vif;
15305625f965SAjay Singh 	}
15315625f965SAjay Singh 
15325625f965SAjay Singh 	return NULL;
15335625f965SAjay Singh }
15345625f965SAjay Singh 
add_virtual_intf(struct wiphy * wiphy,const char * name,unsigned char name_assign_type,enum nl80211_iftype type,struct vif_params * params)15355625f965SAjay Singh static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
15365625f965SAjay Singh 					     const char *name,
15375625f965SAjay Singh 					     unsigned char name_assign_type,
15385625f965SAjay Singh 					     enum nl80211_iftype type,
15395625f965SAjay Singh 					     struct vif_params *params)
15405625f965SAjay Singh {
15415625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
15425625f965SAjay Singh 	struct wilc_vif *vif;
15435625f965SAjay Singh 	struct wireless_dev *wdev;
15445625f965SAjay Singh 	int iftype;
15455625f965SAjay Singh 
15465625f965SAjay Singh 	if (type == NL80211_IFTYPE_MONITOR) {
15475625f965SAjay Singh 		struct net_device *ndev;
15485625f965SAjay Singh 		int srcu_idx;
15495625f965SAjay Singh 
15505625f965SAjay Singh 		srcu_idx = srcu_read_lock(&wl->srcu);
15515625f965SAjay Singh 		vif = wilc_get_vif_from_type(wl, WILC_AP_MODE);
15525625f965SAjay Singh 		if (!vif) {
15535625f965SAjay Singh 			vif = wilc_get_vif_from_type(wl, WILC_GO_MODE);
15545625f965SAjay Singh 			if (!vif) {
15555625f965SAjay Singh 				srcu_read_unlock(&wl->srcu, srcu_idx);
15565625f965SAjay Singh 				goto validate_interface;
15575625f965SAjay Singh 			}
15585625f965SAjay Singh 		}
15595625f965SAjay Singh 
15605625f965SAjay Singh 		if (vif->monitor_flag) {
15615625f965SAjay Singh 			srcu_read_unlock(&wl->srcu, srcu_idx);
15625625f965SAjay Singh 			goto validate_interface;
15635625f965SAjay Singh 		}
15645625f965SAjay Singh 
15655625f965SAjay Singh 		ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev);
15665625f965SAjay Singh 		if (ndev) {
15675625f965SAjay Singh 			vif->monitor_flag = 1;
15685625f965SAjay Singh 		} else {
15695625f965SAjay Singh 			srcu_read_unlock(&wl->srcu, srcu_idx);
15705625f965SAjay Singh 			return ERR_PTR(-EINVAL);
15715625f965SAjay Singh 		}
15725625f965SAjay Singh 
15735625f965SAjay Singh 		wdev = &vif->priv.wdev;
15745625f965SAjay Singh 		srcu_read_unlock(&wl->srcu, srcu_idx);
15755625f965SAjay Singh 		return wdev;
15765625f965SAjay Singh 	}
15775625f965SAjay Singh 
15785625f965SAjay Singh validate_interface:
15795625f965SAjay Singh 	mutex_lock(&wl->vif_mutex);
15805625f965SAjay Singh 	if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) {
15815625f965SAjay Singh 		pr_err("Reached maximum number of interface\n");
15825625f965SAjay Singh 		mutex_unlock(&wl->vif_mutex);
15835625f965SAjay Singh 		return ERR_PTR(-EINVAL);
15845625f965SAjay Singh 	}
15855625f965SAjay Singh 	mutex_unlock(&wl->vif_mutex);
15865625f965SAjay Singh 
15875625f965SAjay Singh 	switch (type) {
15885625f965SAjay Singh 	case NL80211_IFTYPE_STATION:
15895625f965SAjay Singh 		iftype = WILC_STATION_MODE;
15905625f965SAjay Singh 		break;
15915625f965SAjay Singh 	case NL80211_IFTYPE_AP:
15925625f965SAjay Singh 		iftype = WILC_AP_MODE;
15935625f965SAjay Singh 		break;
15945625f965SAjay Singh 	default:
15955625f965SAjay Singh 		return ERR_PTR(-EOPNOTSUPP);
15965625f965SAjay Singh 	}
15975625f965SAjay Singh 
15985625f965SAjay Singh 	vif = wilc_netdev_ifc_init(wl, name, iftype, type, true);
15995625f965SAjay Singh 	if (IS_ERR(vif))
16005625f965SAjay Singh 		return ERR_CAST(vif);
16015625f965SAjay Singh 
16025625f965SAjay Singh 	return &vif->priv.wdev;
16035625f965SAjay Singh }
16045625f965SAjay Singh 
del_virtual_intf(struct wiphy * wiphy,struct wireless_dev * wdev)16055625f965SAjay Singh static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
16065625f965SAjay Singh {
16075625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
16085625f965SAjay Singh 	struct wilc_vif *vif;
16095625f965SAjay Singh 
16105625f965SAjay Singh 	if (wdev->iftype == NL80211_IFTYPE_AP ||
16115625f965SAjay Singh 	    wdev->iftype == NL80211_IFTYPE_P2P_GO)
16125625f965SAjay Singh 		wilc_wfi_deinit_mon_interface(wl, true);
16135625f965SAjay Singh 	vif = netdev_priv(wdev->netdev);
16145625f965SAjay Singh 	cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL);
16152fe8ef10SJohannes Berg 	cfg80211_unregister_netdevice(vif->ndev);
16165625f965SAjay Singh 	vif->monitor_flag = 0;
16175625f965SAjay Singh 
16185625f965SAjay Singh 	mutex_lock(&wl->vif_mutex);
16195625f965SAjay Singh 	list_del_rcu(&vif->list);
16205625f965SAjay Singh 	wl->vif_num--;
16215625f965SAjay Singh 	mutex_unlock(&wl->vif_mutex);
16225625f965SAjay Singh 	synchronize_srcu(&wl->srcu);
16235625f965SAjay Singh 	return 0;
16245625f965SAjay Singh }
16255625f965SAjay Singh 
wilc_suspend(struct wiphy * wiphy,struct cfg80211_wowlan * wow)16265625f965SAjay Singh static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
16275625f965SAjay Singh {
16285625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
16295625f965SAjay Singh 
16305625f965SAjay Singh 	if (!wow && wilc_wlan_get_num_conn_ifcs(wl))
16315625f965SAjay Singh 		wl->suspend_event = true;
16325625f965SAjay Singh 	else
16335625f965SAjay Singh 		wl->suspend_event = false;
16345625f965SAjay Singh 
16355625f965SAjay Singh 	return 0;
16365625f965SAjay Singh }
16375625f965SAjay Singh 
wilc_resume(struct wiphy * wiphy)16385625f965SAjay Singh static int wilc_resume(struct wiphy *wiphy)
16395625f965SAjay Singh {
16405625f965SAjay Singh 	return 0;
16415625f965SAjay Singh }
16425625f965SAjay Singh 
wilc_set_wakeup(struct wiphy * wiphy,bool enabled)16435625f965SAjay Singh static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled)
16445625f965SAjay Singh {
16455625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
16465625f965SAjay Singh 	struct wilc_vif *vif;
16475625f965SAjay Singh 	int srcu_idx;
16485625f965SAjay Singh 
16495625f965SAjay Singh 	srcu_idx = srcu_read_lock(&wl->srcu);
16505625f965SAjay Singh 	vif = wilc_get_wl_to_vif(wl);
16515625f965SAjay Singh 	if (IS_ERR(vif)) {
16525625f965SAjay Singh 		srcu_read_unlock(&wl->srcu, srcu_idx);
16535625f965SAjay Singh 		return;
16545625f965SAjay Singh 	}
16555625f965SAjay Singh 
16565625f965SAjay Singh 	netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled);
16570ec5408cSAjay Singh 	wilc_set_wowlan_trigger(vif, enabled);
16585625f965SAjay Singh 	srcu_read_unlock(&wl->srcu, srcu_idx);
16595625f965SAjay Singh }
16605625f965SAjay Singh 
set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,int mbm)16615625f965SAjay Singh static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
16625625f965SAjay Singh 			enum nl80211_tx_power_setting type, int mbm)
16635625f965SAjay Singh {
16645625f965SAjay Singh 	int ret;
16655625f965SAjay Singh 	int srcu_idx;
16665625f965SAjay Singh 	s32 tx_power = MBM_TO_DBM(mbm);
16675625f965SAjay Singh 	struct wilc *wl = wiphy_priv(wiphy);
16685625f965SAjay Singh 	struct wilc_vif *vif;
16695625f965SAjay Singh 
16705625f965SAjay Singh 	if (!wl->initialized)
16715625f965SAjay Singh 		return -EIO;
16725625f965SAjay Singh 
16735625f965SAjay Singh 	srcu_idx = srcu_read_lock(&wl->srcu);
16745625f965SAjay Singh 	vif = wilc_get_wl_to_vif(wl);
16755625f965SAjay Singh 	if (IS_ERR(vif)) {
16765625f965SAjay Singh 		srcu_read_unlock(&wl->srcu, srcu_idx);
16775625f965SAjay Singh 		return -EINVAL;
16785625f965SAjay Singh 	}
16795625f965SAjay Singh 
16805625f965SAjay Singh 	netdev_info(vif->ndev, "Setting tx power %d\n", tx_power);
16815625f965SAjay Singh 	if (tx_power < 0)
16825625f965SAjay Singh 		tx_power = 0;
16835625f965SAjay Singh 	else if (tx_power > 18)
16845625f965SAjay Singh 		tx_power = 18;
16855625f965SAjay Singh 	ret = wilc_set_tx_power(vif, tx_power);
16865625f965SAjay Singh 	if (ret)
16875625f965SAjay Singh 		netdev_err(vif->ndev, "Failed to set tx power\n");
16885625f965SAjay Singh 	srcu_read_unlock(&wl->srcu, srcu_idx);
16895625f965SAjay Singh 
16905625f965SAjay Singh 	return ret;
16915625f965SAjay Singh }
16925625f965SAjay Singh 
get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)16935625f965SAjay Singh static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
16945625f965SAjay Singh 			int *dbm)
16955625f965SAjay Singh {
16965625f965SAjay Singh 	int ret;
16975625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(wdev->netdev);
16985625f965SAjay Singh 	struct wilc *wl = vif->wilc;
16995625f965SAjay Singh 
17005625f965SAjay Singh 	/* If firmware is not started, return. */
17015625f965SAjay Singh 	if (!wl->initialized)
17025625f965SAjay Singh 		return -EIO;
17035625f965SAjay Singh 
17045625f965SAjay Singh 	ret = wilc_get_tx_power(vif, (u8 *)dbm);
17055625f965SAjay Singh 	if (ret)
17065625f965SAjay Singh 		netdev_err(vif->ndev, "Failed to get tx power\n");
17075625f965SAjay Singh 
17085625f965SAjay Singh 	return ret;
17095625f965SAjay Singh }
17105625f965SAjay Singh 
17115625f965SAjay Singh static const struct cfg80211_ops wilc_cfg80211_ops = {
17125625f965SAjay Singh 	.set_monitor_channel = set_channel,
17135625f965SAjay Singh 	.scan = scan,
17145625f965SAjay Singh 	.connect = connect,
17155625f965SAjay Singh 	.disconnect = disconnect,
17165625f965SAjay Singh 	.add_key = add_key,
17175625f965SAjay Singh 	.del_key = del_key,
17185625f965SAjay Singh 	.get_key = get_key,
17195625f965SAjay Singh 	.set_default_key = set_default_key,
17200e703de3SAjay Singh 	.set_default_mgmt_key = set_default_mgmt_key,
17215625f965SAjay Singh 	.add_virtual_intf = add_virtual_intf,
17225625f965SAjay Singh 	.del_virtual_intf = del_virtual_intf,
17235625f965SAjay Singh 	.change_virtual_intf = change_virtual_intf,
17245625f965SAjay Singh 
17255625f965SAjay Singh 	.start_ap = start_ap,
17265625f965SAjay Singh 	.change_beacon = change_beacon,
17275625f965SAjay Singh 	.stop_ap = stop_ap,
17285625f965SAjay Singh 	.add_station = add_station,
17295625f965SAjay Singh 	.del_station = del_station,
17305625f965SAjay Singh 	.change_station = change_station,
17315625f965SAjay Singh 	.get_station = get_station,
17325625f965SAjay Singh 	.dump_station = dump_station,
17335625f965SAjay Singh 	.change_bss = change_bss,
17345625f965SAjay Singh 	.set_wiphy_params = set_wiphy_params,
17355625f965SAjay Singh 
1736c5b331d4SAjay Singh 	.external_auth = external_auth,
17375625f965SAjay Singh 	.set_pmksa = set_pmksa,
17385625f965SAjay Singh 	.del_pmksa = del_pmksa,
17395625f965SAjay Singh 	.flush_pmksa = flush_pmksa,
17405625f965SAjay Singh 	.remain_on_channel = remain_on_channel,
17415625f965SAjay Singh 	.cancel_remain_on_channel = cancel_remain_on_channel,
17425625f965SAjay Singh 	.mgmt_tx_cancel_wait = mgmt_tx_cancel_wait,
17435625f965SAjay Singh 	.mgmt_tx = mgmt_tx,
17445625f965SAjay Singh 	.update_mgmt_frame_registrations = wilc_update_mgmt_frame_registrations,
17455625f965SAjay Singh 	.set_power_mgmt = set_power_mgmt,
17465625f965SAjay Singh 	.set_cqm_rssi_config = set_cqm_rssi_config,
17475625f965SAjay Singh 
17485625f965SAjay Singh 	.suspend = wilc_suspend,
17495625f965SAjay Singh 	.resume = wilc_resume,
17505625f965SAjay Singh 	.set_wakeup = wilc_set_wakeup,
17515625f965SAjay Singh 	.set_tx_power = set_tx_power,
17525625f965SAjay Singh 	.get_tx_power = get_tx_power,
17535625f965SAjay Singh 
17545625f965SAjay Singh };
17555625f965SAjay Singh 
wlan_init_locks(struct wilc * wl)17565625f965SAjay Singh static void wlan_init_locks(struct wilc *wl)
17575625f965SAjay Singh {
17585625f965SAjay Singh 	mutex_init(&wl->hif_cs);
17595625f965SAjay Singh 	mutex_init(&wl->rxq_cs);
17605625f965SAjay Singh 	mutex_init(&wl->cfg_cmd_lock);
17615625f965SAjay Singh 	mutex_init(&wl->vif_mutex);
1762c8e2036eSAjay Singh 	mutex_init(&wl->deinit_lock);
17635625f965SAjay Singh 
17645625f965SAjay Singh 	spin_lock_init(&wl->txq_spinlock);
17655625f965SAjay Singh 	mutex_init(&wl->txq_add_to_head_cs);
17665625f965SAjay Singh 
17675625f965SAjay Singh 	init_completion(&wl->txq_event);
17685625f965SAjay Singh 	init_completion(&wl->cfg_event);
17695625f965SAjay Singh 	init_completion(&wl->sync_event);
17705625f965SAjay Singh 	init_completion(&wl->txq_thread_started);
17715625f965SAjay Singh 	init_srcu_struct(&wl->srcu);
17725625f965SAjay Singh }
17735625f965SAjay Singh 
wlan_deinit_locks(struct wilc * wilc)17745625f965SAjay Singh void wlan_deinit_locks(struct wilc *wilc)
17755625f965SAjay Singh {
17765625f965SAjay Singh 	mutex_destroy(&wilc->hif_cs);
17775625f965SAjay Singh 	mutex_destroy(&wilc->rxq_cs);
17785625f965SAjay Singh 	mutex_destroy(&wilc->cfg_cmd_lock);
17795625f965SAjay Singh 	mutex_destroy(&wilc->txq_add_to_head_cs);
17805625f965SAjay Singh 	mutex_destroy(&wilc->vif_mutex);
1781c8e2036eSAjay Singh 	mutex_destroy(&wilc->deinit_lock);
17825625f965SAjay Singh 	cleanup_srcu_struct(&wilc->srcu);
17835625f965SAjay Singh }
17845625f965SAjay Singh 
wilc_cfg80211_init(struct wilc ** wilc,struct device * dev,int io_type,const struct wilc_hif_func * ops)17855625f965SAjay Singh int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
17865625f965SAjay Singh 		       const struct wilc_hif_func *ops)
17875625f965SAjay Singh {
17885625f965SAjay Singh 	struct wilc *wl;
17895625f965SAjay Singh 	struct wilc_vif *vif;
1790339754ffSAjay Singh 	int ret, i;
17915625f965SAjay Singh 
17925625f965SAjay Singh 	wl = wilc_create_wiphy(dev);
17935625f965SAjay Singh 	if (!wl)
17945625f965SAjay Singh 		return -EINVAL;
17955625f965SAjay Singh 
17965625f965SAjay Singh 	wlan_init_locks(wl);
17975625f965SAjay Singh 
17985625f965SAjay Singh 	ret = wilc_wlan_cfg_init(wl);
17995625f965SAjay Singh 	if (ret)
18005625f965SAjay Singh 		goto free_wl;
18015625f965SAjay Singh 
18025625f965SAjay Singh 	*wilc = wl;
18035625f965SAjay Singh 	wl->io_type = io_type;
18045625f965SAjay Singh 	wl->hif_func = ops;
1805339754ffSAjay Singh 
1806339754ffSAjay Singh 	for (i = 0; i < NQUEUES; i++)
1807339754ffSAjay Singh 		INIT_LIST_HEAD(&wl->txq[i].txq_head.list);
1808339754ffSAjay Singh 
18095625f965SAjay Singh 	INIT_LIST_HEAD(&wl->rxq_head.list);
18105625f965SAjay Singh 	INIT_LIST_HEAD(&wl->vif_list);
18115625f965SAjay Singh 
1812*4041c60aSAjay Singh 	wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM,
1813*4041c60aSAjay Singh 						    wiphy_name(wl->wiphy));
1814*4041c60aSAjay Singh 	if (!wl->hif_workqueue) {
1815*4041c60aSAjay Singh 		ret = -ENOMEM;
1816*4041c60aSAjay Singh 		goto free_cfg;
1817*4041c60aSAjay Singh 	}
18185625f965SAjay Singh 	vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE,
18195625f965SAjay Singh 				   NL80211_IFTYPE_STATION, false);
18205625f965SAjay Singh 	if (IS_ERR(vif)) {
18215625f965SAjay Singh 		ret = PTR_ERR(vif);
1822*4041c60aSAjay Singh 		goto free_hq;
18235625f965SAjay Singh 	}
18245625f965SAjay Singh 
18255625f965SAjay Singh 	return 0;
18265625f965SAjay Singh 
1827*4041c60aSAjay Singh free_hq:
1828*4041c60aSAjay Singh 	destroy_workqueue(wl->hif_workqueue);
1829*4041c60aSAjay Singh 
18305625f965SAjay Singh free_cfg:
18315625f965SAjay Singh 	wilc_wlan_cfg_deinit(wl);
18325625f965SAjay Singh 
18335625f965SAjay Singh free_wl:
18345625f965SAjay Singh 	wlan_deinit_locks(wl);
18355625f965SAjay Singh 	wiphy_unregister(wl->wiphy);
18365625f965SAjay Singh 	wiphy_free(wl->wiphy);
18375625f965SAjay Singh 	return ret;
18385625f965SAjay Singh }
18395625f965SAjay Singh EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
18405625f965SAjay Singh 
wilc_create_wiphy(struct device * dev)18415625f965SAjay Singh struct wilc *wilc_create_wiphy(struct device *dev)
18425625f965SAjay Singh {
18435625f965SAjay Singh 	struct wiphy *wiphy;
18445625f965SAjay Singh 	struct wilc *wl;
18455625f965SAjay Singh 	int ret;
18465625f965SAjay Singh 
18475625f965SAjay Singh 	wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
18485625f965SAjay Singh 	if (!wiphy)
18495625f965SAjay Singh 		return NULL;
18505625f965SAjay Singh 
18515625f965SAjay Singh 	wl = wiphy_priv(wiphy);
18525625f965SAjay Singh 
18535625f965SAjay Singh 	memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates));
18545625f965SAjay Singh 	memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels));
18555625f965SAjay Singh 	wl->band.bitrates = wl->bitrates;
18565625f965SAjay Singh 	wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates);
18575625f965SAjay Singh 	wl->band.channels = wl->channels;
18585625f965SAjay Singh 	wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels);
18595625f965SAjay Singh 
18605625f965SAjay Singh 	wl->band.ht_cap.ht_supported = 1;
18615625f965SAjay Singh 	wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
18625625f965SAjay Singh 	wl->band.ht_cap.mcs.rx_mask[0] = 0xff;
18635625f965SAjay Singh 	wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K;
18645625f965SAjay Singh 	wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
18655625f965SAjay Singh 
18665625f965SAjay Singh 	wiphy->bands[NL80211_BAND_2GHZ] = &wl->band;
18675625f965SAjay Singh 
18685625f965SAjay Singh 	wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID;
18695625f965SAjay Singh #ifdef CONFIG_PM
18705625f965SAjay Singh 	wiphy->wowlan = &wowlan_support;
18715625f965SAjay Singh #endif
18725625f965SAjay Singh 	wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS;
18735625f965SAjay Singh 	wiphy->max_scan_ie_len = 1000;
18745625f965SAjay Singh 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
18755625f965SAjay Singh 	memcpy(wl->cipher_suites, wilc_cipher_suites,
18765625f965SAjay Singh 	       sizeof(wilc_cipher_suites));
18775625f965SAjay Singh 	wiphy->cipher_suites = wl->cipher_suites;
18785625f965SAjay Singh 	wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites);
18795625f965SAjay Singh 	wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types;
18805625f965SAjay Singh 
18815625f965SAjay Singh 	wiphy->max_remain_on_channel_duration = 500;
18825625f965SAjay Singh 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
18835625f965SAjay Singh 				BIT(NL80211_IFTYPE_AP) |
18845625f965SAjay Singh 				BIT(NL80211_IFTYPE_MONITOR) |
18855625f965SAjay Singh 				BIT(NL80211_IFTYPE_P2P_GO) |
18865625f965SAjay Singh 				BIT(NL80211_IFTYPE_P2P_CLIENT);
18875625f965SAjay Singh 	wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
1888c5b331d4SAjay Singh 	wiphy->features |= NL80211_FEATURE_SAE;
18895625f965SAjay Singh 	set_wiphy_dev(wiphy, dev);
18905625f965SAjay Singh 	wl->wiphy = wiphy;
18915625f965SAjay Singh 	ret = wiphy_register(wiphy);
18925625f965SAjay Singh 	if (ret) {
18935625f965SAjay Singh 		wiphy_free(wiphy);
18945625f965SAjay Singh 		return NULL;
18955625f965SAjay Singh 	}
18965625f965SAjay Singh 	return wl;
18975625f965SAjay Singh }
18985625f965SAjay Singh 
wilc_init_host_int(struct net_device * net)18995625f965SAjay Singh int wilc_init_host_int(struct net_device *net)
19005625f965SAjay Singh {
19015625f965SAjay Singh 	int ret;
19025625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(net);
19035625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
19045625f965SAjay Singh 
19055625f965SAjay Singh 	priv->p2p_listen_state = false;
19065625f965SAjay Singh 
19075625f965SAjay Singh 	mutex_init(&priv->scan_req_lock);
19085625f965SAjay Singh 	ret = wilc_init(net, &priv->hif_drv);
19095625f965SAjay Singh 	if (ret)
19105625f965SAjay Singh 		netdev_err(net, "Error while initializing hostinterface\n");
19115625f965SAjay Singh 
19125625f965SAjay Singh 	return ret;
19135625f965SAjay Singh }
19145625f965SAjay Singh 
wilc_deinit_host_int(struct net_device * net)19155625f965SAjay Singh void wilc_deinit_host_int(struct net_device *net)
19165625f965SAjay Singh {
19175625f965SAjay Singh 	int ret;
19185625f965SAjay Singh 	struct wilc_vif *vif = netdev_priv(net);
19195625f965SAjay Singh 	struct wilc_priv *priv = &vif->priv;
19205625f965SAjay Singh 
19215625f965SAjay Singh 	priv->p2p_listen_state = false;
19225625f965SAjay Singh 
19235625f965SAjay Singh 	flush_workqueue(vif->wilc->hif_workqueue);
19245625f965SAjay Singh 	mutex_destroy(&priv->scan_req_lock);
19255625f965SAjay Singh 	ret = wilc_deinit(vif);
19265625f965SAjay Singh 
19275625f965SAjay Singh 	if (ret)
19285625f965SAjay Singh 		netdev_err(net, "Error while deinitializing host interface\n");
19295625f965SAjay Singh }
19305625f965SAjay Singh 
1931