162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: CFG80211 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "cfg80211.h" 962306a36Sopenharmony_ci#include "main.h" 1062306a36Sopenharmony_ci#include "11n.h" 1162306a36Sopenharmony_ci#include "wmm.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic char *reg_alpha2; 1462306a36Sopenharmony_cimodule_param(reg_alpha2, charp, 0); 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { 1762306a36Sopenharmony_ci { 1862306a36Sopenharmony_ci .max = MWIFIEX_MAX_BSS_NUM, 1962306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION) | 2062306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | 2162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 2262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP), 2362306a36Sopenharmony_ci }, 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const struct ieee80211_iface_combination 2762306a36Sopenharmony_cimwifiex_iface_comb_ap_sta = { 2862306a36Sopenharmony_ci .limits = mwifiex_ap_sta_limits, 2962306a36Sopenharmony_ci .num_different_channels = 1, 3062306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), 3162306a36Sopenharmony_ci .max_interfaces = MWIFIEX_MAX_BSS_NUM, 3262306a36Sopenharmony_ci .beacon_int_infra_match = true, 3362306a36Sopenharmony_ci .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 3462306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 3562306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40), 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic const struct ieee80211_iface_combination 3962306a36Sopenharmony_cimwifiex_iface_comb_ap_sta_vht = { 4062306a36Sopenharmony_ci .limits = mwifiex_ap_sta_limits, 4162306a36Sopenharmony_ci .num_different_channels = 1, 4262306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), 4362306a36Sopenharmony_ci .max_interfaces = MWIFIEX_MAX_BSS_NUM, 4462306a36Sopenharmony_ci .beacon_int_infra_match = true, 4562306a36Sopenharmony_ci .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 4662306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 4762306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40) | 4862306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80), 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic const struct 5262306a36Sopenharmony_ciieee80211_iface_combination mwifiex_iface_comb_ap_sta_drcs = { 5362306a36Sopenharmony_ci .limits = mwifiex_ap_sta_limits, 5462306a36Sopenharmony_ci .num_different_channels = 2, 5562306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), 5662306a36Sopenharmony_ci .max_interfaces = MWIFIEX_MAX_BSS_NUM, 5762306a36Sopenharmony_ci .beacon_int_infra_match = true, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * This function maps the nl802.11 channel type into driver channel type. 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * The mapping is as follows - 6462306a36Sopenharmony_ci * NL80211_CHAN_NO_HT -> IEEE80211_HT_PARAM_CHA_SEC_NONE 6562306a36Sopenharmony_ci * NL80211_CHAN_HT20 -> IEEE80211_HT_PARAM_CHA_SEC_NONE 6662306a36Sopenharmony_ci * NL80211_CHAN_HT40PLUS -> IEEE80211_HT_PARAM_CHA_SEC_ABOVE 6762306a36Sopenharmony_ci * NL80211_CHAN_HT40MINUS -> IEEE80211_HT_PARAM_CHA_SEC_BELOW 6862306a36Sopenharmony_ci * Others -> IEEE80211_HT_PARAM_CHA_SEC_NONE 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ciu8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci switch (chan_type) { 7362306a36Sopenharmony_ci case NL80211_CHAN_NO_HT: 7462306a36Sopenharmony_ci case NL80211_CHAN_HT20: 7562306a36Sopenharmony_ci return IEEE80211_HT_PARAM_CHA_SEC_NONE; 7662306a36Sopenharmony_ci case NL80211_CHAN_HT40PLUS: 7762306a36Sopenharmony_ci return IEEE80211_HT_PARAM_CHA_SEC_ABOVE; 7862306a36Sopenharmony_ci case NL80211_CHAN_HT40MINUS: 7962306a36Sopenharmony_ci return IEEE80211_HT_PARAM_CHA_SEC_BELOW; 8062306a36Sopenharmony_ci default: 8162306a36Sopenharmony_ci return IEEE80211_HT_PARAM_CHA_SEC_NONE; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* This function maps IEEE HT secondary channel type to NL80211 channel type 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ciu8 mwifiex_get_chan_type(struct mwifiex_private *priv) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct mwifiex_channel_band channel_band; 9062306a36Sopenharmony_ci int ret; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ret = mwifiex_get_chan_info(priv, &channel_band); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (!ret) { 9562306a36Sopenharmony_ci switch (channel_band.band_config.chan_width) { 9662306a36Sopenharmony_ci case CHAN_BW_20MHZ: 9762306a36Sopenharmony_ci if (IS_11N_ENABLED(priv)) 9862306a36Sopenharmony_ci return NL80211_CHAN_HT20; 9962306a36Sopenharmony_ci else 10062306a36Sopenharmony_ci return NL80211_CHAN_NO_HT; 10162306a36Sopenharmony_ci case CHAN_BW_40MHZ: 10262306a36Sopenharmony_ci if (channel_band.band_config.chan2_offset == 10362306a36Sopenharmony_ci SEC_CHAN_ABOVE) 10462306a36Sopenharmony_ci return NL80211_CHAN_HT40PLUS; 10562306a36Sopenharmony_ci else 10662306a36Sopenharmony_ci return NL80211_CHAN_HT40MINUS; 10762306a36Sopenharmony_ci default: 10862306a36Sopenharmony_ci return NL80211_CHAN_HT20; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return NL80211_CHAN_HT20; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * This function checks whether WEP is set. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_cistatic int 11962306a36Sopenharmony_cimwifiex_is_alg_wep(u32 cipher) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci switch (cipher) { 12262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 12362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 12462306a36Sopenharmony_ci return 1; 12562306a36Sopenharmony_ci default: 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * This function retrieves the private structure from kernel wiphy structure. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistatic void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return (void *) (*(unsigned long *) wiphy_priv(wiphy)); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * CFG802.11 operation handler to delete a network key. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_cistatic int 14462306a36Sopenharmony_cimwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, 14562306a36Sopenharmony_ci int link_id, u8 key_index, bool pairwise, 14662306a36Sopenharmony_ci const u8 *mac_addr) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); 14962306a36Sopenharmony_ci static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 15062306a36Sopenharmony_ci const u8 *peer_mac = pairwise ? mac_addr : bc_mac; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) { 15362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "deleting the crypto keys\n"); 15462306a36Sopenharmony_ci return -EFAULT; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: crypto keys deleted\n"); 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * This function forms an skb for management frame. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic int 16562306a36Sopenharmony_cimwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci u8 addr[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 16862306a36Sopenharmony_ci u16 pkt_len; 16962306a36Sopenharmony_ci u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci pkt_len = len + ETH_ALEN; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN + 17462306a36Sopenharmony_ci MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); 17562306a36Sopenharmony_ci memcpy(skb_push(skb, sizeof(pkt_len)), &pkt_len, sizeof(pkt_len)); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci memcpy(skb_push(skb, sizeof(tx_control)), 17862306a36Sopenharmony_ci &tx_control, sizeof(tx_control)); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type)); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Add packet data and address4 */ 18362306a36Sopenharmony_ci skb_put_data(skb, buf, sizeof(struct ieee80211_hdr_3addr)); 18462306a36Sopenharmony_ci skb_put_data(skb, addr, ETH_ALEN); 18562306a36Sopenharmony_ci skb_put_data(skb, buf + sizeof(struct ieee80211_hdr_3addr), 18662306a36Sopenharmony_ci len - sizeof(struct ieee80211_hdr_3addr)); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci skb->priority = LOW_PRIO_TID; 18962306a36Sopenharmony_ci __net_timestamp(skb); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* 19562306a36Sopenharmony_ci * CFG802.11 operation handler to transmit a management frame. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_cistatic int 19862306a36Sopenharmony_cimwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, 19962306a36Sopenharmony_ci struct cfg80211_mgmt_tx_params *params, u64 *cookie) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci const u8 *buf = params->buf; 20262306a36Sopenharmony_ci size_t len = params->len; 20362306a36Sopenharmony_ci struct sk_buff *skb; 20462306a36Sopenharmony_ci u16 pkt_len; 20562306a36Sopenharmony_ci const struct ieee80211_mgmt *mgmt; 20662306a36Sopenharmony_ci struct mwifiex_txinfo *tx_info; 20762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!buf || !len) { 21062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "invalid buffer and length\n"); 21162306a36Sopenharmony_ci return -EFAULT; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci mgmt = (const struct ieee80211_mgmt *)buf; 21562306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA && 21662306a36Sopenharmony_ci ieee80211_is_probe_resp(mgmt->frame_control)) { 21762306a36Sopenharmony_ci /* Since we support offload probe resp, we need to skip probe 21862306a36Sopenharmony_ci * resp in AP or GO mode */ 21962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 22062306a36Sopenharmony_ci "info: skip to send probe resp in AP or GO mode\n"); 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci pkt_len = len + ETH_ALEN; 22562306a36Sopenharmony_ci skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN + 22662306a36Sopenharmony_ci MWIFIEX_MGMT_FRAME_HEADER_SIZE + 22762306a36Sopenharmony_ci pkt_len + sizeof(pkt_len)); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (!skb) { 23062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 23162306a36Sopenharmony_ci "allocate skb failed for management frame\n"); 23262306a36Sopenharmony_ci return -ENOMEM; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci tx_info = MWIFIEX_SKB_TXCB(skb); 23662306a36Sopenharmony_ci memset(tx_info, 0, sizeof(*tx_info)); 23762306a36Sopenharmony_ci tx_info->bss_num = priv->bss_num; 23862306a36Sopenharmony_ci tx_info->bss_type = priv->bss_type; 23962306a36Sopenharmony_ci tx_info->pkt_len = pkt_len; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci mwifiex_form_mgmt_frame(skb, buf, len); 24262306a36Sopenharmony_ci *cookie = get_random_u32() | 1; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (ieee80211_is_action(mgmt->frame_control)) 24562306a36Sopenharmony_ci skb = mwifiex_clone_skb_for_tx_status(priv, 24662306a36Sopenharmony_ci skb, 24762306a36Sopenharmony_ci MWIFIEX_BUF_FLAG_ACTION_TX_STATUS, cookie); 24862306a36Sopenharmony_ci else 24962306a36Sopenharmony_ci cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, 25062306a36Sopenharmony_ci GFP_ATOMIC); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci mwifiex_queue_tx_pkt(priv, skb); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: management frame transmitted\n"); 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* 25962306a36Sopenharmony_ci * CFG802.11 operation handler to register a mgmt frame. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_cistatic void 26262306a36Sopenharmony_cimwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy, 26362306a36Sopenharmony_ci struct wireless_dev *wdev, 26462306a36Sopenharmony_ci struct mgmt_frame_regs *upd) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); 26762306a36Sopenharmony_ci u32 mask = upd->interface_stypes; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (mask != priv->mgmt_frame_mask) { 27062306a36Sopenharmony_ci priv->mgmt_frame_mask = mask; 27162306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, 27262306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 27362306a36Sopenharmony_ci &priv->mgmt_frame_mask, false); 27462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: mgmt frame registered\n"); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * CFG802.11 operation handler to remain on channel. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic int 28262306a36Sopenharmony_cimwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy, 28362306a36Sopenharmony_ci struct wireless_dev *wdev, 28462306a36Sopenharmony_ci struct ieee80211_channel *chan, 28562306a36Sopenharmony_ci unsigned int duration, u64 *cookie) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); 28862306a36Sopenharmony_ci int ret; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!chan || !cookie) { 29162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "Invalid parameter for ROC\n"); 29262306a36Sopenharmony_ci return -EINVAL; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (priv->roc_cfg.cookie) { 29662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 29762306a36Sopenharmony_ci "info: ongoing ROC, cookie = 0x%llx\n", 29862306a36Sopenharmony_ci priv->roc_cfg.cookie); 29962306a36Sopenharmony_ci return -EBUSY; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, chan, 30362306a36Sopenharmony_ci duration); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!ret) { 30662306a36Sopenharmony_ci *cookie = get_random_u32() | 1; 30762306a36Sopenharmony_ci priv->roc_cfg.cookie = *cookie; 30862306a36Sopenharmony_ci priv->roc_cfg.chan = *chan; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci cfg80211_ready_on_channel(wdev, *cookie, chan, 31162306a36Sopenharmony_ci duration, GFP_ATOMIC); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 31462306a36Sopenharmony_ci "info: ROC, cookie = 0x%llx\n", *cookie); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return ret; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* 32162306a36Sopenharmony_ci * CFG802.11 operation handler to cancel remain on channel. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_cistatic int 32462306a36Sopenharmony_cimwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, 32562306a36Sopenharmony_ci struct wireless_dev *wdev, u64 cookie) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); 32862306a36Sopenharmony_ci int ret; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (cookie != priv->roc_cfg.cookie) 33162306a36Sopenharmony_ci return -ENOENT; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_REMOVE, 33462306a36Sopenharmony_ci &priv->roc_cfg.chan, 0); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (!ret) { 33762306a36Sopenharmony_ci cfg80211_remain_on_channel_expired(wdev, cookie, 33862306a36Sopenharmony_ci &priv->roc_cfg.chan, 33962306a36Sopenharmony_ci GFP_ATOMIC); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg)); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 34462306a36Sopenharmony_ci "info: cancel ROC, cookie = 0x%llx\n", cookie); 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * CFG802.11 operation handler to set Tx power. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_cistatic int 35462306a36Sopenharmony_cimwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, 35562306a36Sopenharmony_ci struct wireless_dev *wdev, 35662306a36Sopenharmony_ci enum nl80211_tx_power_setting type, 35762306a36Sopenharmony_ci int mbm) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 36062306a36Sopenharmony_ci struct mwifiex_private *priv; 36162306a36Sopenharmony_ci struct mwifiex_power_cfg power_cfg; 36262306a36Sopenharmony_ci int dbm = MBM_TO_DBM(mbm); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci switch (type) { 36562306a36Sopenharmony_ci case NL80211_TX_POWER_FIXED: 36662306a36Sopenharmony_ci power_cfg.is_power_auto = 0; 36762306a36Sopenharmony_ci power_cfg.is_power_fixed = 1; 36862306a36Sopenharmony_ci power_cfg.power_level = dbm; 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci case NL80211_TX_POWER_LIMITED: 37162306a36Sopenharmony_ci power_cfg.is_power_auto = 0; 37262306a36Sopenharmony_ci power_cfg.is_power_fixed = 0; 37362306a36Sopenharmony_ci power_cfg.power_level = dbm; 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci case NL80211_TX_POWER_AUTOMATIC: 37662306a36Sopenharmony_ci power_cfg.is_power_auto = 1; 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return mwifiex_set_tx_power(priv, &power_cfg); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/* 38662306a36Sopenharmony_ci * CFG802.11 operation handler to get Tx power. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_cistatic int 38962306a36Sopenharmony_cimwifiex_cfg80211_get_tx_power(struct wiphy *wiphy, 39062306a36Sopenharmony_ci struct wireless_dev *wdev, 39162306a36Sopenharmony_ci int *dbm) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 39462306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_get_priv(adapter, 39562306a36Sopenharmony_ci MWIFIEX_BSS_ROLE_ANY); 39662306a36Sopenharmony_ci int ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR, 39762306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, 0, NULL, true); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (ret < 0) 40062306a36Sopenharmony_ci return ret; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* tx_power_level is set in HostCmd_CMD_RF_TX_PWR command handler */ 40362306a36Sopenharmony_ci *dbm = priv->tx_power_level; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* 40962306a36Sopenharmony_ci * CFG802.11 operation handler to set Power Save option. 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * The timeout value, if provided, is currently ignored. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_cistatic int 41462306a36Sopenharmony_cimwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, 41562306a36Sopenharmony_ci struct net_device *dev, 41662306a36Sopenharmony_ci bool enabled, int timeout) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 41962306a36Sopenharmony_ci u32 ps_mode; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (timeout) 42262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 42362306a36Sopenharmony_ci "info: ignore timeout value for IEEE Power Save\n"); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ps_mode = enabled; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return mwifiex_drv_set_power(priv, &ps_mode); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci/* 43162306a36Sopenharmony_ci * CFG802.11 operation handler to set the default network key. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_cistatic int 43462306a36Sopenharmony_cimwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, 43562306a36Sopenharmony_ci int link_id, u8 key_index, bool unicast, 43662306a36Sopenharmony_ci bool multicast) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* Return if WEP key not configured */ 44162306a36Sopenharmony_ci if (!priv->sec_info.wep_enabled) 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) { 44562306a36Sopenharmony_ci priv->wep_key_curr_index = key_index; 44662306a36Sopenharmony_ci } else if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, 44762306a36Sopenharmony_ci NULL, 0)) { 44862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "set default Tx key index\n"); 44962306a36Sopenharmony_ci return -EFAULT; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci/* 45662306a36Sopenharmony_ci * CFG802.11 operation handler to add a network key. 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_cistatic int 45962306a36Sopenharmony_cimwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, 46062306a36Sopenharmony_ci int link_id, u8 key_index, bool pairwise, 46162306a36Sopenharmony_ci const u8 *mac_addr, struct key_params *params) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); 46462306a36Sopenharmony_ci struct mwifiex_wep_key *wep_key; 46562306a36Sopenharmony_ci static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 46662306a36Sopenharmony_ci const u8 *peer_mac = pairwise ? mac_addr : bc_mac; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP && 46962306a36Sopenharmony_ci (params->cipher == WLAN_CIPHER_SUITE_WEP40 || 47062306a36Sopenharmony_ci params->cipher == WLAN_CIPHER_SUITE_WEP104)) { 47162306a36Sopenharmony_ci if (params->key && params->key_len) { 47262306a36Sopenharmony_ci wep_key = &priv->wep_key[key_index]; 47362306a36Sopenharmony_ci memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); 47462306a36Sopenharmony_ci memcpy(wep_key->key_material, params->key, 47562306a36Sopenharmony_ci params->key_len); 47662306a36Sopenharmony_ci wep_key->key_index = key_index; 47762306a36Sopenharmony_ci wep_key->key_length = params->key_len; 47862306a36Sopenharmony_ci priv->sec_info.wep_enabled = 1; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (mwifiex_set_encode(priv, params, params->key, params->key_len, 48462306a36Sopenharmony_ci key_index, peer_mac, 0)) { 48562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "crypto keys added\n"); 48662306a36Sopenharmony_ci return -EFAULT; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return 0; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/* 49362306a36Sopenharmony_ci * CFG802.11 operation handler to set default mgmt key. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_cistatic int 49662306a36Sopenharmony_cimwifiex_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, 49762306a36Sopenharmony_ci struct net_device *netdev, 49862306a36Sopenharmony_ci int link_id, 49962306a36Sopenharmony_ci u8 key_index) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); 50262306a36Sopenharmony_ci struct mwifiex_ds_encrypt_key encrypt_key; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci wiphy_dbg(wiphy, "set default mgmt key, key index=%d\n", key_index); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); 50762306a36Sopenharmony_ci encrypt_key.key_len = WLAN_KEY_LEN_CCMP; 50862306a36Sopenharmony_ci encrypt_key.key_index = key_index; 50962306a36Sopenharmony_ci encrypt_key.is_igtk_def_key = true; 51062306a36Sopenharmony_ci eth_broadcast_addr(encrypt_key.mac_addr); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, 51362306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, true, &encrypt_key, true)) { 51462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 51562306a36Sopenharmony_ci "Sending KEY_MATERIAL command failed\n"); 51662306a36Sopenharmony_ci return -1; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/* 52362306a36Sopenharmony_ci * This function sends domain information to the firmware. 52462306a36Sopenharmony_ci * 52562306a36Sopenharmony_ci * The following information are passed to the firmware - 52662306a36Sopenharmony_ci * - Country codes 52762306a36Sopenharmony_ci * - Sub bands (first channel, number of channels, maximum Tx power) 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_ciint mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci u8 no_of_triplet = 0; 53262306a36Sopenharmony_ci struct ieee80211_country_ie_triplet *t; 53362306a36Sopenharmony_ci u8 no_of_parsed_chan = 0; 53462306a36Sopenharmony_ci u8 first_chan = 0, next_chan = 0, max_pwr = 0; 53562306a36Sopenharmony_ci u8 i, flag = 0; 53662306a36Sopenharmony_ci enum nl80211_band band; 53762306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 53862306a36Sopenharmony_ci struct ieee80211_channel *ch; 53962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 54062306a36Sopenharmony_ci struct mwifiex_private *priv; 54162306a36Sopenharmony_ci struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* Set country code */ 54462306a36Sopenharmony_ci domain_info->country_code[0] = adapter->country_code[0]; 54562306a36Sopenharmony_ci domain_info->country_code[1] = adapter->country_code[1]; 54662306a36Sopenharmony_ci domain_info->country_code[2] = ' '; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci band = mwifiex_band_to_radio_type(adapter->config_bands); 54962306a36Sopenharmony_ci if (!wiphy->bands[band]) { 55062306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 55162306a36Sopenharmony_ci "11D: setting domain info in FW\n"); 55262306a36Sopenharmony_ci return -1; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci sband = wiphy->bands[band]; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci for (i = 0; i < sband->n_channels ; i++) { 55862306a36Sopenharmony_ci ch = &sband->channels[i]; 55962306a36Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_DISABLED) 56062306a36Sopenharmony_ci continue; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (!flag) { 56362306a36Sopenharmony_ci flag = 1; 56462306a36Sopenharmony_ci first_chan = (u32) ch->hw_value; 56562306a36Sopenharmony_ci next_chan = first_chan; 56662306a36Sopenharmony_ci max_pwr = ch->max_power; 56762306a36Sopenharmony_ci no_of_parsed_chan = 1; 56862306a36Sopenharmony_ci continue; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (ch->hw_value == next_chan + 1 && 57262306a36Sopenharmony_ci ch->max_power == max_pwr) { 57362306a36Sopenharmony_ci next_chan++; 57462306a36Sopenharmony_ci no_of_parsed_chan++; 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci t = &domain_info->triplet[no_of_triplet]; 57762306a36Sopenharmony_ci t->chans.first_channel = first_chan; 57862306a36Sopenharmony_ci t->chans.num_channels = no_of_parsed_chan; 57962306a36Sopenharmony_ci t->chans.max_power = max_pwr; 58062306a36Sopenharmony_ci no_of_triplet++; 58162306a36Sopenharmony_ci first_chan = (u32) ch->hw_value; 58262306a36Sopenharmony_ci next_chan = first_chan; 58362306a36Sopenharmony_ci max_pwr = ch->max_power; 58462306a36Sopenharmony_ci no_of_parsed_chan = 1; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (flag) { 58962306a36Sopenharmony_ci t = &domain_info->triplet[no_of_triplet]; 59062306a36Sopenharmony_ci t->chans.first_channel = first_chan; 59162306a36Sopenharmony_ci t->chans.num_channels = no_of_parsed_chan; 59262306a36Sopenharmony_ci t->chans.max_power = max_pwr; 59362306a36Sopenharmony_ci no_of_triplet++; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci domain_info->no_of_triplet = no_of_triplet; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, 60162306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, false)) { 60262306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 60362306a36Sopenharmony_ci "11D: setting domain info in FW\n"); 60462306a36Sopenharmony_ci return -1; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void mwifiex_reg_apply_radar_flags(struct wiphy *wiphy) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 61362306a36Sopenharmony_ci struct ieee80211_channel *chan; 61462306a36Sopenharmony_ci unsigned int i; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (!wiphy->bands[NL80211_BAND_5GHZ]) 61762306a36Sopenharmony_ci return; 61862306a36Sopenharmony_ci sband = wiphy->bands[NL80211_BAND_5GHZ]; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 62162306a36Sopenharmony_ci chan = &sband->channels[i]; 62262306a36Sopenharmony_ci if ((!(chan->flags & IEEE80211_CHAN_DISABLED)) && 62362306a36Sopenharmony_ci (chan->flags & IEEE80211_CHAN_RADAR)) 62462306a36Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_IR; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/* 62962306a36Sopenharmony_ci * CFG802.11 regulatory domain callback function. 63062306a36Sopenharmony_ci * 63162306a36Sopenharmony_ci * This function is called when the regulatory domain is changed due to the 63262306a36Sopenharmony_ci * following reasons - 63362306a36Sopenharmony_ci * - Set by driver 63462306a36Sopenharmony_ci * - Set by system core 63562306a36Sopenharmony_ci * - Set by user 63662306a36Sopenharmony_ci * - Set bt Country IE 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_cistatic void mwifiex_reg_notifier(struct wiphy *wiphy, 63962306a36Sopenharmony_ci struct regulatory_request *request) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 64262306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_get_priv(adapter, 64362306a36Sopenharmony_ci MWIFIEX_BSS_ROLE_ANY); 64462306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 64562306a36Sopenharmony_ci "info: cfg80211 regulatory domain callback for %c%c\n", 64662306a36Sopenharmony_ci request->alpha2[0], request->alpha2[1]); 64762306a36Sopenharmony_ci mwifiex_reg_apply_radar_flags(wiphy); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci switch (request->initiator) { 65062306a36Sopenharmony_ci case NL80211_REGDOM_SET_BY_DRIVER: 65162306a36Sopenharmony_ci case NL80211_REGDOM_SET_BY_CORE: 65262306a36Sopenharmony_ci case NL80211_REGDOM_SET_BY_USER: 65362306a36Sopenharmony_ci case NL80211_REGDOM_SET_BY_COUNTRY_IE: 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci default: 65662306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 65762306a36Sopenharmony_ci "unknown regdom initiator: %d\n", 65862306a36Sopenharmony_ci request->initiator); 65962306a36Sopenharmony_ci return; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* Don't send world or same regdom info to firmware */ 66362306a36Sopenharmony_ci if (strncmp(request->alpha2, "00", 2) && 66462306a36Sopenharmony_ci strncmp(request->alpha2, adapter->country_code, 66562306a36Sopenharmony_ci sizeof(request->alpha2))) { 66662306a36Sopenharmony_ci memcpy(adapter->country_code, request->alpha2, 66762306a36Sopenharmony_ci sizeof(request->alpha2)); 66862306a36Sopenharmony_ci mwifiex_send_domain_info_cmd_fw(wiphy); 66962306a36Sopenharmony_ci mwifiex_dnld_txpwr_table(priv); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci/* 67462306a36Sopenharmony_ci * This function sets the fragmentation threshold. 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE 67762306a36Sopenharmony_ci * and MWIFIEX_FRAG_MAX_VALUE. 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_cistatic int 68062306a36Sopenharmony_cimwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci if (frag_thr < MWIFIEX_FRAG_MIN_VALUE || 68362306a36Sopenharmony_ci frag_thr > MWIFIEX_FRAG_MAX_VALUE) 68462306a36Sopenharmony_ci frag_thr = MWIFIEX_FRAG_MAX_VALUE; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 68762306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, FRAG_THRESH_I, 68862306a36Sopenharmony_ci &frag_thr, true); 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci/* 69262306a36Sopenharmony_ci * This function sets the RTS threshold. 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci * The rts value must lie between MWIFIEX_RTS_MIN_VALUE 69562306a36Sopenharmony_ci * and MWIFIEX_RTS_MAX_VALUE. 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_cistatic int 69862306a36Sopenharmony_cimwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) 70162306a36Sopenharmony_ci rts_thr = MWIFIEX_RTS_MAX_VALUE; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 70462306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, RTS_THRESH_I, 70562306a36Sopenharmony_ci &rts_thr, true); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci/* 70962306a36Sopenharmony_ci * CFG802.11 operation handler to set wiphy parameters. 71062306a36Sopenharmony_ci * 71162306a36Sopenharmony_ci * This function can be used to set the RTS threshold and the 71262306a36Sopenharmony_ci * Fragmentation threshold of the driver. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_cistatic int 71562306a36Sopenharmony_cimwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 71862306a36Sopenharmony_ci struct mwifiex_private *priv; 71962306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg; 72062306a36Sopenharmony_ci int ret; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci switch (priv->bss_role) { 72562306a36Sopenharmony_ci case MWIFIEX_BSS_ROLE_UAP: 72662306a36Sopenharmony_ci if (priv->bss_started) { 72762306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 72862306a36Sopenharmony_ci "cannot change wiphy params when bss started"); 72962306a36Sopenharmony_ci return -EINVAL; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL); 73362306a36Sopenharmony_ci if (!bss_cfg) 73462306a36Sopenharmony_ci return -ENOMEM; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci mwifiex_set_sys_config_invalid_data(bss_cfg); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (changed & WIPHY_PARAM_RTS_THRESHOLD) 73962306a36Sopenharmony_ci bss_cfg->rts_threshold = wiphy->rts_threshold; 74062306a36Sopenharmony_ci if (changed & WIPHY_PARAM_FRAG_THRESHOLD) 74162306a36Sopenharmony_ci bss_cfg->frag_threshold = wiphy->frag_threshold; 74262306a36Sopenharmony_ci if (changed & WIPHY_PARAM_RETRY_LONG) 74362306a36Sopenharmony_ci bss_cfg->retry_limit = wiphy->retry_long; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, 74662306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 74762306a36Sopenharmony_ci UAP_BSS_PARAMS_I, bss_cfg, 74862306a36Sopenharmony_ci false); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci kfree(bss_cfg); 75162306a36Sopenharmony_ci if (ret) { 75262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 75362306a36Sopenharmony_ci "Failed to set wiphy phy params\n"); 75462306a36Sopenharmony_ci return ret; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci case MWIFIEX_BSS_ROLE_STA: 75962306a36Sopenharmony_ci if (priv->media_connected) { 76062306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 76162306a36Sopenharmony_ci "cannot change wiphy params when connected"); 76262306a36Sopenharmony_ci return -EINVAL; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci if (changed & WIPHY_PARAM_RTS_THRESHOLD) { 76562306a36Sopenharmony_ci ret = mwifiex_set_rts(priv, 76662306a36Sopenharmony_ci wiphy->rts_threshold); 76762306a36Sopenharmony_ci if (ret) 76862306a36Sopenharmony_ci return ret; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { 77162306a36Sopenharmony_ci ret = mwifiex_set_frag(priv, 77262306a36Sopenharmony_ci wiphy->frag_threshold); 77362306a36Sopenharmony_ci if (ret) 77462306a36Sopenharmony_ci return ret; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic int 78362306a36Sopenharmony_cimwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci u16 mode = P2P_MODE_DISABLE; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, 78862306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &mode, true)) 78962306a36Sopenharmony_ci return -1; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci/* 79562306a36Sopenharmony_ci * This function initializes the functionalities for P2P client. 79662306a36Sopenharmony_ci * The P2P client initialization sequence is: 79762306a36Sopenharmony_ci * disable -> device -> client 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_cistatic int 80062306a36Sopenharmony_cimwifiex_cfg80211_init_p2p_client(struct mwifiex_private *priv) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci u16 mode; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (mwifiex_cfg80211_deinit_p2p(priv)) 80562306a36Sopenharmony_ci return -1; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci mode = P2P_MODE_DEVICE; 80862306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, 80962306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &mode, true)) 81062306a36Sopenharmony_ci return -1; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci mode = P2P_MODE_CLIENT; 81362306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, 81462306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &mode, true)) 81562306a36Sopenharmony_ci return -1; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return 0; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/* 82162306a36Sopenharmony_ci * This function initializes the functionalities for P2P GO. 82262306a36Sopenharmony_ci * The P2P GO initialization sequence is: 82362306a36Sopenharmony_ci * disable -> device -> GO 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_cistatic int 82662306a36Sopenharmony_cimwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci u16 mode; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (mwifiex_cfg80211_deinit_p2p(priv)) 83162306a36Sopenharmony_ci return -1; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci mode = P2P_MODE_DEVICE; 83462306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, 83562306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &mode, true)) 83662306a36Sopenharmony_ci return -1; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci mode = P2P_MODE_GO; 83962306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, 84062306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &mode, true)) 84162306a36Sopenharmony_ci return -1; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int mwifiex_deinit_priv_params(struct mwifiex_private *priv) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 84962306a36Sopenharmony_ci unsigned long flags; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci priv->mgmt_frame_mask = 0; 85262306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, 85362306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 85462306a36Sopenharmony_ci &priv->mgmt_frame_mask, false)) { 85562306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 85662306a36Sopenharmony_ci "could not unregister mgmt frame rx\n"); 85762306a36Sopenharmony_ci return -1; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci mwifiex_deauthenticate(priv, NULL); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci spin_lock_irqsave(&adapter->main_proc_lock, flags); 86362306a36Sopenharmony_ci adapter->main_locked = true; 86462306a36Sopenharmony_ci if (adapter->mwifiex_processing) { 86562306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 86662306a36Sopenharmony_ci flush_workqueue(adapter->workqueue); 86762306a36Sopenharmony_ci } else { 86862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci spin_lock_bh(&adapter->rx_proc_lock); 87262306a36Sopenharmony_ci adapter->rx_locked = true; 87362306a36Sopenharmony_ci if (adapter->rx_processing) { 87462306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 87562306a36Sopenharmony_ci flush_workqueue(adapter->rx_workqueue); 87662306a36Sopenharmony_ci } else { 87762306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci mwifiex_free_priv(priv); 88162306a36Sopenharmony_ci priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; 88262306a36Sopenharmony_ci priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; 88362306a36Sopenharmony_ci priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return 0; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic int 88962306a36Sopenharmony_cimwifiex_init_new_priv_params(struct mwifiex_private *priv, 89062306a36Sopenharmony_ci struct net_device *dev, 89162306a36Sopenharmony_ci enum nl80211_iftype type) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 89462306a36Sopenharmony_ci unsigned long flags; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci mwifiex_init_priv(priv); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci priv->bss_mode = type; 89962306a36Sopenharmony_ci priv->wdev.iftype = type; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci mwifiex_init_priv_params(priv, priv->netdev); 90262306a36Sopenharmony_ci priv->bss_started = 0; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci switch (type) { 90562306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 90662306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 90762306a36Sopenharmony_ci priv->bss_role = MWIFIEX_BSS_ROLE_STA; 90862306a36Sopenharmony_ci priv->bss_type = MWIFIEX_BSS_TYPE_STA; 90962306a36Sopenharmony_ci break; 91062306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 91162306a36Sopenharmony_ci priv->bss_role = MWIFIEX_BSS_ROLE_STA; 91262306a36Sopenharmony_ci priv->bss_type = MWIFIEX_BSS_TYPE_P2P; 91362306a36Sopenharmony_ci break; 91462306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 91562306a36Sopenharmony_ci priv->bss_role = MWIFIEX_BSS_ROLE_UAP; 91662306a36Sopenharmony_ci priv->bss_type = MWIFIEX_BSS_TYPE_P2P; 91762306a36Sopenharmony_ci break; 91862306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 91962306a36Sopenharmony_ci priv->bss_role = MWIFIEX_BSS_ROLE_UAP; 92062306a36Sopenharmony_ci priv->bss_type = MWIFIEX_BSS_TYPE_UAP; 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci default: 92362306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 92462306a36Sopenharmony_ci "%s: changing to %d not supported\n", 92562306a36Sopenharmony_ci dev->name, type); 92662306a36Sopenharmony_ci return -EOPNOTSUPP; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci spin_lock_irqsave(&adapter->main_proc_lock, flags); 93062306a36Sopenharmony_ci adapter->main_locked = false; 93162306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->main_proc_lock, flags); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci spin_lock_bh(&adapter->rx_proc_lock); 93462306a36Sopenharmony_ci adapter->rx_locked = false; 93562306a36Sopenharmony_ci spin_unlock_bh(&adapter->rx_proc_lock); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci mwifiex_set_mac_address(priv, dev, false, NULL); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci return 0; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic bool 94362306a36Sopenharmony_ciis_vif_type_change_allowed(struct mwifiex_adapter *adapter, 94462306a36Sopenharmony_ci enum nl80211_iftype old_iftype, 94562306a36Sopenharmony_ci enum nl80211_iftype new_iftype) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci switch (old_iftype) { 94862306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 94962306a36Sopenharmony_ci switch (new_iftype) { 95062306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 95162306a36Sopenharmony_ci return true; 95262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 95362306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 95462306a36Sopenharmony_ci return adapter->curr_iface_comb.p2p_intf != 95562306a36Sopenharmony_ci adapter->iface_limit.p2p_intf; 95662306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 95762306a36Sopenharmony_ci return adapter->curr_iface_comb.uap_intf != 95862306a36Sopenharmony_ci adapter->iface_limit.uap_intf; 95962306a36Sopenharmony_ci default: 96062306a36Sopenharmony_ci return false; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 96462306a36Sopenharmony_ci switch (new_iftype) { 96562306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 96662306a36Sopenharmony_ci return true; 96762306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 96862306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 96962306a36Sopenharmony_ci return adapter->curr_iface_comb.p2p_intf != 97062306a36Sopenharmony_ci adapter->iface_limit.p2p_intf; 97162306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 97262306a36Sopenharmony_ci return adapter->curr_iface_comb.uap_intf != 97362306a36Sopenharmony_ci adapter->iface_limit.uap_intf; 97462306a36Sopenharmony_ci default: 97562306a36Sopenharmony_ci return false; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 97962306a36Sopenharmony_ci switch (new_iftype) { 98062306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 98162306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 98262306a36Sopenharmony_ci return adapter->curr_iface_comb.sta_intf != 98362306a36Sopenharmony_ci adapter->iface_limit.sta_intf; 98462306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 98562306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 98662306a36Sopenharmony_ci return adapter->curr_iface_comb.p2p_intf != 98762306a36Sopenharmony_ci adapter->iface_limit.p2p_intf; 98862306a36Sopenharmony_ci default: 98962306a36Sopenharmony_ci return false; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 99362306a36Sopenharmony_ci switch (new_iftype) { 99462306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 99562306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 99662306a36Sopenharmony_ci return true; 99762306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 99862306a36Sopenharmony_ci return true; 99962306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 100062306a36Sopenharmony_ci return adapter->curr_iface_comb.uap_intf != 100162306a36Sopenharmony_ci adapter->iface_limit.uap_intf; 100262306a36Sopenharmony_ci default: 100362306a36Sopenharmony_ci return false; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 100762306a36Sopenharmony_ci switch (new_iftype) { 100862306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 100962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 101062306a36Sopenharmony_ci return true; 101162306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 101262306a36Sopenharmony_ci return true; 101362306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 101462306a36Sopenharmony_ci return adapter->curr_iface_comb.uap_intf != 101562306a36Sopenharmony_ci adapter->iface_limit.uap_intf; 101662306a36Sopenharmony_ci default: 101762306a36Sopenharmony_ci return false; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci default: 102162306a36Sopenharmony_ci break; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return false; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic void 102862306a36Sopenharmony_ciupdate_vif_type_counter(struct mwifiex_adapter *adapter, 102962306a36Sopenharmony_ci enum nl80211_iftype iftype, 103062306a36Sopenharmony_ci int change) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci switch (iftype) { 103362306a36Sopenharmony_ci case NL80211_IFTYPE_UNSPECIFIED: 103462306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 103562306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 103662306a36Sopenharmony_ci adapter->curr_iface_comb.sta_intf += change; 103762306a36Sopenharmony_ci break; 103862306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 103962306a36Sopenharmony_ci adapter->curr_iface_comb.uap_intf += change; 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 104262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 104362306a36Sopenharmony_ci adapter->curr_iface_comb.p2p_intf += change; 104462306a36Sopenharmony_ci break; 104562306a36Sopenharmony_ci default: 104662306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 104762306a36Sopenharmony_ci "%s: Unsupported iftype passed: %d\n", 104862306a36Sopenharmony_ci __func__, iftype); 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cistatic int 105462306a36Sopenharmony_cimwifiex_change_vif_to_p2p(struct net_device *dev, 105562306a36Sopenharmony_ci enum nl80211_iftype curr_iftype, 105662306a36Sopenharmony_ci enum nl80211_iftype type, 105762306a36Sopenharmony_ci struct vif_params *params) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct mwifiex_private *priv; 106062306a36Sopenharmony_ci struct mwifiex_adapter *adapter; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci priv = mwifiex_netdev_get_priv(dev); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (!priv) 106562306a36Sopenharmony_ci return -1; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci adapter = priv->adapter; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 107062306a36Sopenharmony_ci "%s: changing role to p2p\n", dev->name); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (mwifiex_deinit_priv_params(priv)) 107362306a36Sopenharmony_ci return -1; 107462306a36Sopenharmony_ci if (mwifiex_init_new_priv_params(priv, dev, type)) 107562306a36Sopenharmony_ci return -1; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci update_vif_type_counter(adapter, curr_iftype, -1); 107862306a36Sopenharmony_ci update_vif_type_counter(adapter, type, +1); 107962306a36Sopenharmony_ci dev->ieee80211_ptr->iftype = type; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci switch (type) { 108262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 108362306a36Sopenharmony_ci if (mwifiex_cfg80211_init_p2p_client(priv)) 108462306a36Sopenharmony_ci return -EFAULT; 108562306a36Sopenharmony_ci break; 108662306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 108762306a36Sopenharmony_ci if (mwifiex_cfg80211_init_p2p_go(priv)) 108862306a36Sopenharmony_ci return -EFAULT; 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci default: 109162306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 109262306a36Sopenharmony_ci "%s: changing to %d not supported\n", 109362306a36Sopenharmony_ci dev->name, type); 109462306a36Sopenharmony_ci return -EOPNOTSUPP; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, 109862306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true)) 109962306a36Sopenharmony_ci return -1; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (mwifiex_sta_init_cmd(priv, false, false)) 110262306a36Sopenharmony_ci return -1; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci return 0; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic int 110862306a36Sopenharmony_cimwifiex_change_vif_to_sta_adhoc(struct net_device *dev, 110962306a36Sopenharmony_ci enum nl80211_iftype curr_iftype, 111062306a36Sopenharmony_ci enum nl80211_iftype type, 111162306a36Sopenharmony_ci struct vif_params *params) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci struct mwifiex_private *priv; 111462306a36Sopenharmony_ci struct mwifiex_adapter *adapter; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci priv = mwifiex_netdev_get_priv(dev); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (!priv) 111962306a36Sopenharmony_ci return -1; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci adapter = priv->adapter; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci if (type == NL80211_IFTYPE_STATION) 112462306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 112562306a36Sopenharmony_ci "%s: changing role to station\n", dev->name); 112662306a36Sopenharmony_ci else 112762306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 112862306a36Sopenharmony_ci "%s: changing role to adhoc\n", dev->name); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (mwifiex_deinit_priv_params(priv)) 113162306a36Sopenharmony_ci return -1; 113262306a36Sopenharmony_ci if (mwifiex_init_new_priv_params(priv, dev, type)) 113362306a36Sopenharmony_ci return -1; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci update_vif_type_counter(adapter, curr_iftype, -1); 113662306a36Sopenharmony_ci update_vif_type_counter(adapter, type, +1); 113762306a36Sopenharmony_ci dev->ieee80211_ptr->iftype = type; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, 114062306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true)) 114162306a36Sopenharmony_ci return -1; 114262306a36Sopenharmony_ci if (mwifiex_sta_init_cmd(priv, false, false)) 114362306a36Sopenharmony_ci return -1; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic int 114962306a36Sopenharmony_cimwifiex_change_vif_to_ap(struct net_device *dev, 115062306a36Sopenharmony_ci enum nl80211_iftype curr_iftype, 115162306a36Sopenharmony_ci enum nl80211_iftype type, 115262306a36Sopenharmony_ci struct vif_params *params) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct mwifiex_private *priv; 115562306a36Sopenharmony_ci struct mwifiex_adapter *adapter; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci priv = mwifiex_netdev_get_priv(dev); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (!priv) 116062306a36Sopenharmony_ci return -1; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci adapter = priv->adapter; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 116562306a36Sopenharmony_ci "%s: changing role to AP\n", dev->name); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (mwifiex_deinit_priv_params(priv)) 116862306a36Sopenharmony_ci return -1; 116962306a36Sopenharmony_ci if (mwifiex_init_new_priv_params(priv, dev, type)) 117062306a36Sopenharmony_ci return -1; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci update_vif_type_counter(adapter, curr_iftype, -1); 117362306a36Sopenharmony_ci update_vif_type_counter(adapter, type, +1); 117462306a36Sopenharmony_ci dev->ieee80211_ptr->iftype = type; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, 117762306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true)) 117862306a36Sopenharmony_ci return -1; 117962306a36Sopenharmony_ci if (mwifiex_sta_init_cmd(priv, false, false)) 118062306a36Sopenharmony_ci return -1; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci return 0; 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci/* 118562306a36Sopenharmony_ci * CFG802.11 operation handler to change interface type. 118662306a36Sopenharmony_ci */ 118762306a36Sopenharmony_cistatic int 118862306a36Sopenharmony_cimwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, 118962306a36Sopenharmony_ci struct net_device *dev, 119062306a36Sopenharmony_ci enum nl80211_iftype type, 119162306a36Sopenharmony_ci struct vif_params *params) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 119462306a36Sopenharmony_ci enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (priv->scan_request) { 119762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 119862306a36Sopenharmony_ci "change virtual interface: scan in process\n"); 119962306a36Sopenharmony_ci return -EBUSY; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (type == NL80211_IFTYPE_UNSPECIFIED) { 120362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 120462306a36Sopenharmony_ci "%s: no new type specified, keeping old type %d\n", 120562306a36Sopenharmony_ci dev->name, curr_iftype); 120662306a36Sopenharmony_ci return 0; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (curr_iftype == type) { 121062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 121162306a36Sopenharmony_ci "%s: interface already is of type %d\n", 121262306a36Sopenharmony_ci dev->name, curr_iftype); 121362306a36Sopenharmony_ci return 0; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (!is_vif_type_change_allowed(priv->adapter, curr_iftype, type)) { 121762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 121862306a36Sopenharmony_ci "%s: change from type %d to %d is not allowed\n", 121962306a36Sopenharmony_ci dev->name, curr_iftype, type); 122062306a36Sopenharmony_ci return -EOPNOTSUPP; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci switch (curr_iftype) { 122462306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 122562306a36Sopenharmony_ci switch (type) { 122662306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 122762306a36Sopenharmony_ci priv->bss_mode = type; 122862306a36Sopenharmony_ci priv->sec_info.authentication_mode = 122962306a36Sopenharmony_ci NL80211_AUTHTYPE_OPEN_SYSTEM; 123062306a36Sopenharmony_ci dev->ieee80211_ptr->iftype = type; 123162306a36Sopenharmony_ci mwifiex_deauthenticate(priv, NULL); 123262306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, 123362306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, 123462306a36Sopenharmony_ci true); 123562306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 123662306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 123762306a36Sopenharmony_ci return mwifiex_change_vif_to_p2p(dev, curr_iftype, 123862306a36Sopenharmony_ci type, params); 123962306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 124062306a36Sopenharmony_ci return mwifiex_change_vif_to_ap(dev, curr_iftype, type, 124162306a36Sopenharmony_ci params); 124262306a36Sopenharmony_ci default: 124362306a36Sopenharmony_ci goto errnotsupp; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 124762306a36Sopenharmony_ci switch (type) { 124862306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 124962306a36Sopenharmony_ci priv->bss_mode = type; 125062306a36Sopenharmony_ci priv->sec_info.authentication_mode = 125162306a36Sopenharmony_ci NL80211_AUTHTYPE_OPEN_SYSTEM; 125262306a36Sopenharmony_ci dev->ieee80211_ptr->iftype = type; 125362306a36Sopenharmony_ci mwifiex_deauthenticate(priv, NULL); 125462306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, 125562306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, 125662306a36Sopenharmony_ci true); 125762306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 125862306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 125962306a36Sopenharmony_ci return mwifiex_change_vif_to_p2p(dev, curr_iftype, 126062306a36Sopenharmony_ci type, params); 126162306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 126262306a36Sopenharmony_ci return mwifiex_change_vif_to_ap(dev, curr_iftype, type, 126362306a36Sopenharmony_ci params); 126462306a36Sopenharmony_ci default: 126562306a36Sopenharmony_ci goto errnotsupp; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 126962306a36Sopenharmony_ci switch (type) { 127062306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 127162306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 127262306a36Sopenharmony_ci return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, 127362306a36Sopenharmony_ci type, params); 127462306a36Sopenharmony_ci break; 127562306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 127662306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 127762306a36Sopenharmony_ci return mwifiex_change_vif_to_p2p(dev, curr_iftype, 127862306a36Sopenharmony_ci type, params); 127962306a36Sopenharmony_ci default: 128062306a36Sopenharmony_ci goto errnotsupp; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 128462306a36Sopenharmony_ci if (mwifiex_cfg80211_deinit_p2p(priv)) 128562306a36Sopenharmony_ci return -EFAULT; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci switch (type) { 128862306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 128962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 129062306a36Sopenharmony_ci return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, 129162306a36Sopenharmony_ci type, params); 129262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 129362306a36Sopenharmony_ci return mwifiex_change_vif_to_p2p(dev, curr_iftype, 129462306a36Sopenharmony_ci type, params); 129562306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 129662306a36Sopenharmony_ci return mwifiex_change_vif_to_ap(dev, curr_iftype, type, 129762306a36Sopenharmony_ci params); 129862306a36Sopenharmony_ci default: 129962306a36Sopenharmony_ci goto errnotsupp; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 130362306a36Sopenharmony_ci if (mwifiex_cfg80211_deinit_p2p(priv)) 130462306a36Sopenharmony_ci return -EFAULT; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci switch (type) { 130762306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 130862306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 130962306a36Sopenharmony_ci return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, 131062306a36Sopenharmony_ci type, params); 131162306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 131262306a36Sopenharmony_ci return mwifiex_change_vif_to_p2p(dev, curr_iftype, 131362306a36Sopenharmony_ci type, params); 131462306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 131562306a36Sopenharmony_ci return mwifiex_change_vif_to_ap(dev, curr_iftype, type, 131662306a36Sopenharmony_ci params); 131762306a36Sopenharmony_ci default: 131862306a36Sopenharmony_ci goto errnotsupp; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci default: 132262306a36Sopenharmony_ci goto errnotsupp; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci return 0; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cierrnotsupp: 132962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 133062306a36Sopenharmony_ci "unsupported interface type transition: %d to %d\n", 133162306a36Sopenharmony_ci curr_iftype, type); 133262306a36Sopenharmony_ci return -EOPNOTSUPP; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic void 133662306a36Sopenharmony_cimwifiex_parse_htinfo(struct mwifiex_private *priv, u8 rateinfo, u8 htinfo, 133762306a36Sopenharmony_ci struct rate_info *rate) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci if (adapter->is_hw_11ac_capable) { 134262306a36Sopenharmony_ci /* bit[1-0]: 00=LG 01=HT 10=VHT */ 134362306a36Sopenharmony_ci if (htinfo & BIT(0)) { 134462306a36Sopenharmony_ci /* HT */ 134562306a36Sopenharmony_ci rate->mcs = rateinfo; 134662306a36Sopenharmony_ci rate->flags |= RATE_INFO_FLAGS_MCS; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci if (htinfo & BIT(1)) { 134962306a36Sopenharmony_ci /* VHT */ 135062306a36Sopenharmony_ci rate->mcs = rateinfo & 0x0F; 135162306a36Sopenharmony_ci rate->flags |= RATE_INFO_FLAGS_VHT_MCS; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (htinfo & (BIT(1) | BIT(0))) { 135562306a36Sopenharmony_ci /* HT or VHT */ 135662306a36Sopenharmony_ci switch (htinfo & (BIT(3) | BIT(2))) { 135762306a36Sopenharmony_ci case 0: 135862306a36Sopenharmony_ci rate->bw = RATE_INFO_BW_20; 135962306a36Sopenharmony_ci break; 136062306a36Sopenharmony_ci case (BIT(2)): 136162306a36Sopenharmony_ci rate->bw = RATE_INFO_BW_40; 136262306a36Sopenharmony_ci break; 136362306a36Sopenharmony_ci case (BIT(3)): 136462306a36Sopenharmony_ci rate->bw = RATE_INFO_BW_80; 136562306a36Sopenharmony_ci break; 136662306a36Sopenharmony_ci case (BIT(3) | BIT(2)): 136762306a36Sopenharmony_ci rate->bw = RATE_INFO_BW_160; 136862306a36Sopenharmony_ci break; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (htinfo & BIT(4)) 137262306a36Sopenharmony_ci rate->flags |= RATE_INFO_FLAGS_SHORT_GI; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if ((rateinfo >> 4) == 1) 137562306a36Sopenharmony_ci rate->nss = 2; 137662306a36Sopenharmony_ci else 137762306a36Sopenharmony_ci rate->nss = 1; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci } else { 138062306a36Sopenharmony_ci /* 138162306a36Sopenharmony_ci * Bit 0 in htinfo indicates that current rate is 11n. Valid 138262306a36Sopenharmony_ci * MCS index values for us are 0 to 15. 138362306a36Sopenharmony_ci */ 138462306a36Sopenharmony_ci if ((htinfo & BIT(0)) && (rateinfo < 16)) { 138562306a36Sopenharmony_ci rate->mcs = rateinfo; 138662306a36Sopenharmony_ci rate->flags |= RATE_INFO_FLAGS_MCS; 138762306a36Sopenharmony_ci rate->bw = RATE_INFO_BW_20; 138862306a36Sopenharmony_ci if (htinfo & BIT(1)) 138962306a36Sopenharmony_ci rate->bw = RATE_INFO_BW_40; 139062306a36Sopenharmony_ci if (htinfo & BIT(2)) 139162306a36Sopenharmony_ci rate->flags |= RATE_INFO_FLAGS_SHORT_GI; 139262306a36Sopenharmony_ci } 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci /* Decode legacy rates for non-HT. */ 139662306a36Sopenharmony_ci if (!(htinfo & (BIT(0) | BIT(1)))) { 139762306a36Sopenharmony_ci /* Bitrates in multiples of 100kb/s. */ 139862306a36Sopenharmony_ci static const int legacy_rates[] = { 139962306a36Sopenharmony_ci [0] = 10, 140062306a36Sopenharmony_ci [1] = 20, 140162306a36Sopenharmony_ci [2] = 55, 140262306a36Sopenharmony_ci [3] = 110, 140362306a36Sopenharmony_ci [4] = 60, /* MWIFIEX_RATE_INDEX_OFDM0 */ 140462306a36Sopenharmony_ci [5] = 60, 140562306a36Sopenharmony_ci [6] = 90, 140662306a36Sopenharmony_ci [7] = 120, 140762306a36Sopenharmony_ci [8] = 180, 140862306a36Sopenharmony_ci [9] = 240, 140962306a36Sopenharmony_ci [10] = 360, 141062306a36Sopenharmony_ci [11] = 480, 141162306a36Sopenharmony_ci [12] = 540, 141262306a36Sopenharmony_ci }; 141362306a36Sopenharmony_ci if (rateinfo < ARRAY_SIZE(legacy_rates)) 141462306a36Sopenharmony_ci rate->legacy = legacy_rates[rateinfo]; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci/* 141962306a36Sopenharmony_ci * This function dumps the station information on a buffer. 142062306a36Sopenharmony_ci * 142162306a36Sopenharmony_ci * The following information are shown - 142262306a36Sopenharmony_ci * - Total bytes transmitted 142362306a36Sopenharmony_ci * - Total bytes received 142462306a36Sopenharmony_ci * - Total packets transmitted 142562306a36Sopenharmony_ci * - Total packets received 142662306a36Sopenharmony_ci * - Signal quality level 142762306a36Sopenharmony_ci * - Transmission rate 142862306a36Sopenharmony_ci */ 142962306a36Sopenharmony_cistatic int 143062306a36Sopenharmony_cimwifiex_dump_station_info(struct mwifiex_private *priv, 143162306a36Sopenharmony_ci struct mwifiex_sta_node *node, 143262306a36Sopenharmony_ci struct station_info *sinfo) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci u32 rate; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci sinfo->filled = BIT_ULL(NL80211_STA_INFO_RX_BYTES) | BIT_ULL(NL80211_STA_INFO_TX_BYTES) | 143762306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_RX_PACKETS) | BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | 143862306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_TX_BITRATE) | 143962306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_SIGNAL) | BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 144262306a36Sopenharmony_ci if (!node) 144362306a36Sopenharmony_ci return -ENOENT; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) | 144662306a36Sopenharmony_ci BIT_ULL(NL80211_STA_INFO_TX_FAILED); 144762306a36Sopenharmony_ci sinfo->inactive_time = 144862306a36Sopenharmony_ci jiffies_to_msecs(jiffies - node->stats.last_rx); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci sinfo->signal = node->stats.rssi; 145162306a36Sopenharmony_ci sinfo->signal_avg = node->stats.rssi; 145262306a36Sopenharmony_ci sinfo->rx_bytes = node->stats.rx_bytes; 145362306a36Sopenharmony_ci sinfo->tx_bytes = node->stats.tx_bytes; 145462306a36Sopenharmony_ci sinfo->rx_packets = node->stats.rx_packets; 145562306a36Sopenharmony_ci sinfo->tx_packets = node->stats.tx_packets; 145662306a36Sopenharmony_ci sinfo->tx_failed = node->stats.tx_failed; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci mwifiex_parse_htinfo(priv, priv->tx_rate, 145962306a36Sopenharmony_ci node->stats.last_tx_htinfo, 146062306a36Sopenharmony_ci &sinfo->txrate); 146162306a36Sopenharmony_ci sinfo->txrate.legacy = node->stats.last_tx_rate * 5; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci return 0; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* Get signal information from the firmware */ 146762306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, 146862306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, 0, NULL, true)) { 146962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 147062306a36Sopenharmony_ci "failed to get signal information\n"); 147162306a36Sopenharmony_ci return -EFAULT; 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (mwifiex_drv_get_data_rate(priv, &rate)) { 147562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 147662306a36Sopenharmony_ci "getting data rate error\n"); 147762306a36Sopenharmony_ci return -EFAULT; 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci /* Get DTIM period information from firmware */ 148162306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 148262306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, DTIM_PERIOD_I, 148362306a36Sopenharmony_ci &priv->dtim_period, true); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci mwifiex_parse_htinfo(priv, priv->tx_rate, priv->tx_htinfo, 148662306a36Sopenharmony_ci &sinfo->txrate); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci sinfo->signal_avg = priv->bcn_rssi_avg; 148962306a36Sopenharmony_ci sinfo->rx_bytes = priv->stats.rx_bytes; 149062306a36Sopenharmony_ci sinfo->tx_bytes = priv->stats.tx_bytes; 149162306a36Sopenharmony_ci sinfo->rx_packets = priv->stats.rx_packets; 149262306a36Sopenharmony_ci sinfo->tx_packets = priv->stats.tx_packets; 149362306a36Sopenharmony_ci sinfo->signal = priv->bcn_rssi_avg; 149462306a36Sopenharmony_ci /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */ 149562306a36Sopenharmony_ci sinfo->txrate.legacy = rate * 5; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); 149862306a36Sopenharmony_ci mwifiex_parse_htinfo(priv, priv->rxpd_rate, priv->rxpd_htinfo, 149962306a36Sopenharmony_ci &sinfo->rxrate); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (priv->bss_mode == NL80211_IFTYPE_STATION) { 150262306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BSS_PARAM); 150362306a36Sopenharmony_ci sinfo->bss_param.flags = 0; 150462306a36Sopenharmony_ci if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & 150562306a36Sopenharmony_ci WLAN_CAPABILITY_SHORT_PREAMBLE) 150662306a36Sopenharmony_ci sinfo->bss_param.flags |= 150762306a36Sopenharmony_ci BSS_PARAM_FLAGS_SHORT_PREAMBLE; 150862306a36Sopenharmony_ci if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & 150962306a36Sopenharmony_ci WLAN_CAPABILITY_SHORT_SLOT_TIME) 151062306a36Sopenharmony_ci sinfo->bss_param.flags |= 151162306a36Sopenharmony_ci BSS_PARAM_FLAGS_SHORT_SLOT_TIME; 151262306a36Sopenharmony_ci sinfo->bss_param.dtim_period = priv->dtim_period; 151362306a36Sopenharmony_ci sinfo->bss_param.beacon_interval = 151462306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.beacon_period; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci return 0; 151862306a36Sopenharmony_ci} 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci/* 152162306a36Sopenharmony_ci * CFG802.11 operation handler to get station information. 152262306a36Sopenharmony_ci * 152362306a36Sopenharmony_ci * This function only works in connected mode, and dumps the 152462306a36Sopenharmony_ci * requested station information, if available. 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_cistatic int 152762306a36Sopenharmony_cimwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, 152862306a36Sopenharmony_ci const u8 *mac, struct station_info *sinfo) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if (!priv->media_connected) 153362306a36Sopenharmony_ci return -ENOENT; 153462306a36Sopenharmony_ci if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) 153562306a36Sopenharmony_ci return -ENOENT; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci return mwifiex_dump_station_info(priv, NULL, sinfo); 153862306a36Sopenharmony_ci} 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci/* 154162306a36Sopenharmony_ci * CFG802.11 operation handler to dump station information. 154262306a36Sopenharmony_ci */ 154362306a36Sopenharmony_cistatic int 154462306a36Sopenharmony_cimwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, 154562306a36Sopenharmony_ci int idx, u8 *mac, struct station_info *sinfo) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 154862306a36Sopenharmony_ci struct mwifiex_sta_node *node; 154962306a36Sopenharmony_ci int i; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 155262306a36Sopenharmony_ci priv->media_connected && idx == 0) { 155362306a36Sopenharmony_ci ether_addr_copy(mac, priv->cfg_bssid); 155462306a36Sopenharmony_ci return mwifiex_dump_station_info(priv, NULL, sinfo); 155562306a36Sopenharmony_ci } else if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 155662306a36Sopenharmony_ci mwifiex_send_cmd(priv, HOST_CMD_APCMD_STA_LIST, 155762306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, 0, NULL, true); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci i = 0; 156062306a36Sopenharmony_ci list_for_each_entry(node, &priv->sta_list, list) { 156162306a36Sopenharmony_ci if (i++ != idx) 156262306a36Sopenharmony_ci continue; 156362306a36Sopenharmony_ci ether_addr_copy(mac, node->mac_addr); 156462306a36Sopenharmony_ci return mwifiex_dump_station_info(priv, node, sinfo); 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci return -ENOENT; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic int 157262306a36Sopenharmony_cimwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev, 157362306a36Sopenharmony_ci int idx, struct survey_info *survey) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 157662306a36Sopenharmony_ci struct mwifiex_chan_stats *pchan_stats = priv->adapter->chan_stats; 157762306a36Sopenharmony_ci enum nl80211_band band; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, DUMP, "dump_survey idx=%d\n", idx); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci memset(survey, 0, sizeof(struct survey_info)); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 158462306a36Sopenharmony_ci priv->media_connected && idx == 0) { 158562306a36Sopenharmony_ci u8 curr_bss_band = priv->curr_bss_params.band; 158662306a36Sopenharmony_ci u32 chan = priv->curr_bss_params.bss_descriptor.channel; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci band = mwifiex_band_to_radio_type(curr_bss_band); 158962306a36Sopenharmony_ci survey->channel = ieee80211_get_channel(wiphy, 159062306a36Sopenharmony_ci ieee80211_channel_to_frequency(chan, band)); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci if (priv->bcn_nf_last) { 159362306a36Sopenharmony_ci survey->filled = SURVEY_INFO_NOISE_DBM; 159462306a36Sopenharmony_ci survey->noise = priv->bcn_nf_last; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci return 0; 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci if (idx >= priv->adapter->num_in_chan_stats) 160062306a36Sopenharmony_ci return -ENOENT; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (!pchan_stats[idx].cca_scan_dur) 160362306a36Sopenharmony_ci return 0; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci band = pchan_stats[idx].bandcfg; 160662306a36Sopenharmony_ci survey->channel = ieee80211_get_channel(wiphy, 160762306a36Sopenharmony_ci ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band)); 160862306a36Sopenharmony_ci survey->filled = SURVEY_INFO_NOISE_DBM | 160962306a36Sopenharmony_ci SURVEY_INFO_TIME | 161062306a36Sopenharmony_ci SURVEY_INFO_TIME_BUSY; 161162306a36Sopenharmony_ci survey->noise = pchan_stats[idx].noise; 161262306a36Sopenharmony_ci survey->time = pchan_stats[idx].cca_scan_dur; 161362306a36Sopenharmony_ci survey->time_busy = pchan_stats[idx].cca_busy_dur; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci return 0; 161662306a36Sopenharmony_ci} 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci/* Supported rates to be advertised to the cfg80211 */ 161962306a36Sopenharmony_cistatic struct ieee80211_rate mwifiex_rates[] = { 162062306a36Sopenharmony_ci {.bitrate = 10, .hw_value = 2, }, 162162306a36Sopenharmony_ci {.bitrate = 20, .hw_value = 4, }, 162262306a36Sopenharmony_ci {.bitrate = 55, .hw_value = 11, }, 162362306a36Sopenharmony_ci {.bitrate = 110, .hw_value = 22, }, 162462306a36Sopenharmony_ci {.bitrate = 60, .hw_value = 12, }, 162562306a36Sopenharmony_ci {.bitrate = 90, .hw_value = 18, }, 162662306a36Sopenharmony_ci {.bitrate = 120, .hw_value = 24, }, 162762306a36Sopenharmony_ci {.bitrate = 180, .hw_value = 36, }, 162862306a36Sopenharmony_ci {.bitrate = 240, .hw_value = 48, }, 162962306a36Sopenharmony_ci {.bitrate = 360, .hw_value = 72, }, 163062306a36Sopenharmony_ci {.bitrate = 480, .hw_value = 96, }, 163162306a36Sopenharmony_ci {.bitrate = 540, .hw_value = 108, }, 163262306a36Sopenharmony_ci}; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci/* Channel definitions to be advertised to cfg80211 */ 163562306a36Sopenharmony_cistatic struct ieee80211_channel mwifiex_channels_2ghz[] = { 163662306a36Sopenharmony_ci {.center_freq = 2412, .hw_value = 1, }, 163762306a36Sopenharmony_ci {.center_freq = 2417, .hw_value = 2, }, 163862306a36Sopenharmony_ci {.center_freq = 2422, .hw_value = 3, }, 163962306a36Sopenharmony_ci {.center_freq = 2427, .hw_value = 4, }, 164062306a36Sopenharmony_ci {.center_freq = 2432, .hw_value = 5, }, 164162306a36Sopenharmony_ci {.center_freq = 2437, .hw_value = 6, }, 164262306a36Sopenharmony_ci {.center_freq = 2442, .hw_value = 7, }, 164362306a36Sopenharmony_ci {.center_freq = 2447, .hw_value = 8, }, 164462306a36Sopenharmony_ci {.center_freq = 2452, .hw_value = 9, }, 164562306a36Sopenharmony_ci {.center_freq = 2457, .hw_value = 10, }, 164662306a36Sopenharmony_ci {.center_freq = 2462, .hw_value = 11, }, 164762306a36Sopenharmony_ci {.center_freq = 2467, .hw_value = 12, }, 164862306a36Sopenharmony_ci {.center_freq = 2472, .hw_value = 13, }, 164962306a36Sopenharmony_ci {.center_freq = 2484, .hw_value = 14, }, 165062306a36Sopenharmony_ci}; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_cistatic struct ieee80211_supported_band mwifiex_band_2ghz = { 165362306a36Sopenharmony_ci .channels = mwifiex_channels_2ghz, 165462306a36Sopenharmony_ci .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz), 165562306a36Sopenharmony_ci .bitrates = mwifiex_rates, 165662306a36Sopenharmony_ci .n_bitrates = ARRAY_SIZE(mwifiex_rates), 165762306a36Sopenharmony_ci}; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_cistatic struct ieee80211_channel mwifiex_channels_5ghz[] = { 166062306a36Sopenharmony_ci {.center_freq = 5040, .hw_value = 8, }, 166162306a36Sopenharmony_ci {.center_freq = 5060, .hw_value = 12, }, 166262306a36Sopenharmony_ci {.center_freq = 5080, .hw_value = 16, }, 166362306a36Sopenharmony_ci {.center_freq = 5170, .hw_value = 34, }, 166462306a36Sopenharmony_ci {.center_freq = 5190, .hw_value = 38, }, 166562306a36Sopenharmony_ci {.center_freq = 5210, .hw_value = 42, }, 166662306a36Sopenharmony_ci {.center_freq = 5230, .hw_value = 46, }, 166762306a36Sopenharmony_ci {.center_freq = 5180, .hw_value = 36, }, 166862306a36Sopenharmony_ci {.center_freq = 5200, .hw_value = 40, }, 166962306a36Sopenharmony_ci {.center_freq = 5220, .hw_value = 44, }, 167062306a36Sopenharmony_ci {.center_freq = 5240, .hw_value = 48, }, 167162306a36Sopenharmony_ci {.center_freq = 5260, .hw_value = 52, }, 167262306a36Sopenharmony_ci {.center_freq = 5280, .hw_value = 56, }, 167362306a36Sopenharmony_ci {.center_freq = 5300, .hw_value = 60, }, 167462306a36Sopenharmony_ci {.center_freq = 5320, .hw_value = 64, }, 167562306a36Sopenharmony_ci {.center_freq = 5500, .hw_value = 100, }, 167662306a36Sopenharmony_ci {.center_freq = 5520, .hw_value = 104, }, 167762306a36Sopenharmony_ci {.center_freq = 5540, .hw_value = 108, }, 167862306a36Sopenharmony_ci {.center_freq = 5560, .hw_value = 112, }, 167962306a36Sopenharmony_ci {.center_freq = 5580, .hw_value = 116, }, 168062306a36Sopenharmony_ci {.center_freq = 5600, .hw_value = 120, }, 168162306a36Sopenharmony_ci {.center_freq = 5620, .hw_value = 124, }, 168262306a36Sopenharmony_ci {.center_freq = 5640, .hw_value = 128, }, 168362306a36Sopenharmony_ci {.center_freq = 5660, .hw_value = 132, }, 168462306a36Sopenharmony_ci {.center_freq = 5680, .hw_value = 136, }, 168562306a36Sopenharmony_ci {.center_freq = 5700, .hw_value = 140, }, 168662306a36Sopenharmony_ci {.center_freq = 5745, .hw_value = 149, }, 168762306a36Sopenharmony_ci {.center_freq = 5765, .hw_value = 153, }, 168862306a36Sopenharmony_ci {.center_freq = 5785, .hw_value = 157, }, 168962306a36Sopenharmony_ci {.center_freq = 5805, .hw_value = 161, }, 169062306a36Sopenharmony_ci {.center_freq = 5825, .hw_value = 165, }, 169162306a36Sopenharmony_ci}; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cistatic struct ieee80211_supported_band mwifiex_band_5ghz = { 169462306a36Sopenharmony_ci .channels = mwifiex_channels_5ghz, 169562306a36Sopenharmony_ci .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz), 169662306a36Sopenharmony_ci .bitrates = mwifiex_rates + 4, 169762306a36Sopenharmony_ci .n_bitrates = ARRAY_SIZE(mwifiex_rates) - 4, 169862306a36Sopenharmony_ci}; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci/* Supported crypto cipher suits to be advertised to cfg80211 */ 170262306a36Sopenharmony_cistatic const u32 mwifiex_cipher_suites[] = { 170362306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP40, 170462306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP104, 170562306a36Sopenharmony_ci WLAN_CIPHER_SUITE_TKIP, 170662306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP, 170762306a36Sopenharmony_ci WLAN_CIPHER_SUITE_SMS4, 170862306a36Sopenharmony_ci WLAN_CIPHER_SUITE_AES_CMAC, 170962306a36Sopenharmony_ci}; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci/* Supported mgmt frame types to be advertised to cfg80211 */ 171262306a36Sopenharmony_cistatic const struct ieee80211_txrx_stypes 171362306a36Sopenharmony_cimwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = { 171462306a36Sopenharmony_ci [NL80211_IFTYPE_STATION] = { 171562306a36Sopenharmony_ci .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | 171662306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_RESP >> 4), 171762306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 171862306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 171962306a36Sopenharmony_ci }, 172062306a36Sopenharmony_ci [NL80211_IFTYPE_AP] = { 172162306a36Sopenharmony_ci .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | 172262306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_RESP >> 4), 172362306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 172462306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 172562306a36Sopenharmony_ci }, 172662306a36Sopenharmony_ci [NL80211_IFTYPE_P2P_CLIENT] = { 172762306a36Sopenharmony_ci .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | 172862306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_RESP >> 4), 172962306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 173062306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 173162306a36Sopenharmony_ci }, 173262306a36Sopenharmony_ci [NL80211_IFTYPE_P2P_GO] = { 173362306a36Sopenharmony_ci .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | 173462306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_RESP >> 4), 173562306a36Sopenharmony_ci .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | 173662306a36Sopenharmony_ci BIT(IEEE80211_STYPE_PROBE_REQ >> 4), 173762306a36Sopenharmony_ci }, 173862306a36Sopenharmony_ci}; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci/* 174162306a36Sopenharmony_ci * CFG802.11 operation handler for setting bit rates. 174262306a36Sopenharmony_ci * 174362306a36Sopenharmony_ci * Function configures data rates to firmware using bitrate mask 174462306a36Sopenharmony_ci * provided by cfg80211. 174562306a36Sopenharmony_ci */ 174662306a36Sopenharmony_cistatic int 174762306a36Sopenharmony_cimwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, 174862306a36Sopenharmony_ci struct net_device *dev, 174962306a36Sopenharmony_ci unsigned int link_id, 175062306a36Sopenharmony_ci const u8 *peer, 175162306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 175262306a36Sopenharmony_ci{ 175362306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 175462306a36Sopenharmony_ci u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; 175562306a36Sopenharmony_ci enum nl80211_band band; 175662306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (!priv->media_connected) { 175962306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 176062306a36Sopenharmony_ci "Can not set Tx data rate in disconnected state\n"); 176162306a36Sopenharmony_ci return -EINVAL; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci memset(bitmap_rates, 0, sizeof(bitmap_rates)); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci /* Fill HR/DSSS rates. */ 176962306a36Sopenharmony_ci if (band == NL80211_BAND_2GHZ) 177062306a36Sopenharmony_ci bitmap_rates[0] = mask->control[band].legacy & 0x000f; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci /* Fill OFDM rates */ 177362306a36Sopenharmony_ci if (band == NL80211_BAND_2GHZ) 177462306a36Sopenharmony_ci bitmap_rates[1] = (mask->control[band].legacy & 0x0ff0) >> 4; 177562306a36Sopenharmony_ci else 177662306a36Sopenharmony_ci bitmap_rates[1] = mask->control[band].legacy; 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci /* Fill HT MCS rates */ 177962306a36Sopenharmony_ci bitmap_rates[2] = mask->control[band].ht_mcs[0]; 178062306a36Sopenharmony_ci if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) 178162306a36Sopenharmony_ci bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci /* Fill VHT MCS rates */ 178462306a36Sopenharmony_ci if (adapter->fw_api_ver == MWIFIEX_FW_V15) { 178562306a36Sopenharmony_ci bitmap_rates[10] = mask->control[band].vht_mcs[0]; 178662306a36Sopenharmony_ci if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) 178762306a36Sopenharmony_ci bitmap_rates[11] = mask->control[band].vht_mcs[1]; 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG, 179162306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, bitmap_rates, true); 179262306a36Sopenharmony_ci} 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci/* 179562306a36Sopenharmony_ci * CFG802.11 operation handler for connection quality monitoring. 179662306a36Sopenharmony_ci * 179762306a36Sopenharmony_ci * This function subscribes/unsubscribes HIGH_RSSI and LOW_RSSI 179862306a36Sopenharmony_ci * events to FW. 179962306a36Sopenharmony_ci */ 180062306a36Sopenharmony_cistatic int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, 180162306a36Sopenharmony_ci struct net_device *dev, 180262306a36Sopenharmony_ci s32 rssi_thold, u32 rssi_hyst) 180362306a36Sopenharmony_ci{ 180462306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 180562306a36Sopenharmony_ci struct mwifiex_ds_misc_subsc_evt subsc_evt; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci priv->cqm_rssi_thold = rssi_thold; 180862306a36Sopenharmony_ci priv->cqm_rssi_hyst = rssi_hyst; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci memset(&subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt)); 181162306a36Sopenharmony_ci subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci /* Subscribe/unsubscribe low and high rssi events */ 181462306a36Sopenharmony_ci if (rssi_thold && rssi_hyst) { 181562306a36Sopenharmony_ci subsc_evt.action = HostCmd_ACT_BITWISE_SET; 181662306a36Sopenharmony_ci subsc_evt.bcn_l_rssi_cfg.abs_value = abs(rssi_thold); 181762306a36Sopenharmony_ci subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold); 181862306a36Sopenharmony_ci subsc_evt.bcn_l_rssi_cfg.evt_freq = 1; 181962306a36Sopenharmony_ci subsc_evt.bcn_h_rssi_cfg.evt_freq = 1; 182062306a36Sopenharmony_ci return mwifiex_send_cmd(priv, 182162306a36Sopenharmony_ci HostCmd_CMD_802_11_SUBSCRIBE_EVENT, 182262306a36Sopenharmony_ci 0, 0, &subsc_evt, true); 182362306a36Sopenharmony_ci } else { 182462306a36Sopenharmony_ci subsc_evt.action = HostCmd_ACT_BITWISE_CLR; 182562306a36Sopenharmony_ci return mwifiex_send_cmd(priv, 182662306a36Sopenharmony_ci HostCmd_CMD_802_11_SUBSCRIBE_EVENT, 182762306a36Sopenharmony_ci 0, 0, &subsc_evt, true); 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci return 0; 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci/* cfg80211 operation handler for change_beacon. 183462306a36Sopenharmony_ci * Function retrieves and sets modified management IEs to FW. 183562306a36Sopenharmony_ci */ 183662306a36Sopenharmony_cistatic int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, 183762306a36Sopenharmony_ci struct net_device *dev, 183862306a36Sopenharmony_ci struct cfg80211_beacon_data *data) 183962306a36Sopenharmony_ci{ 184062306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 184162306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci mwifiex_cancel_scan(adapter); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) { 184662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 184762306a36Sopenharmony_ci "%s: bss_type mismatched\n", __func__); 184862306a36Sopenharmony_ci return -EINVAL; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci if (!priv->bss_started) { 185262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 185362306a36Sopenharmony_ci "%s: bss not started\n", __func__); 185462306a36Sopenharmony_ci return -EINVAL; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (mwifiex_set_mgmt_ies(priv, data)) { 185862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 185962306a36Sopenharmony_ci "%s: setting mgmt ies failed\n", __func__); 186062306a36Sopenharmony_ci return -EFAULT; 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci return 0; 186462306a36Sopenharmony_ci} 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci/* cfg80211 operation handler for del_station. 186762306a36Sopenharmony_ci * Function deauthenticates station which value is provided in mac parameter. 186862306a36Sopenharmony_ci * If mac is NULL/broadcast, all stations in associated station list are 186962306a36Sopenharmony_ci * deauthenticated. If bss is not started or there are no stations in 187062306a36Sopenharmony_ci * associated stations list, no action is taken. 187162306a36Sopenharmony_ci */ 187262306a36Sopenharmony_cistatic int 187362306a36Sopenharmony_cimwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, 187462306a36Sopenharmony_ci struct station_del_parameters *params) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 187762306a36Sopenharmony_ci struct mwifiex_sta_node *sta_node; 187862306a36Sopenharmony_ci u8 deauth_mac[ETH_ALEN]; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (!priv->bss_started && priv->wdev.cac_started) { 188162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "%s: abort CAC!\n", __func__); 188262306a36Sopenharmony_ci mwifiex_abort_cac(priv); 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci if (list_empty(&priv->sta_list) || !priv->bss_started) 188662306a36Sopenharmony_ci return 0; 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci if (!params->mac || is_broadcast_ether_addr(params->mac)) 188962306a36Sopenharmony_ci return 0; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "%s: mac address %pM\n", 189262306a36Sopenharmony_ci __func__, params->mac); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci eth_zero_addr(deauth_mac); 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 189762306a36Sopenharmony_ci sta_node = mwifiex_get_sta_entry(priv, params->mac); 189862306a36Sopenharmony_ci if (sta_node) 189962306a36Sopenharmony_ci ether_addr_copy(deauth_mac, params->mac); 190062306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci if (is_valid_ether_addr(deauth_mac)) { 190362306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH, 190462306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 190562306a36Sopenharmony_ci deauth_mac, true)) 190662306a36Sopenharmony_ci return -1; 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci return 0; 191062306a36Sopenharmony_ci} 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_cistatic int 191362306a36Sopenharmony_cimwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) 191462306a36Sopenharmony_ci{ 191562306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 191662306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_get_priv(adapter, 191762306a36Sopenharmony_ci MWIFIEX_BSS_ROLE_ANY); 191862306a36Sopenharmony_ci struct mwifiex_ds_ant_cfg ant_cfg; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci if (!tx_ant || !rx_ant) 192162306a36Sopenharmony_ci return -EOPNOTSUPP; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci if (adapter->hw_dev_mcs_support != HT_STREAM_2X2) { 192462306a36Sopenharmony_ci /* Not a MIMO chip. User should provide specific antenna number 192562306a36Sopenharmony_ci * for Tx/Rx path or enable all antennas for diversity 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci if (tx_ant != rx_ant) 192862306a36Sopenharmony_ci return -EOPNOTSUPP; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci if ((tx_ant & (tx_ant - 1)) && 193162306a36Sopenharmony_ci (tx_ant != BIT(adapter->number_of_antenna) - 1)) 193262306a36Sopenharmony_ci return -EOPNOTSUPP; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if ((tx_ant == BIT(adapter->number_of_antenna) - 1) && 193562306a36Sopenharmony_ci (priv->adapter->number_of_antenna > 1)) { 193662306a36Sopenharmony_ci tx_ant = RF_ANTENNA_AUTO; 193762306a36Sopenharmony_ci rx_ant = RF_ANTENNA_AUTO; 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci } else { 194062306a36Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_info; 194162306a36Sopenharmony_ci int rx_mcs_supp; 194262306a36Sopenharmony_ci enum nl80211_band band; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if ((tx_ant == 0x1 && rx_ant == 0x1)) { 194562306a36Sopenharmony_ci adapter->user_dev_mcs_support = HT_STREAM_1X1; 194662306a36Sopenharmony_ci if (adapter->is_hw_11ac_capable) 194762306a36Sopenharmony_ci adapter->usr_dot_11ac_mcs_support = 194862306a36Sopenharmony_ci MWIFIEX_11AC_MCS_MAP_1X1; 194962306a36Sopenharmony_ci } else { 195062306a36Sopenharmony_ci adapter->user_dev_mcs_support = HT_STREAM_2X2; 195162306a36Sopenharmony_ci if (adapter->is_hw_11ac_capable) 195262306a36Sopenharmony_ci adapter->usr_dot_11ac_mcs_support = 195362306a36Sopenharmony_ci MWIFIEX_11AC_MCS_MAP_2X2; 195462306a36Sopenharmony_ci } 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 195762306a36Sopenharmony_ci if (!adapter->wiphy->bands[band]) 195862306a36Sopenharmony_ci continue; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci ht_info = &adapter->wiphy->bands[band]->ht_cap; 196162306a36Sopenharmony_ci rx_mcs_supp = 196262306a36Sopenharmony_ci GET_RXMCSSUPP(adapter->user_dev_mcs_support); 196362306a36Sopenharmony_ci memset(&ht_info->mcs, 0, adapter->number_of_antenna); 196462306a36Sopenharmony_ci memset(&ht_info->mcs, 0xff, rx_mcs_supp); 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci ant_cfg.tx_ant = tx_ant; 196962306a36Sopenharmony_ci ant_cfg.rx_ant = rx_ant; 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA, 197262306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &ant_cfg, true); 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_cistatic int 197662306a36Sopenharmony_cimwifiex_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 197962306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_get_priv(adapter, 198062306a36Sopenharmony_ci MWIFIEX_BSS_ROLE_ANY); 198162306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA, 198262306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, 0, NULL, true); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci *tx_ant = priv->tx_ant; 198562306a36Sopenharmony_ci *rx_ant = priv->rx_ant; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci return 0; 198862306a36Sopenharmony_ci} 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci/* cfg80211 operation handler for stop ap. 199162306a36Sopenharmony_ci * Function stops BSS running at uAP interface. 199262306a36Sopenharmony_ci */ 199362306a36Sopenharmony_cistatic int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, 199462306a36Sopenharmony_ci unsigned int link_id) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci mwifiex_abort_cac(priv); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci if (mwifiex_del_mgmt_ies(priv)) 200162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 200262306a36Sopenharmony_ci "Failed to delete mgmt IEs!\n"); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci priv->ap_11n_enabled = 0; 200562306a36Sopenharmony_ci memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg)); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, 200862306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true)) { 200962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 201062306a36Sopenharmony_ci "Failed to stop the BSS\n"); 201162306a36Sopenharmony_ci return -1; 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET, 201562306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true)) { 201662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 201762306a36Sopenharmony_ci "Failed to reset BSS\n"); 201862306a36Sopenharmony_ci return -1; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci if (netif_carrier_ok(priv->netdev)) 202262306a36Sopenharmony_ci netif_carrier_off(priv->netdev); 202362306a36Sopenharmony_ci mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci return 0; 202662306a36Sopenharmony_ci} 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci/* cfg80211 operation handler for start_ap. 202962306a36Sopenharmony_ci * Function sets beacon period, DTIM period, SSID and security into 203062306a36Sopenharmony_ci * AP config structure. 203162306a36Sopenharmony_ci * AP is configured with these settings and BSS is started. 203262306a36Sopenharmony_ci */ 203362306a36Sopenharmony_cistatic int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, 203462306a36Sopenharmony_ci struct net_device *dev, 203562306a36Sopenharmony_ci struct cfg80211_ap_settings *params) 203662306a36Sopenharmony_ci{ 203762306a36Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg; 203862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) 204162306a36Sopenharmony_ci return -1; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); 204462306a36Sopenharmony_ci if (!bss_cfg) 204562306a36Sopenharmony_ci return -ENOMEM; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci mwifiex_set_sys_config_invalid_data(bss_cfg); 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci memcpy(bss_cfg->mac_addr, priv->curr_addr, ETH_ALEN); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if (params->beacon_interval) 205262306a36Sopenharmony_ci bss_cfg->beacon_period = params->beacon_interval; 205362306a36Sopenharmony_ci if (params->dtim_period) 205462306a36Sopenharmony_ci bss_cfg->dtim_period = params->dtim_period; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci if (params->ssid && params->ssid_len) { 205762306a36Sopenharmony_ci memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); 205862306a36Sopenharmony_ci bss_cfg->ssid.ssid_len = params->ssid_len; 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci if (params->inactivity_timeout > 0) { 206162306a36Sopenharmony_ci /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ 206262306a36Sopenharmony_ci bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; 206362306a36Sopenharmony_ci bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; 206462306a36Sopenharmony_ci } 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci switch (params->hidden_ssid) { 206762306a36Sopenharmony_ci case NL80211_HIDDEN_SSID_NOT_IN_USE: 206862306a36Sopenharmony_ci bss_cfg->bcast_ssid_ctl = 1; 206962306a36Sopenharmony_ci break; 207062306a36Sopenharmony_ci case NL80211_HIDDEN_SSID_ZERO_LEN: 207162306a36Sopenharmony_ci bss_cfg->bcast_ssid_ctl = 0; 207262306a36Sopenharmony_ci break; 207362306a36Sopenharmony_ci case NL80211_HIDDEN_SSID_ZERO_CONTENTS: 207462306a36Sopenharmony_ci bss_cfg->bcast_ssid_ctl = 2; 207562306a36Sopenharmony_ci break; 207662306a36Sopenharmony_ci default: 207762306a36Sopenharmony_ci kfree(bss_cfg); 207862306a36Sopenharmony_ci return -EINVAL; 207962306a36Sopenharmony_ci } 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci mwifiex_uap_set_channel(priv, bss_cfg, params->chandef); 208262306a36Sopenharmony_ci mwifiex_set_uap_rates(bss_cfg, params); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci if (mwifiex_set_secure_params(priv, bss_cfg, params)) { 208562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 208662306a36Sopenharmony_ci "Failed to parse security parameters!\n"); 208762306a36Sopenharmony_ci goto out; 208862306a36Sopenharmony_ci } 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci mwifiex_set_ht_params(priv, bss_cfg, params); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci if (priv->adapter->is_hw_11ac_capable) { 209362306a36Sopenharmony_ci mwifiex_set_vht_params(priv, bss_cfg, params); 209462306a36Sopenharmony_ci mwifiex_set_vht_width(priv, params->chandef.width, 209562306a36Sopenharmony_ci priv->ap_11ac_enabled); 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci if (priv->ap_11ac_enabled) 209962306a36Sopenharmony_ci mwifiex_set_11ac_ba_params(priv); 210062306a36Sopenharmony_ci else 210162306a36Sopenharmony_ci mwifiex_set_ba_params(priv); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci mwifiex_set_wmm_params(priv, bss_cfg, params); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (mwifiex_is_11h_active(priv)) 210662306a36Sopenharmony_ci mwifiex_set_tpc_params(priv, bss_cfg, params); 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci if (mwifiex_is_11h_active(priv) && 210962306a36Sopenharmony_ci !cfg80211_chandef_dfs_required(wiphy, ¶ms->chandef, 211062306a36Sopenharmony_ci priv->bss_mode)) { 211162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 211262306a36Sopenharmony_ci "Disable 11h extensions in FW\n"); 211362306a36Sopenharmony_ci if (mwifiex_11h_activate(priv, false)) { 211462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 211562306a36Sopenharmony_ci "Failed to disable 11h extensions!!"); 211662306a36Sopenharmony_ci goto out; 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci priv->state_11h.is_11h_active = false; 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci mwifiex_config_uap_11d(priv, ¶ms->beacon); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci if (mwifiex_config_start_uap(priv, bss_cfg)) { 212462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 212562306a36Sopenharmony_ci "Failed to start AP\n"); 212662306a36Sopenharmony_ci goto out; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) 213062306a36Sopenharmony_ci goto out; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci if (!netif_carrier_ok(priv->netdev)) 213362306a36Sopenharmony_ci netif_carrier_on(priv->netdev); 213462306a36Sopenharmony_ci mwifiex_wake_up_net_dev_queue(priv->netdev, priv->adapter); 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); 213762306a36Sopenharmony_ci kfree(bss_cfg); 213862306a36Sopenharmony_ci return 0; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ciout: 214162306a36Sopenharmony_ci kfree(bss_cfg); 214262306a36Sopenharmony_ci return -1; 214362306a36Sopenharmony_ci} 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci/* 214662306a36Sopenharmony_ci * CFG802.11 operation handler for disconnection request. 214762306a36Sopenharmony_ci * 214862306a36Sopenharmony_ci * This function does not work when there is already a disconnection 214962306a36Sopenharmony_ci * procedure going on. 215062306a36Sopenharmony_ci */ 215162306a36Sopenharmony_cistatic int 215262306a36Sopenharmony_cimwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, 215362306a36Sopenharmony_ci u16 reason_code) 215462306a36Sopenharmony_ci{ 215562306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci if (!mwifiex_stop_bg_scan(priv)) 215862306a36Sopenharmony_ci cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci if (mwifiex_deauthenticate(priv, NULL)) 216162306a36Sopenharmony_ci return -EFAULT; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci eth_zero_addr(priv->cfg_bssid); 216462306a36Sopenharmony_ci priv->hs2_enabled = false; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci return 0; 216762306a36Sopenharmony_ci} 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci/* 217062306a36Sopenharmony_ci * This function informs the CFG802.11 subsystem of a new IBSS. 217162306a36Sopenharmony_ci * 217262306a36Sopenharmony_ci * The following information are sent to the CFG802.11 subsystem 217362306a36Sopenharmony_ci * to register the new IBSS. If we do not register the new IBSS, 217462306a36Sopenharmony_ci * a kernel panic will result. 217562306a36Sopenharmony_ci * - SSID 217662306a36Sopenharmony_ci * - SSID length 217762306a36Sopenharmony_ci * - BSSID 217862306a36Sopenharmony_ci * - Channel 217962306a36Sopenharmony_ci */ 218062306a36Sopenharmony_cistatic int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) 218162306a36Sopenharmony_ci{ 218262306a36Sopenharmony_ci struct ieee80211_channel *chan; 218362306a36Sopenharmony_ci struct mwifiex_bss_info bss_info; 218462306a36Sopenharmony_ci struct cfg80211_bss *bss; 218562306a36Sopenharmony_ci int ie_len; 218662306a36Sopenharmony_ci u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; 218762306a36Sopenharmony_ci enum nl80211_band band; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci if (mwifiex_get_bss_info(priv, &bss_info)) 219062306a36Sopenharmony_ci return -1; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci ie_buf[0] = WLAN_EID_SSID; 219362306a36Sopenharmony_ci ie_buf[1] = bss_info.ssid.ssid_len; 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci memcpy(&ie_buf[sizeof(struct ieee_types_header)], 219662306a36Sopenharmony_ci &bss_info.ssid.ssid, bss_info.ssid.ssid_len); 219762306a36Sopenharmony_ci ie_len = ie_buf[1] + sizeof(struct ieee_types_header); 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); 220062306a36Sopenharmony_ci chan = ieee80211_get_channel(priv->wdev.wiphy, 220162306a36Sopenharmony_ci ieee80211_channel_to_frequency(bss_info.bss_chan, 220262306a36Sopenharmony_ci band)); 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, 220562306a36Sopenharmony_ci CFG80211_BSS_FTYPE_UNKNOWN, 220662306a36Sopenharmony_ci bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, 220762306a36Sopenharmony_ci 0, ie_buf, ie_len, 0, GFP_KERNEL); 220862306a36Sopenharmony_ci if (bss) { 220962306a36Sopenharmony_ci cfg80211_put_bss(priv->wdev.wiphy, bss); 221062306a36Sopenharmony_ci ether_addr_copy(priv->cfg_bssid, bss_info.bssid); 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci return 0; 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci/* 221762306a36Sopenharmony_ci * This function connects with a BSS. 221862306a36Sopenharmony_ci * 221962306a36Sopenharmony_ci * This function handles both Infra and Ad-Hoc modes. It also performs 222062306a36Sopenharmony_ci * validity checking on the provided parameters, disconnects from the 222162306a36Sopenharmony_ci * current BSS (if any), sets up the association/scan parameters, 222262306a36Sopenharmony_ci * including security settings, and performs specific SSID scan before 222362306a36Sopenharmony_ci * trying to connect. 222462306a36Sopenharmony_ci * 222562306a36Sopenharmony_ci * For Infra mode, the function returns failure if the specified SSID 222662306a36Sopenharmony_ci * is not found in scan table. However, for Ad-Hoc mode, it can create 222762306a36Sopenharmony_ci * the IBSS if it does not exist. On successful completion in either case, 222862306a36Sopenharmony_ci * the function notifies the CFG802.11 subsystem of the new BSS connection. 222962306a36Sopenharmony_ci */ 223062306a36Sopenharmony_cistatic int 223162306a36Sopenharmony_cimwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, 223262306a36Sopenharmony_ci const u8 *ssid, const u8 *bssid, int mode, 223362306a36Sopenharmony_ci struct ieee80211_channel *channel, 223462306a36Sopenharmony_ci struct cfg80211_connect_params *sme, bool privacy, 223562306a36Sopenharmony_ci struct cfg80211_bss **sel_bss) 223662306a36Sopenharmony_ci{ 223762306a36Sopenharmony_ci struct cfg80211_ssid req_ssid; 223862306a36Sopenharmony_ci int ret, auth_type = 0; 223962306a36Sopenharmony_ci struct cfg80211_bss *bss = NULL; 224062306a36Sopenharmony_ci u8 is_scanning_required = 0; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci req_ssid.ssid_len = ssid_len; 224562306a36Sopenharmony_ci if (ssid_len > IEEE80211_MAX_SSID_LEN) { 224662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "invalid SSID - aborting\n"); 224762306a36Sopenharmony_ci return -EINVAL; 224862306a36Sopenharmony_ci } 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci memcpy(req_ssid.ssid, ssid, ssid_len); 225162306a36Sopenharmony_ci if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { 225262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "invalid SSID - aborting\n"); 225362306a36Sopenharmony_ci return -EINVAL; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci /* As this is new association, clear locally stored 225762306a36Sopenharmony_ci * keys and security related flags */ 225862306a36Sopenharmony_ci priv->sec_info.wpa_enabled = false; 225962306a36Sopenharmony_ci priv->sec_info.wpa2_enabled = false; 226062306a36Sopenharmony_ci priv->wep_key_curr_index = 0; 226162306a36Sopenharmony_ci priv->sec_info.encryption_mode = 0; 226262306a36Sopenharmony_ci priv->sec_info.is_authtype_auto = 0; 226362306a36Sopenharmony_ci ret = mwifiex_set_encode(priv, NULL, NULL, 0, 0, NULL, 1); 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci if (mode == NL80211_IFTYPE_ADHOC) { 226662306a36Sopenharmony_ci u16 enable = true; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci /* set ibss coalescing_status */ 226962306a36Sopenharmony_ci ret = mwifiex_send_cmd( 227062306a36Sopenharmony_ci priv, 227162306a36Sopenharmony_ci HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, 227262306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &enable, true); 227362306a36Sopenharmony_ci if (ret) 227462306a36Sopenharmony_ci return ret; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci /* "privacy" is set only for ad-hoc mode */ 227762306a36Sopenharmony_ci if (privacy) { 227862306a36Sopenharmony_ci /* 227962306a36Sopenharmony_ci * Keep WLAN_CIPHER_SUITE_WEP104 for now so that 228062306a36Sopenharmony_ci * the firmware can find a matching network from the 228162306a36Sopenharmony_ci * scan. The cfg80211 does not give us the encryption 228262306a36Sopenharmony_ci * mode at this stage so just setting it to WEP here. 228362306a36Sopenharmony_ci */ 228462306a36Sopenharmony_ci priv->sec_info.encryption_mode = 228562306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP104; 228662306a36Sopenharmony_ci priv->sec_info.authentication_mode = 228762306a36Sopenharmony_ci NL80211_AUTHTYPE_OPEN_SYSTEM; 228862306a36Sopenharmony_ci } 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci goto done; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci /* Now handle infra mode. "sme" is valid for infra mode only */ 229462306a36Sopenharmony_ci if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { 229562306a36Sopenharmony_ci auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; 229662306a36Sopenharmony_ci priv->sec_info.is_authtype_auto = 1; 229762306a36Sopenharmony_ci } else { 229862306a36Sopenharmony_ci auth_type = sme->auth_type; 229962306a36Sopenharmony_ci } 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci if (sme->crypto.n_ciphers_pairwise) { 230262306a36Sopenharmony_ci priv->sec_info.encryption_mode = 230362306a36Sopenharmony_ci sme->crypto.ciphers_pairwise[0]; 230462306a36Sopenharmony_ci priv->sec_info.authentication_mode = auth_type; 230562306a36Sopenharmony_ci } 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (sme->crypto.cipher_group) { 230862306a36Sopenharmony_ci priv->sec_info.encryption_mode = sme->crypto.cipher_group; 230962306a36Sopenharmony_ci priv->sec_info.authentication_mode = auth_type; 231062306a36Sopenharmony_ci } 231162306a36Sopenharmony_ci if (sme->ie) 231262306a36Sopenharmony_ci ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci if (sme->key) { 231562306a36Sopenharmony_ci if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) { 231662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 231762306a36Sopenharmony_ci "info: setting wep encryption\t" 231862306a36Sopenharmony_ci "with key len %d\n", sme->key_len); 231962306a36Sopenharmony_ci priv->wep_key_curr_index = sme->key_idx; 232062306a36Sopenharmony_ci ret = mwifiex_set_encode(priv, NULL, sme->key, 232162306a36Sopenharmony_ci sme->key_len, sme->key_idx, 232262306a36Sopenharmony_ci NULL, 0); 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci } 232562306a36Sopenharmony_cidone: 232662306a36Sopenharmony_ci /* 232762306a36Sopenharmony_ci * Scan entries are valid for some time (15 sec). So we can save one 232862306a36Sopenharmony_ci * active scan time if we just try cfg80211_get_bss first. If it fails 232962306a36Sopenharmony_ci * then request scan and cfg80211_get_bss() again for final output. 233062306a36Sopenharmony_ci */ 233162306a36Sopenharmony_ci while (1) { 233262306a36Sopenharmony_ci if (is_scanning_required) { 233362306a36Sopenharmony_ci /* Do specific SSID scanning */ 233462306a36Sopenharmony_ci if (mwifiex_request_scan(priv, &req_ssid)) { 233562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "scan error\n"); 233662306a36Sopenharmony_ci return -EFAULT; 233762306a36Sopenharmony_ci } 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci /* Find the BSS we want using available scan results */ 234162306a36Sopenharmony_ci if (mode == NL80211_IFTYPE_ADHOC) 234262306a36Sopenharmony_ci bss = cfg80211_get_bss(priv->wdev.wiphy, channel, 234362306a36Sopenharmony_ci bssid, ssid, ssid_len, 234462306a36Sopenharmony_ci IEEE80211_BSS_TYPE_IBSS, 234562306a36Sopenharmony_ci IEEE80211_PRIVACY_ANY); 234662306a36Sopenharmony_ci else 234762306a36Sopenharmony_ci bss = cfg80211_get_bss(priv->wdev.wiphy, channel, 234862306a36Sopenharmony_ci bssid, ssid, ssid_len, 234962306a36Sopenharmony_ci IEEE80211_BSS_TYPE_ESS, 235062306a36Sopenharmony_ci IEEE80211_PRIVACY_ANY); 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci if (!bss) { 235362306a36Sopenharmony_ci if (is_scanning_required) { 235462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 235562306a36Sopenharmony_ci "assoc: requested bss not found in scan results\n"); 235662306a36Sopenharmony_ci break; 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci is_scanning_required = 1; 235962306a36Sopenharmony_ci } else { 236062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 236162306a36Sopenharmony_ci "info: trying to associate to bssid %pM\n", 236262306a36Sopenharmony_ci bss->bssid); 236362306a36Sopenharmony_ci memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN); 236462306a36Sopenharmony_ci break; 236562306a36Sopenharmony_ci } 236662306a36Sopenharmony_ci } 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci if (bss) 236962306a36Sopenharmony_ci cfg80211_ref_bss(priv->adapter->wiphy, bss); 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci ret = mwifiex_bss_start(priv, bss, &req_ssid); 237262306a36Sopenharmony_ci if (ret) 237362306a36Sopenharmony_ci goto cleanup; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci if (mode == NL80211_IFTYPE_ADHOC) { 237662306a36Sopenharmony_ci /* Inform the BSS information to kernel, otherwise 237762306a36Sopenharmony_ci * kernel will give a panic after successful assoc */ 237862306a36Sopenharmony_ci if (mwifiex_cfg80211_inform_ibss_bss(priv)) { 237962306a36Sopenharmony_ci ret = -EFAULT; 238062306a36Sopenharmony_ci goto cleanup; 238162306a36Sopenharmony_ci } 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci /* Pass the selected BSS entry to caller. */ 238562306a36Sopenharmony_ci if (sel_bss) { 238662306a36Sopenharmony_ci *sel_bss = bss; 238762306a36Sopenharmony_ci bss = NULL; 238862306a36Sopenharmony_ci } 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_cicleanup: 239162306a36Sopenharmony_ci if (bss) 239262306a36Sopenharmony_ci cfg80211_put_bss(priv->adapter->wiphy, bss); 239362306a36Sopenharmony_ci return ret; 239462306a36Sopenharmony_ci} 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci/* 239762306a36Sopenharmony_ci * CFG802.11 operation handler for association request. 239862306a36Sopenharmony_ci * 239962306a36Sopenharmony_ci * This function does not work when the current mode is set to Ad-Hoc, or 240062306a36Sopenharmony_ci * when there is already an association procedure going on. The given BSS 240162306a36Sopenharmony_ci * information is used to associate. 240262306a36Sopenharmony_ci */ 240362306a36Sopenharmony_cistatic int 240462306a36Sopenharmony_cimwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, 240562306a36Sopenharmony_ci struct cfg80211_connect_params *sme) 240662306a36Sopenharmony_ci{ 240762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 240862306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 240962306a36Sopenharmony_ci struct cfg80211_bss *bss = NULL; 241062306a36Sopenharmony_ci int ret; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { 241362306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 241462306a36Sopenharmony_ci "%s: reject infra assoc request in non-STA role\n", 241562306a36Sopenharmony_ci dev->name); 241662306a36Sopenharmony_ci return -EINVAL; 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci if (priv->wdev.connected) { 242062306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 242162306a36Sopenharmony_ci "%s: already connected\n", dev->name); 242262306a36Sopenharmony_ci return -EALREADY; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci if (priv->scan_block) 242662306a36Sopenharmony_ci priv->scan_block = false; 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags) || 242962306a36Sopenharmony_ci test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags)) { 243062306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 243162306a36Sopenharmony_ci "%s: Ignore connection.\t" 243262306a36Sopenharmony_ci "Card removed or FW in bad state\n", 243362306a36Sopenharmony_ci dev->name); 243462306a36Sopenharmony_ci return -EFAULT; 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 243862306a36Sopenharmony_ci "info: Trying to associate to bssid %pM\n", sme->bssid); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (!mwifiex_stop_bg_scan(priv)) 244162306a36Sopenharmony_ci cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0); 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, 244462306a36Sopenharmony_ci priv->bss_mode, sme->channel, sme, 0, 244562306a36Sopenharmony_ci &bss); 244662306a36Sopenharmony_ci if (!ret) { 244762306a36Sopenharmony_ci cfg80211_connect_bss(priv->netdev, priv->cfg_bssid, bss, NULL, 244862306a36Sopenharmony_ci 0, NULL, 0, WLAN_STATUS_SUCCESS, 244962306a36Sopenharmony_ci GFP_KERNEL, NL80211_TIMEOUT_UNSPECIFIED); 245062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 245162306a36Sopenharmony_ci "info: associated to bssid %pM successfully\n", 245262306a36Sopenharmony_ci priv->cfg_bssid); 245362306a36Sopenharmony_ci if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && 245462306a36Sopenharmony_ci priv->adapter->auto_tdls && 245562306a36Sopenharmony_ci priv->bss_type == MWIFIEX_BSS_TYPE_STA) 245662306a36Sopenharmony_ci mwifiex_setup_auto_tdls_timer(priv); 245762306a36Sopenharmony_ci } else { 245862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 245962306a36Sopenharmony_ci "info: association to bssid %pM failed\n", 246062306a36Sopenharmony_ci priv->cfg_bssid); 246162306a36Sopenharmony_ci eth_zero_addr(priv->cfg_bssid); 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci if (ret > 0) 246462306a36Sopenharmony_ci cfg80211_connect_result(priv->netdev, priv->cfg_bssid, 246562306a36Sopenharmony_ci NULL, 0, NULL, 0, ret, 246662306a36Sopenharmony_ci GFP_KERNEL); 246762306a36Sopenharmony_ci else 246862306a36Sopenharmony_ci cfg80211_connect_result(priv->netdev, priv->cfg_bssid, 246962306a36Sopenharmony_ci NULL, 0, NULL, 0, 247062306a36Sopenharmony_ci WLAN_STATUS_UNSPECIFIED_FAILURE, 247162306a36Sopenharmony_ci GFP_KERNEL); 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci return 0; 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci/* 247862306a36Sopenharmony_ci * This function sets following parameters for ibss network. 247962306a36Sopenharmony_ci * - channel 248062306a36Sopenharmony_ci * - start band 248162306a36Sopenharmony_ci * - 11n flag 248262306a36Sopenharmony_ci * - secondary channel offset 248362306a36Sopenharmony_ci */ 248462306a36Sopenharmony_cistatic int mwifiex_set_ibss_params(struct mwifiex_private *priv, 248562306a36Sopenharmony_ci struct cfg80211_ibss_params *params) 248662306a36Sopenharmony_ci{ 248762306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 248862306a36Sopenharmony_ci int index = 0, i; 248962306a36Sopenharmony_ci u8 config_bands = 0; 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci if (params->chandef.chan->band == NL80211_BAND_2GHZ) { 249262306a36Sopenharmony_ci if (!params->basic_rates) { 249362306a36Sopenharmony_ci config_bands = BAND_B | BAND_G; 249462306a36Sopenharmony_ci } else { 249562306a36Sopenharmony_ci for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { 249662306a36Sopenharmony_ci /* 249762306a36Sopenharmony_ci * Rates below 6 Mbps in the table are CCK 249862306a36Sopenharmony_ci * rates; 802.11b and from 6 they are OFDM; 249962306a36Sopenharmony_ci * 802.11G 250062306a36Sopenharmony_ci */ 250162306a36Sopenharmony_ci if (mwifiex_rates[i].bitrate == 60) { 250262306a36Sopenharmony_ci index = 1 << i; 250362306a36Sopenharmony_ci break; 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci if (params->basic_rates < index) { 250862306a36Sopenharmony_ci config_bands = BAND_B; 250962306a36Sopenharmony_ci } else { 251062306a36Sopenharmony_ci config_bands = BAND_G; 251162306a36Sopenharmony_ci if (params->basic_rates % index) 251262306a36Sopenharmony_ci config_bands |= BAND_B; 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci } 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci if (cfg80211_get_chandef_type(¶ms->chandef) != 251762306a36Sopenharmony_ci NL80211_CHAN_NO_HT) 251862306a36Sopenharmony_ci config_bands |= BAND_G | BAND_GN; 251962306a36Sopenharmony_ci } else { 252062306a36Sopenharmony_ci if (cfg80211_get_chandef_type(¶ms->chandef) == 252162306a36Sopenharmony_ci NL80211_CHAN_NO_HT) 252262306a36Sopenharmony_ci config_bands = BAND_A; 252362306a36Sopenharmony_ci else 252462306a36Sopenharmony_ci config_bands = BAND_AN | BAND_A; 252562306a36Sopenharmony_ci } 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) { 252862306a36Sopenharmony_ci adapter->config_bands = config_bands; 252962306a36Sopenharmony_ci adapter->adhoc_start_band = config_bands; 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci if ((config_bands & BAND_GN) || (config_bands & BAND_AN)) 253262306a36Sopenharmony_ci adapter->adhoc_11n_enabled = true; 253362306a36Sopenharmony_ci else 253462306a36Sopenharmony_ci adapter->adhoc_11n_enabled = false; 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci adapter->sec_chan_offset = 253862306a36Sopenharmony_ci mwifiex_chan_type_to_sec_chan_offset( 253962306a36Sopenharmony_ci cfg80211_get_chandef_type(¶ms->chandef)); 254062306a36Sopenharmony_ci priv->adhoc_channel = ieee80211_frequency_to_channel( 254162306a36Sopenharmony_ci params->chandef.chan->center_freq); 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 254462306a36Sopenharmony_ci "info: set ibss band %d, chan %d, chan offset %d\n", 254562306a36Sopenharmony_ci config_bands, priv->adhoc_channel, 254662306a36Sopenharmony_ci adapter->sec_chan_offset); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci return 0; 254962306a36Sopenharmony_ci} 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci/* 255262306a36Sopenharmony_ci * CFG802.11 operation handler to join an IBSS. 255362306a36Sopenharmony_ci * 255462306a36Sopenharmony_ci * This function does not work in any mode other than Ad-Hoc, or if 255562306a36Sopenharmony_ci * a join operation is already in progress. 255662306a36Sopenharmony_ci */ 255762306a36Sopenharmony_cistatic int 255862306a36Sopenharmony_cimwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, 255962306a36Sopenharmony_ci struct cfg80211_ibss_params *params) 256062306a36Sopenharmony_ci{ 256162306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 256262306a36Sopenharmony_ci int ret = 0; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { 256562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 256662306a36Sopenharmony_ci "request to join ibss received\t" 256762306a36Sopenharmony_ci "when station is not in ibss mode\n"); 256862306a36Sopenharmony_ci goto done; 256962306a36Sopenharmony_ci } 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, "info: trying to join to bssid %pM\n", 257262306a36Sopenharmony_ci params->bssid); 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci mwifiex_set_ibss_params(priv, params); 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, 257762306a36Sopenharmony_ci params->bssid, priv->bss_mode, 257862306a36Sopenharmony_ci params->chandef.chan, NULL, 257962306a36Sopenharmony_ci params->privacy, NULL); 258062306a36Sopenharmony_cidone: 258162306a36Sopenharmony_ci if (!ret) { 258262306a36Sopenharmony_ci cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, 258362306a36Sopenharmony_ci params->chandef.chan, GFP_KERNEL); 258462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 258562306a36Sopenharmony_ci "info: joined/created adhoc network with bssid\t" 258662306a36Sopenharmony_ci "%pM successfully\n", priv->cfg_bssid); 258762306a36Sopenharmony_ci } else { 258862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 258962306a36Sopenharmony_ci "info: failed creating/joining adhoc network\n"); 259062306a36Sopenharmony_ci } 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci return ret; 259362306a36Sopenharmony_ci} 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci/* 259662306a36Sopenharmony_ci * CFG802.11 operation handler to leave an IBSS. 259762306a36Sopenharmony_ci * 259862306a36Sopenharmony_ci * This function does not work if a leave operation is 259962306a36Sopenharmony_ci * already in progress. 260062306a36Sopenharmony_ci */ 260162306a36Sopenharmony_cistatic int 260262306a36Sopenharmony_cimwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) 260362306a36Sopenharmony_ci{ 260462306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, "info: disconnecting from essid %pM\n", 260762306a36Sopenharmony_ci priv->cfg_bssid); 260862306a36Sopenharmony_ci if (mwifiex_deauthenticate(priv, NULL)) 260962306a36Sopenharmony_ci return -EFAULT; 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci eth_zero_addr(priv->cfg_bssid); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci return 0; 261462306a36Sopenharmony_ci} 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci/* 261762306a36Sopenharmony_ci * CFG802.11 operation handler for scan request. 261862306a36Sopenharmony_ci * 261962306a36Sopenharmony_ci * This function issues a scan request to the firmware based upon 262062306a36Sopenharmony_ci * the user specified scan configuration. On successful completion, 262162306a36Sopenharmony_ci * it also informs the results. 262262306a36Sopenharmony_ci */ 262362306a36Sopenharmony_cistatic int 262462306a36Sopenharmony_cimwifiex_cfg80211_scan(struct wiphy *wiphy, 262562306a36Sopenharmony_ci struct cfg80211_scan_request *request) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci struct net_device *dev = request->wdev->netdev; 262862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 262962306a36Sopenharmony_ci int i, offset, ret; 263062306a36Sopenharmony_ci struct ieee80211_channel *chan; 263162306a36Sopenharmony_ci struct ieee_types_header *ie; 263262306a36Sopenharmony_ci struct mwifiex_user_scan_cfg *user_scan_cfg; 263362306a36Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, CMD, 263662306a36Sopenharmony_ci "info: received scan request on %s\n", dev->name); 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci /* Block scan request if scan operation or scan cleanup when interface 263962306a36Sopenharmony_ci * is disabled is in process 264062306a36Sopenharmony_ci */ 264162306a36Sopenharmony_ci if (priv->scan_request || priv->scan_aborting) { 264262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, WARN, 264362306a36Sopenharmony_ci "cmd: Scan already in process..\n"); 264462306a36Sopenharmony_ci return -EBUSY; 264562306a36Sopenharmony_ci } 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci if (!priv->wdev.connected && priv->scan_block) 264862306a36Sopenharmony_ci priv->scan_block = false; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci if (!mwifiex_stop_bg_scan(priv)) 265162306a36Sopenharmony_ci cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0); 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); 265462306a36Sopenharmony_ci if (!user_scan_cfg) 265562306a36Sopenharmony_ci return -ENOMEM; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci priv->scan_request = request; 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { 266062306a36Sopenharmony_ci get_random_mask_addr(mac_addr, request->mac_addr, 266162306a36Sopenharmony_ci request->mac_addr_mask); 266262306a36Sopenharmony_ci ether_addr_copy(request->mac_addr, mac_addr); 266362306a36Sopenharmony_ci ether_addr_copy(user_scan_cfg->random_mac, mac_addr); 266462306a36Sopenharmony_ci } 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci user_scan_cfg->num_ssids = request->n_ssids; 266762306a36Sopenharmony_ci user_scan_cfg->ssid_list = request->ssids; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci if (request->ie && request->ie_len) { 267062306a36Sopenharmony_ci offset = 0; 267162306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { 267262306a36Sopenharmony_ci if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR) 267362306a36Sopenharmony_ci continue; 267462306a36Sopenharmony_ci priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_SCAN; 267562306a36Sopenharmony_ci ie = (struct ieee_types_header *)(request->ie + offset); 267662306a36Sopenharmony_ci memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len); 267762306a36Sopenharmony_ci offset += sizeof(*ie) + ie->len; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci if (offset >= request->ie_len) 268062306a36Sopenharmony_ci break; 268162306a36Sopenharmony_ci } 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci for (i = 0; i < min_t(u32, request->n_channels, 268562306a36Sopenharmony_ci MWIFIEX_USER_SCAN_CHAN_MAX); i++) { 268662306a36Sopenharmony_ci chan = request->channels[i]; 268762306a36Sopenharmony_ci user_scan_cfg->chan_list[i].chan_number = chan->hw_value; 268862306a36Sopenharmony_ci user_scan_cfg->chan_list[i].radio_type = chan->band; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids) 269162306a36Sopenharmony_ci user_scan_cfg->chan_list[i].scan_type = 269262306a36Sopenharmony_ci MWIFIEX_SCAN_TYPE_PASSIVE; 269362306a36Sopenharmony_ci else 269462306a36Sopenharmony_ci user_scan_cfg->chan_list[i].scan_type = 269562306a36Sopenharmony_ci MWIFIEX_SCAN_TYPE_ACTIVE; 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci user_scan_cfg->chan_list[i].scan_time = 0; 269862306a36Sopenharmony_ci } 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci if (priv->adapter->scan_chan_gap_enabled && 270162306a36Sopenharmony_ci mwifiex_is_any_intf_active(priv)) 270262306a36Sopenharmony_ci user_scan_cfg->scan_chan_gap = 270362306a36Sopenharmony_ci priv->adapter->scan_chan_gap_time; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci ret = mwifiex_scan_networks(priv, user_scan_cfg); 270662306a36Sopenharmony_ci kfree(user_scan_cfg); 270762306a36Sopenharmony_ci if (ret) { 270862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 270962306a36Sopenharmony_ci "scan failed: %d\n", ret); 271062306a36Sopenharmony_ci priv->scan_aborting = false; 271162306a36Sopenharmony_ci priv->scan_request = NULL; 271262306a36Sopenharmony_ci return ret; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci if (request->ie && request->ie_len) { 271662306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { 271762306a36Sopenharmony_ci if (priv->vs_ie[i].mask == MWIFIEX_VSIE_MASK_SCAN) { 271862306a36Sopenharmony_ci priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_CLEAR; 271962306a36Sopenharmony_ci memset(&priv->vs_ie[i].ie, 0, 272062306a36Sopenharmony_ci MWIFIEX_MAX_VSIE_LEN); 272162306a36Sopenharmony_ci } 272262306a36Sopenharmony_ci } 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci return 0; 272562306a36Sopenharmony_ci} 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci/* CFG802.11 operation handler for sched_scan_start. 272862306a36Sopenharmony_ci * 272962306a36Sopenharmony_ci * This function issues a bgscan config request to the firmware based upon 273062306a36Sopenharmony_ci * the user specified sched_scan configuration. On successful completion, 273162306a36Sopenharmony_ci * firmware will generate BGSCAN_REPORT event, driver should issue bgscan 273262306a36Sopenharmony_ci * query command to get sched_scan results from firmware. 273362306a36Sopenharmony_ci */ 273462306a36Sopenharmony_cistatic int 273562306a36Sopenharmony_cimwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy, 273662306a36Sopenharmony_ci struct net_device *dev, 273762306a36Sopenharmony_ci struct cfg80211_sched_scan_request *request) 273862306a36Sopenharmony_ci{ 273962306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 274062306a36Sopenharmony_ci int i, offset; 274162306a36Sopenharmony_ci struct ieee80211_channel *chan; 274262306a36Sopenharmony_ci struct mwifiex_bg_scan_cfg *bgscan_cfg; 274362306a36Sopenharmony_ci struct ieee_types_header *ie; 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci if (!request || (!request->n_ssids && !request->n_match_sets)) { 274662306a36Sopenharmony_ci wiphy_err(wiphy, "%s : Invalid Sched_scan parameters", 274762306a36Sopenharmony_ci __func__); 274862306a36Sopenharmony_ci return -EINVAL; 274962306a36Sopenharmony_ci } 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci wiphy_info(wiphy, "sched_scan start : n_ssids=%d n_match_sets=%d ", 275262306a36Sopenharmony_ci request->n_ssids, request->n_match_sets); 275362306a36Sopenharmony_ci wiphy_info(wiphy, "n_channels=%d interval=%d ie_len=%d\n", 275462306a36Sopenharmony_ci request->n_channels, request->scan_plans->interval, 275562306a36Sopenharmony_ci (int)request->ie_len); 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL); 275862306a36Sopenharmony_ci if (!bgscan_cfg) 275962306a36Sopenharmony_ci return -ENOMEM; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci if (priv->scan_request || priv->scan_aborting) 276262306a36Sopenharmony_ci bgscan_cfg->start_later = true; 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci bgscan_cfg->num_ssids = request->n_match_sets; 276562306a36Sopenharmony_ci bgscan_cfg->ssid_list = request->match_sets; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci if (request->ie && request->ie_len) { 276862306a36Sopenharmony_ci offset = 0; 276962306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { 277062306a36Sopenharmony_ci if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR) 277162306a36Sopenharmony_ci continue; 277262306a36Sopenharmony_ci priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_BGSCAN; 277362306a36Sopenharmony_ci ie = (struct ieee_types_header *)(request->ie + offset); 277462306a36Sopenharmony_ci memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len); 277562306a36Sopenharmony_ci offset += sizeof(*ie) + ie->len; 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci if (offset >= request->ie_len) 277862306a36Sopenharmony_ci break; 277962306a36Sopenharmony_ci } 278062306a36Sopenharmony_ci } 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci for (i = 0; i < min_t(u32, request->n_channels, 278362306a36Sopenharmony_ci MWIFIEX_BG_SCAN_CHAN_MAX); i++) { 278462306a36Sopenharmony_ci chan = request->channels[i]; 278562306a36Sopenharmony_ci bgscan_cfg->chan_list[i].chan_number = chan->hw_value; 278662306a36Sopenharmony_ci bgscan_cfg->chan_list[i].radio_type = chan->band; 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids) 278962306a36Sopenharmony_ci bgscan_cfg->chan_list[i].scan_type = 279062306a36Sopenharmony_ci MWIFIEX_SCAN_TYPE_PASSIVE; 279162306a36Sopenharmony_ci else 279262306a36Sopenharmony_ci bgscan_cfg->chan_list[i].scan_type = 279362306a36Sopenharmony_ci MWIFIEX_SCAN_TYPE_ACTIVE; 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci bgscan_cfg->chan_list[i].scan_time = 0; 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci bgscan_cfg->chan_per_scan = min_t(u32, request->n_channels, 279962306a36Sopenharmony_ci MWIFIEX_BG_SCAN_CHAN_MAX); 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci /* Use at least 15 second for per scan cycle */ 280262306a36Sopenharmony_ci bgscan_cfg->scan_interval = (request->scan_plans->interval > 280362306a36Sopenharmony_ci MWIFIEX_BGSCAN_INTERVAL) ? 280462306a36Sopenharmony_ci request->scan_plans->interval : 280562306a36Sopenharmony_ci MWIFIEX_BGSCAN_INTERVAL; 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci bgscan_cfg->repeat_count = MWIFIEX_BGSCAN_REPEAT_COUNT; 280862306a36Sopenharmony_ci bgscan_cfg->report_condition = MWIFIEX_BGSCAN_SSID_MATCH | 280962306a36Sopenharmony_ci MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE; 281062306a36Sopenharmony_ci bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA; 281162306a36Sopenharmony_ci bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET; 281262306a36Sopenharmony_ci bgscan_cfg->enable = true; 281362306a36Sopenharmony_ci if (request->min_rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) { 281462306a36Sopenharmony_ci bgscan_cfg->report_condition |= MWIFIEX_BGSCAN_SSID_RSSI_MATCH; 281562306a36Sopenharmony_ci bgscan_cfg->rssi_threshold = request->min_rssi_thold; 281662306a36Sopenharmony_ci } 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG, 281962306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) { 282062306a36Sopenharmony_ci kfree(bgscan_cfg); 282162306a36Sopenharmony_ci return -EFAULT; 282262306a36Sopenharmony_ci } 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci priv->sched_scanning = true; 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci kfree(bgscan_cfg); 282762306a36Sopenharmony_ci return 0; 282862306a36Sopenharmony_ci} 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci/* CFG802.11 operation handler for sched_scan_stop. 283162306a36Sopenharmony_ci * 283262306a36Sopenharmony_ci * This function issues a bgscan config command to disable 283362306a36Sopenharmony_ci * previous bgscan configuration in the firmware 283462306a36Sopenharmony_ci */ 283562306a36Sopenharmony_cistatic int mwifiex_cfg80211_sched_scan_stop(struct wiphy *wiphy, 283662306a36Sopenharmony_ci struct net_device *dev, u64 reqid) 283762306a36Sopenharmony_ci{ 283862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci wiphy_info(wiphy, "sched scan stop!"); 284162306a36Sopenharmony_ci mwifiex_stop_bg_scan(priv); 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci return 0; 284462306a36Sopenharmony_ci} 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_cistatic void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info, 284762306a36Sopenharmony_ci struct mwifiex_private *priv) 284862306a36Sopenharmony_ci{ 284962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci vht_info->vht_supported = true; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci vht_info->cap = adapter->hw_dot_11ac_dev_cap; 285462306a36Sopenharmony_ci /* Update MCS support for VHT */ 285562306a36Sopenharmony_ci vht_info->vht_mcs.rx_mcs_map = cpu_to_le16( 285662306a36Sopenharmony_ci adapter->hw_dot_11ac_mcs_support & 0xFFFF); 285762306a36Sopenharmony_ci vht_info->vht_mcs.rx_highest = 0; 285862306a36Sopenharmony_ci vht_info->vht_mcs.tx_mcs_map = cpu_to_le16( 285962306a36Sopenharmony_ci adapter->hw_dot_11ac_mcs_support >> 16); 286062306a36Sopenharmony_ci vht_info->vht_mcs.tx_highest = 0; 286162306a36Sopenharmony_ci} 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci/* 286462306a36Sopenharmony_ci * This function sets up the CFG802.11 specific HT capability fields 286562306a36Sopenharmony_ci * with default values. 286662306a36Sopenharmony_ci * 286762306a36Sopenharmony_ci * The following default values are set - 286862306a36Sopenharmony_ci * - HT Supported = True 286962306a36Sopenharmony_ci * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K 287062306a36Sopenharmony_ci * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE 287162306a36Sopenharmony_ci * - HT Capabilities supported by firmware 287262306a36Sopenharmony_ci * - MCS information, Rx mask = 0xff 287362306a36Sopenharmony_ci * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) 287462306a36Sopenharmony_ci */ 287562306a36Sopenharmony_cistatic void 287662306a36Sopenharmony_cimwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, 287762306a36Sopenharmony_ci struct mwifiex_private *priv) 287862306a36Sopenharmony_ci{ 287962306a36Sopenharmony_ci int rx_mcs_supp; 288062306a36Sopenharmony_ci struct ieee80211_mcs_info mcs_set; 288162306a36Sopenharmony_ci u8 *mcs = (u8 *)&mcs_set; 288262306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci ht_info->ht_supported = true; 288562306a36Sopenharmony_ci ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 288662306a36Sopenharmony_ci ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci /* Fill HT capability information */ 289162306a36Sopenharmony_ci if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) 289262306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 289362306a36Sopenharmony_ci else 289462306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) 289762306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_SGI_20; 289862306a36Sopenharmony_ci else 289962306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) 290262306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_SGI_40; 290362306a36Sopenharmony_ci else 290462306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci if (adapter->user_dev_mcs_support == HT_STREAM_2X2) 290762306a36Sopenharmony_ci ht_info->cap |= 2 << IEEE80211_HT_CAP_RX_STBC_SHIFT; 290862306a36Sopenharmony_ci else 290962306a36Sopenharmony_ci ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) 291262306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; 291362306a36Sopenharmony_ci else 291462306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_ci if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) 291762306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; 291862306a36Sopenharmony_ci else 291962306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_GRN_FLD; 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci if (ISENABLED_40MHZ_INTOLERANT(adapter->hw_dot_11n_dev_cap)) 292262306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; 292362306a36Sopenharmony_ci else 292462306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_40MHZ_INTOLERANT; 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci if (ISSUPP_RXLDPC(adapter->hw_dot_11n_dev_cap)) 292762306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; 292862306a36Sopenharmony_ci else 292962306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_LDPC_CODING; 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; 293262306a36Sopenharmony_ci ht_info->cap |= IEEE80211_HT_CAP_SM_PS; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci rx_mcs_supp = GET_RXMCSSUPP(adapter->user_dev_mcs_support); 293562306a36Sopenharmony_ci /* Set MCS for 1x1/2x2 */ 293662306a36Sopenharmony_ci memset(mcs, 0xff, rx_mcs_supp); 293762306a36Sopenharmony_ci /* Clear all the other values */ 293862306a36Sopenharmony_ci memset(&mcs[rx_mcs_supp], 0, 293962306a36Sopenharmony_ci sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); 294062306a36Sopenharmony_ci if (priv->bss_mode == NL80211_IFTYPE_STATION || 294162306a36Sopenharmony_ci ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) 294262306a36Sopenharmony_ci /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ 294362306a36Sopenharmony_ci SETHT_MCS32(mcs_set.rx_mask); 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info)); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 294862306a36Sopenharmony_ci} 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci/* 295162306a36Sopenharmony_ci * create a new virtual interface with the given name and name assign type 295262306a36Sopenharmony_ci */ 295362306a36Sopenharmony_cistruct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, 295462306a36Sopenharmony_ci const char *name, 295562306a36Sopenharmony_ci unsigned char name_assign_type, 295662306a36Sopenharmony_ci enum nl80211_iftype type, 295762306a36Sopenharmony_ci struct vif_params *params) 295862306a36Sopenharmony_ci{ 295962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 296062306a36Sopenharmony_ci struct mwifiex_private *priv; 296162306a36Sopenharmony_ci struct net_device *dev; 296262306a36Sopenharmony_ci void *mdev_priv; 296362306a36Sopenharmony_ci int ret; 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci if (!adapter) 296662306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci switch (type) { 296962306a36Sopenharmony_ci case NL80211_IFTYPE_UNSPECIFIED: 297062306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 297162306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 297262306a36Sopenharmony_ci if (adapter->curr_iface_comb.sta_intf == 297362306a36Sopenharmony_ci adapter->iface_limit.sta_intf) { 297462306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 297562306a36Sopenharmony_ci "cannot create multiple sta/adhoc ifaces\n"); 297662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 297762306a36Sopenharmony_ci } 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci priv = mwifiex_get_unused_priv_by_bss_type( 298062306a36Sopenharmony_ci adapter, MWIFIEX_BSS_TYPE_STA); 298162306a36Sopenharmony_ci if (!priv) { 298262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 298362306a36Sopenharmony_ci "could not get free private struct\n"); 298462306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 298562306a36Sopenharmony_ci } 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci priv->wdev.wiphy = wiphy; 298862306a36Sopenharmony_ci priv->wdev.iftype = NL80211_IFTYPE_STATION; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci if (type == NL80211_IFTYPE_UNSPECIFIED) 299162306a36Sopenharmony_ci priv->bss_mode = NL80211_IFTYPE_STATION; 299262306a36Sopenharmony_ci else 299362306a36Sopenharmony_ci priv->bss_mode = type; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci priv->bss_type = MWIFIEX_BSS_TYPE_STA; 299662306a36Sopenharmony_ci priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; 299762306a36Sopenharmony_ci priv->bss_priority = 0; 299862306a36Sopenharmony_ci priv->bss_role = MWIFIEX_BSS_ROLE_STA; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci break; 300162306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 300262306a36Sopenharmony_ci if (adapter->curr_iface_comb.uap_intf == 300362306a36Sopenharmony_ci adapter->iface_limit.uap_intf) { 300462306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 300562306a36Sopenharmony_ci "cannot create multiple AP ifaces\n"); 300662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci priv = mwifiex_get_unused_priv_by_bss_type( 301062306a36Sopenharmony_ci adapter, MWIFIEX_BSS_TYPE_UAP); 301162306a36Sopenharmony_ci if (!priv) { 301262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 301362306a36Sopenharmony_ci "could not get free private struct\n"); 301462306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 301562306a36Sopenharmony_ci } 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_ci priv->wdev.wiphy = wiphy; 301862306a36Sopenharmony_ci priv->wdev.iftype = NL80211_IFTYPE_AP; 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci priv->bss_type = MWIFIEX_BSS_TYPE_UAP; 302162306a36Sopenharmony_ci priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; 302262306a36Sopenharmony_ci priv->bss_priority = 0; 302362306a36Sopenharmony_ci priv->bss_role = MWIFIEX_BSS_ROLE_UAP; 302462306a36Sopenharmony_ci priv->bss_started = 0; 302562306a36Sopenharmony_ci priv->bss_mode = type; 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci break; 302862306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 302962306a36Sopenharmony_ci if (adapter->curr_iface_comb.p2p_intf == 303062306a36Sopenharmony_ci adapter->iface_limit.p2p_intf) { 303162306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 303262306a36Sopenharmony_ci "cannot create multiple P2P ifaces\n"); 303362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 303462306a36Sopenharmony_ci } 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci priv = mwifiex_get_unused_priv_by_bss_type( 303762306a36Sopenharmony_ci adapter, MWIFIEX_BSS_TYPE_P2P); 303862306a36Sopenharmony_ci if (!priv) { 303962306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 304062306a36Sopenharmony_ci "could not get free private struct\n"); 304162306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 304262306a36Sopenharmony_ci } 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci priv->wdev.wiphy = wiphy; 304562306a36Sopenharmony_ci /* At start-up, wpa_supplicant tries to change the interface 304662306a36Sopenharmony_ci * to NL80211_IFTYPE_STATION if it is not managed mode. 304762306a36Sopenharmony_ci */ 304862306a36Sopenharmony_ci priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; 304962306a36Sopenharmony_ci priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT; 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ci /* Setting bss_type to P2P tells firmware that this interface 305262306a36Sopenharmony_ci * is receiving P2P peers found during find phase and doing 305362306a36Sopenharmony_ci * action frame handshake. 305462306a36Sopenharmony_ci */ 305562306a36Sopenharmony_ci priv->bss_type = MWIFIEX_BSS_TYPE_P2P; 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; 305862306a36Sopenharmony_ci priv->bss_priority = 0; 305962306a36Sopenharmony_ci priv->bss_role = MWIFIEX_BSS_ROLE_STA; 306062306a36Sopenharmony_ci priv->bss_started = 0; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci if (mwifiex_cfg80211_init_p2p_client(priv)) { 306362306a36Sopenharmony_ci memset(&priv->wdev, 0, sizeof(priv->wdev)); 306462306a36Sopenharmony_ci priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; 306562306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 306662306a36Sopenharmony_ci } 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci break; 306962306a36Sopenharmony_ci default: 307062306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "type not supported\n"); 307162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 307262306a36Sopenharmony_ci } 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name, 307562306a36Sopenharmony_ci name_assign_type, ether_setup, 307662306a36Sopenharmony_ci IEEE80211_NUM_ACS, 1); 307762306a36Sopenharmony_ci if (!dev) { 307862306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 307962306a36Sopenharmony_ci "no memory available for netdevice\n"); 308062306a36Sopenharmony_ci ret = -ENOMEM; 308162306a36Sopenharmony_ci goto err_alloc_netdev; 308262306a36Sopenharmony_ci } 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci mwifiex_init_priv_params(priv, dev); 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci priv->netdev = dev; 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci if (!adapter->mfg_mode) { 308962306a36Sopenharmony_ci mwifiex_set_mac_address(priv, dev, false, NULL); 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, 309262306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true); 309362306a36Sopenharmony_ci if (ret) 309462306a36Sopenharmony_ci goto err_set_bss_mode; 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci ret = mwifiex_sta_init_cmd(priv, false, false); 309762306a36Sopenharmony_ci if (ret) 309862306a36Sopenharmony_ci goto err_sta_init; 309962306a36Sopenharmony_ci } 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv); 310262306a36Sopenharmony_ci if (adapter->is_hw_11ac_capable) 310362306a36Sopenharmony_ci mwifiex_setup_vht_caps( 310462306a36Sopenharmony_ci &wiphy->bands[NL80211_BAND_2GHZ]->vht_cap, priv); 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci if (adapter->config_bands & BAND_A) 310762306a36Sopenharmony_ci mwifiex_setup_ht_caps( 310862306a36Sopenharmony_ci &wiphy->bands[NL80211_BAND_5GHZ]->ht_cap, priv); 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci if ((adapter->config_bands & BAND_A) && adapter->is_hw_11ac_capable) 311162306a36Sopenharmony_ci mwifiex_setup_vht_caps( 311262306a36Sopenharmony_ci &wiphy->bands[NL80211_BAND_5GHZ]->vht_cap, priv); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci dev_net_set(dev, wiphy_net(wiphy)); 311562306a36Sopenharmony_ci dev->ieee80211_ptr = &priv->wdev; 311662306a36Sopenharmony_ci dev->ieee80211_ptr->iftype = priv->bss_mode; 311762306a36Sopenharmony_ci SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci dev->flags |= IFF_BROADCAST | IFF_MULTICAST; 312062306a36Sopenharmony_ci dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; 312162306a36Sopenharmony_ci dev->needed_headroom = MWIFIEX_MIN_DATA_HEADER_LEN; 312262306a36Sopenharmony_ci dev->ethtool_ops = &mwifiex_ethtool_ops; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci mdev_priv = netdev_priv(dev); 312562306a36Sopenharmony_ci *((unsigned long *) mdev_priv) = (unsigned long) priv; 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci SET_NETDEV_DEV(dev, adapter->dev); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC%s", 313062306a36Sopenharmony_ci WQ_HIGHPRI | 313162306a36Sopenharmony_ci WQ_MEM_RECLAIM | 313262306a36Sopenharmony_ci WQ_UNBOUND, 0, name); 313362306a36Sopenharmony_ci if (!priv->dfs_cac_workqueue) { 313462306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "cannot alloc DFS CAC queue\n"); 313562306a36Sopenharmony_ci ret = -ENOMEM; 313662306a36Sopenharmony_ci goto err_alloc_cac; 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci priv->dfs_chan_sw_workqueue = alloc_workqueue("MWIFIEX_DFS_CHSW%s", 314262306a36Sopenharmony_ci WQ_HIGHPRI | WQ_UNBOUND | 314362306a36Sopenharmony_ci WQ_MEM_RECLAIM, 0, name); 314462306a36Sopenharmony_ci if (!priv->dfs_chan_sw_workqueue) { 314562306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "cannot alloc DFS channel sw queue\n"); 314662306a36Sopenharmony_ci ret = -ENOMEM; 314762306a36Sopenharmony_ci goto err_alloc_chsw; 314862306a36Sopenharmony_ci } 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, 315162306a36Sopenharmony_ci mwifiex_dfs_chan_sw_work_queue); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci mutex_init(&priv->async_mutex); 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci /* Register network device */ 315662306a36Sopenharmony_ci if (cfg80211_register_netdevice(dev)) { 315762306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "cannot register network device\n"); 315862306a36Sopenharmony_ci ret = -EFAULT; 315962306a36Sopenharmony_ci goto err_reg_netdev; 316062306a36Sopenharmony_ci } 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 316362306a36Sopenharmony_ci "info: %s: Marvell 802.11 Adapter\n", dev->name); 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 316662306a36Sopenharmony_ci mwifiex_dev_debugfs_init(priv); 316762306a36Sopenharmony_ci#endif 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci update_vif_type_counter(adapter, type, +1); 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci return &priv->wdev; 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_cierr_reg_netdev: 317462306a36Sopenharmony_ci destroy_workqueue(priv->dfs_chan_sw_workqueue); 317562306a36Sopenharmony_ci priv->dfs_chan_sw_workqueue = NULL; 317662306a36Sopenharmony_cierr_alloc_chsw: 317762306a36Sopenharmony_ci destroy_workqueue(priv->dfs_cac_workqueue); 317862306a36Sopenharmony_ci priv->dfs_cac_workqueue = NULL; 317962306a36Sopenharmony_cierr_alloc_cac: 318062306a36Sopenharmony_ci free_netdev(dev); 318162306a36Sopenharmony_ci priv->netdev = NULL; 318262306a36Sopenharmony_cierr_sta_init: 318362306a36Sopenharmony_cierr_set_bss_mode: 318462306a36Sopenharmony_cierr_alloc_netdev: 318562306a36Sopenharmony_ci memset(&priv->wdev, 0, sizeof(priv->wdev)); 318662306a36Sopenharmony_ci priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; 318762306a36Sopenharmony_ci priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; 318862306a36Sopenharmony_ci return ERR_PTR(ret); 318962306a36Sopenharmony_ci} 319062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci/* 319362306a36Sopenharmony_ci * del_virtual_intf: remove the virtual interface determined by dev 319462306a36Sopenharmony_ci */ 319562306a36Sopenharmony_ciint mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) 319662306a36Sopenharmony_ci{ 319762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); 319862306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 319962306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 320262306a36Sopenharmony_ci mwifiex_dev_debugfs_remove(priv); 320362306a36Sopenharmony_ci#endif 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci if (priv->sched_scanning) 320662306a36Sopenharmony_ci priv->sched_scanning = false; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci mwifiex_stop_net_dev_queue(priv->netdev, adapter); 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) { 321162306a36Sopenharmony_ci skb_unlink(skb, &priv->bypass_txq); 321262306a36Sopenharmony_ci mwifiex_write_data_complete(priv->adapter, skb, 0, -1); 321362306a36Sopenharmony_ci } 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci if (netif_carrier_ok(priv->netdev)) 321662306a36Sopenharmony_ci netif_carrier_off(priv->netdev); 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci if (wdev->netdev->reg_state == NETREG_REGISTERED) 321962306a36Sopenharmony_ci cfg80211_unregister_netdevice(wdev->netdev); 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci if (priv->dfs_cac_workqueue) { 322262306a36Sopenharmony_ci destroy_workqueue(priv->dfs_cac_workqueue); 322362306a36Sopenharmony_ci priv->dfs_cac_workqueue = NULL; 322462306a36Sopenharmony_ci } 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_ci if (priv->dfs_chan_sw_workqueue) { 322762306a36Sopenharmony_ci destroy_workqueue(priv->dfs_chan_sw_workqueue); 322862306a36Sopenharmony_ci priv->dfs_chan_sw_workqueue = NULL; 322962306a36Sopenharmony_ci } 323062306a36Sopenharmony_ci /* Clear the priv in adapter */ 323162306a36Sopenharmony_ci priv->netdev = NULL; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci update_vif_type_counter(adapter, priv->bss_mode, -1); 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || 323862306a36Sopenharmony_ci GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) 323962306a36Sopenharmony_ci kfree(priv->hist_data); 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci return 0; 324262306a36Sopenharmony_ci} 324362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_cistatic bool 324662306a36Sopenharmony_cimwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, 324762306a36Sopenharmony_ci u8 max_byte_seq) 324862306a36Sopenharmony_ci{ 324962306a36Sopenharmony_ci int j, k, valid_byte_cnt = 0; 325062306a36Sopenharmony_ci bool dont_care_byte = false; 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) { 325362306a36Sopenharmony_ci for (k = 0; k < 8; k++) { 325462306a36Sopenharmony_ci if (pat->mask[j] & 1 << k) { 325562306a36Sopenharmony_ci memcpy(byte_seq + valid_byte_cnt, 325662306a36Sopenharmony_ci &pat->pattern[j * 8 + k], 1); 325762306a36Sopenharmony_ci valid_byte_cnt++; 325862306a36Sopenharmony_ci if (dont_care_byte) 325962306a36Sopenharmony_ci return false; 326062306a36Sopenharmony_ci } else { 326162306a36Sopenharmony_ci if (valid_byte_cnt) 326262306a36Sopenharmony_ci dont_care_byte = true; 326362306a36Sopenharmony_ci } 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci /* wildcard bytes record as the offset 326662306a36Sopenharmony_ci * before the valid byte 326762306a36Sopenharmony_ci */ 326862306a36Sopenharmony_ci if (!valid_byte_cnt && !dont_care_byte) 326962306a36Sopenharmony_ci pat->pkt_offset++; 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci if (valid_byte_cnt > max_byte_seq) 327262306a36Sopenharmony_ci return false; 327362306a36Sopenharmony_ci } 327462306a36Sopenharmony_ci } 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci byte_seq[max_byte_seq] = valid_byte_cnt; 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci return true; 327962306a36Sopenharmony_ci} 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci#ifdef CONFIG_PM 328262306a36Sopenharmony_cistatic void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv, 328362306a36Sopenharmony_ci struct mwifiex_mef_entry *mef_entry) 328462306a36Sopenharmony_ci{ 328562306a36Sopenharmony_ci int i, filt_num = 0, num_ipv4 = 0; 328662306a36Sopenharmony_ci struct in_device *in_dev; 328762306a36Sopenharmony_ci struct in_ifaddr *ifa; 328862306a36Sopenharmony_ci __be32 ips[MWIFIEX_MAX_SUPPORTED_IPADDR]; 328962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci mef_entry->mode = MEF_MODE_HOST_SLEEP; 329262306a36Sopenharmony_ci mef_entry->action = MEF_ACTION_AUTO_ARP; 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci /* Enable ARP offload feature */ 329562306a36Sopenharmony_ci memset(ips, 0, sizeof(ips)); 329662306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { 329762306a36Sopenharmony_ci if (adapter->priv[i]->netdev) { 329862306a36Sopenharmony_ci in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev); 329962306a36Sopenharmony_ci if (!in_dev) 330062306a36Sopenharmony_ci continue; 330162306a36Sopenharmony_ci ifa = rtnl_dereference(in_dev->ifa_list); 330262306a36Sopenharmony_ci if (!ifa || !ifa->ifa_local) 330362306a36Sopenharmony_ci continue; 330462306a36Sopenharmony_ci ips[i] = ifa->ifa_local; 330562306a36Sopenharmony_ci num_ipv4++; 330662306a36Sopenharmony_ci } 330762306a36Sopenharmony_ci } 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_ci for (i = 0; i < num_ipv4; i++) { 331062306a36Sopenharmony_ci if (!ips[i]) 331162306a36Sopenharmony_ci continue; 331262306a36Sopenharmony_ci mef_entry->filter[filt_num].repeat = 1; 331362306a36Sopenharmony_ci memcpy(mef_entry->filter[filt_num].byte_seq, 331462306a36Sopenharmony_ci (u8 *)&ips[i], sizeof(ips[i])); 331562306a36Sopenharmony_ci mef_entry->filter[filt_num]. 331662306a36Sopenharmony_ci byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 331762306a36Sopenharmony_ci sizeof(ips[i]); 331862306a36Sopenharmony_ci mef_entry->filter[filt_num].offset = 46; 331962306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_type = TYPE_EQ; 332062306a36Sopenharmony_ci if (filt_num) { 332162306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_action = 332262306a36Sopenharmony_ci TYPE_OR; 332362306a36Sopenharmony_ci } 332462306a36Sopenharmony_ci filt_num++; 332562306a36Sopenharmony_ci } 332662306a36Sopenharmony_ci 332762306a36Sopenharmony_ci mef_entry->filter[filt_num].repeat = 1; 332862306a36Sopenharmony_ci mef_entry->filter[filt_num].byte_seq[0] = 0x08; 332962306a36Sopenharmony_ci mef_entry->filter[filt_num].byte_seq[1] = 0x06; 333062306a36Sopenharmony_ci mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 2; 333162306a36Sopenharmony_ci mef_entry->filter[filt_num].offset = 20; 333262306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_type = TYPE_EQ; 333362306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_action = TYPE_AND; 333462306a36Sopenharmony_ci} 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_cistatic int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, 333762306a36Sopenharmony_ci struct mwifiex_ds_mef_cfg *mef_cfg, 333862306a36Sopenharmony_ci struct mwifiex_mef_entry *mef_entry, 333962306a36Sopenharmony_ci struct cfg80211_wowlan *wowlan) 334062306a36Sopenharmony_ci{ 334162306a36Sopenharmony_ci int i, filt_num = 0, ret = 0; 334262306a36Sopenharmony_ci bool first_pat = true; 334362306a36Sopenharmony_ci u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; 334462306a36Sopenharmony_ci static const u8 ipv4_mc_mac[] = {0x33, 0x33}; 334562306a36Sopenharmony_ci static const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci mef_entry->mode = MEF_MODE_HOST_SLEEP; 334862306a36Sopenharmony_ci mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST; 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci for (i = 0; i < wowlan->n_patterns; i++) { 335162306a36Sopenharmony_ci memset(byte_seq, 0, sizeof(byte_seq)); 335262306a36Sopenharmony_ci if (!mwifiex_is_pattern_supported(&wowlan->patterns[i], 335362306a36Sopenharmony_ci byte_seq, 335462306a36Sopenharmony_ci MWIFIEX_MEF_MAX_BYTESEQ)) { 335562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 335662306a36Sopenharmony_ci "Pattern not supported\n"); 335762306a36Sopenharmony_ci return -EOPNOTSUPP; 335862306a36Sopenharmony_ci } 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci if (!wowlan->patterns[i].pkt_offset) { 336162306a36Sopenharmony_ci if (!(byte_seq[0] & 0x01) && 336262306a36Sopenharmony_ci (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { 336362306a36Sopenharmony_ci mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; 336462306a36Sopenharmony_ci continue; 336562306a36Sopenharmony_ci } else if (is_broadcast_ether_addr(byte_seq)) { 336662306a36Sopenharmony_ci mef_cfg->criteria |= MWIFIEX_CRITERIA_BROADCAST; 336762306a36Sopenharmony_ci continue; 336862306a36Sopenharmony_ci } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && 336962306a36Sopenharmony_ci (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) || 337062306a36Sopenharmony_ci (!memcmp(byte_seq, ipv6_mc_mac, 3) && 337162306a36Sopenharmony_ci (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) { 337262306a36Sopenharmony_ci mef_cfg->criteria |= MWIFIEX_CRITERIA_MULTICAST; 337362306a36Sopenharmony_ci continue; 337462306a36Sopenharmony_ci } 337562306a36Sopenharmony_ci } 337662306a36Sopenharmony_ci mef_entry->filter[filt_num].repeat = 1; 337762306a36Sopenharmony_ci mef_entry->filter[filt_num].offset = 337862306a36Sopenharmony_ci wowlan->patterns[i].pkt_offset; 337962306a36Sopenharmony_ci memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq, 338062306a36Sopenharmony_ci sizeof(byte_seq)); 338162306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_type = TYPE_EQ; 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci if (first_pat) { 338462306a36Sopenharmony_ci first_pat = false; 338562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "Wake on patterns\n"); 338662306a36Sopenharmony_ci } else { 338762306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_action = TYPE_AND; 338862306a36Sopenharmony_ci } 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci filt_num++; 339162306a36Sopenharmony_ci } 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci if (wowlan->magic_pkt) { 339462306a36Sopenharmony_ci mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; 339562306a36Sopenharmony_ci mef_entry->filter[filt_num].repeat = 16; 339662306a36Sopenharmony_ci memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, 339762306a36Sopenharmony_ci ETH_ALEN); 339862306a36Sopenharmony_ci mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 339962306a36Sopenharmony_ci ETH_ALEN; 340062306a36Sopenharmony_ci mef_entry->filter[filt_num].offset = 28; 340162306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_type = TYPE_EQ; 340262306a36Sopenharmony_ci if (filt_num) 340362306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_action = TYPE_OR; 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci filt_num++; 340662306a36Sopenharmony_ci mef_entry->filter[filt_num].repeat = 16; 340762306a36Sopenharmony_ci memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, 340862306a36Sopenharmony_ci ETH_ALEN); 340962306a36Sopenharmony_ci mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 341062306a36Sopenharmony_ci ETH_ALEN; 341162306a36Sopenharmony_ci mef_entry->filter[filt_num].offset = 56; 341262306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_type = TYPE_EQ; 341362306a36Sopenharmony_ci mef_entry->filter[filt_num].filt_action = TYPE_OR; 341462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "Wake on magic packet\n"); 341562306a36Sopenharmony_ci } 341662306a36Sopenharmony_ci return ret; 341762306a36Sopenharmony_ci} 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_cistatic int mwifiex_set_mef_filter(struct mwifiex_private *priv, 342062306a36Sopenharmony_ci struct cfg80211_wowlan *wowlan) 342162306a36Sopenharmony_ci{ 342262306a36Sopenharmony_ci int ret = 0, num_entries = 1; 342362306a36Sopenharmony_ci struct mwifiex_ds_mef_cfg mef_cfg; 342462306a36Sopenharmony_ci struct mwifiex_mef_entry *mef_entry; 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_ci if (wowlan->n_patterns || wowlan->magic_pkt) 342762306a36Sopenharmony_ci num_entries++; 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci mef_entry = kcalloc(num_entries, sizeof(*mef_entry), GFP_KERNEL); 343062306a36Sopenharmony_ci if (!mef_entry) 343162306a36Sopenharmony_ci return -ENOMEM; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci memset(&mef_cfg, 0, sizeof(mef_cfg)); 343462306a36Sopenharmony_ci mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST | 343562306a36Sopenharmony_ci MWIFIEX_CRITERIA_UNICAST; 343662306a36Sopenharmony_ci mef_cfg.num_entries = num_entries; 343762306a36Sopenharmony_ci mef_cfg.mef_entry = mef_entry; 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]); 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci if (wowlan->n_patterns || wowlan->magic_pkt) { 344262306a36Sopenharmony_ci ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg, 344362306a36Sopenharmony_ci &mef_entry[1], wowlan); 344462306a36Sopenharmony_ci if (ret) 344562306a36Sopenharmony_ci goto err; 344662306a36Sopenharmony_ci } 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci if (!mef_cfg.criteria) 344962306a36Sopenharmony_ci mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | 345062306a36Sopenharmony_ci MWIFIEX_CRITERIA_UNICAST | 345162306a36Sopenharmony_ci MWIFIEX_CRITERIA_MULTICAST; 345262306a36Sopenharmony_ci 345362306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, 345462306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 345562306a36Sopenharmony_ci &mef_cfg, true); 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_cierr: 345862306a36Sopenharmony_ci kfree(mef_entry); 345962306a36Sopenharmony_ci return ret; 346062306a36Sopenharmony_ci} 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_cistatic int mwifiex_cfg80211_suspend(struct wiphy *wiphy, 346362306a36Sopenharmony_ci struct cfg80211_wowlan *wowlan) 346462306a36Sopenharmony_ci{ 346562306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 346662306a36Sopenharmony_ci struct mwifiex_ds_hs_cfg hs_cfg; 346762306a36Sopenharmony_ci int i, ret = 0, retry_num = 10; 346862306a36Sopenharmony_ci struct mwifiex_private *priv; 346962306a36Sopenharmony_ci struct mwifiex_private *sta_priv = 347062306a36Sopenharmony_ci mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci sta_priv->scan_aborting = true; 347362306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 347462306a36Sopenharmony_ci priv = adapter->priv[i]; 347562306a36Sopenharmony_ci mwifiex_abort_cac(priv); 347662306a36Sopenharmony_ci } 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci mwifiex_cancel_all_pending_cmd(adapter); 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 348162306a36Sopenharmony_ci priv = adapter->priv[i]; 348262306a36Sopenharmony_ci if (priv && priv->netdev) 348362306a36Sopenharmony_ci netif_device_detach(priv->netdev); 348462306a36Sopenharmony_ci } 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci for (i = 0; i < retry_num; i++) { 348762306a36Sopenharmony_ci if (!mwifiex_wmm_lists_empty(adapter) || 348862306a36Sopenharmony_ci !mwifiex_bypass_txlist_empty(adapter) || 348962306a36Sopenharmony_ci !skb_queue_empty(&adapter->tx_data_q)) 349062306a36Sopenharmony_ci usleep_range(10000, 15000); 349162306a36Sopenharmony_ci else 349262306a36Sopenharmony_ci break; 349362306a36Sopenharmony_ci } 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci if (!wowlan) { 349662306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 349762306a36Sopenharmony_ci "None of the WOWLAN triggers enabled\n"); 349862306a36Sopenharmony_ci ret = 0; 349962306a36Sopenharmony_ci goto done; 350062306a36Sopenharmony_ci } 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci if (!sta_priv->media_connected && !wowlan->nd_config) { 350362306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 350462306a36Sopenharmony_ci "Can not configure WOWLAN in disconnected state\n"); 350562306a36Sopenharmony_ci ret = 0; 350662306a36Sopenharmony_ci goto done; 350762306a36Sopenharmony_ci } 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci ret = mwifiex_set_mef_filter(sta_priv, wowlan); 351062306a36Sopenharmony_ci if (ret) { 351162306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "Failed to set MEF filter\n"); 351262306a36Sopenharmony_ci goto done; 351362306a36Sopenharmony_ci } 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci memset(&hs_cfg, 0, sizeof(hs_cfg)); 351662306a36Sopenharmony_ci hs_cfg.conditions = le32_to_cpu(adapter->hs_cfg.conditions); 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci if (wowlan->nd_config) { 351962306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "Wake on net detect\n"); 352062306a36Sopenharmony_ci hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; 352162306a36Sopenharmony_ci mwifiex_cfg80211_sched_scan_start(wiphy, sta_priv->netdev, 352262306a36Sopenharmony_ci wowlan->nd_config); 352362306a36Sopenharmony_ci } 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_ci if (wowlan->disconnect) { 352662306a36Sopenharmony_ci hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT; 352762306a36Sopenharmony_ci mwifiex_dbg(sta_priv->adapter, INFO, "Wake on device disconnect\n"); 352862306a36Sopenharmony_ci } 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci hs_cfg.is_invoke_hostcmd = false; 353162306a36Sopenharmony_ci hs_cfg.gpio = adapter->hs_cfg.gpio; 353262306a36Sopenharmony_ci hs_cfg.gap = adapter->hs_cfg.gap; 353362306a36Sopenharmony_ci ret = mwifiex_set_hs_params(sta_priv, HostCmd_ACT_GEN_SET, 353462306a36Sopenharmony_ci MWIFIEX_SYNC_CMD, &hs_cfg); 353562306a36Sopenharmony_ci if (ret) 353662306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "Failed to set HS params\n"); 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_cidone: 353962306a36Sopenharmony_ci sta_priv->scan_aborting = false; 354062306a36Sopenharmony_ci return ret; 354162306a36Sopenharmony_ci} 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_cistatic int mwifiex_cfg80211_resume(struct wiphy *wiphy) 354462306a36Sopenharmony_ci{ 354562306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 354662306a36Sopenharmony_ci struct mwifiex_private *priv; 354762306a36Sopenharmony_ci struct mwifiex_ds_wakeup_reason wakeup_reason; 354862306a36Sopenharmony_ci struct cfg80211_wowlan_wakeup wakeup_report; 354962306a36Sopenharmony_ci int i; 355062306a36Sopenharmony_ci bool report_wakeup_reason = true; 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 355362306a36Sopenharmony_ci priv = adapter->priv[i]; 355462306a36Sopenharmony_ci if (priv && priv->netdev) 355562306a36Sopenharmony_ci netif_device_attach(priv->netdev); 355662306a36Sopenharmony_ci } 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci if (!wiphy->wowlan_config) 355962306a36Sopenharmony_ci goto done; 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); 356262306a36Sopenharmony_ci mwifiex_get_wakeup_reason(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD, 356362306a36Sopenharmony_ci &wakeup_reason); 356462306a36Sopenharmony_ci memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup)); 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_ci wakeup_report.pattern_idx = -1; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci switch (wakeup_reason.hs_wakeup_reason) { 356962306a36Sopenharmony_ci case NO_HSWAKEUP_REASON: 357062306a36Sopenharmony_ci break; 357162306a36Sopenharmony_ci case BCAST_DATA_MATCHED: 357262306a36Sopenharmony_ci break; 357362306a36Sopenharmony_ci case MCAST_DATA_MATCHED: 357462306a36Sopenharmony_ci break; 357562306a36Sopenharmony_ci case UCAST_DATA_MATCHED: 357662306a36Sopenharmony_ci break; 357762306a36Sopenharmony_ci case MASKTABLE_EVENT_MATCHED: 357862306a36Sopenharmony_ci break; 357962306a36Sopenharmony_ci case NON_MASKABLE_EVENT_MATCHED: 358062306a36Sopenharmony_ci if (wiphy->wowlan_config->disconnect) 358162306a36Sopenharmony_ci wakeup_report.disconnect = true; 358262306a36Sopenharmony_ci if (wiphy->wowlan_config->nd_config) 358362306a36Sopenharmony_ci wakeup_report.net_detect = adapter->nd_info; 358462306a36Sopenharmony_ci break; 358562306a36Sopenharmony_ci case NON_MASKABLE_CONDITION_MATCHED: 358662306a36Sopenharmony_ci break; 358762306a36Sopenharmony_ci case MAGIC_PATTERN_MATCHED: 358862306a36Sopenharmony_ci if (wiphy->wowlan_config->magic_pkt) 358962306a36Sopenharmony_ci wakeup_report.magic_pkt = true; 359062306a36Sopenharmony_ci if (wiphy->wowlan_config->n_patterns) 359162306a36Sopenharmony_ci wakeup_report.pattern_idx = 1; 359262306a36Sopenharmony_ci break; 359362306a36Sopenharmony_ci case GTK_REKEY_FAILURE: 359462306a36Sopenharmony_ci if (wiphy->wowlan_config->gtk_rekey_failure) 359562306a36Sopenharmony_ci wakeup_report.gtk_rekey_failure = true; 359662306a36Sopenharmony_ci break; 359762306a36Sopenharmony_ci default: 359862306a36Sopenharmony_ci report_wakeup_reason = false; 359962306a36Sopenharmony_ci break; 360062306a36Sopenharmony_ci } 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci if (report_wakeup_reason) 360362306a36Sopenharmony_ci cfg80211_report_wowlan_wakeup(&priv->wdev, &wakeup_report, 360462306a36Sopenharmony_ci GFP_KERNEL); 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_cidone: 360762306a36Sopenharmony_ci if (adapter->nd_info) { 360862306a36Sopenharmony_ci for (i = 0 ; i < adapter->nd_info->n_matches ; i++) 360962306a36Sopenharmony_ci kfree(adapter->nd_info->matches[i]); 361062306a36Sopenharmony_ci kfree(adapter->nd_info); 361162306a36Sopenharmony_ci adapter->nd_info = NULL; 361262306a36Sopenharmony_ci } 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci return 0; 361562306a36Sopenharmony_ci} 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_cistatic void mwifiex_cfg80211_set_wakeup(struct wiphy *wiphy, 361862306a36Sopenharmony_ci bool enabled) 361962306a36Sopenharmony_ci{ 362062306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci device_set_wakeup_enable(adapter->dev, enabled); 362362306a36Sopenharmony_ci} 362462306a36Sopenharmony_ci 362562306a36Sopenharmony_cistatic int mwifiex_set_rekey_data(struct wiphy *wiphy, struct net_device *dev, 362662306a36Sopenharmony_ci struct cfg80211_gtk_rekey_data *data) 362762306a36Sopenharmony_ci{ 362862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci if (!ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) 363162306a36Sopenharmony_ci return -EOPNOTSUPP; 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG, 363462306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, data, true); 363562306a36Sopenharmony_ci} 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci#endif 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_cistatic int mwifiex_get_coalesce_pkt_type(u8 *byte_seq) 364062306a36Sopenharmony_ci{ 364162306a36Sopenharmony_ci static const u8 ipv4_mc_mac[] = {0x33, 0x33}; 364262306a36Sopenharmony_ci static const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; 364362306a36Sopenharmony_ci static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff}; 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci if ((byte_seq[0] & 0x01) && 364662306a36Sopenharmony_ci (byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 1)) 364762306a36Sopenharmony_ci return PACKET_TYPE_UNICAST; 364862306a36Sopenharmony_ci else if (!memcmp(byte_seq, bc_mac, 4)) 364962306a36Sopenharmony_ci return PACKET_TYPE_BROADCAST; 365062306a36Sopenharmony_ci else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && 365162306a36Sopenharmony_ci byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 2) || 365262306a36Sopenharmony_ci (!memcmp(byte_seq, ipv6_mc_mac, 3) && 365362306a36Sopenharmony_ci byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ] == 3)) 365462306a36Sopenharmony_ci return PACKET_TYPE_MULTICAST; 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci return 0; 365762306a36Sopenharmony_ci} 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_cistatic int 366062306a36Sopenharmony_cimwifiex_fill_coalesce_rule_info(struct mwifiex_private *priv, 366162306a36Sopenharmony_ci struct cfg80211_coalesce_rules *crule, 366262306a36Sopenharmony_ci struct mwifiex_coalesce_rule *mrule) 366362306a36Sopenharmony_ci{ 366462306a36Sopenharmony_ci u8 byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ + 1]; 366562306a36Sopenharmony_ci struct filt_field_param *param; 366662306a36Sopenharmony_ci int i; 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ci mrule->max_coalescing_delay = crule->delay; 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci param = mrule->params; 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_ci for (i = 0; i < crule->n_patterns; i++) { 367362306a36Sopenharmony_ci memset(byte_seq, 0, sizeof(byte_seq)); 367462306a36Sopenharmony_ci if (!mwifiex_is_pattern_supported(&crule->patterns[i], 367562306a36Sopenharmony_ci byte_seq, 367662306a36Sopenharmony_ci MWIFIEX_COALESCE_MAX_BYTESEQ)) { 367762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 367862306a36Sopenharmony_ci "Pattern not supported\n"); 367962306a36Sopenharmony_ci return -EOPNOTSUPP; 368062306a36Sopenharmony_ci } 368162306a36Sopenharmony_ci 368262306a36Sopenharmony_ci if (!crule->patterns[i].pkt_offset) { 368362306a36Sopenharmony_ci u8 pkt_type; 368462306a36Sopenharmony_ci 368562306a36Sopenharmony_ci pkt_type = mwifiex_get_coalesce_pkt_type(byte_seq); 368662306a36Sopenharmony_ci if (pkt_type && mrule->pkt_type) { 368762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 368862306a36Sopenharmony_ci "Multiple packet types not allowed\n"); 368962306a36Sopenharmony_ci return -EOPNOTSUPP; 369062306a36Sopenharmony_ci } else if (pkt_type) { 369162306a36Sopenharmony_ci mrule->pkt_type = pkt_type; 369262306a36Sopenharmony_ci continue; 369362306a36Sopenharmony_ci } 369462306a36Sopenharmony_ci } 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci if (crule->condition == NL80211_COALESCE_CONDITION_MATCH) 369762306a36Sopenharmony_ci param->operation = RECV_FILTER_MATCH_TYPE_EQ; 369862306a36Sopenharmony_ci else 369962306a36Sopenharmony_ci param->operation = RECV_FILTER_MATCH_TYPE_NE; 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci param->operand_len = byte_seq[MWIFIEX_COALESCE_MAX_BYTESEQ]; 370262306a36Sopenharmony_ci memcpy(param->operand_byte_stream, byte_seq, 370362306a36Sopenharmony_ci param->operand_len); 370462306a36Sopenharmony_ci param->offset = crule->patterns[i].pkt_offset; 370562306a36Sopenharmony_ci param++; 370662306a36Sopenharmony_ci 370762306a36Sopenharmony_ci mrule->num_of_fields++; 370862306a36Sopenharmony_ci } 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci if (!mrule->pkt_type) { 371162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 371262306a36Sopenharmony_ci "Packet type can not be determined\n"); 371362306a36Sopenharmony_ci return -EOPNOTSUPP; 371462306a36Sopenharmony_ci } 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci return 0; 371762306a36Sopenharmony_ci} 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_cistatic int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy, 372062306a36Sopenharmony_ci struct cfg80211_coalesce *coalesce) 372162306a36Sopenharmony_ci{ 372262306a36Sopenharmony_ci struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); 372362306a36Sopenharmony_ci int i, ret; 372462306a36Sopenharmony_ci struct mwifiex_ds_coalesce_cfg coalesce_cfg; 372562306a36Sopenharmony_ci struct mwifiex_private *priv = 372662306a36Sopenharmony_ci mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); 372762306a36Sopenharmony_ci 372862306a36Sopenharmony_ci memset(&coalesce_cfg, 0, sizeof(coalesce_cfg)); 372962306a36Sopenharmony_ci if (!coalesce) { 373062306a36Sopenharmony_ci mwifiex_dbg(adapter, WARN, 373162306a36Sopenharmony_ci "Disable coalesce and reset all previous rules\n"); 373262306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG, 373362306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 373462306a36Sopenharmony_ci &coalesce_cfg, true); 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci coalesce_cfg.num_of_rules = coalesce->n_rules; 373862306a36Sopenharmony_ci for (i = 0; i < coalesce->n_rules; i++) { 373962306a36Sopenharmony_ci ret = mwifiex_fill_coalesce_rule_info(priv, &coalesce->rules[i], 374062306a36Sopenharmony_ci &coalesce_cfg.rule[i]); 374162306a36Sopenharmony_ci if (ret) { 374262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 374362306a36Sopenharmony_ci "Recheck the patterns provided for rule %d\n", 374462306a36Sopenharmony_ci i + 1); 374562306a36Sopenharmony_ci return ret; 374662306a36Sopenharmony_ci } 374762306a36Sopenharmony_ci } 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG, 375062306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &coalesce_cfg, true); 375162306a36Sopenharmony_ci} 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci/* cfg80211 ops handler for tdls_mgmt. 375462306a36Sopenharmony_ci * Function prepares TDLS action frame packets and forwards them to FW 375562306a36Sopenharmony_ci */ 375662306a36Sopenharmony_cistatic int 375762306a36Sopenharmony_cimwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, 375862306a36Sopenharmony_ci const u8 *peer, int link_id, u8 action_code, 375962306a36Sopenharmony_ci u8 dialog_token, u16 status_code, 376062306a36Sopenharmony_ci u32 peer_capability, bool initiator, 376162306a36Sopenharmony_ci const u8 *extra_ies, size_t extra_ies_len) 376262306a36Sopenharmony_ci{ 376362306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 376462306a36Sopenharmony_ci int ret; 376562306a36Sopenharmony_ci 376662306a36Sopenharmony_ci if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) 376762306a36Sopenharmony_ci return -EOPNOTSUPP; 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci /* make sure we are in station mode and connected */ 377062306a36Sopenharmony_ci if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) 377162306a36Sopenharmony_ci return -EOPNOTSUPP; 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ci switch (action_code) { 377462306a36Sopenharmony_ci case WLAN_TDLS_SETUP_REQUEST: 377562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 377662306a36Sopenharmony_ci "Send TDLS Setup Request to %pM status_code=%d\n", 377762306a36Sopenharmony_ci peer, status_code); 377862306a36Sopenharmony_ci mwifiex_add_auto_tdls_peer(priv, peer); 377962306a36Sopenharmony_ci ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, 378062306a36Sopenharmony_ci dialog_token, status_code, 378162306a36Sopenharmony_ci extra_ies, extra_ies_len); 378262306a36Sopenharmony_ci break; 378362306a36Sopenharmony_ci case WLAN_TDLS_SETUP_RESPONSE: 378462306a36Sopenharmony_ci mwifiex_add_auto_tdls_peer(priv, peer); 378562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 378662306a36Sopenharmony_ci "Send TDLS Setup Response to %pM status_code=%d\n", 378762306a36Sopenharmony_ci peer, status_code); 378862306a36Sopenharmony_ci ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, 378962306a36Sopenharmony_ci dialog_token, status_code, 379062306a36Sopenharmony_ci extra_ies, extra_ies_len); 379162306a36Sopenharmony_ci break; 379262306a36Sopenharmony_ci case WLAN_TDLS_SETUP_CONFIRM: 379362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 379462306a36Sopenharmony_ci "Send TDLS Confirm to %pM status_code=%d\n", peer, 379562306a36Sopenharmony_ci status_code); 379662306a36Sopenharmony_ci ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, 379762306a36Sopenharmony_ci dialog_token, status_code, 379862306a36Sopenharmony_ci extra_ies, extra_ies_len); 379962306a36Sopenharmony_ci break; 380062306a36Sopenharmony_ci case WLAN_TDLS_TEARDOWN: 380162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 380262306a36Sopenharmony_ci "Send TDLS Tear down to %pM\n", peer); 380362306a36Sopenharmony_ci ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, 380462306a36Sopenharmony_ci dialog_token, status_code, 380562306a36Sopenharmony_ci extra_ies, extra_ies_len); 380662306a36Sopenharmony_ci break; 380762306a36Sopenharmony_ci case WLAN_TDLS_DISCOVERY_REQUEST: 380862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 380962306a36Sopenharmony_ci "Send TDLS Discovery Request to %pM\n", peer); 381062306a36Sopenharmony_ci ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, 381162306a36Sopenharmony_ci dialog_token, status_code, 381262306a36Sopenharmony_ci extra_ies, extra_ies_len); 381362306a36Sopenharmony_ci break; 381462306a36Sopenharmony_ci case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: 381562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 381662306a36Sopenharmony_ci "Send TDLS Discovery Response to %pM\n", peer); 381762306a36Sopenharmony_ci ret = mwifiex_send_tdls_action_frame(priv, peer, action_code, 381862306a36Sopenharmony_ci dialog_token, status_code, 381962306a36Sopenharmony_ci extra_ies, extra_ies_len); 382062306a36Sopenharmony_ci break; 382162306a36Sopenharmony_ci default: 382262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 382362306a36Sopenharmony_ci "Unknown TDLS mgmt/action frame %pM\n", peer); 382462306a36Sopenharmony_ci ret = -EINVAL; 382562306a36Sopenharmony_ci break; 382662306a36Sopenharmony_ci } 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci return ret; 382962306a36Sopenharmony_ci} 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_cistatic int 383262306a36Sopenharmony_cimwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, 383362306a36Sopenharmony_ci const u8 *peer, enum nl80211_tdls_operation action) 383462306a36Sopenharmony_ci{ 383562306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) || 383862306a36Sopenharmony_ci !(wiphy->flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) 383962306a36Sopenharmony_ci return -EOPNOTSUPP; 384062306a36Sopenharmony_ci 384162306a36Sopenharmony_ci /* make sure we are in station mode and connected */ 384262306a36Sopenharmony_ci if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) 384362306a36Sopenharmony_ci return -EOPNOTSUPP; 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 384662306a36Sopenharmony_ci "TDLS peer=%pM, oper=%d\n", peer, action); 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_ci switch (action) { 384962306a36Sopenharmony_ci case NL80211_TDLS_ENABLE_LINK: 385062306a36Sopenharmony_ci action = MWIFIEX_TDLS_ENABLE_LINK; 385162306a36Sopenharmony_ci break; 385262306a36Sopenharmony_ci case NL80211_TDLS_DISABLE_LINK: 385362306a36Sopenharmony_ci action = MWIFIEX_TDLS_DISABLE_LINK; 385462306a36Sopenharmony_ci break; 385562306a36Sopenharmony_ci case NL80211_TDLS_TEARDOWN: 385662306a36Sopenharmony_ci /* shouldn't happen!*/ 385762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 385862306a36Sopenharmony_ci "tdls_oper: teardown from driver not supported\n"); 385962306a36Sopenharmony_ci return -EINVAL; 386062306a36Sopenharmony_ci case NL80211_TDLS_SETUP: 386162306a36Sopenharmony_ci /* shouldn't happen!*/ 386262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 386362306a36Sopenharmony_ci "tdls_oper: setup from driver not supported\n"); 386462306a36Sopenharmony_ci return -EINVAL; 386562306a36Sopenharmony_ci case NL80211_TDLS_DISCOVERY_REQ: 386662306a36Sopenharmony_ci /* shouldn't happen!*/ 386762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 386862306a36Sopenharmony_ci "tdls_oper: discovery from driver not supported\n"); 386962306a36Sopenharmony_ci return -EINVAL; 387062306a36Sopenharmony_ci default: 387162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 387262306a36Sopenharmony_ci "tdls_oper: operation not supported\n"); 387362306a36Sopenharmony_ci return -EOPNOTSUPP; 387462306a36Sopenharmony_ci } 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci return mwifiex_tdls_oper(priv, peer, action); 387762306a36Sopenharmony_ci} 387862306a36Sopenharmony_ci 387962306a36Sopenharmony_cistatic int 388062306a36Sopenharmony_cimwifiex_cfg80211_tdls_chan_switch(struct wiphy *wiphy, struct net_device *dev, 388162306a36Sopenharmony_ci const u8 *addr, u8 oper_class, 388262306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 388362306a36Sopenharmony_ci{ 388462306a36Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 388562306a36Sopenharmony_ci u16 chan; 388662306a36Sopenharmony_ci u8 second_chan_offset, band; 388762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 389062306a36Sopenharmony_ci sta_ptr = mwifiex_get_sta_entry(priv, addr); 389162306a36Sopenharmony_ci if (!sta_ptr) { 389262306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 389362306a36Sopenharmony_ci wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", 389462306a36Sopenharmony_ci __func__, addr); 389562306a36Sopenharmony_ci return -ENOENT; 389662306a36Sopenharmony_ci } 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci if (!(sta_ptr->tdls_cap.extcap.ext_capab[3] & 389962306a36Sopenharmony_ci WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)) { 390062306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 390162306a36Sopenharmony_ci wiphy_err(wiphy, "%pM do not support tdls cs\n", addr); 390262306a36Sopenharmony_ci return -ENOENT; 390362306a36Sopenharmony_ci } 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci if (sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || 390662306a36Sopenharmony_ci sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) { 390762306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 390862306a36Sopenharmony_ci wiphy_err(wiphy, "channel switch is running, abort request\n"); 390962306a36Sopenharmony_ci return -EALREADY; 391062306a36Sopenharmony_ci } 391162306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci chan = chandef->chan->hw_value; 391462306a36Sopenharmony_ci second_chan_offset = mwifiex_get_sec_chan_offset(chan); 391562306a36Sopenharmony_ci band = chandef->chan->band; 391662306a36Sopenharmony_ci mwifiex_start_tdls_cs(priv, addr, chan, second_chan_offset, band); 391762306a36Sopenharmony_ci 391862306a36Sopenharmony_ci return 0; 391962306a36Sopenharmony_ci} 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_cistatic void 392262306a36Sopenharmony_cimwifiex_cfg80211_tdls_cancel_chan_switch(struct wiphy *wiphy, 392362306a36Sopenharmony_ci struct net_device *dev, 392462306a36Sopenharmony_ci const u8 *addr) 392562306a36Sopenharmony_ci{ 392662306a36Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 392762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 393062306a36Sopenharmony_ci sta_ptr = mwifiex_get_sta_entry(priv, addr); 393162306a36Sopenharmony_ci if (!sta_ptr) { 393262306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 393362306a36Sopenharmony_ci wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", 393462306a36Sopenharmony_ci __func__, addr); 393562306a36Sopenharmony_ci } else if (!(sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || 393662306a36Sopenharmony_ci sta_ptr->tdls_status == TDLS_IN_BASE_CHAN || 393762306a36Sopenharmony_ci sta_ptr->tdls_status == TDLS_IN_OFF_CHAN)) { 393862306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 393962306a36Sopenharmony_ci wiphy_err(wiphy, "tdls chan switch not initialize by %pM\n", 394062306a36Sopenharmony_ci addr); 394162306a36Sopenharmony_ci } else { 394262306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 394362306a36Sopenharmony_ci mwifiex_stop_tdls_cs(priv, addr); 394462306a36Sopenharmony_ci } 394562306a36Sopenharmony_ci} 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_cistatic int 394862306a36Sopenharmony_cimwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, 394962306a36Sopenharmony_ci const u8 *mac, struct station_parameters *params) 395062306a36Sopenharmony_ci{ 395162306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_ci if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) 395462306a36Sopenharmony_ci return -EOPNOTSUPP; 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci /* make sure we are in station mode and connected */ 395762306a36Sopenharmony_ci if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected) 395862306a36Sopenharmony_ci return -EOPNOTSUPP; 395962306a36Sopenharmony_ci 396062306a36Sopenharmony_ci return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK); 396162306a36Sopenharmony_ci} 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_cistatic int 396462306a36Sopenharmony_cimwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, 396562306a36Sopenharmony_ci struct cfg80211_csa_settings *params) 396662306a36Sopenharmony_ci{ 396762306a36Sopenharmony_ci struct ieee_types_header *chsw_ie; 396862306a36Sopenharmony_ci struct ieee80211_channel_sw_ie *channel_sw; 396962306a36Sopenharmony_ci int chsw_msec; 397062306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci if (priv->adapter->scan_processing) { 397362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 397462306a36Sopenharmony_ci "radar detection: scan in process...\n"); 397562306a36Sopenharmony_ci return -EBUSY; 397662306a36Sopenharmony_ci } 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci if (priv->wdev.cac_started) 397962306a36Sopenharmony_ci return -EBUSY; 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci if (cfg80211_chandef_identical(¶ms->chandef, 398262306a36Sopenharmony_ci &priv->dfs_chandef)) 398362306a36Sopenharmony_ci return -EINVAL; 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, 398662306a36Sopenharmony_ci params->beacon_csa.tail, 398762306a36Sopenharmony_ci params->beacon_csa.tail_len); 398862306a36Sopenharmony_ci if (!chsw_ie) { 398962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 399062306a36Sopenharmony_ci "Could not parse channel switch announcement IE\n"); 399162306a36Sopenharmony_ci return -EINVAL; 399262306a36Sopenharmony_ci } 399362306a36Sopenharmony_ci 399462306a36Sopenharmony_ci channel_sw = (void *)(chsw_ie + 1); 399562306a36Sopenharmony_ci if (channel_sw->mode) { 399662306a36Sopenharmony_ci if (netif_carrier_ok(priv->netdev)) 399762306a36Sopenharmony_ci netif_carrier_off(priv->netdev); 399862306a36Sopenharmony_ci mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); 399962306a36Sopenharmony_ci } 400062306a36Sopenharmony_ci 400162306a36Sopenharmony_ci if (mwifiex_del_mgmt_ies(priv)) 400262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 400362306a36Sopenharmony_ci "Failed to delete mgmt IEs!\n"); 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon_csa)) { 400662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 400762306a36Sopenharmony_ci "%s: setting mgmt ies failed\n", __func__); 400862306a36Sopenharmony_ci return -EFAULT; 400962306a36Sopenharmony_ci } 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ci memcpy(&priv->dfs_chandef, ¶ms->chandef, sizeof(priv->dfs_chandef)); 401262306a36Sopenharmony_ci memcpy(&priv->beacon_after, ¶ms->beacon_after, 401362306a36Sopenharmony_ci sizeof(priv->beacon_after)); 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_ci chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100); 401662306a36Sopenharmony_ci queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work, 401762306a36Sopenharmony_ci msecs_to_jiffies(chsw_msec)); 401862306a36Sopenharmony_ci return 0; 401962306a36Sopenharmony_ci} 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_cistatic int mwifiex_cfg80211_get_channel(struct wiphy *wiphy, 402262306a36Sopenharmony_ci struct wireless_dev *wdev, 402362306a36Sopenharmony_ci unsigned int link_id, 402462306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 402562306a36Sopenharmony_ci{ 402662306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); 402762306a36Sopenharmony_ci struct mwifiex_bssdescriptor *curr_bss; 402862306a36Sopenharmony_ci struct ieee80211_channel *chan; 402962306a36Sopenharmony_ci enum nl80211_channel_type chan_type; 403062306a36Sopenharmony_ci enum nl80211_band band; 403162306a36Sopenharmony_ci int freq; 403262306a36Sopenharmony_ci int ret = -ENODATA; 403362306a36Sopenharmony_ci 403462306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP && 403562306a36Sopenharmony_ci cfg80211_chandef_valid(&priv->bss_chandef)) { 403662306a36Sopenharmony_ci *chandef = priv->bss_chandef; 403762306a36Sopenharmony_ci ret = 0; 403862306a36Sopenharmony_ci } else if (priv->media_connected) { 403962306a36Sopenharmony_ci curr_bss = &priv->curr_bss_params.bss_descriptor; 404062306a36Sopenharmony_ci band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); 404162306a36Sopenharmony_ci freq = ieee80211_channel_to_frequency(curr_bss->channel, band); 404262306a36Sopenharmony_ci chan = ieee80211_get_channel(wiphy, freq); 404362306a36Sopenharmony_ci 404462306a36Sopenharmony_ci if (priv->ht_param_present) { 404562306a36Sopenharmony_ci chan_type = mwifiex_get_chan_type(priv); 404662306a36Sopenharmony_ci cfg80211_chandef_create(chandef, chan, chan_type); 404762306a36Sopenharmony_ci } else { 404862306a36Sopenharmony_ci cfg80211_chandef_create(chandef, chan, 404962306a36Sopenharmony_ci NL80211_CHAN_NO_HT); 405062306a36Sopenharmony_ci } 405162306a36Sopenharmony_ci ret = 0; 405262306a36Sopenharmony_ci } 405362306a36Sopenharmony_ci 405462306a36Sopenharmony_ci return ret; 405562306a36Sopenharmony_ci} 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE 405862306a36Sopenharmony_ci 405962306a36Sopenharmony_cienum mwifiex_tm_attr { 406062306a36Sopenharmony_ci __MWIFIEX_TM_ATTR_INVALID = 0, 406162306a36Sopenharmony_ci MWIFIEX_TM_ATTR_CMD = 1, 406262306a36Sopenharmony_ci MWIFIEX_TM_ATTR_DATA = 2, 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_ci /* keep last */ 406562306a36Sopenharmony_ci __MWIFIEX_TM_ATTR_AFTER_LAST, 406662306a36Sopenharmony_ci MWIFIEX_TM_ATTR_MAX = __MWIFIEX_TM_ATTR_AFTER_LAST - 1, 406762306a36Sopenharmony_ci}; 406862306a36Sopenharmony_ci 406962306a36Sopenharmony_cistatic const struct nla_policy mwifiex_tm_policy[MWIFIEX_TM_ATTR_MAX + 1] = { 407062306a36Sopenharmony_ci [MWIFIEX_TM_ATTR_CMD] = { .type = NLA_U32 }, 407162306a36Sopenharmony_ci [MWIFIEX_TM_ATTR_DATA] = { .type = NLA_BINARY, 407262306a36Sopenharmony_ci .len = MWIFIEX_SIZE_OF_CMD_BUFFER }, 407362306a36Sopenharmony_ci}; 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_cienum mwifiex_tm_command { 407662306a36Sopenharmony_ci MWIFIEX_TM_CMD_HOSTCMD = 0, 407762306a36Sopenharmony_ci}; 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_cistatic int mwifiex_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, 408062306a36Sopenharmony_ci void *data, int len) 408162306a36Sopenharmony_ci{ 408262306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); 408362306a36Sopenharmony_ci struct mwifiex_ds_misc_cmd *hostcmd; 408462306a36Sopenharmony_ci struct nlattr *tb[MWIFIEX_TM_ATTR_MAX + 1]; 408562306a36Sopenharmony_ci struct sk_buff *skb; 408662306a36Sopenharmony_ci int err; 408762306a36Sopenharmony_ci 408862306a36Sopenharmony_ci if (!priv) 408962306a36Sopenharmony_ci return -EINVAL; 409062306a36Sopenharmony_ci 409162306a36Sopenharmony_ci err = nla_parse_deprecated(tb, MWIFIEX_TM_ATTR_MAX, data, len, 409262306a36Sopenharmony_ci mwifiex_tm_policy, NULL); 409362306a36Sopenharmony_ci if (err) 409462306a36Sopenharmony_ci return err; 409562306a36Sopenharmony_ci 409662306a36Sopenharmony_ci if (!tb[MWIFIEX_TM_ATTR_CMD]) 409762306a36Sopenharmony_ci return -EINVAL; 409862306a36Sopenharmony_ci 409962306a36Sopenharmony_ci switch (nla_get_u32(tb[MWIFIEX_TM_ATTR_CMD])) { 410062306a36Sopenharmony_ci case MWIFIEX_TM_CMD_HOSTCMD: 410162306a36Sopenharmony_ci if (!tb[MWIFIEX_TM_ATTR_DATA]) 410262306a36Sopenharmony_ci return -EINVAL; 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci hostcmd = kzalloc(sizeof(*hostcmd), GFP_KERNEL); 410562306a36Sopenharmony_ci if (!hostcmd) 410662306a36Sopenharmony_ci return -ENOMEM; 410762306a36Sopenharmony_ci 410862306a36Sopenharmony_ci hostcmd->len = nla_len(tb[MWIFIEX_TM_ATTR_DATA]); 410962306a36Sopenharmony_ci memcpy(hostcmd->cmd, nla_data(tb[MWIFIEX_TM_ATTR_DATA]), 411062306a36Sopenharmony_ci hostcmd->len); 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, 0, 0, 0, hostcmd, true)) { 411362306a36Sopenharmony_ci dev_err(priv->adapter->dev, "Failed to process hostcmd\n"); 411462306a36Sopenharmony_ci kfree(hostcmd); 411562306a36Sopenharmony_ci return -EFAULT; 411662306a36Sopenharmony_ci } 411762306a36Sopenharmony_ci 411862306a36Sopenharmony_ci /* process hostcmd response*/ 411962306a36Sopenharmony_ci skb = cfg80211_testmode_alloc_reply_skb(wiphy, hostcmd->len); 412062306a36Sopenharmony_ci if (!skb) { 412162306a36Sopenharmony_ci kfree(hostcmd); 412262306a36Sopenharmony_ci return -ENOMEM; 412362306a36Sopenharmony_ci } 412462306a36Sopenharmony_ci err = nla_put(skb, MWIFIEX_TM_ATTR_DATA, 412562306a36Sopenharmony_ci hostcmd->len, hostcmd->cmd); 412662306a36Sopenharmony_ci if (err) { 412762306a36Sopenharmony_ci kfree(hostcmd); 412862306a36Sopenharmony_ci kfree_skb(skb); 412962306a36Sopenharmony_ci return -EMSGSIZE; 413062306a36Sopenharmony_ci } 413162306a36Sopenharmony_ci 413262306a36Sopenharmony_ci err = cfg80211_testmode_reply(skb); 413362306a36Sopenharmony_ci kfree(hostcmd); 413462306a36Sopenharmony_ci return err; 413562306a36Sopenharmony_ci default: 413662306a36Sopenharmony_ci return -EOPNOTSUPP; 413762306a36Sopenharmony_ci } 413862306a36Sopenharmony_ci} 413962306a36Sopenharmony_ci#endif 414062306a36Sopenharmony_ci 414162306a36Sopenharmony_cistatic int 414262306a36Sopenharmony_cimwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, 414362306a36Sopenharmony_ci struct net_device *dev, 414462306a36Sopenharmony_ci struct cfg80211_chan_def *chandef, 414562306a36Sopenharmony_ci u32 cac_time_ms) 414662306a36Sopenharmony_ci{ 414762306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 414862306a36Sopenharmony_ci struct mwifiex_radar_params radar_params; 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ci if (priv->adapter->scan_processing) { 415162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 415262306a36Sopenharmony_ci "radar detection: scan already in process...\n"); 415362306a36Sopenharmony_ci return -EBUSY; 415462306a36Sopenharmony_ci } 415562306a36Sopenharmony_ci 415662306a36Sopenharmony_ci if (!mwifiex_is_11h_active(priv)) { 415762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 415862306a36Sopenharmony_ci "Enable 11h extensions in FW\n"); 415962306a36Sopenharmony_ci if (mwifiex_11h_activate(priv, true)) { 416062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 416162306a36Sopenharmony_ci "Failed to activate 11h extensions!!"); 416262306a36Sopenharmony_ci return -1; 416362306a36Sopenharmony_ci } 416462306a36Sopenharmony_ci priv->state_11h.is_11h_active = true; 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci memset(&radar_params, 0, sizeof(struct mwifiex_radar_params)); 416862306a36Sopenharmony_ci radar_params.chandef = chandef; 416962306a36Sopenharmony_ci radar_params.cac_time_ms = cac_time_ms; 417062306a36Sopenharmony_ci 417162306a36Sopenharmony_ci memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef)); 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST, 417462306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &radar_params, true)) 417562306a36Sopenharmony_ci return -1; 417662306a36Sopenharmony_ci 417762306a36Sopenharmony_ci queue_delayed_work(priv->dfs_cac_workqueue, &priv->dfs_cac_work, 417862306a36Sopenharmony_ci msecs_to_jiffies(cac_time_ms)); 417962306a36Sopenharmony_ci return 0; 418062306a36Sopenharmony_ci} 418162306a36Sopenharmony_ci 418262306a36Sopenharmony_cistatic int 418362306a36Sopenharmony_cimwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, 418462306a36Sopenharmony_ci const u8 *mac, 418562306a36Sopenharmony_ci struct station_parameters *params) 418662306a36Sopenharmony_ci{ 418762306a36Sopenharmony_ci int ret; 418862306a36Sopenharmony_ci struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci /* we support change_station handler only for TDLS peers*/ 419162306a36Sopenharmony_ci if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) 419262306a36Sopenharmony_ci return -EOPNOTSUPP; 419362306a36Sopenharmony_ci 419462306a36Sopenharmony_ci /* make sure we are in station mode and connected */ 419562306a36Sopenharmony_ci if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected) 419662306a36Sopenharmony_ci return -EOPNOTSUPP; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci priv->sta_params = params; 419962306a36Sopenharmony_ci 420062306a36Sopenharmony_ci ret = mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CONFIG_LINK); 420162306a36Sopenharmony_ci priv->sta_params = NULL; 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci return ret; 420462306a36Sopenharmony_ci} 420562306a36Sopenharmony_ci 420662306a36Sopenharmony_ci/* station cfg80211 operations */ 420762306a36Sopenharmony_cistatic struct cfg80211_ops mwifiex_cfg80211_ops = { 420862306a36Sopenharmony_ci .add_virtual_intf = mwifiex_add_virtual_intf, 420962306a36Sopenharmony_ci .del_virtual_intf = mwifiex_del_virtual_intf, 421062306a36Sopenharmony_ci .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, 421162306a36Sopenharmony_ci .scan = mwifiex_cfg80211_scan, 421262306a36Sopenharmony_ci .connect = mwifiex_cfg80211_connect, 421362306a36Sopenharmony_ci .disconnect = mwifiex_cfg80211_disconnect, 421462306a36Sopenharmony_ci .get_station = mwifiex_cfg80211_get_station, 421562306a36Sopenharmony_ci .dump_station = mwifiex_cfg80211_dump_station, 421662306a36Sopenharmony_ci .dump_survey = mwifiex_cfg80211_dump_survey, 421762306a36Sopenharmony_ci .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, 421862306a36Sopenharmony_ci .join_ibss = mwifiex_cfg80211_join_ibss, 421962306a36Sopenharmony_ci .leave_ibss = mwifiex_cfg80211_leave_ibss, 422062306a36Sopenharmony_ci .add_key = mwifiex_cfg80211_add_key, 422162306a36Sopenharmony_ci .del_key = mwifiex_cfg80211_del_key, 422262306a36Sopenharmony_ci .set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key, 422362306a36Sopenharmony_ci .mgmt_tx = mwifiex_cfg80211_mgmt_tx, 422462306a36Sopenharmony_ci .update_mgmt_frame_registrations = 422562306a36Sopenharmony_ci mwifiex_cfg80211_update_mgmt_frame_registrations, 422662306a36Sopenharmony_ci .remain_on_channel = mwifiex_cfg80211_remain_on_channel, 422762306a36Sopenharmony_ci .cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel, 422862306a36Sopenharmony_ci .set_default_key = mwifiex_cfg80211_set_default_key, 422962306a36Sopenharmony_ci .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, 423062306a36Sopenharmony_ci .set_tx_power = mwifiex_cfg80211_set_tx_power, 423162306a36Sopenharmony_ci .get_tx_power = mwifiex_cfg80211_get_tx_power, 423262306a36Sopenharmony_ci .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, 423362306a36Sopenharmony_ci .start_ap = mwifiex_cfg80211_start_ap, 423462306a36Sopenharmony_ci .stop_ap = mwifiex_cfg80211_stop_ap, 423562306a36Sopenharmony_ci .change_beacon = mwifiex_cfg80211_change_beacon, 423662306a36Sopenharmony_ci .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, 423762306a36Sopenharmony_ci .set_antenna = mwifiex_cfg80211_set_antenna, 423862306a36Sopenharmony_ci .get_antenna = mwifiex_cfg80211_get_antenna, 423962306a36Sopenharmony_ci .del_station = mwifiex_cfg80211_del_station, 424062306a36Sopenharmony_ci .sched_scan_start = mwifiex_cfg80211_sched_scan_start, 424162306a36Sopenharmony_ci .sched_scan_stop = mwifiex_cfg80211_sched_scan_stop, 424262306a36Sopenharmony_ci#ifdef CONFIG_PM 424362306a36Sopenharmony_ci .suspend = mwifiex_cfg80211_suspend, 424462306a36Sopenharmony_ci .resume = mwifiex_cfg80211_resume, 424562306a36Sopenharmony_ci .set_wakeup = mwifiex_cfg80211_set_wakeup, 424662306a36Sopenharmony_ci .set_rekey_data = mwifiex_set_rekey_data, 424762306a36Sopenharmony_ci#endif 424862306a36Sopenharmony_ci .set_coalesce = mwifiex_cfg80211_set_coalesce, 424962306a36Sopenharmony_ci .tdls_mgmt = mwifiex_cfg80211_tdls_mgmt, 425062306a36Sopenharmony_ci .tdls_oper = mwifiex_cfg80211_tdls_oper, 425162306a36Sopenharmony_ci .tdls_channel_switch = mwifiex_cfg80211_tdls_chan_switch, 425262306a36Sopenharmony_ci .tdls_cancel_channel_switch = mwifiex_cfg80211_tdls_cancel_chan_switch, 425362306a36Sopenharmony_ci .add_station = mwifiex_cfg80211_add_station, 425462306a36Sopenharmony_ci .change_station = mwifiex_cfg80211_change_station, 425562306a36Sopenharmony_ci CFG80211_TESTMODE_CMD(mwifiex_tm_cmd) 425662306a36Sopenharmony_ci .get_channel = mwifiex_cfg80211_get_channel, 425762306a36Sopenharmony_ci .start_radar_detection = mwifiex_cfg80211_start_radar_detection, 425862306a36Sopenharmony_ci .channel_switch = mwifiex_cfg80211_channel_switch, 425962306a36Sopenharmony_ci}; 426062306a36Sopenharmony_ci 426162306a36Sopenharmony_ci#ifdef CONFIG_PM 426262306a36Sopenharmony_cistatic const struct wiphy_wowlan_support mwifiex_wowlan_support = { 426362306a36Sopenharmony_ci .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | 426462306a36Sopenharmony_ci WIPHY_WOWLAN_NET_DETECT | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | 426562306a36Sopenharmony_ci WIPHY_WOWLAN_GTK_REKEY_FAILURE, 426662306a36Sopenharmony_ci .n_patterns = MWIFIEX_MEF_MAX_FILTERS, 426762306a36Sopenharmony_ci .pattern_min_len = 1, 426862306a36Sopenharmony_ci .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, 426962306a36Sopenharmony_ci .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, 427062306a36Sopenharmony_ci .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS, 427162306a36Sopenharmony_ci}; 427262306a36Sopenharmony_ci 427362306a36Sopenharmony_cistatic const struct wiphy_wowlan_support mwifiex_wowlan_support_no_gtk = { 427462306a36Sopenharmony_ci .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | 427562306a36Sopenharmony_ci WIPHY_WOWLAN_NET_DETECT, 427662306a36Sopenharmony_ci .n_patterns = MWIFIEX_MEF_MAX_FILTERS, 427762306a36Sopenharmony_ci .pattern_min_len = 1, 427862306a36Sopenharmony_ci .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, 427962306a36Sopenharmony_ci .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, 428062306a36Sopenharmony_ci .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS, 428162306a36Sopenharmony_ci}; 428262306a36Sopenharmony_ci#endif 428362306a36Sopenharmony_ci 428462306a36Sopenharmony_cistatic bool mwifiex_is_valid_alpha2(const char *alpha2) 428562306a36Sopenharmony_ci{ 428662306a36Sopenharmony_ci if (!alpha2 || strlen(alpha2) != 2) 428762306a36Sopenharmony_ci return false; 428862306a36Sopenharmony_ci 428962306a36Sopenharmony_ci if (isalpha(alpha2[0]) && isalpha(alpha2[1])) 429062306a36Sopenharmony_ci return true; 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_ci return false; 429362306a36Sopenharmony_ci} 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_cistatic const struct wiphy_coalesce_support mwifiex_coalesce_support = { 429662306a36Sopenharmony_ci .n_rules = MWIFIEX_COALESCE_MAX_RULES, 429762306a36Sopenharmony_ci .max_delay = MWIFIEX_MAX_COALESCING_DELAY, 429862306a36Sopenharmony_ci .n_patterns = MWIFIEX_COALESCE_MAX_FILTERS, 429962306a36Sopenharmony_ci .pattern_min_len = 1, 430062306a36Sopenharmony_ci .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, 430162306a36Sopenharmony_ci .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, 430262306a36Sopenharmony_ci}; 430362306a36Sopenharmony_ci 430462306a36Sopenharmony_ciint mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter) 430562306a36Sopenharmony_ci{ 430662306a36Sopenharmony_ci u32 n_channels_bg, n_channels_a = 0; 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci n_channels_bg = mwifiex_band_2ghz.n_channels; 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_ci if (adapter->config_bands & BAND_A) 431162306a36Sopenharmony_ci n_channels_a = mwifiex_band_5ghz.n_channels; 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci /* allocate twice the number total channels, since the driver issues an 431462306a36Sopenharmony_ci * additional active scan request for hidden SSIDs on passive channels. 431562306a36Sopenharmony_ci */ 431662306a36Sopenharmony_ci adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a); 431762306a36Sopenharmony_ci adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats), 431862306a36Sopenharmony_ci adapter->num_in_chan_stats)); 431962306a36Sopenharmony_ci 432062306a36Sopenharmony_ci if (!adapter->chan_stats) 432162306a36Sopenharmony_ci return -ENOMEM; 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_ci return 0; 432462306a36Sopenharmony_ci} 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci/* 432762306a36Sopenharmony_ci * This function registers the device with CFG802.11 subsystem. 432862306a36Sopenharmony_ci * 432962306a36Sopenharmony_ci * The function creates the wireless device/wiphy, populates it with 433062306a36Sopenharmony_ci * default parameters and handler function pointers, and finally 433162306a36Sopenharmony_ci * registers the device. 433262306a36Sopenharmony_ci */ 433362306a36Sopenharmony_ci 433462306a36Sopenharmony_ciint mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) 433562306a36Sopenharmony_ci{ 433662306a36Sopenharmony_ci int ret; 433762306a36Sopenharmony_ci void *wdev_priv; 433862306a36Sopenharmony_ci struct wiphy *wiphy; 433962306a36Sopenharmony_ci struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; 434062306a36Sopenharmony_ci u8 *country_code; 434162306a36Sopenharmony_ci u32 thr, retry; 434262306a36Sopenharmony_ci 434362306a36Sopenharmony_ci /* create a new wiphy for use with cfg80211 */ 434462306a36Sopenharmony_ci wiphy = wiphy_new(&mwifiex_cfg80211_ops, 434562306a36Sopenharmony_ci sizeof(struct mwifiex_adapter *)); 434662306a36Sopenharmony_ci if (!wiphy) { 434762306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 434862306a36Sopenharmony_ci "%s: creating new wiphy\n", __func__); 434962306a36Sopenharmony_ci return -ENOMEM; 435062306a36Sopenharmony_ci } 435162306a36Sopenharmony_ci wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; 435262306a36Sopenharmony_ci wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; 435362306a36Sopenharmony_ci wiphy->mgmt_stypes = mwifiex_mgmt_stypes; 435462306a36Sopenharmony_ci wiphy->max_remain_on_channel_duration = 5000; 435562306a36Sopenharmony_ci wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 435662306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 435762306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | 435862306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP); 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_ci if (ISSUPP_ADHOC_ENABLED(adapter->fw_cap_info)) 436162306a36Sopenharmony_ci wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_ci wiphy->bands[NL80211_BAND_2GHZ] = &mwifiex_band_2ghz; 436462306a36Sopenharmony_ci if (adapter->config_bands & BAND_A) 436562306a36Sopenharmony_ci wiphy->bands[NL80211_BAND_5GHZ] = &mwifiex_band_5ghz; 436662306a36Sopenharmony_ci else 436762306a36Sopenharmony_ci wiphy->bands[NL80211_BAND_5GHZ] = NULL; 436862306a36Sopenharmony_ci 436962306a36Sopenharmony_ci if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) 437062306a36Sopenharmony_ci wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; 437162306a36Sopenharmony_ci else if (adapter->is_hw_11ac_capable) 437262306a36Sopenharmony_ci wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_vht; 437362306a36Sopenharmony_ci else 437462306a36Sopenharmony_ci wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; 437562306a36Sopenharmony_ci wiphy->n_iface_combinations = 1; 437662306a36Sopenharmony_ci 437762306a36Sopenharmony_ci if (adapter->max_sta_conn > adapter->max_p2p_conn) 437862306a36Sopenharmony_ci wiphy->max_ap_assoc_sta = adapter->max_sta_conn; 437962306a36Sopenharmony_ci else 438062306a36Sopenharmony_ci wiphy->max_ap_assoc_sta = adapter->max_p2p_conn; 438162306a36Sopenharmony_ci 438262306a36Sopenharmony_ci /* Initialize cipher suits */ 438362306a36Sopenharmony_ci wiphy->cipher_suites = mwifiex_cipher_suites; 438462306a36Sopenharmony_ci wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); 438562306a36Sopenharmony_ci 438662306a36Sopenharmony_ci if (adapter->regd) { 438762306a36Sopenharmony_ci wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | 438862306a36Sopenharmony_ci REGULATORY_DISABLE_BEACON_HINTS | 438962306a36Sopenharmony_ci REGULATORY_COUNTRY_IE_IGNORE; 439062306a36Sopenharmony_ci wiphy_apply_custom_regulatory(wiphy, adapter->regd); 439162306a36Sopenharmony_ci } 439262306a36Sopenharmony_ci 439362306a36Sopenharmony_ci ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); 439462306a36Sopenharmony_ci wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 439562306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | 439662306a36Sopenharmony_ci WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | 439762306a36Sopenharmony_ci WIPHY_FLAG_AP_UAPSD | 439862306a36Sopenharmony_ci WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | 439962306a36Sopenharmony_ci WIPHY_FLAG_HAS_CHANNEL_SWITCH | 440062306a36Sopenharmony_ci WIPHY_FLAG_NETNS_OK | 440162306a36Sopenharmony_ci WIPHY_FLAG_PS_ON_BY_DEFAULT; 440262306a36Sopenharmony_ci 440362306a36Sopenharmony_ci if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) 440462306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 440562306a36Sopenharmony_ci WIPHY_FLAG_TDLS_EXTERNAL_SETUP; 440662306a36Sopenharmony_ci 440762306a36Sopenharmony_ci#ifdef CONFIG_PM 440862306a36Sopenharmony_ci if (ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) 440962306a36Sopenharmony_ci wiphy->wowlan = &mwifiex_wowlan_support; 441062306a36Sopenharmony_ci else 441162306a36Sopenharmony_ci wiphy->wowlan = &mwifiex_wowlan_support_no_gtk; 441262306a36Sopenharmony_ci#endif 441362306a36Sopenharmony_ci 441462306a36Sopenharmony_ci wiphy->coalesce = &mwifiex_coalesce_support; 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | 441762306a36Sopenharmony_ci NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | 441862306a36Sopenharmony_ci NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci wiphy->max_sched_scan_reqs = 1; 442162306a36Sopenharmony_ci wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; 442262306a36Sopenharmony_ci wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; 442362306a36Sopenharmony_ci wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH; 442462306a36Sopenharmony_ci 442562306a36Sopenharmony_ci wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; 442662306a36Sopenharmony_ci wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; 442762306a36Sopenharmony_ci 442862306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER | 442962306a36Sopenharmony_ci NL80211_FEATURE_LOW_PRIORITY_SCAN | 443062306a36Sopenharmony_ci NL80211_FEATURE_NEED_OBSS_SCAN; 443162306a36Sopenharmony_ci 443262306a36Sopenharmony_ci if (ISSUPP_ADHOC_ENABLED(adapter->fw_cap_info)) 443362306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_HT_IBSS; 443462306a36Sopenharmony_ci 443562306a36Sopenharmony_ci if (ISSUPP_RANDOM_MAC(adapter->fw_cap_info)) 443662306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | 443762306a36Sopenharmony_ci NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | 443862306a36Sopenharmony_ci NL80211_FEATURE_ND_RANDOM_MAC_ADDR; 443962306a36Sopenharmony_ci 444062306a36Sopenharmony_ci if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) 444162306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; 444262306a36Sopenharmony_ci 444362306a36Sopenharmony_ci if (adapter->fw_api_ver == MWIFIEX_FW_V15) 444462306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; 444562306a36Sopenharmony_ci 444662306a36Sopenharmony_ci /* Reserve space for mwifiex specific private data for BSS */ 444762306a36Sopenharmony_ci wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); 444862306a36Sopenharmony_ci 444962306a36Sopenharmony_ci wiphy->reg_notifier = mwifiex_reg_notifier; 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_ci /* Set struct mwifiex_adapter pointer in wiphy_priv */ 445262306a36Sopenharmony_ci wdev_priv = wiphy_priv(wiphy); 445362306a36Sopenharmony_ci *(unsigned long *)wdev_priv = (unsigned long)adapter; 445462306a36Sopenharmony_ci 445562306a36Sopenharmony_ci set_wiphy_dev(wiphy, priv->adapter->dev); 445662306a36Sopenharmony_ci 445762306a36Sopenharmony_ci ret = wiphy_register(wiphy); 445862306a36Sopenharmony_ci if (ret < 0) { 445962306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 446062306a36Sopenharmony_ci "%s: wiphy_register failed: %d\n", __func__, ret); 446162306a36Sopenharmony_ci wiphy_free(wiphy); 446262306a36Sopenharmony_ci return ret; 446362306a36Sopenharmony_ci } 446462306a36Sopenharmony_ci 446562306a36Sopenharmony_ci if (!adapter->regd) { 446662306a36Sopenharmony_ci if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) { 446762306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 446862306a36Sopenharmony_ci "driver hint alpha2: %2.2s\n", reg_alpha2); 446962306a36Sopenharmony_ci regulatory_hint(wiphy, reg_alpha2); 447062306a36Sopenharmony_ci } else { 447162306a36Sopenharmony_ci if (adapter->region_code == 0x00) { 447262306a36Sopenharmony_ci mwifiex_dbg(adapter, WARN, 447362306a36Sopenharmony_ci "Ignore world regulatory domain\n"); 447462306a36Sopenharmony_ci } else { 447562306a36Sopenharmony_ci wiphy->regulatory_flags |= 447662306a36Sopenharmony_ci REGULATORY_DISABLE_BEACON_HINTS | 447762306a36Sopenharmony_ci REGULATORY_COUNTRY_IE_IGNORE; 447862306a36Sopenharmony_ci country_code = 447962306a36Sopenharmony_ci mwifiex_11d_code_2_region( 448062306a36Sopenharmony_ci adapter->region_code); 448162306a36Sopenharmony_ci if (country_code && 448262306a36Sopenharmony_ci regulatory_hint(wiphy, country_code)) 448362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 448462306a36Sopenharmony_ci "regulatory_hint() failed\n"); 448562306a36Sopenharmony_ci } 448662306a36Sopenharmony_ci } 448762306a36Sopenharmony_ci } 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 449062306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, FRAG_THRESH_I, &thr, true); 449162306a36Sopenharmony_ci wiphy->frag_threshold = thr; 449262306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 449362306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, RTS_THRESH_I, &thr, true); 449462306a36Sopenharmony_ci wiphy->rts_threshold = thr; 449562306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 449662306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, SHORT_RETRY_LIM_I, &retry, true); 449762306a36Sopenharmony_ci wiphy->retry_short = (u8) retry; 449862306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 449962306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, LONG_RETRY_LIM_I, &retry, true); 450062306a36Sopenharmony_ci wiphy->retry_long = (u8) retry; 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci adapter->wiphy = wiphy; 450362306a36Sopenharmony_ci return ret; 450462306a36Sopenharmony_ci} 4505