Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Conflicts: drivers/net/wireless/iwlwifi/mvm/mac80211.c
This commit is contained in:
commit
812fd64596
@ -127,12 +127,11 @@
|
||||
!Finclude/net/cfg80211.h cfg80211_ibss_params
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_params
|
||||
!Finclude/net/cfg80211.h cfg80211_pmksa
|
||||
!Finclude/net/cfg80211.h cfg80211_send_rx_auth
|
||||
!Finclude/net/cfg80211.h cfg80211_send_auth_timeout
|
||||
!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
|
||||
!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
|
||||
!Finclude/net/cfg80211.h cfg80211_send_deauth
|
||||
!Finclude/net/cfg80211.h cfg80211_send_disassoc
|
||||
!Finclude/net/cfg80211.h cfg80211_rx_mlme_mgmt
|
||||
!Finclude/net/cfg80211.h cfg80211_auth_timeout
|
||||
!Finclude/net/cfg80211.h cfg80211_rx_assoc_resp
|
||||
!Finclude/net/cfg80211.h cfg80211_assoc_timeout
|
||||
!Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt
|
||||
!Finclude/net/cfg80211.h cfg80211_ibss_joined
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_result
|
||||
!Finclude/net/cfg80211.h cfg80211_roamed
|
||||
|
@ -3175,10 +3175,21 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
{
|
||||
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
|
||||
struct ath6kl *ar = ath6kl_priv(vif->ndev);
|
||||
u32 id;
|
||||
u32 id, freq;
|
||||
const struct ieee80211_mgmt *mgmt;
|
||||
bool more_data, queued;
|
||||
|
||||
/* default to the current channel, but use the one specified as argument
|
||||
* if any
|
||||
*/
|
||||
freq = vif->ch_hint;
|
||||
if (chan)
|
||||
freq = chan->center_freq;
|
||||
|
||||
/* never send freq zero to the firmware */
|
||||
if (WARN_ON(freq == 0))
|
||||
return -EINVAL;
|
||||
|
||||
mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
|
||||
ieee80211_is_probe_resp(mgmt->frame_control) &&
|
||||
@ -3188,8 +3199,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
* command to allow the target to fill in the generic IEs.
|
||||
*/
|
||||
*cookie = 0; /* TX status not supported */
|
||||
return ath6kl_send_go_probe_resp(vif, buf, len,
|
||||
chan->center_freq);
|
||||
return ath6kl_send_go_probe_resp(vif, buf, len, freq);
|
||||
}
|
||||
|
||||
id = vif->send_action_id++;
|
||||
@ -3205,17 +3215,14 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
|
||||
/* AP mode Power saving processing */
|
||||
if (vif->nw_type == AP_NETWORK) {
|
||||
queued = ath6kl_mgmt_powersave_ap(vif,
|
||||
id, chan->center_freq,
|
||||
wait, buf,
|
||||
len, &more_data, no_cck);
|
||||
queued = ath6kl_mgmt_powersave_ap(vif, id, freq, wait, buf, len,
|
||||
&more_data, no_cck);
|
||||
if (queued)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
|
||||
chan->center_freq, wait,
|
||||
buf, len, no_cck);
|
||||
return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, freq,
|
||||
wait, buf, len, no_cck);
|
||||
}
|
||||
|
||||
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
|
||||
@ -3679,6 +3686,20 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct wiphy_wowlan_support ath6kl_wowlan_support = {
|
||||
.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
|
||||
WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
|
||||
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
|
||||
WIPHY_WOWLAN_4WAY_HANDSHAKE,
|
||||
.n_patterns = WOW_MAX_FILTERS_PER_LIST,
|
||||
.pattern_min_len = 1,
|
||||
.pattern_max_len = WOW_PATTERN_SIZE,
|
||||
};
|
||||
#endif
|
||||
|
||||
int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
{
|
||||
struct wiphy *wiphy = ar->wiphy;
|
||||
@ -3772,15 +3793,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
|
||||
WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
|
||||
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
|
||||
WIPHY_WOWLAN_4WAY_HANDSHAKE;
|
||||
wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
|
||||
wiphy->wowlan.pattern_min_len = 1;
|
||||
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
|
||||
wiphy->wowlan = &ath6kl_wowlan_support;
|
||||
#endif
|
||||
|
||||
wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
|
||||
|
@ -755,6 +755,15 @@ static const struct ieee80211_iface_combination if_comb[] = {
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct wiphy_wowlan_support ath9k_wowlan_support = {
|
||||
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
|
||||
.n_patterns = MAX_NUM_USER_PATTERN,
|
||||
.pattern_min_len = 1,
|
||||
.pattern_max_len = MAX_PATTERN_SIZE,
|
||||
};
|
||||
#endif
|
||||
|
||||
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
@ -802,13 +811,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
|
||||
device_can_wakeup(sc->dev)) {
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT;
|
||||
hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN;
|
||||
hw->wiphy->wowlan.pattern_min_len = 1;
|
||||
hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE;
|
||||
}
|
||||
device_can_wakeup(sc->dev))
|
||||
hw->wiphy->wowlan = &ath9k_wowlan_support;
|
||||
|
||||
atomic_set(&sc->wow_sleep_proc_intr, -1);
|
||||
atomic_set(&sc->wow_got_bmiss_intr, -1);
|
||||
|
@ -3982,6 +3982,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct brcmf_fil_af_params_le *af_params;
|
||||
bool ack;
|
||||
s32 chan_nr;
|
||||
u32 freq;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
@ -3994,6 +3995,8 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
|
||||
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
/* Right now the only reason to get a probe response */
|
||||
/* is for p2p listen response or for p2p GO from */
|
||||
@ -4009,7 +4012,6 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
ie_offset = DOT11_MGMT_HDR_LEN +
|
||||
DOT11_BCN_PRB_FIXED_LEN;
|
||||
ie_len = len - ie_offset;
|
||||
vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
|
||||
if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
|
||||
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
|
||||
err = brcmf_vif_set_mgmt_ie(vif,
|
||||
@ -4033,8 +4035,15 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
|
||||
/* Add the length exepted for 802.11 header */
|
||||
action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
|
||||
/* Add the channel */
|
||||
chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
|
||||
/* Add the channel. Use the one specified as parameter if any or
|
||||
* the current one (got from the firmware) otherwise
|
||||
*/
|
||||
if (chan)
|
||||
freq = chan->center_freq;
|
||||
else
|
||||
brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
|
||||
&freq);
|
||||
chan_nr = ieee80211_frequency_to_channel(freq);
|
||||
af_params->channel = cpu_to_le32(chan_nr);
|
||||
|
||||
memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
|
||||
|
@ -245,6 +245,14 @@ module_param(cw1200_ba_tx_tids, int, 0644);
|
||||
MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
|
||||
MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct wiphy_wowlan_support cw1200_wowlan_support = {
|
||||
/* Support only for limited wowlan functionalities */
|
||||
.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
|
||||
const bool have_5ghz)
|
||||
{
|
||||
@ -289,10 +297,7 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
|
||||
BIT(NL80211_IFTYPE_P2P_GO);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/* Support only for limited wowlan functionalities */
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY |
|
||||
WIPHY_WOWLAN_DISCONNECT;
|
||||
hw->wiphy->wowlan.n_patterns = 0;
|
||||
hw->wiphy->wowlan = &cw1200_wowlan_support;
|
||||
#endif
|
||||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
||||
|
@ -915,6 +915,9 @@ struct iwl_priv {
|
||||
__le64 replay_ctr;
|
||||
__le16 last_seq_ctl;
|
||||
bool have_rekey_data;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct wiphy_wowlan_support wowlan_support;
|
||||
#endif
|
||||
|
||||
/* device_pointers: pointers to ucode event tables */
|
||||
struct {
|
||||
|
@ -208,20 +208,21 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
||||
priv->trans->ops->d3_suspend &&
|
||||
priv->trans->ops->d3_resume &&
|
||||
device_can_wakeup(priv->trans->dev)) {
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
|
||||
WIPHY_WOWLAN_RFKILL_RELEASE;
|
||||
priv->wowlan_support.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
|
||||
WIPHY_WOWLAN_RFKILL_RELEASE;
|
||||
if (!iwlwifi_mod_params.sw_crypto)
|
||||
hw->wiphy->wowlan.flags |=
|
||||
priv->wowlan_support.flags |=
|
||||
WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
|
||||
WIPHY_WOWLAN_GTK_REKEY_FAILURE;
|
||||
|
||||
hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
|
||||
hw->wiphy->wowlan.pattern_min_len =
|
||||
priv->wowlan_support.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
|
||||
priv->wowlan_support.pattern_min_len =
|
||||
IWLAGN_WOWLAN_MIN_PATTERN_LEN;
|
||||
hw->wiphy->wowlan.pattern_max_len =
|
||||
priv->wowlan_support.pattern_max_len =
|
||||
IWLAGN_WOWLAN_MAX_PATTERN_LEN;
|
||||
hw->wiphy->wowlan = &priv->wowlan_support;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -236,20 +236,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
mvm->trans->ops->d3_suspend &&
|
||||
mvm->trans->ops->d3_resume &&
|
||||
device_can_wakeup(mvm->trans->dev)) {
|
||||
hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
|
||||
WIPHY_WOWLAN_RFKILL_RELEASE;
|
||||
mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_EAP_IDENTITY_REQ |
|
||||
WIPHY_WOWLAN_RFKILL_RELEASE;
|
||||
if (!iwlwifi_mod_params.sw_crypto)
|
||||
hw->wiphy->wowlan.flags |=
|
||||
WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
|
||||
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
|
||||
WIPHY_WOWLAN_4WAY_HANDSHAKE;
|
||||
mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
|
||||
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
|
||||
WIPHY_WOWLAN_4WAY_HANDSHAKE;
|
||||
|
||||
hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
|
||||
hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
|
||||
hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
|
||||
hw->wiphy->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
|
||||
mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
|
||||
mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
|
||||
mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
|
||||
mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
|
||||
hw->wiphy->wowlan = &mvm->wowlan;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -777,7 +777,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
ret = iwl_mvm_power_update_mode(mvm, vif);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update power mode\n");
|
||||
} else if (changes & BSS_CHANGED_DTIM_PERIOD) {
|
||||
} else if (changes & BSS_CHANGED_BEACON_INFO) {
|
||||
/*
|
||||
* We received a beacon _after_ association so
|
||||
* remove the session protection.
|
||||
|
@ -458,6 +458,7 @@ struct iwl_mvm {
|
||||
struct ieee80211_vif *p2p_device_vif;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct wiphy_wowlan_support wowlan;
|
||||
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
bool d3_test_active;
|
||||
|
@ -2475,6 +2475,16 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct wiphy_wowlan_support mwifiex_wowlan_support = {
|
||||
.flags = WIPHY_WOWLAN_MAGIC_PKT,
|
||||
.n_patterns = MWIFIEX_MAX_FILTERS,
|
||||
.pattern_min_len = 1,
|
||||
.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
|
||||
.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function registers the device with CFG802.11 subsystem.
|
||||
*
|
||||
@ -2532,11 +2542,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
||||
wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
|
||||
wiphy->wowlan.n_patterns = MWIFIEX_MAX_FILTERS;
|
||||
wiphy->wowlan.pattern_min_len = 1;
|
||||
wiphy->wowlan.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN;
|
||||
wiphy->wowlan.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN;
|
||||
wiphy->wowlan = &mwifiex_wowlan_support;
|
||||
#endif
|
||||
|
||||
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
|
||||
|
@ -6018,6 +6018,15 @@ int wlcore_free_hw(struct wl1271 *wl)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_free_hw);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct wiphy_wowlan_support wlcore_wowlan_support = {
|
||||
.flags = WIPHY_WOWLAN_ANY,
|
||||
.n_patterns = WL1271_MAX_RX_FILTERS,
|
||||
.pattern_min_len = 1,
|
||||
.pattern_max_len = WL1271_RX_FILTER_MAX_PATTERN_SIZE,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void wlcore_nvs_cb(const struct firmware *fw, void *context)
|
||||
{
|
||||
struct wl1271 *wl = context;
|
||||
@ -6071,14 +6080,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
|
||||
if (!ret) {
|
||||
wl->irq_wake_enabled = true;
|
||||
device_init_wakeup(wl->dev, 1);
|
||||
if (pdata->pwr_in_suspend) {
|
||||
wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
|
||||
wl->hw->wiphy->wowlan.n_patterns =
|
||||
WL1271_MAX_RX_FILTERS;
|
||||
wl->hw->wiphy->wowlan.pattern_min_len = 1;
|
||||
wl->hw->wiphy->wowlan.pattern_max_len =
|
||||
WL1271_RX_FILTER_MAX_PATTERN_SIZE;
|
||||
}
|
||||
if (pdata->pwr_in_suspend)
|
||||
wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
|
||||
}
|
||||
#endif
|
||||
disable_irq(wl->irq);
|
||||
|
@ -146,6 +146,7 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
|
||||
#define IEEE80211_MAX_RTS_THRESHOLD 2353
|
||||
#define IEEE80211_MAX_AID 2007
|
||||
#define IEEE80211_MAX_TIM_LEN 251
|
||||
#define IEEE80211_MAX_MESH_PEERINGS 63
|
||||
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
|
||||
6.2.1.1.2.
|
||||
|
||||
|
@ -1124,6 +1124,9 @@ struct bss_parameters {
|
||||
* setting for new peer links.
|
||||
* @dot11MeshAwakeWindowDuration: The duration in TUs the STA will remain awake
|
||||
* after transmitting its beacon.
|
||||
* @plink_timeout: If no tx activity is seen from a STA we've established
|
||||
* peering with for longer than this time (in seconds), then remove it
|
||||
* from the STA's list of peers. Default is 30 minutes.
|
||||
*/
|
||||
struct mesh_config {
|
||||
u16 dot11MeshRetryTimeout;
|
||||
@ -1153,6 +1156,7 @@ struct mesh_config {
|
||||
u16 dot11MeshHWMPconfirmationInterval;
|
||||
enum nl80211_mesh_power_mode power_mode;
|
||||
u16 dot11MeshAwakeWindowDuration;
|
||||
u32 plink_timeout;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1172,6 +1176,7 @@ struct mesh_config {
|
||||
* @dtim_period: DTIM period to use
|
||||
* @beacon_interval: beacon interval to use
|
||||
* @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
|
||||
* @basic_rates: basic rates to use when creating the mesh
|
||||
*
|
||||
* These parameters are fixed when the mesh is created.
|
||||
*/
|
||||
@ -1191,6 +1196,7 @@ struct mesh_setup {
|
||||
u8 dtim_period;
|
||||
u16 beacon_interval;
|
||||
int mcast_rate[IEEE80211_NUM_BANDS];
|
||||
u32 basic_rates;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2654,7 +2660,7 @@ struct wiphy {
|
||||
u32 hw_version;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct wiphy_wowlan_support wowlan;
|
||||
const struct wiphy_wowlan_support *wowlan;
|
||||
struct cfg80211_wowlan *wowlan_config;
|
||||
#endif
|
||||
|
||||
@ -2853,7 +2859,7 @@ struct cfg80211_cached_keys;
|
||||
* @current_bss: (private) Used by the internal configuration code
|
||||
* @channel: (private) Used by the internal configuration code to track
|
||||
* the user-set AP, monitor and WDS channel
|
||||
* @preset_chan: (private) Used by the internal configuration code to
|
||||
* @preset_chandef: (private) Used by the internal configuration code to
|
||||
* track the channel to be used for AP later
|
||||
* @bssid: (private) Used by the internal configuration code
|
||||
* @ssid: (private) Used by the internal configuration code
|
||||
@ -2875,6 +2881,15 @@ struct cfg80211_cached_keys;
|
||||
* @p2p_started: true if this is a P2P Device that has been started
|
||||
* @cac_started: true if DFS channel availability check has been started
|
||||
* @cac_start_time: timestamp (jiffies) when the dfs state was entered.
|
||||
* @ps: powersave mode is enabled
|
||||
* @ps_timeout: dynamic powersave timeout
|
||||
* @ap_unexpected_nlportid: (private) netlink port ID of application
|
||||
* registered for unexpected class 3 frames (AP mode)
|
||||
* @conn: (private) cfg80211 software SME connection state machine data
|
||||
* @connect_keys: (private) keys to set after connection is established
|
||||
* @ibss_fixed: (private) IBSS is using fixed BSSID
|
||||
* @event_list: (private) list for internal event processing
|
||||
* @event_lock: (private) lock for event list
|
||||
*/
|
||||
struct wireless_dev {
|
||||
struct wiphy *wiphy;
|
||||
@ -2898,11 +2913,6 @@ struct wireless_dev {
|
||||
/* currently used for IBSS and SME - might be rearranged later */
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len, mesh_id_len, mesh_id_up_len;
|
||||
enum {
|
||||
CFG80211_SME_IDLE,
|
||||
CFG80211_SME_CONNECTING,
|
||||
CFG80211_SME_CONNECTED,
|
||||
} sme_state;
|
||||
struct cfg80211_conn *conn;
|
||||
struct cfg80211_cached_keys *connect_keys;
|
||||
|
||||
@ -3432,59 +3442,66 @@ void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
|
||||
void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
|
||||
|
||||
/**
|
||||
* cfg80211_send_rx_auth - notification of processed authentication
|
||||
* cfg80211_rx_mlme_mgmt - notification of processed MLME management frame
|
||||
* @dev: network device
|
||||
* @buf: authentication frame (header + body)
|
||||
* @len: length of the frame data
|
||||
*
|
||||
* This function is called whenever an authentication has been processed in
|
||||
* station mode. The driver is required to call either this function or
|
||||
* cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth()
|
||||
* call. This function may sleep. The caller must hold the corresponding wdev's
|
||||
* mutex.
|
||||
* This function is called whenever an authentication, disassociation or
|
||||
* deauthentication frame has been received and processed in station mode.
|
||||
* After being asked to authenticate via cfg80211_ops::auth() the driver must
|
||||
* call either this function or cfg80211_auth_timeout().
|
||||
* After being asked to associate via cfg80211_ops::assoc() the driver must
|
||||
* call either this function or cfg80211_auth_timeout().
|
||||
* While connected, the driver must calls this for received and processed
|
||||
* disassociation and deauthentication frames. If the frame couldn't be used
|
||||
* because it was unprotected, the driver must call the function
|
||||
* cfg80211_rx_unprot_mlme_mgmt() instead.
|
||||
*
|
||||
* This function may sleep. The caller must hold the corresponding wdev's mutex.
|
||||
*/
|
||||
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
|
||||
void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* cfg80211_send_auth_timeout - notification of timed out authentication
|
||||
* cfg80211_auth_timeout - notification of timed out authentication
|
||||
* @dev: network device
|
||||
* @addr: The MAC address of the device with which the authentication timed out
|
||||
*
|
||||
* This function may sleep. The caller must hold the corresponding wdev's
|
||||
* mutex.
|
||||
*/
|
||||
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
|
||||
void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
|
||||
|
||||
/**
|
||||
* cfg80211_send_rx_assoc - notification of processed association
|
||||
* cfg80211_rx_assoc_resp - notification of processed association response
|
||||
* @dev: network device
|
||||
* @bss: the BSS struct association was requested for, the struct reference
|
||||
* is owned by cfg80211 after this call
|
||||
* @buf: (re)association response frame (header + body)
|
||||
* @bss: the BSS that association was requested with, ownership of the pointer
|
||||
* moves to cfg80211 in this call
|
||||
* @buf: authentication frame (header + body)
|
||||
* @len: length of the frame data
|
||||
*
|
||||
* This function is called whenever a (re)association response has been
|
||||
* processed in station mode. The driver is required to call either this
|
||||
* function or cfg80211_send_assoc_timeout() to indicate the result of
|
||||
* cfg80211_ops::assoc() call. This function may sleep. The caller must hold
|
||||
* the corresponding wdev's mutex.
|
||||
* After being asked to associate via cfg80211_ops::assoc() the driver must
|
||||
* call either this function or cfg80211_auth_timeout().
|
||||
*
|
||||
* This function may sleep. The caller must hold the corresponding wdev's mutex.
|
||||
*/
|
||||
void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
|
||||
void cfg80211_rx_assoc_resp(struct net_device *dev,
|
||||
struct cfg80211_bss *bss,
|
||||
const u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* cfg80211_send_assoc_timeout - notification of timed out association
|
||||
* cfg80211_assoc_timeout - notification of timed out association
|
||||
* @dev: network device
|
||||
* @addr: The MAC address of the device with which the association timed out
|
||||
*
|
||||
* This function may sleep. The caller must hold the corresponding wdev's mutex.
|
||||
*/
|
||||
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
|
||||
void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr);
|
||||
|
||||
/**
|
||||
* cfg80211_send_deauth - notification of processed deauthentication
|
||||
* cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame
|
||||
* @dev: network device
|
||||
* @buf: deauthentication frame (header + body)
|
||||
* @buf: 802.11 frame (header + body)
|
||||
* @len: length of the frame data
|
||||
*
|
||||
* This function is called whenever deauthentication has been processed in
|
||||
@ -3492,46 +3509,20 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
|
||||
* locally generated ones. This function may sleep. The caller must hold the
|
||||
* corresponding wdev's mutex.
|
||||
*/
|
||||
void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len);
|
||||
void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* cfg80211_send_disassoc - notification of processed disassociation
|
||||
* @dev: network device
|
||||
* @buf: disassociation response frame (header + body)
|
||||
* @len: length of the frame data
|
||||
*
|
||||
* This function is called whenever disassociation has been processed in
|
||||
* station mode. This includes both received disassociation frames and locally
|
||||
* generated ones. This function may sleep. The caller must hold the
|
||||
* corresponding wdev's mutex.
|
||||
*/
|
||||
void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* cfg80211_send_unprot_deauth - notification of unprotected deauthentication
|
||||
* cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame
|
||||
* @dev: network device
|
||||
* @buf: deauthentication frame (header + body)
|
||||
* @len: length of the frame data
|
||||
*
|
||||
* This function is called whenever a received Deauthentication frame has been
|
||||
* dropped in station mode because of MFP being used but the Deauthentication
|
||||
* This function is called whenever a received deauthentication or dissassoc
|
||||
* frame has been dropped in station mode because of MFP being used but the
|
||||
* frame was not protected. This function may sleep.
|
||||
*/
|
||||
void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* cfg80211_send_unprot_disassoc - notification of unprotected disassociation
|
||||
* @dev: network device
|
||||
* @buf: disassociation frame (header + body)
|
||||
* @len: length of the frame data
|
||||
*
|
||||
* This function is called whenever a received Disassociation frame has been
|
||||
* dropped in station mode because of MFP being used but the Disassociation
|
||||
* frame was not protected. This function may sleep.
|
||||
*/
|
||||
void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
|
||||
size_t len);
|
||||
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev,
|
||||
const u8 *buf, size_t len);
|
||||
|
||||
/**
|
||||
* cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
|
||||
|
@ -217,8 +217,8 @@ struct ieee80211_chanctx_conf {
|
||||
* @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
|
||||
* @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS)
|
||||
* changed (currently only in P2P client mode, GO mode will be later)
|
||||
* @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when
|
||||
* it becomes valid, managed mode only)
|
||||
* @BSS_CHANGED_BEACON_INFO: Data from the AP's beacon became available:
|
||||
* currently dtim_period only is under consideration.
|
||||
* @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed,
|
||||
* note that this is only called when it changes after the channel
|
||||
* context had been assigned.
|
||||
@ -244,7 +244,7 @@ enum ieee80211_bss_change {
|
||||
BSS_CHANGED_PS = 1<<17,
|
||||
BSS_CHANGED_TXPOWER = 1<<18,
|
||||
BSS_CHANGED_P2P_PS = 1<<19,
|
||||
BSS_CHANGED_DTIM_PERIOD = 1<<20,
|
||||
BSS_CHANGED_BEACON_INFO = 1<<20,
|
||||
BSS_CHANGED_BANDWIDTH = 1<<21,
|
||||
|
||||
/* when adding here, make sure to change ieee80211_reconfig */
|
||||
@ -288,7 +288,7 @@ enum ieee80211_rssi_event {
|
||||
* IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
|
||||
* @dtim_period: num of beacons before the next DTIM, for beaconing,
|
||||
* valid in station mode only if after the driver was notified
|
||||
* with the %BSS_CHANGED_DTIM_PERIOD flag, will be non-zero then.
|
||||
* with the %BSS_CHANGED_BEACON_INFO flag, will be non-zero then.
|
||||
* @sync_tsf: last beacon's/probe response's TSF timestamp (could be old
|
||||
* as it may have been received during scanning long ago). If the
|
||||
* HW flag %IEEE80211_HW_TIMING_BEACON_ONLY is set, then this can
|
||||
@ -460,6 +460,8 @@ struct ieee80211_bss_conf {
|
||||
* @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
|
||||
* would be fragmented by size (this is optional, only used for
|
||||
* monitor injection).
|
||||
* @IEEE80211_TX_CTL_PS_RESPONSE: This frame is a response to a poll
|
||||
* frame (PS-Poll or uAPSD).
|
||||
*
|
||||
* Note: If you have to add new flags to the enumeration, then don't
|
||||
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
|
||||
@ -495,6 +497,7 @@ enum mac80211_tx_control_flags {
|
||||
IEEE80211_TX_STATUS_EOSP = BIT(28),
|
||||
IEEE80211_TX_CTL_USE_MINRATE = BIT(29),
|
||||
IEEE80211_TX_CTL_DONTFRAG = BIT(30),
|
||||
IEEE80211_TX_CTL_PS_RESPONSE = BIT(31),
|
||||
};
|
||||
|
||||
#define IEEE80211_TX_CTL_STBC_SHIFT 23
|
||||
|
@ -2577,6 +2577,10 @@ enum nl80211_mesh_power_mode {
|
||||
*
|
||||
* @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
|
||||
*
|
||||
* @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've
|
||||
* established peering with for longer than this time (in seconds), then
|
||||
* remove it from the STA's list of peers. Default is 30 minutes.
|
||||
*
|
||||
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
enum nl80211_meshconf_params {
|
||||
@ -2608,6 +2612,7 @@ enum nl80211_meshconf_params {
|
||||
NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
|
||||
NL80211_MESHCONF_POWER_MODE,
|
||||
NL80211_MESHCONF_AWAKE_WINDOW,
|
||||
NL80211_MESHCONF_PLINK_TIMEOUT,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_MESHCONF_ATTR_AFTER_LAST,
|
||||
@ -3579,6 +3584,10 @@ enum nl80211_ap_sme_features {
|
||||
* Peering Management entity which may be implemented by registering for
|
||||
* beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
|
||||
* still generated by the driver.
|
||||
* @NL80211_FEATURE_ACTIVE_MONITOR: This driver supports an active monitor
|
||||
* interface. An active monitor interface behaves like a normal monitor
|
||||
* interface, but gets added to the driver. It ensures that incoming
|
||||
* unicast packets directed at the configured interface address get ACKed.
|
||||
*/
|
||||
enum nl80211_feature_flags {
|
||||
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
|
||||
|
@ -1759,6 +1759,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
|
||||
/* mcast rate setting in Mesh Node */
|
||||
memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
|
||||
sizeof(setup->mcast_rate));
|
||||
sdata->vif.bss_conf.basic_rates = setup->basic_rates;
|
||||
|
||||
sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
|
||||
sdata->vif.bss_conf.dtim_period = setup->dtim_period;
|
||||
@ -1871,6 +1872,8 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
|
||||
if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask))
|
||||
conf->dot11MeshAwakeWindowDuration =
|
||||
nconf->dot11MeshAwakeWindowDuration;
|
||||
if (_chg_mesh_attr(NL80211_MESHCONF_PLINK_TIMEOUT, mask))
|
||||
conf->plink_timeout = nconf->plink_timeout;
|
||||
ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON);
|
||||
return 0;
|
||||
}
|
||||
@ -2838,6 +2841,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* configurations requiring offchan cannot work if no channel has been
|
||||
* specified
|
||||
*/
|
||||
if (need_offchan && !chan)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
/* Check if the operating channel is the requested channel */
|
||||
@ -2847,10 +2856,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
|
||||
if (chanctx_conf)
|
||||
need_offchan = chan != chanctx_conf->def.chan;
|
||||
else
|
||||
if (chanctx_conf) {
|
||||
need_offchan = chan && (chan != chanctx_conf->def.chan);
|
||||
} else if (!chan) {
|
||||
ret = -EINVAL;
|
||||
rcu_read_unlock();
|
||||
goto out_unlock;
|
||||
} else {
|
||||
need_offchan = true;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
@ -366,7 +366,7 @@ struct ieee80211_mgd_assoc_data {
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
bool wmm, uapsd;
|
||||
bool have_beacon, need_beacon;
|
||||
bool need_beacon;
|
||||
bool synced;
|
||||
bool timeout_started;
|
||||
|
||||
@ -404,6 +404,7 @@ struct ieee80211_if_managed {
|
||||
|
||||
bool powersave; /* powersave requested for this iface */
|
||||
bool broken_ap; /* AP is broken -- turn off powersave */
|
||||
bool have_beacon;
|
||||
u8 dtim_period;
|
||||
enum ieee80211_smps_mode req_smps, /* requested smps mode */
|
||||
driver_smps_mode; /* smps mode request */
|
||||
|
@ -686,8 +686,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) &&
|
||||
(!local->ops->suspend || !local->ops->resume))
|
||||
if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
|
@ -274,8 +274,7 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
|
||||
*pos++ = ifmsh->mesh_auth_id;
|
||||
/* Mesh Formation Info - number of neighbors */
|
||||
neighbors = atomic_read(&ifmsh->estab_plinks);
|
||||
/* Number of neighbor mesh STAs or 15 whichever is smaller */
|
||||
neighbors = (neighbors > 15) ? 15 : neighbors;
|
||||
neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
|
||||
*pos++ = neighbors << 1;
|
||||
/* Mesh capability */
|
||||
*pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
|
||||
@ -576,13 +575,11 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u32 changed;
|
||||
|
||||
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
|
||||
ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
|
||||
mesh_path_expire(sdata);
|
||||
|
||||
changed = mesh_accept_plinks_update(sdata);
|
||||
sdata_lock(sdata);
|
||||
ieee80211_mbss_info_change_notify(sdata, changed);
|
||||
sdata_unlock(sdata);
|
||||
|
||||
mod_timer(&ifmsh->housekeeping_timer,
|
||||
round_jiffies(jiffies +
|
||||
@ -741,9 +738,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
BSS_CHANGED_HT |
|
||||
BSS_CHANGED_BASIC_RATES |
|
||||
BSS_CHANGED_BEACON_INT;
|
||||
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
|
||||
struct ieee80211_supported_band *sband =
|
||||
sdata->local->hw.wiphy->bands[band];
|
||||
|
||||
local->fif_other_bss++;
|
||||
/* mesh ifaces must set allmulti to forward mcast traffic */
|
||||
@ -761,7 +755,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->vif.bss_conf.ht_operation_mode =
|
||||
ifmsh->mshcfg.ht_opmode;
|
||||
sdata->vif.bss_conf.enable_beacon = true;
|
||||
sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sband);
|
||||
|
||||
changed |= ieee80211_mps_local_status_update(sdata);
|
||||
|
||||
@ -789,12 +782,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
sdata_lock(sdata);
|
||||
bcn = rcu_dereference_protected(ifmsh->beacon,
|
||||
lockdep_is_held(&sdata->wdev.mtx));
|
||||
rcu_assign_pointer(ifmsh->beacon, NULL);
|
||||
kfree_rcu(bcn, rcu_head);
|
||||
sdata_unlock(sdata);
|
||||
|
||||
/* flush STAs and mpaths on this iface */
|
||||
sta_info_flush(sdata);
|
||||
@ -807,14 +798,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
del_timer_sync(&sdata->u.mesh.housekeeping_timer);
|
||||
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
|
||||
del_timer_sync(&sdata->u.mesh.mesh_path_timer);
|
||||
/*
|
||||
* If the timer fired while we waited for it, it will have
|
||||
* requeued the work. Now the work will be running again
|
||||
* but will not rearm the timer again because it checks
|
||||
* whether the interface is running, which, at this point,
|
||||
* it no longer is.
|
||||
*/
|
||||
cancel_work_sync(&sdata->work);
|
||||
|
||||
local->fif_other_bss--;
|
||||
atomic_dec(&local->iff_allmultis);
|
||||
@ -955,6 +938,12 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u16 stype;
|
||||
|
||||
sdata_lock(sdata);
|
||||
|
||||
/* mesh already went down */
|
||||
if (!sdata->wdev.mesh_id_len)
|
||||
goto out;
|
||||
|
||||
rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
mgmt = (struct ieee80211_mgmt *) skb->data;
|
||||
stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
|
||||
@ -972,12 +961,20 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
||||
sdata_lock(sdata);
|
||||
|
||||
/* mesh already went down */
|
||||
if (!sdata->wdev.mesh_id_len)
|
||||
goto out;
|
||||
|
||||
if (ifmsh->preq_queue_len &&
|
||||
time_after(jiffies,
|
||||
ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
|
||||
@ -997,6 +994,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
|
||||
mesh_sync_adjust_tbtt(sdata);
|
||||
|
||||
out:
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
|
||||
|
@ -188,7 +188,6 @@ struct mesh_rmc {
|
||||
u32 idx_mask;
|
||||
};
|
||||
|
||||
#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
|
||||
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
|
||||
|
||||
#define MESH_PATH_EXPIRE (600 * HZ)
|
||||
@ -324,14 +323,14 @@ static inline
|
||||
u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
atomic_inc(&sdata->u.mesh.estab_plinks);
|
||||
return mesh_accept_plinks_update(sdata);
|
||||
return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON;
|
||||
}
|
||||
|
||||
static inline
|
||||
u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
atomic_dec(&sdata->u.mesh.estab_plinks);
|
||||
return mesh_accept_plinks_update(sdata);
|
||||
return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON;
|
||||
}
|
||||
|
||||
static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -517,9 +517,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_mps_frame_release(sta, elems);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
sdata_lock(sdata);
|
||||
ieee80211_mbss_info_change_notify(sdata, changed);
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
static void mesh_plink_timer(unsigned long data)
|
||||
@ -1070,9 +1068,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (changed) {
|
||||
sdata_lock(sdata);
|
||||
if (changed)
|
||||
ieee80211_mbss_info_change_notify(sdata, changed);
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
}
|
||||
|
@ -880,6 +880,10 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||
IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
|
||||
if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
|
||||
IEEE80211_STA_CONNECTION_POLL))
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
|
||||
@ -1356,7 +1360,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
|
||||
IEEE80211_STA_CONNECTION_POLL))
|
||||
return false;
|
||||
|
||||
if (!sdata->vif.bss_conf.dtim_period)
|
||||
if (!mgd->have_beacon)
|
||||
return false;
|
||||
|
||||
rcu_read_lock();
|
||||
@ -1767,7 +1771,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_led_assoc(local, 1);
|
||||
|
||||
if (sdata->u.mgd.assoc_data->have_beacon) {
|
||||
if (sdata->u.mgd.have_beacon) {
|
||||
/*
|
||||
* If the AP is buggy we may get here with no DTIM period
|
||||
* known, so assume it's 1 which is the only safe assumption
|
||||
@ -1775,7 +1779,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||
* probably just won't work at all.
|
||||
*/
|
||||
bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
|
||||
bss_info_changed |= BSS_CHANGED_DTIM_PERIOD;
|
||||
bss_info_changed |= BSS_CHANGED_BEACON_INFO;
|
||||
} else {
|
||||
bss_conf->dtim_period = 0;
|
||||
}
|
||||
@ -1899,6 +1903,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
del_timer_sync(&sdata->u.mgd.chswitch_timer);
|
||||
|
||||
sdata->vif.bss_conf.dtim_period = 0;
|
||||
ifmgd->have_beacon = false;
|
||||
|
||||
ifmgd->flags = 0;
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
@ -2151,7 +2156,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
|
||||
IEEE80211_MAX_QUEUE_MAP,
|
||||
IEEE80211_QUEUE_STOP_REASON_CSA);
|
||||
|
||||
cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
|
||||
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
@ -2298,7 +2304,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
|
||||
sdata_info(sdata, "%pM denied authentication (status %d)\n",
|
||||
mgmt->sa, status_code);
|
||||
ieee80211_destroy_auth_data(sdata, false);
|
||||
cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len);
|
||||
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2333,7 +2339,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
|
||||
* Report auth frame to user space for processing since another
|
||||
* round of Authentication frames is still needed.
|
||||
*/
|
||||
cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len);
|
||||
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2350,7 +2356,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
|
||||
cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len);
|
||||
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
|
||||
return;
|
||||
out_err:
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
@ -2383,7 +2389,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, len);
|
||||
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
|
||||
}
|
||||
|
||||
|
||||
@ -2409,7 +2415,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, len);
|
||||
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
|
||||
}
|
||||
|
||||
static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
|
||||
@ -2707,7 +2713,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
/* oops -- internal error -- send timeout for now */
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
cfg80211_put_bss(sdata->local->hw.wiphy, bss);
|
||||
cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
|
||||
cfg80211_assoc_timeout(sdata->dev, mgmt->bssid);
|
||||
return;
|
||||
}
|
||||
sdata_info(sdata, "associated\n");
|
||||
@ -2720,7 +2726,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_destroy_assoc_data(sdata, true);
|
||||
}
|
||||
|
||||
cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, len);
|
||||
cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
@ -2732,24 +2738,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
int freq;
|
||||
struct ieee80211_bss *bss;
|
||||
struct ieee80211_channel *channel;
|
||||
bool need_ps = false;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
if ((sdata->u.mgd.associated &&
|
||||
ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
|
||||
(sdata->u.mgd.assoc_data &&
|
||||
ether_addr_equal(mgmt->bssid,
|
||||
sdata->u.mgd.assoc_data->bss->bssid))) {
|
||||
/* not previously set so we may need to recalc */
|
||||
need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period;
|
||||
|
||||
if (elems->tim && !elems->parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems->tim;
|
||||
sdata->u.mgd.dtim_period = tim_ie->dtim_period;
|
||||
}
|
||||
}
|
||||
|
||||
if (elems->ds_params)
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0],
|
||||
rx_status->band);
|
||||
@ -2770,12 +2761,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
!ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
|
||||
return;
|
||||
|
||||
if (need_ps) {
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
|
||||
elems, true);
|
||||
|
||||
@ -2889,7 +2874,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
len - baselen, false, &elems);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
ifmgd->assoc_data->have_beacon = true;
|
||||
if (elems.tim && !elems.parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems.tim;
|
||||
ifmgd->dtim_period = tim_ie->dtim_period;
|
||||
}
|
||||
ifmgd->have_beacon = true;
|
||||
ifmgd->assoc_data->need_beacon = false;
|
||||
if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
|
||||
sdata->vif.bss_conf.sync_tsf =
|
||||
@ -3071,7 +3060,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
* If we haven't had a beacon before, tell the driver about the
|
||||
* DTIM period (and beacon timing if desired) now.
|
||||
*/
|
||||
if (!bss_conf->dtim_period) {
|
||||
if (!ifmgd->have_beacon) {
|
||||
/* a few bogus AP send dtim_period = 0 or no TIM IE */
|
||||
if (elems.tim)
|
||||
bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
|
||||
@ -3090,7 +3079,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
}
|
||||
|
||||
changed |= BSS_CHANGED_DTIM_PERIOD;
|
||||
changed |= BSS_CHANGED_BEACON_INFO;
|
||||
ifmgd->have_beacon = true;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
ieee80211_recalc_ps_vif(sdata);
|
||||
}
|
||||
|
||||
@ -3113,8 +3108,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||||
WLAN_REASON_DEAUTH_LEAVING,
|
||||
true, deauth_buf);
|
||||
cfg80211_send_deauth(sdata->dev, deauth_buf,
|
||||
sizeof(deauth_buf));
|
||||
cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf,
|
||||
sizeof(deauth_buf));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3232,7 +3227,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
|
||||
tx, frame_buf);
|
||||
|
||||
cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
|
||||
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
}
|
||||
|
||||
static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
||||
@ -3423,15 +3419,14 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
ieee80211_destroy_auth_data(sdata, false);
|
||||
|
||||
cfg80211_send_auth_timeout(sdata->dev, bssid);
|
||||
cfg80211_auth_timeout(sdata->dev, bssid);
|
||||
}
|
||||
} else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started)
|
||||
run_again(sdata, ifmgd->auth_data->timeout);
|
||||
|
||||
if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started &&
|
||||
time_after(jiffies, ifmgd->assoc_data->timeout)) {
|
||||
if ((ifmgd->assoc_data->need_beacon &&
|
||||
!ifmgd->assoc_data->have_beacon) ||
|
||||
if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
|
||||
ieee80211_do_assoc(sdata)) {
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
@ -3439,7 +3434,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
|
||||
cfg80211_send_assoc_timeout(sdata->dev, bssid);
|
||||
cfg80211_assoc_timeout(sdata->dev, bssid);
|
||||
}
|
||||
} else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
|
||||
run_again(sdata, ifmgd->assoc_data->timeout);
|
||||
@ -3988,8 +3983,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||
WLAN_REASON_UNSPECIFIED,
|
||||
false, frame_buf);
|
||||
|
||||
cfg80211_send_deauth(sdata->dev, frame_buf,
|
||||
sizeof(frame_buf));
|
||||
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
|
||||
sizeof(frame_buf));
|
||||
}
|
||||
|
||||
sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
|
||||
@ -4051,8 +4046,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
WLAN_REASON_UNSPECIFIED,
|
||||
false, frame_buf);
|
||||
|
||||
cfg80211_send_deauth(sdata->dev, frame_buf,
|
||||
sizeof(frame_buf));
|
||||
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
|
||||
sizeof(frame_buf));
|
||||
}
|
||||
|
||||
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
|
||||
@ -4199,6 +4194,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ifmgd->assoc_data = assoc_data;
|
||||
ifmgd->dtim_period = 0;
|
||||
ifmgd->have_beacon = false;
|
||||
|
||||
err = ieee80211_prep_connection(sdata, req->bss, true);
|
||||
if (err)
|
||||
@ -4230,7 +4226,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
ifmgd->dtim_period = tim->dtim_period;
|
||||
dtim_count = tim->dtim_count;
|
||||
}
|
||||
assoc_data->have_beacon = true;
|
||||
ifmgd->have_beacon = true;
|
||||
assoc_data->timeout = jiffies;
|
||||
assoc_data->timeout_started = true;
|
||||
|
||||
@ -4305,8 +4301,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
out:
|
||||
if (report_frame)
|
||||
cfg80211_send_deauth(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4336,8 +4332,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
req->reason_code, !req->local_state_change,
|
||||
frame_buf);
|
||||
|
||||
cfg80211_send_disassoc(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1747,27 +1747,21 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
|
||||
if (unlikely(!ieee80211_has_protected(fc) &&
|
||||
ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
|
||||
rx->key)) {
|
||||
if (ieee80211_is_deauth(fc))
|
||||
cfg80211_send_unprot_deauth(rx->sdata->dev,
|
||||
rx->skb->data,
|
||||
rx->skb->len);
|
||||
else if (ieee80211_is_disassoc(fc))
|
||||
cfg80211_send_unprot_disassoc(rx->sdata->dev,
|
||||
rx->skb->data,
|
||||
rx->skb->len);
|
||||
if (ieee80211_is_deauth(fc) ||
|
||||
ieee80211_is_disassoc(fc))
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
rx->skb->data,
|
||||
rx->skb->len);
|
||||
return -EACCES;
|
||||
}
|
||||
/* BIP does not use Protected field, so need to check MMIE */
|
||||
if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
|
||||
ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
|
||||
if (ieee80211_is_deauth(fc))
|
||||
cfg80211_send_unprot_deauth(rx->sdata->dev,
|
||||
rx->skb->data,
|
||||
rx->skb->len);
|
||||
else if (ieee80211_is_disassoc(fc))
|
||||
cfg80211_send_unprot_disassoc(rx->sdata->dev,
|
||||
rx->skb->data,
|
||||
rx->skb->len);
|
||||
if (ieee80211_is_deauth(fc) ||
|
||||
ieee80211_is_disassoc(fc))
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
rx->skb->data,
|
||||
rx->skb->len);
|
||||
return -EACCES;
|
||||
}
|
||||
/*
|
||||
|
@ -1132,6 +1132,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
||||
* ends the poll/service period.
|
||||
*/
|
||||
info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
|
||||
IEEE80211_TX_CTL_PS_RESPONSE |
|
||||
IEEE80211_TX_STATUS_EOSP |
|
||||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
|
||||
@ -1269,7 +1270,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
* STA may still remain is PS mode after this frame
|
||||
* exchange.
|
||||
*/
|
||||
info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
|
||||
info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
|
||||
IEEE80211_TX_CTL_PS_RESPONSE;
|
||||
|
||||
/*
|
||||
* Use MoreData flag to indicate whether there are
|
||||
|
@ -297,6 +297,9 @@ struct sta_ampdu_mlme {
|
||||
* @rcu_head: RCU head used for freeing this station struct
|
||||
* @cur_max_bandwidth: maximum bandwidth to use for TX to the station,
|
||||
* taken from HT/VHT capabilities or VHT operating mode notification
|
||||
* @chains: chains ever used for RX from this station
|
||||
* @chain_signal_last: last signal (per chain)
|
||||
* @chain_signal_avg: signal average (per chain)
|
||||
*/
|
||||
struct sta_info {
|
||||
/* General information, mostly static */
|
||||
|
@ -1790,12 +1790,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
|
||||
/* Do not send frames with mesh_ttl == 0 */
|
||||
sdata->u.mesh.mshstats.dropped_frames_ttl++;
|
||||
goto fail_rcu;
|
||||
}
|
||||
|
||||
if (!is_multicast_ether_addr(skb->data)) {
|
||||
struct sta_info *next_hop;
|
||||
bool mpp_lookup = true;
|
||||
|
@ -1584,8 +1584,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
BSS_CHANGED_ARP_FILTER |
|
||||
BSS_CHANGED_PS;
|
||||
|
||||
if (sdata->u.mgd.dtim_period)
|
||||
changed |= BSS_CHANGED_DTIM_PERIOD;
|
||||
/* Re-send beacon info report to the driver */
|
||||
if (sdata->u.mgd.have_beacon)
|
||||
changed |= BSS_CHANGED_BEACON_INFO;
|
||||
|
||||
sdata_lock(sdata);
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
|
@ -301,6 +301,9 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* atomic_inc_return makes it start at 1, make it start at 0 */
|
||||
rdev->wiphy_idx--;
|
||||
|
||||
/* give it a proper name */
|
||||
dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
|
||||
|
||||
@ -449,8 +452,13 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
u16 ifmodes = wiphy->interface_modes;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
|
||||
!(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
|
||||
if (WARN_ON(wiphy->wowlan &&
|
||||
(wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
|
||||
!(wiphy->wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(wiphy->wowlan &&
|
||||
!wiphy->wowlan->flags && !wiphy->wowlan->n_patterns &&
|
||||
!wiphy->wowlan->tcp))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
@ -540,25 +548,28 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (rdev->wiphy.wowlan.n_patterns) {
|
||||
if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
|
||||
rdev->wiphy.wowlan.pattern_min_len >
|
||||
rdev->wiphy.wowlan.pattern_max_len))
|
||||
return -EINVAL;
|
||||
}
|
||||
if (WARN_ON(rdev->wiphy.wowlan && rdev->wiphy.wowlan->n_patterns &&
|
||||
(!rdev->wiphy.wowlan->pattern_min_len ||
|
||||
rdev->wiphy.wowlan->pattern_min_len >
|
||||
rdev->wiphy.wowlan->pattern_max_len)))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
/* check and set up bitrates */
|
||||
ieee80211_set_bitrate_flags(wiphy);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
res = device_add(&rdev->wiphy.dev);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = rfkill_register(rdev->rfkill);
|
||||
if (res) {
|
||||
rtnl_unlock();
|
||||
device_del(&rdev->wiphy.dev);
|
||||
return res;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
/* set up regulatory info */
|
||||
wiphy_regulatory_register(wiphy);
|
||||
|
||||
@ -585,17 +596,6 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
|
||||
cfg80211_debugfs_rdev_add(rdev);
|
||||
|
||||
res = rfkill_register(rdev->rfkill);
|
||||
if (res) {
|
||||
device_del(&rdev->wiphy.dev);
|
||||
|
||||
debugfs_remove_recursive(rdev->wiphy.debugfsdir);
|
||||
list_del_rcu(&rdev->list);
|
||||
wiphy_regulatory_deregister(wiphy);
|
||||
rtnl_unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
rdev->wiphy.registered = true;
|
||||
rtnl_unlock();
|
||||
return 0;
|
||||
@ -632,11 +632,11 @@ void wiphy_unregister(struct wiphy *wiphy)
|
||||
rtnl_unlock();
|
||||
__count == 0; }));
|
||||
|
||||
rfkill_unregister(rdev->rfkill);
|
||||
|
||||
rtnl_lock();
|
||||
rdev->wiphy.registered = false;
|
||||
|
||||
rfkill_unregister(rdev->rfkill);
|
||||
|
||||
BUG_ON(!list_empty(&rdev->wdev_list));
|
||||
|
||||
/*
|
||||
@ -817,7 +817,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
pr_err("failed to add phy80211 symlink to netdev!\n");
|
||||
}
|
||||
wdev->netdev = dev;
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
wdev->wext.default_key = -1;
|
||||
wdev->wext.default_mgmt_key = -1;
|
||||
|
@ -308,11 +308,6 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
|
||||
bool local_state_change);
|
||||
void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev);
|
||||
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
u16 status, bool wextev,
|
||||
struct cfg80211_bss *bss);
|
||||
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
|
||||
u16 frame_type, const u8 *match_data,
|
||||
int match_len);
|
||||
@ -328,12 +323,19 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
|
||||
void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
|
||||
const struct ieee80211_vht_cap *vht_capa_mask);
|
||||
|
||||
/* SME */
|
||||
/* SME events */
|
||||
int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_connect_params *connect,
|
||||
struct cfg80211_cached_keys *connkeys,
|
||||
const u8 *prev_bssid);
|
||||
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
u16 status, bool wextev,
|
||||
struct cfg80211_bss *bss);
|
||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
size_t ie_len, u16 reason, bool from_ap);
|
||||
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, u16 reason,
|
||||
bool wextev);
|
||||
@ -344,21 +346,21 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
|
||||
/* SME implementation */
|
||||
void cfg80211_conn_work(struct work_struct *work);
|
||||
void cfg80211_sme_failed_assoc(struct wireless_dev *wdev);
|
||||
bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
|
||||
void cfg80211_sme_scan_done(struct net_device *dev);
|
||||
bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status);
|
||||
void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len);
|
||||
void cfg80211_sme_disassoc(struct wireless_dev *wdev);
|
||||
void cfg80211_sme_deauth(struct wireless_dev *wdev);
|
||||
void cfg80211_sme_auth_timeout(struct wireless_dev *wdev);
|
||||
void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev);
|
||||
|
||||
/* internal helpers */
|
||||
bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
|
||||
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
|
||||
struct key_params *params, int key_idx,
|
||||
bool pairwise, const u8 *mac_addr);
|
||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
size_t ie_len, u16 reason, bool from_ap);
|
||||
void cfg80211_sme_scan_done(struct net_device *dev);
|
||||
void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
|
||||
void cfg80211_sme_disassoc(struct net_device *dev,
|
||||
struct cfg80211_internal_bss *bss);
|
||||
void __cfg80211_scan_done(struct work_struct *wk);
|
||||
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
|
||||
void __cfg80211_sched_scan_results(struct work_struct *wk);
|
||||
|
@ -43,7 +43,6 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
wdev->current_bss = bss_from_pub(bss);
|
||||
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
cfg80211_upload_connect_keys(wdev);
|
||||
|
||||
nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
|
||||
@ -64,8 +63,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
|
||||
|
||||
trace_cfg80211_ibss_joined(dev, bssid);
|
||||
|
||||
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
|
||||
|
||||
ev = kzalloc(sizeof(*ev), gfp);
|
||||
if (!ev)
|
||||
return;
|
||||
@ -120,7 +117,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
wdev->wext.ibss.chandef = params->chandef;
|
||||
#endif
|
||||
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan,
|
||||
params->channel_fixed
|
||||
@ -134,7 +130,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
err = rdev_join_ibss(rdev, dev, params);
|
||||
if (err) {
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -186,7 +181,6 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
|
||||
}
|
||||
|
||||
wdev->current_bss = NULL;
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
wdev->ssid_len = 0;
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
if (!nowext)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define MESH_PATH_TO_ROOT_TIMEOUT 6000
|
||||
#define MESH_ROOT_INTERVAL 5000
|
||||
#define MESH_ROOT_CONFIRMATION_INTERVAL 2000
|
||||
#define MESH_DEFAULT_PLINK_TIMEOUT 1800 /* timeout in seconds */
|
||||
|
||||
/*
|
||||
* Minimum interval between two consecutive PREQs originated by the same
|
||||
@ -75,6 +76,7 @@ const struct mesh_config default_mesh_config = {
|
||||
.dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
|
||||
.power_mode = NL80211_MESH_POWER_ACTIVE,
|
||||
.dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW,
|
||||
.plink_timeout = MESH_DEFAULT_PLINK_TIMEOUT,
|
||||
};
|
||||
|
||||
const struct mesh_setup default_mesh_setup = {
|
||||
@ -160,6 +162,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
setup->chandef.center_freq1 = setup->chandef.chan->center_freq;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if basic rates are available otherwise use mandatory rates as
|
||||
* basic rates
|
||||
*/
|
||||
if (!setup->basic_rates) {
|
||||
struct ieee80211_supported_band *sband =
|
||||
rdev->wiphy.bands[setup->chandef.chan->band];
|
||||
setup->basic_rates = ieee80211_mandatory_rates(sband);
|
||||
}
|
||||
|
||||
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -18,150 +18,107 @@
|
||||
#include "rdev-ops.h"
|
||||
|
||||
|
||||
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_send_rx_auth(dev);
|
||||
|
||||
nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
|
||||
cfg80211_sme_rx_auth(dev, buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_rx_auth);
|
||||
|
||||
void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
|
||||
void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
u16 status_code;
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
||||
u8 *ie = mgmt->u.assoc_resp.variable;
|
||||
int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
|
||||
u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
|
||||
trace_cfg80211_send_rx_assoc(dev, bss);
|
||||
|
||||
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
|
||||
/*
|
||||
* This is a bit of a hack, we don't notify userspace of
|
||||
* a (re-)association reply if we tried to send a reassoc
|
||||
* and got a reject -- we only try again with an assoc
|
||||
* frame instead of reassoc.
|
||||
*/
|
||||
if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
|
||||
cfg80211_sme_failed_reassoc(wdev)) {
|
||||
if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
|
||||
|
||||
if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) {
|
||||
cfg80211_sme_failed_assoc(wdev);
|
||||
/*
|
||||
* do not call connect_result() now because the
|
||||
* sme will schedule work that does it later.
|
||||
*/
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
|
||||
/*
|
||||
* This is for the userspace SME, the CONNECTING
|
||||
* state will be changed to CONNECTED by
|
||||
* __cfg80211_connect_result() below.
|
||||
*/
|
||||
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||||
}
|
||||
|
||||
/* this consumes the bss reference */
|
||||
/* update current_bss etc., consumes the bss reference */
|
||||
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
|
||||
status_code,
|
||||
status_code == WLAN_STATUS_SUCCESS, bss);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_rx_assoc);
|
||||
EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
|
||||
|
||||
void cfg80211_send_deauth(struct net_device *dev,
|
||||
const u8 *buf, size_t len)
|
||||
static void cfg80211_process_auth(struct wireless_dev *wdev,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
||||
const u8 *bssid = mgmt->bssid;
|
||||
bool was_current = false;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
|
||||
trace_cfg80211_send_deauth(dev);
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->current_bss &&
|
||||
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
was_current = true;
|
||||
}
|
||||
|
||||
nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
|
||||
|
||||
if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
|
||||
u16 reason_code;
|
||||
bool from_ap;
|
||||
|
||||
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
|
||||
|
||||
from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
|
||||
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
|
||||
} else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
|
||||
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
false, NULL);
|
||||
}
|
||||
nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
|
||||
cfg80211_sme_rx_auth(wdev, buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_deauth);
|
||||
|
||||
void cfg80211_send_disassoc(struct net_device *dev,
|
||||
const u8 *buf, size_t len)
|
||||
static void cfg80211_process_deauth(struct wireless_dev *wdev,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
||||
const u8 *bssid = mgmt->bssid;
|
||||
u16 reason_code;
|
||||
bool from_ap;
|
||||
u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
|
||||
bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
|
||||
|
||||
trace_cfg80211_send_disassoc(dev);
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
|
||||
|
||||
nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTED)
|
||||
if (!wdev->current_bss ||
|
||||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
|
||||
return;
|
||||
|
||||
if (wdev->current_bss &&
|
||||
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
|
||||
cfg80211_sme_disassoc(dev, wdev->current_bss);
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
} else
|
||||
WARN_ON(1);
|
||||
|
||||
|
||||
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
|
||||
|
||||
from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
|
||||
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
|
||||
__cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
|
||||
cfg80211_sme_deauth(wdev);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_disassoc);
|
||||
|
||||
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
|
||||
static void cfg80211_process_disassoc(struct wireless_dev *wdev,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
||||
const u8 *bssid = mgmt->bssid;
|
||||
u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
|
||||
bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
|
||||
|
||||
nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL);
|
||||
|
||||
if (WARN_ON(!wdev->current_bss ||
|
||||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
|
||||
return;
|
||||
|
||||
__cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
|
||||
cfg80211_sme_disassoc(wdev);
|
||||
}
|
||||
|
||||
void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_mgmt *mgmt = (void *)buf;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
trace_cfg80211_rx_mlme_mgmt(dev, buf, len);
|
||||
|
||||
if (WARN_ON(len < 2))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_auth(mgmt->frame_control))
|
||||
cfg80211_process_auth(wdev, buf, len);
|
||||
else if (ieee80211_is_deauth(mgmt->frame_control))
|
||||
cfg80211_process_deauth(wdev, buf, len);
|
||||
else if (ieee80211_is_disassoc(mgmt->frame_control))
|
||||
cfg80211_process_disassoc(wdev, buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
|
||||
|
||||
void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
@ -170,14 +127,11 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
|
||||
trace_cfg80211_send_auth_timeout(dev, addr);
|
||||
|
||||
nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
|
||||
if (wdev->sme_state == CFG80211_SME_CONNECTING)
|
||||
__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
false, NULL);
|
||||
cfg80211_sme_auth_timeout(wdev);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_auth_timeout);
|
||||
EXPORT_SYMBOL(cfg80211_auth_timeout);
|
||||
|
||||
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
|
||||
void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
@ -186,12 +140,28 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
|
||||
trace_cfg80211_send_assoc_timeout(dev, addr);
|
||||
|
||||
nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
|
||||
if (wdev->sme_state == CFG80211_SME_CONNECTING)
|
||||
__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
false, NULL);
|
||||
cfg80211_sme_assoc_timeout(wdev);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
|
||||
EXPORT_SYMBOL(cfg80211_assoc_timeout);
|
||||
|
||||
void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_mgmt *mgmt = (void *)buf;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
trace_cfg80211_tx_mlme_mgmt(dev, buf, len);
|
||||
|
||||
if (WARN_ON(len < 2))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_deauth(mgmt->frame_control))
|
||||
cfg80211_process_deauth(wdev, buf, len);
|
||||
else
|
||||
cfg80211_process_disassoc(wdev, buf, len);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt);
|
||||
|
||||
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
|
||||
enum nl80211_key_type key_type, int key_id,
|
||||
@ -314,21 +284,12 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
bool was_connected = false;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->current_bss && req->prev_bssid &&
|
||||
ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) {
|
||||
/*
|
||||
* Trying to reassociate: Allow this to proceed and let the old
|
||||
* association to be dropped when the new one is completed.
|
||||
*/
|
||||
if (wdev->sme_state == CFG80211_SME_CONNECTED) {
|
||||
was_connected = true;
|
||||
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||||
}
|
||||
} else if (wdev->current_bss)
|
||||
if (wdev->current_bss &&
|
||||
(!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid,
|
||||
req->prev_bssid)))
|
||||
return -EALREADY;
|
||||
|
||||
cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
|
||||
@ -338,11 +299,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
|
||||
req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
if (!req->bss) {
|
||||
if (was_connected)
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
if (!req->bss)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
@ -351,11 +309,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
err = rdev_assoc(rdev, dev, req);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
if (was_connected)
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
if (err)
|
||||
cfg80211_put_bss(&rdev->wiphy, req->bss);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -376,8 +331,9 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (local_state_change && (!wdev->current_bss ||
|
||||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
|
||||
if (local_state_change &&
|
||||
(!wdev->current_bss ||
|
||||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
|
||||
return 0;
|
||||
|
||||
return rdev_deauth(rdev, dev, &req);
|
||||
@ -395,13 +351,11 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
|
||||
.ie = ie,
|
||||
.ie_len = ie_len,
|
||||
};
|
||||
int err;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTED)
|
||||
return -ENOTCONN;
|
||||
|
||||
if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state))
|
||||
if (!wdev->current_bss)
|
||||
return -ENOTCONN;
|
||||
|
||||
if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
|
||||
@ -409,7 +363,13 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
|
||||
else
|
||||
return -ENOTCONN;
|
||||
|
||||
return rdev_disassoc(rdev, dev, &req);
|
||||
err = rdev_disassoc(rdev, dev, &req);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* driver should have reported the disassoc */
|
||||
WARN_ON(wdev->current_bss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
||||
@ -417,10 +377,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
u8 bssid[ETH_ALEN];
|
||||
struct cfg80211_deauth_request req = {
|
||||
.reason_code = WLAN_REASON_DEAUTH_LEAVING,
|
||||
.bssid = bssid,
|
||||
};
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
@ -431,13 +387,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
||||
return;
|
||||
|
||||
memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
|
||||
rdev_deauth(rdev, dev, &req);
|
||||
|
||||
if (wdev->current_bss) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
}
|
||||
cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
|
||||
WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
}
|
||||
|
||||
struct cfg80211_mgmt_registration {
|
||||
|
@ -800,12 +800,9 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (!wdev->current_bss)
|
||||
return -ENOLINK;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTED)
|
||||
if (!wdev->current_bss)
|
||||
return -ENOLINK;
|
||||
break;
|
||||
default:
|
||||
@ -908,7 +905,7 @@ nla_put_failure:
|
||||
static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
|
||||
struct sk_buff *msg)
|
||||
{
|
||||
const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp;
|
||||
const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
|
||||
struct nlattr *nl_tcp;
|
||||
|
||||
if (!tcp)
|
||||
@ -951,37 +948,37 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
|
||||
{
|
||||
struct nlattr *nl_wowlan;
|
||||
|
||||
if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns)
|
||||
if (!dev->wiphy.wowlan)
|
||||
return 0;
|
||||
|
||||
nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
|
||||
if (!nl_wowlan)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
|
||||
if (((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
|
||||
((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
|
||||
((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
|
||||
((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
|
||||
((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
|
||||
((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
|
||||
((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
|
||||
((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
|
||||
((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
|
||||
((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
|
||||
((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
|
||||
((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
|
||||
((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
|
||||
((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
|
||||
((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
|
||||
nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (dev->wiphy.wowlan.n_patterns) {
|
||||
if (dev->wiphy.wowlan->n_patterns) {
|
||||
struct nl80211_wowlan_pattern_support pat = {
|
||||
.max_patterns = dev->wiphy.wowlan.n_patterns,
|
||||
.min_pattern_len = dev->wiphy.wowlan.pattern_min_len,
|
||||
.max_pattern_len = dev->wiphy.wowlan.pattern_max_len,
|
||||
.max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset,
|
||||
.max_patterns = dev->wiphy.wowlan->n_patterns,
|
||||
.min_pattern_len = dev->wiphy.wowlan->pattern_min_len,
|
||||
.max_pattern_len = dev->wiphy.wowlan->pattern_max_len,
|
||||
.max_pkt_offset = dev->wiphy.wowlan->max_pkt_offset,
|
||||
};
|
||||
|
||||
if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
|
||||
@ -1544,8 +1541,10 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
|
||||
|
||||
netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||
if (!netdev)
|
||||
if (!netdev) {
|
||||
rtnl_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
if (netdev->ieee80211_ptr) {
|
||||
dev = wiphy_to_dev(
|
||||
netdev->ieee80211_ptr->wiphy);
|
||||
@ -1589,6 +1588,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
!skb->len &&
|
||||
cb->min_dump_alloc < 4096) {
|
||||
cb->min_dump_alloc = 4096;
|
||||
rtnl_unlock();
|
||||
return 1;
|
||||
}
|
||||
idx--;
|
||||
@ -3975,10 +3975,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
params.listen_interval =
|
||||
nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_STA_AID])
|
||||
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
|
||||
else
|
||||
if (info->attrs[NL80211_ATTR_PEER_AID])
|
||||
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
|
||||
else
|
||||
params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
|
||||
if (!params.aid || params.aid > IEEE80211_MAX_AID)
|
||||
return -EINVAL;
|
||||
|
||||
@ -4030,7 +4030,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
|
||||
|
||||
/* TDLS peers cannot be added */
|
||||
if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
|
||||
if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
|
||||
info->attrs[NL80211_ATTR_PEER_AID])
|
||||
return -EINVAL;
|
||||
/* but don't bother the driver with it */
|
||||
params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
|
||||
@ -4056,7 +4057,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
|
||||
return -EINVAL;
|
||||
/* TDLS peers cannot be added */
|
||||
if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
|
||||
if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
|
||||
info->attrs[NL80211_ATTR_PEER_AID])
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@ -4578,7 +4580,9 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
|
||||
nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
|
||||
cur_params.power_mode) ||
|
||||
nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
|
||||
cur_params.dot11MeshAwakeWindowDuration))
|
||||
cur_params.dot11MeshAwakeWindowDuration) ||
|
||||
nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
|
||||
cur_params.plink_timeout))
|
||||
goto nla_put_failure;
|
||||
nla_nest_end(msg, pinfoattr);
|
||||
genlmsg_end(msg, hdr);
|
||||
@ -4619,6 +4623,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
|
||||
[NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
|
||||
[NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
|
||||
[NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
|
||||
[NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
@ -4756,6 +4761,9 @@ do { \
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
|
||||
0, 65535, mask,
|
||||
NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff,
|
||||
mask, NL80211_MESHCONF_PLINK_TIMEOUT,
|
||||
nla_get_u32);
|
||||
if (mask_out)
|
||||
*mask_out = mask;
|
||||
|
||||
@ -7142,6 +7150,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
|
||||
return -EINVAL;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
@ -7149,7 +7160,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
@ -7177,9 +7187,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
|
||||
|
||||
err = nl80211_parse_chandef(rdev, info, &chandef);
|
||||
if (err)
|
||||
return err;
|
||||
/* get the channel if any has been specified, otherwise pass NULL to
|
||||
* the driver. The latter will use the current one
|
||||
*/
|
||||
chandef.chan = NULL;
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
|
||||
err = nl80211_parse_chandef(rdev, info, &chandef);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!chandef.chan && offchan)
|
||||
return -EINVAL;
|
||||
|
||||
if (!dont_wait_for_ack) {
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
@ -7484,6 +7503,23 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
|
||||
setup.chandef.chan = NULL;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
|
||||
u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
|
||||
int n_rates =
|
||||
nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
if (!setup.chandef.chan)
|
||||
return -EINVAL;
|
||||
|
||||
sband = rdev->wiphy.bands[setup.chandef.chan->band];
|
||||
|
||||
err = ieee80211_get_ratemask(sband, rates, n_rates,
|
||||
&setup.basic_rates);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
|
||||
}
|
||||
|
||||
@ -7580,8 +7616,7 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
void *hdr;
|
||||
u32 size = NLMSG_DEFAULT_SIZE;
|
||||
|
||||
if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns &&
|
||||
!rdev->wiphy.wowlan.tcp)
|
||||
if (!rdev->wiphy.wowlan)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
|
||||
@ -7654,7 +7689,7 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
|
||||
u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
|
||||
int err, port;
|
||||
|
||||
if (!rdev->wiphy.wowlan.tcp)
|
||||
if (!rdev->wiphy.wowlan->tcp)
|
||||
return -EINVAL;
|
||||
|
||||
err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP,
|
||||
@ -7674,16 +7709,16 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
|
||||
return -EINVAL;
|
||||
|
||||
data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
|
||||
if (data_size > rdev->wiphy.wowlan.tcp->data_payload_max)
|
||||
if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
|
||||
return -EINVAL;
|
||||
|
||||
if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
|
||||
rdev->wiphy.wowlan.tcp->data_interval_max ||
|
||||
rdev->wiphy.wowlan->tcp->data_interval_max ||
|
||||
nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
|
||||
if (wake_size > rdev->wiphy.wowlan.tcp->wake_payload_max)
|
||||
if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
|
||||
return -EINVAL;
|
||||
|
||||
wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
|
||||
@ -7698,13 +7733,13 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
|
||||
|
||||
if (!tok->len || tokens_size % tok->len)
|
||||
return -EINVAL;
|
||||
if (!rdev->wiphy.wowlan.tcp->tok)
|
||||
if (!rdev->wiphy.wowlan->tcp->tok)
|
||||
return -EINVAL;
|
||||
if (tok->len > rdev->wiphy.wowlan.tcp->tok->max_len)
|
||||
if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
|
||||
return -EINVAL;
|
||||
if (tok->len < rdev->wiphy.wowlan.tcp->tok->min_len)
|
||||
if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
|
||||
return -EINVAL;
|
||||
if (tokens_size > rdev->wiphy.wowlan.tcp->tok->bufsize)
|
||||
if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
|
||||
return -EINVAL;
|
||||
if (tok->offset + tok->len > data_size)
|
||||
return -EINVAL;
|
||||
@ -7712,7 +7747,7 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
|
||||
|
||||
if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
|
||||
seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
|
||||
if (!rdev->wiphy.wowlan.tcp->seq)
|
||||
if (!rdev->wiphy.wowlan->tcp->seq)
|
||||
return -EINVAL;
|
||||
if (seq->len == 0 || seq->len > 4)
|
||||
return -EINVAL;
|
||||
@ -7793,12 +7828,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
|
||||
struct cfg80211_wowlan new_triggers = {};
|
||||
struct cfg80211_wowlan *ntrig;
|
||||
struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
|
||||
const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
|
||||
int err, i;
|
||||
bool prev_enabled = rdev->wiphy.wowlan_config;
|
||||
|
||||
if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns &&
|
||||
!rdev->wiphy.wowlan.tcp)
|
||||
if (!wowlan)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
|
||||
@ -9315,31 +9349,27 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
|
||||
NL80211_CMD_DISASSOCIATE, gfp);
|
||||
}
|
||||
|
||||
void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
|
||||
size_t len)
|
||||
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
const struct ieee80211_mgmt *mgmt = (void *)buf;
|
||||
u32 cmd;
|
||||
|
||||
trace_cfg80211_send_unprot_deauth(dev);
|
||||
nl80211_send_mlme_event(rdev, dev, buf, len,
|
||||
NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC);
|
||||
if (WARN_ON(len < 2))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_deauth(mgmt->frame_control))
|
||||
cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
|
||||
else
|
||||
cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
|
||||
|
||||
trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
|
||||
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
|
||||
|
||||
void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_send_unprot_disassoc(dev);
|
||||
nl80211_send_mlme_event(rdev, dev, buf, len,
|
||||
NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
|
||||
EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
|
||||
|
||||
static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, int cmd,
|
||||
@ -9850,7 +9880,6 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
int err;
|
||||
u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
|
||||
|
||||
if (!nlportid)
|
||||
@ -9871,12 +9900,7 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
|
||||
goto nla_put_failure;
|
||||
|
||||
err = genlmsg_end(msg, hdr);
|
||||
if (err < 0) {
|
||||
nlmsg_free(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
|
||||
return true;
|
||||
|
||||
@ -10319,10 +10343,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
|
||||
if (nl80211_send_chandef(msg, chandef))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (genlmsg_end(msg, hdr) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
||||
nl80211_mlme_mcgrp.id, gfp);
|
||||
@ -10388,7 +10409,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
trace_cfg80211_probe_status(dev, addr, cookie, acked);
|
||||
|
||||
@ -10410,11 +10430,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
|
||||
(acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
|
||||
goto nla_put_failure;
|
||||
|
||||
err = genlmsg_end(msg, hdr);
|
||||
if (err < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
||||
nl80211_mlme_mcgrp.id, gfp);
|
||||
@ -10480,7 +10496,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
int err, size = 200;
|
||||
int size = 200;
|
||||
|
||||
trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
|
||||
|
||||
@ -10566,9 +10582,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
|
||||
nla_nest_end(msg, reasons);
|
||||
}
|
||||
|
||||
err = genlmsg_end(msg, hdr);
|
||||
if (err < 0)
|
||||
goto free_msg;
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
||||
nl80211_mlme_mcgrp.id, gfp);
|
||||
@ -10588,7 +10602,6 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
|
||||
reason_code);
|
||||
@ -10611,11 +10624,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
|
||||
nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
|
||||
goto nla_put_failure;
|
||||
|
||||
err = genlmsg_end(msg, hdr);
|
||||
if (err < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
||||
nl80211_mlme_mcgrp.id, gfp);
|
||||
@ -10673,7 +10682,6 @@ void cfg80211_ft_event(struct net_device *netdev,
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
trace_cfg80211_ft_event(wiphy, netdev, ft_event);
|
||||
|
||||
@ -10699,11 +10707,7 @@ void cfg80211_ft_event(struct net_device *netdev,
|
||||
nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
|
||||
ft_event->ric_ies);
|
||||
|
||||
err = genlmsg_end(msg, hdr);
|
||||
if (err < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
||||
nl80211_mlme_mcgrp.id, GFP_KERNEL);
|
||||
|
@ -1345,7 +1345,7 @@ get_reg_request_treatment(struct wiphy *wiphy,
|
||||
return REG_REQ_OK;
|
||||
return REG_REQ_ALREADY_SET;
|
||||
}
|
||||
return 0;
|
||||
return REG_REQ_OK;
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
|
||||
if (regdom_changes(pending_request->alpha2))
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* SME code for cfg80211's connect emulation.
|
||||
* SME code for cfg80211
|
||||
* both driver SME event handling and the SME implementation
|
||||
* (for nl80211's connect() and wext)
|
||||
*
|
||||
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright (C) 2009 Intel Corporation. All rights reserved.
|
||||
@ -18,18 +20,24 @@
|
||||
#include "reg.h"
|
||||
#include "rdev-ops.h"
|
||||
|
||||
/*
|
||||
* Software SME in cfg80211, using auth/assoc/deauth calls to the
|
||||
* driver. This is is for implementing nl80211's connect/disconnect
|
||||
* and wireless extensions (if configured.)
|
||||
*/
|
||||
|
||||
struct cfg80211_conn {
|
||||
struct cfg80211_connect_params params;
|
||||
/* these are sub-states of the _CONNECTING sme_state */
|
||||
enum {
|
||||
CFG80211_CONN_IDLE,
|
||||
CFG80211_CONN_SCANNING,
|
||||
CFG80211_CONN_SCAN_AGAIN,
|
||||
CFG80211_CONN_AUTHENTICATE_NEXT,
|
||||
CFG80211_CONN_AUTHENTICATING,
|
||||
CFG80211_CONN_ASSOCIATE_NEXT,
|
||||
CFG80211_CONN_ASSOCIATING,
|
||||
CFG80211_CONN_DEAUTH_ASSOC_FAIL,
|
||||
CFG80211_CONN_DEAUTH,
|
||||
CFG80211_CONN_CONNECTED,
|
||||
} state;
|
||||
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
|
||||
u8 *ie;
|
||||
@ -37,39 +45,16 @@ struct cfg80211_conn {
|
||||
bool auto_auth, prev_bssid_valid;
|
||||
};
|
||||
|
||||
static bool cfg80211_is_all_idle(void)
|
||||
static void cfg80211_sme_free(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct wireless_dev *wdev;
|
||||
bool is_all_idle = true;
|
||||
if (!wdev->conn)
|
||||
return;
|
||||
|
||||
/*
|
||||
* All devices must be idle as otherwise if you are actively
|
||||
* scanning some new beacon hints could be learned and would
|
||||
* count as new regulatory hints.
|
||||
*/
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
wdev_lock(wdev);
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE)
|
||||
is_all_idle = false;
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
}
|
||||
|
||||
return is_all_idle;
|
||||
kfree(wdev->conn->ie);
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
}
|
||||
|
||||
static void disconnect_work(struct work_struct *work)
|
||||
{
|
||||
rtnl_lock();
|
||||
if (cfg80211_is_all_idle())
|
||||
regulatory_hint_disconnect();
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
|
||||
|
||||
static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
@ -164,6 +149,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
||||
params = &wdev->conn->params;
|
||||
|
||||
switch (wdev->conn->state) {
|
||||
case CFG80211_CONN_SCANNING:
|
||||
/* didn't find it during scan ... */
|
||||
return -ENOENT;
|
||||
case CFG80211_CONN_SCAN_AGAIN:
|
||||
return cfg80211_conn_scan(wdev);
|
||||
case CFG80211_CONN_AUTHENTICATE_NEXT:
|
||||
@ -200,12 +188,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
||||
WLAN_REASON_DEAUTH_LEAVING,
|
||||
false);
|
||||
return err;
|
||||
case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
|
||||
case CFG80211_CONN_DEAUTH:
|
||||
cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
|
||||
NULL, 0,
|
||||
WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
/* return an error so that we call __cfg80211_connect_result() */
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -229,7 +216,8 @@ void cfg80211_conn_work(struct work_struct *work)
|
||||
wdev_unlock(wdev);
|
||||
continue;
|
||||
}
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) {
|
||||
if (!wdev->conn ||
|
||||
wdev->conn->state == CFG80211_CONN_CONNECTED) {
|
||||
wdev_unlock(wdev);
|
||||
continue;
|
||||
}
|
||||
@ -237,12 +225,14 @@ void cfg80211_conn_work(struct work_struct *work)
|
||||
memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
|
||||
bssid = bssid_buf;
|
||||
}
|
||||
if (cfg80211_conn_do_work(wdev))
|
||||
if (cfg80211_conn_do_work(wdev)) {
|
||||
__cfg80211_connect_result(
|
||||
wdev->netdev, bssid,
|
||||
NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
false, NULL);
|
||||
cfg80211_sme_free(wdev);
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
|
||||
@ -286,9 +276,6 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTING)
|
||||
return;
|
||||
|
||||
if (!wdev->conn)
|
||||
return;
|
||||
|
||||
@ -297,20 +284,10 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
|
||||
return;
|
||||
|
||||
bss = cfg80211_get_conn_bss(wdev);
|
||||
if (bss) {
|
||||
if (bss)
|
||||
cfg80211_put_bss(&rdev->wiphy, bss);
|
||||
} else {
|
||||
/* not found */
|
||||
if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
|
||||
schedule_work(&rdev->conn_work);
|
||||
else
|
||||
__cfg80211_connect_result(
|
||||
wdev->netdev,
|
||||
wdev->conn->params.bssid,
|
||||
NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
false, NULL);
|
||||
}
|
||||
else
|
||||
schedule_work(&rdev->conn_work);
|
||||
}
|
||||
|
||||
void cfg80211_sme_scan_done(struct net_device *dev)
|
||||
@ -322,10 +299,8 @@ void cfg80211_sme_scan_done(struct net_device *dev)
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
|
||||
void cfg80211_sme_rx_auth(struct net_device *dev,
|
||||
const u8 *buf, size_t len)
|
||||
void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
||||
@ -333,11 +308,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
/* should only RX auth frames when connecting */
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTING)
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wdev->conn))
|
||||
if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED)
|
||||
return;
|
||||
|
||||
if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
|
||||
@ -366,46 +337,226 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
|
||||
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
} else if (status_code != WLAN_STATUS_SUCCESS) {
|
||||
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
|
||||
__cfg80211_connect_result(wdev->netdev, mgmt->bssid,
|
||||
NULL, 0, NULL, 0,
|
||||
status_code, false, NULL);
|
||||
} else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
|
||||
wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
|
||||
} else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
|
||||
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
}
|
||||
}
|
||||
|
||||
bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev)
|
||||
bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
|
||||
{
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
|
||||
if (WARN_ON(!wdev->conn))
|
||||
if (!wdev->conn)
|
||||
return false;
|
||||
|
||||
if (!wdev->conn->prev_bssid_valid)
|
||||
if (status == WLAN_STATUS_SUCCESS) {
|
||||
wdev->conn->state = CFG80211_CONN_CONNECTED;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wdev->conn->prev_bssid_valid) {
|
||||
/*
|
||||
* Some stupid APs don't accept reassoc, so we
|
||||
* need to fall back to trying regular assoc;
|
||||
* return true so no event is sent to userspace.
|
||||
*/
|
||||
wdev->conn->prev_bssid_valid = false;
|
||||
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
return true;
|
||||
}
|
||||
|
||||
wdev->conn->state = CFG80211_CONN_DEAUTH;
|
||||
schedule_work(&rdev->conn_work);
|
||||
return false;
|
||||
}
|
||||
|
||||
void cfg80211_sme_deauth(struct wireless_dev *wdev)
|
||||
{
|
||||
cfg80211_sme_free(wdev);
|
||||
}
|
||||
|
||||
void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
|
||||
{
|
||||
cfg80211_sme_free(wdev);
|
||||
}
|
||||
|
||||
void cfg80211_sme_disassoc(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
|
||||
if (!wdev->conn)
|
||||
return;
|
||||
|
||||
wdev->conn->state = CFG80211_CONN_DEAUTH;
|
||||
schedule_work(&rdev->conn_work);
|
||||
}
|
||||
|
||||
void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
|
||||
{
|
||||
cfg80211_sme_disassoc(wdev);
|
||||
}
|
||||
|
||||
static int cfg80211_sme_connect(struct wireless_dev *wdev,
|
||||
struct cfg80211_connect_params *connect,
|
||||
const u8 *prev_bssid)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct cfg80211_bss *bss;
|
||||
int err;
|
||||
|
||||
if (!rdev->ops->auth || !rdev->ops->assoc)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (wdev->current_bss)
|
||||
return -EALREADY;
|
||||
|
||||
if (WARN_ON(wdev->conn))
|
||||
return -EINPROGRESS;
|
||||
|
||||
wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
|
||||
if (!wdev->conn)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Some stupid APs don't accept reassoc, so we
|
||||
* need to fall back to trying regular assoc.
|
||||
* Copy all parameters, and treat explicitly IEs, BSSID, SSID.
|
||||
*/
|
||||
wdev->conn->prev_bssid_valid = false;
|
||||
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
memcpy(&wdev->conn->params, connect, sizeof(*connect));
|
||||
if (connect->bssid) {
|
||||
wdev->conn->params.bssid = wdev->conn->bssid;
|
||||
memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
return true;
|
||||
if (connect->ie) {
|
||||
wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
|
||||
GFP_KERNEL);
|
||||
wdev->conn->params.ie = wdev->conn->ie;
|
||||
if (!wdev->conn->ie) {
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
|
||||
wdev->conn->auto_auth = true;
|
||||
/* start with open system ... should mostly work */
|
||||
wdev->conn->params.auth_type =
|
||||
NL80211_AUTHTYPE_OPEN_SYSTEM;
|
||||
} else {
|
||||
wdev->conn->auto_auth = false;
|
||||
}
|
||||
|
||||
wdev->conn->params.ssid = wdev->ssid;
|
||||
wdev->conn->params.ssid_len = connect->ssid_len;
|
||||
|
||||
/* see if we have the bss already */
|
||||
bss = cfg80211_get_conn_bss(wdev);
|
||||
|
||||
if (prev_bssid) {
|
||||
memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
|
||||
wdev->conn->prev_bssid_valid = true;
|
||||
}
|
||||
|
||||
/* we're good if we have a matching bss struct */
|
||||
if (bss) {
|
||||
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
|
||||
err = cfg80211_conn_do_work(wdev);
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
} else {
|
||||
/* otherwise we'll need to scan for the AP first */
|
||||
err = cfg80211_conn_scan(wdev);
|
||||
|
||||
/*
|
||||
* If we can't scan right now, then we need to scan again
|
||||
* after the current scan finished, since the parameters
|
||||
* changed (unless we find a good AP anyway).
|
||||
*/
|
||||
if (err == -EBUSY) {
|
||||
err = 0;
|
||||
wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
cfg80211_sme_free(wdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void cfg80211_sme_failed_assoc(struct wireless_dev *wdev)
|
||||
static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
|
||||
{
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
int err;
|
||||
|
||||
wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL;
|
||||
schedule_work(&rdev->conn_work);
|
||||
if (!wdev->conn)
|
||||
return 0;
|
||||
|
||||
if (!rdev->ops->deauth)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (wdev->conn->state == CFG80211_CONN_SCANNING ||
|
||||
wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) {
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* wdev->conn->params.bssid must be set if > SCANNING */
|
||||
err = cfg80211_mlme_deauth(rdev, wdev->netdev,
|
||||
wdev->conn->params.bssid,
|
||||
NULL, 0, reason, false);
|
||||
out:
|
||||
cfg80211_sme_free(wdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* code shared for in-device and software SME
|
||||
*/
|
||||
|
||||
static bool cfg80211_is_all_idle(void)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct wireless_dev *wdev;
|
||||
bool is_all_idle = true;
|
||||
|
||||
/*
|
||||
* All devices must be idle as otherwise if you are actively
|
||||
* scanning some new beacon hints could be learned and would
|
||||
* count as new regulatory hints.
|
||||
*/
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
wdev_lock(wdev);
|
||||
if (wdev->conn || wdev->current_bss)
|
||||
is_all_idle = false;
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
}
|
||||
|
||||
return is_all_idle;
|
||||
}
|
||||
|
||||
static void disconnect_work(struct work_struct *work)
|
||||
{
|
||||
rtnl_lock();
|
||||
if (cfg80211_is_all_idle())
|
||||
regulatory_hint_disconnect();
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
|
||||
|
||||
|
||||
/*
|
||||
* API calls for drivers implementing connect/disconnect and
|
||||
* SME event handling
|
||||
*/
|
||||
|
||||
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
@ -424,9 +575,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
|
||||
return;
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTING)
|
||||
return;
|
||||
|
||||
nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
|
||||
bssid, req_ie, req_ie_len,
|
||||
resp_ie, resp_ie_len,
|
||||
@ -463,15 +611,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
wdev->current_bss = NULL;
|
||||
}
|
||||
|
||||
if (wdev->conn)
|
||||
wdev->conn->state = CFG80211_CONN_IDLE;
|
||||
|
||||
if (status != WLAN_STATUS_SUCCESS) {
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
if (wdev->conn)
|
||||
kfree(wdev->conn->ie);
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
@ -480,21 +620,16 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
}
|
||||
|
||||
if (!bss)
|
||||
bss = cfg80211_get_bss(wdev->wiphy,
|
||||
wdev->conn ? wdev->conn->params.channel :
|
||||
NULL,
|
||||
bssid,
|
||||
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||||
wdev->ssid, wdev->ssid_len,
|
||||
WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
wdev->current_bss = bss_from_pub(bss);
|
||||
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
cfg80211_upload_connect_keys(wdev);
|
||||
|
||||
rcu_read_lock();
|
||||
@ -530,8 +665,6 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
|
||||
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
|
||||
|
||||
ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
|
||||
if (!ev)
|
||||
return;
|
||||
@ -572,14 +705,9 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
|
||||
goto out;
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTED)
|
||||
if (WARN_ON(!wdev->current_bss))
|
||||
goto out;
|
||||
|
||||
/* internal error -- how did we get to CONNECTED w/o BSS? */
|
||||
if (WARN_ON(!wdev->current_bss)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
@ -628,8 +756,6 @@ void cfg80211_roamed(struct net_device *dev,
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_bss *bss;
|
||||
|
||||
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
|
||||
|
||||
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
|
||||
wdev->ssid_len, WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
@ -651,8 +777,6 @@ void cfg80211_roamed_bss(struct net_device *dev,
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
|
||||
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
|
||||
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
|
||||
@ -694,25 +818,14 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
|
||||
return;
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_CONNECTED)
|
||||
return;
|
||||
|
||||
if (wdev->current_bss) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
}
|
||||
|
||||
wdev->current_bss = NULL;
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
wdev->ssid_len = 0;
|
||||
|
||||
if (wdev->conn) {
|
||||
kfree(wdev->conn->ie);
|
||||
wdev->conn->ie = NULL;
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
}
|
||||
|
||||
nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
|
||||
|
||||
/*
|
||||
@ -741,8 +854,6 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
|
||||
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
|
||||
|
||||
ev = kzalloc(sizeof(*ev) + ie_len, gfp);
|
||||
if (!ev)
|
||||
return;
|
||||
@ -760,6 +871,9 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_disconnected);
|
||||
|
||||
/*
|
||||
* API calls for nl80211/wext compatibility code
|
||||
*/
|
||||
int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_connect_params *connect,
|
||||
@ -767,14 +881,10 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
const u8 *prev_bssid)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_bss *bss = NULL;
|
||||
int err;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE)
|
||||
return -EALREADY;
|
||||
|
||||
if (WARN_ON(wdev->connect_keys)) {
|
||||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
@ -810,105 +920,22 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (!rdev->ops->connect) {
|
||||
if (!rdev->ops->auth || !rdev->ops->assoc)
|
||||
return -EOPNOTSUPP;
|
||||
wdev->connect_keys = connkeys;
|
||||
memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
|
||||
wdev->ssid_len = connect->ssid_len;
|
||||
|
||||
if (WARN_ON(wdev->conn))
|
||||
return -EINPROGRESS;
|
||||
|
||||
wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
|
||||
if (!wdev->conn)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Copy all parameters, and treat explicitly IEs, BSSID, SSID.
|
||||
*/
|
||||
memcpy(&wdev->conn->params, connect, sizeof(*connect));
|
||||
if (connect->bssid) {
|
||||
wdev->conn->params.bssid = wdev->conn->bssid;
|
||||
memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
if (connect->ie) {
|
||||
wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
|
||||
GFP_KERNEL);
|
||||
wdev->conn->params.ie = wdev->conn->ie;
|
||||
if (!wdev->conn->ie) {
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
|
||||
wdev->conn->auto_auth = true;
|
||||
/* start with open system ... should mostly work */
|
||||
wdev->conn->params.auth_type =
|
||||
NL80211_AUTHTYPE_OPEN_SYSTEM;
|
||||
} else {
|
||||
wdev->conn->auto_auth = false;
|
||||
}
|
||||
|
||||
memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
|
||||
wdev->ssid_len = connect->ssid_len;
|
||||
wdev->conn->params.ssid = wdev->ssid;
|
||||
wdev->conn->params.ssid_len = connect->ssid_len;
|
||||
|
||||
/* see if we have the bss already */
|
||||
bss = cfg80211_get_conn_bss(wdev);
|
||||
|
||||
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||||
wdev->connect_keys = connkeys;
|
||||
|
||||
if (prev_bssid) {
|
||||
memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
|
||||
wdev->conn->prev_bssid_valid = true;
|
||||
}
|
||||
|
||||
/* we're good if we have a matching bss struct */
|
||||
if (bss) {
|
||||
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
|
||||
err = cfg80211_conn_do_work(wdev);
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
} else {
|
||||
/* otherwise we'll need to scan for the AP first */
|
||||
err = cfg80211_conn_scan(wdev);
|
||||
/*
|
||||
* If we can't scan right now, then we need to scan again
|
||||
* after the current scan finished, since the parameters
|
||||
* changed (unless we find a good AP anyway).
|
||||
*/
|
||||
if (err == -EBUSY) {
|
||||
err = 0;
|
||||
wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
|
||||
}
|
||||
}
|
||||
if (err) {
|
||||
kfree(wdev->conn->ie);
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
}
|
||||
|
||||
return err;
|
||||
} else {
|
||||
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||||
wdev->connect_keys = connkeys;
|
||||
if (!rdev->ops->connect)
|
||||
err = cfg80211_sme_connect(wdev, connect, prev_bssid);
|
||||
else
|
||||
err = rdev_connect(rdev, dev, connect);
|
||||
if (err) {
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
|
||||
wdev->ssid_len = connect->ssid_len;
|
||||
|
||||
return 0;
|
||||
if (err) {
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
||||
@ -919,78 +946,17 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->sme_state == CFG80211_SME_IDLE)
|
||||
return -EINVAL;
|
||||
|
||||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
|
||||
if (!rdev->ops->disconnect) {
|
||||
if (!rdev->ops->deauth)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* was it connected by userspace SME? */
|
||||
if (!wdev->conn) {
|
||||
cfg80211_mlme_down(rdev, dev);
|
||||
goto disconnect;
|
||||
}
|
||||
|
||||
if (wdev->sme_state == CFG80211_SME_CONNECTING &&
|
||||
(wdev->conn->state == CFG80211_CONN_SCANNING ||
|
||||
wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
|
||||
wdev->sme_state = CFG80211_SME_IDLE;
|
||||
kfree(wdev->conn->ie);
|
||||
kfree(wdev->conn);
|
||||
wdev->conn = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wdev->conn->params.bssid must be set if > SCANNING */
|
||||
err = cfg80211_mlme_deauth(rdev, dev,
|
||||
wdev->conn->params.bssid,
|
||||
NULL, 0, reason, false);
|
||||
if (err)
|
||||
return err;
|
||||
if (wdev->conn) {
|
||||
err = cfg80211_sme_disconnect(wdev, reason);
|
||||
} else if (!rdev->ops->disconnect) {
|
||||
cfg80211_mlme_down(rdev, dev);
|
||||
err = 0;
|
||||
} else {
|
||||
err = rdev_disconnect(rdev, dev, reason);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
disconnect:
|
||||
if (wdev->sme_state == CFG80211_SME_CONNECTED)
|
||||
__cfg80211_disconnected(dev, NULL, 0, 0, false);
|
||||
else if (wdev->sme_state == CFG80211_SME_CONNECTING)
|
||||
__cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
wextev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cfg80211_sme_disassoc(struct net_device *dev,
|
||||
struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!wdev->conn)
|
||||
return;
|
||||
|
||||
if (wdev->conn->state == CFG80211_CONN_IDLE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Ok, so the association was made by this SME -- we don't
|
||||
* want it any more so deauthenticate too.
|
||||
*/
|
||||
|
||||
memcpy(bssid, bss->pub.bssid, ETH_ALEN);
|
||||
|
||||
cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
|
||||
WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
return err;
|
||||
}
|
||||
|
@ -1911,24 +1911,46 @@ TRACE_EVENT(cfg80211_send_rx_assoc,
|
||||
NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(netdev_evt_only, cfg80211_send_deauth,
|
||||
TP_PROTO(struct net_device *netdev),
|
||||
TP_ARGS(netdev)
|
||||
DECLARE_EVENT_CLASS(netdev_frame_event,
|
||||
TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
|
||||
TP_ARGS(netdev, buf, len),
|
||||
TP_STRUCT__entry(
|
||||
NETDEV_ENTRY
|
||||
__dynamic_array(u8, frame, len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
NETDEV_ASSIGN;
|
||||
memcpy(__get_dynamic_array(frame), buf, len);
|
||||
),
|
||||
TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x",
|
||||
NETDEV_PR_ARG,
|
||||
le16_to_cpup((__le16 *)__get_dynamic_array(frame)))
|
||||
);
|
||||
|
||||
DEFINE_EVENT(netdev_evt_only, cfg80211_send_disassoc,
|
||||
TP_PROTO(struct net_device *netdev),
|
||||
TP_ARGS(netdev)
|
||||
DEFINE_EVENT(netdev_frame_event, cfg80211_rx_unprot_mlme_mgmt,
|
||||
TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
|
||||
TP_ARGS(netdev, buf, len)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_deauth,
|
||||
TP_PROTO(struct net_device *netdev),
|
||||
TP_ARGS(netdev)
|
||||
DEFINE_EVENT(netdev_frame_event, cfg80211_rx_mlme_mgmt,
|
||||
TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
|
||||
TP_ARGS(netdev, buf, len)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_disassoc,
|
||||
TP_PROTO(struct net_device *netdev),
|
||||
TP_ARGS(netdev)
|
||||
TRACE_EVENT(cfg80211_tx_mlme_mgmt,
|
||||
TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
|
||||
TP_ARGS(netdev, buf, len),
|
||||
TP_STRUCT__entry(
|
||||
NETDEV_ENTRY
|
||||
__dynamic_array(u8, frame, len)
|
||||
),
|
||||
TP_fast_assign(
|
||||
NETDEV_ASSIGN;
|
||||
memcpy(__get_dynamic_array(frame), buf, len);
|
||||
),
|
||||
TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x",
|
||||
NETDEV_PR_ARG,
|
||||
le16_to_cpup((__le16 *)__get_dynamic_array(frame)))
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(netdev_mac_evt,
|
||||
|
@ -89,7 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
|
||||
|
||||
wdev_lock(wdev);
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE) {
|
||||
if (wdev->conn) {
|
||||
bool event = true;
|
||||
|
||||
if (wdev->wext.connect.channel == chan) {
|
||||
@ -188,7 +188,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
|
||||
|
||||
err = 0;
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE) {
|
||||
if (wdev->conn) {
|
||||
bool event = true;
|
||||
|
||||
if (wdev->wext.connect.ssid && len &&
|
||||
@ -277,7 +277,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
|
||||
|
||||
wdev_lock(wdev);
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE) {
|
||||
if (wdev->conn) {
|
||||
err = 0;
|
||||
/* both automatic */
|
||||
if (!bssid && !wdev->wext.connect.bssid)
|
||||
@ -364,7 +364,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
|
||||
wdev->wext.ie = ie;
|
||||
wdev->wext.ie_len = ie_len;
|
||||
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE) {
|
||||
if (wdev->conn) {
|
||||
err = cfg80211_disconnect(rdev, dev,
|
||||
WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
if (err)
|
||||
|
Loading…
Reference in New Issue
Block a user