forked from Minki/linux
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
4fe0c75eed
@ -767,7 +767,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
|
||||
nw_type & ADHOC_CREATOR ? "creator" : "joiner");
|
||||
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(ar->wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -778,7 +778,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
|
||||
assoc_req_ie, assoc_req_len,
|
||||
assoc_resp_ie, assoc_resp_len,
|
||||
WLAN_STATUS_SUCCESS, GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(ar->wiphy, bss);
|
||||
} else if (vif->sme_state == SME_CONNECTED) {
|
||||
/* inform roam event to cfg80211 */
|
||||
cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
|
||||
|
@ -1108,7 +1108,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
kfree(mgmt);
|
||||
if (bss == NULL)
|
||||
return -ENOMEM;
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(ar->wiphy, bss);
|
||||
|
||||
/*
|
||||
* Firmware doesn't return any event when scheduled scan has
|
||||
|
@ -341,7 +341,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
}
|
||||
|
||||
out:
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
|
||||
if (bss) {
|
||||
wil_dbg_wmi(wil, "Added BSS %pM\n",
|
||||
rx_mgmt_frame->bssid);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
} else {
|
||||
wil_err(wil, "cfg80211_inform_bss() failed\n");
|
||||
}
|
||||
|
@ -2323,7 +2323,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
|
||||
if (!bss)
|
||||
return -ENOMEM;
|
||||
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -2429,7 +2429,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
|
||||
goto CleanUp;
|
||||
}
|
||||
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
|
||||
CleanUp:
|
||||
|
||||
|
@ -151,8 +151,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
||||
IEEE80211_HW_QUEUE_CONTROL |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
|
||||
IEEE80211_HW_WANT_MONITOR_VIF |
|
||||
IEEE80211_HW_SCAN_WHILE_IDLE;
|
||||
IEEE80211_HW_WANT_MONITOR_VIF;
|
||||
|
||||
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
|
||||
hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
|
||||
|
@ -113,7 +113,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
|
||||
IEEE80211_HW_QUEUE_CONTROL |
|
||||
IEEE80211_HW_WANT_MONITOR_VIF |
|
||||
IEEE80211_HW_SCAN_WHILE_IDLE |
|
||||
IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
|
||||
IEEE80211_HW_SUPPORTS_PS |
|
||||
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
|
||||
|
@ -657,7 +657,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
|
||||
capa, intvl, ie, ielen,
|
||||
LBS_SCAN_RSSI_TO_MBM(rssi),
|
||||
GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
} else
|
||||
lbs_deb_scan("scan response: missing BSS channel IE\n");
|
||||
@ -1444,7 +1444,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
done:
|
||||
if (bss)
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -1766,7 +1766,7 @@ static void lbs_join_post(struct lbs_private *priv,
|
||||
params->beacon_interval,
|
||||
fake_ie, fake - fake_ie,
|
||||
0, GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(priv->wdev->wiphy, bss);
|
||||
|
||||
memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
|
||||
priv->wdev->ssid_len = params->ssid_len;
|
||||
@ -2011,7 +2011,7 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
if (bss) {
|
||||
ret = lbs_ibss_join_existing(priv, params, bss);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
} else
|
||||
ret = lbs_ibss_start_new(priv, params);
|
||||
|
||||
|
@ -1430,7 +1430,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
|
||||
bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
|
||||
bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
|
||||
0, ie_buf, ie_len, 0, GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(priv->wdev->wiphy, bss);
|
||||
memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
|
||||
|
||||
return 0;
|
||||
|
@ -1746,7 +1746,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
||||
.mac_address, ETH_ALEN))
|
||||
mwifiex_update_curr_bss_params(priv,
|
||||
bss);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(priv->wdev->wiphy, bss);
|
||||
}
|
||||
} else {
|
||||
dev_dbg(adapter->dev, "missing BSS channel IE\n");
|
||||
|
@ -162,13 +162,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(bss->ies);
|
||||
if (WARN_ON(!ies)) {
|
||||
/* should never happen */
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC);
|
||||
beacon_ie_len = ies->len;
|
||||
bss_desc->timestamp = ies->tsf;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!beacon_ie) {
|
||||
@ -184,7 +180,6 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
|
||||
bss_desc->cap_info_bitmap = bss->capability;
|
||||
bss_desc->bss_band = bss_priv->band;
|
||||
bss_desc->fw_tsf = bss_priv->fw_tsf;
|
||||
bss_desc->timestamp = bss->tsf;
|
||||
if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
|
||||
dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
|
||||
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
|
||||
@ -324,7 +319,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
|
||||
}
|
||||
|
||||
if (bss)
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(priv->adapter->wiphy, bss);
|
||||
} else {
|
||||
/* Adhoc mode */
|
||||
/* If the requested SSID matches current SSID, return */
|
||||
@ -354,7 +349,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
|
||||
" list. Joining...\n");
|
||||
ret = mwifiex_adhoc_join(priv, bss_desc);
|
||||
if (bss)
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(priv->adapter->wiphy, bss);
|
||||
} else {
|
||||
dev_dbg(adapter->dev, "info: Network not found in "
|
||||
"the list, creating adhoc with ssid = %s\n",
|
||||
|
@ -125,7 +125,7 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
|
||||
cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
|
||||
capability, beacon_interval, ie_buf, ie_len,
|
||||
signal, GFP_KERNEL);
|
||||
cfg80211_put_bss(cbss);
|
||||
cfg80211_put_bss(wiphy, cbss);
|
||||
}
|
||||
|
||||
void orinoco_add_extscan_result(struct orinoco_private *priv,
|
||||
@ -158,7 +158,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
|
||||
cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
|
||||
capability, beacon_interval, ie, ie_len,
|
||||
signal, GFP_KERNEL);
|
||||
cfg80211_put_bss(cbss);
|
||||
cfg80211_put_bss(wiphy, cbss);
|
||||
}
|
||||
|
||||
void orinoco_add_hostscan_results(struct orinoco_private *priv,
|
||||
|
@ -2029,7 +2029,7 @@ static bool rndis_bss_info_update(struct usbnet *usbdev,
|
||||
bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
|
||||
timestamp, capability, beacon_interval, ie, ie_len, signal,
|
||||
GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(priv->wdev.wiphy, bss);
|
||||
|
||||
return (bss != NULL);
|
||||
}
|
||||
@ -2718,7 +2718,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
|
||||
bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
|
||||
timestamp, capability, beacon_period, ie_buf, ie_len,
|
||||
signal, GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(priv->wdev.wiphy, bss);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -29,6 +29,8 @@
|
||||
static int wl1251_event_scan_complete(struct wl1251 *wl,
|
||||
struct event_mailbox *mbox)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
|
||||
mbox->scheduled_scan_status,
|
||||
mbox->scheduled_scan_channels);
|
||||
@ -37,9 +39,11 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
|
||||
ieee80211_scan_completed(wl->hw, false);
|
||||
wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
|
||||
wl->scanning = false;
|
||||
if (wl->hw->conf.flags & IEEE80211_CONF_IDLE)
|
||||
ret = wl1251_ps_set_mode(wl, STATION_IDLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
|
||||
|
@ -623,7 +623,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
|
||||
if (changed & IEEE80211_CONF_CHANGE_IDLE && !wl->scanning) {
|
||||
if (conf->flags & IEEE80211_CONF_IDLE) {
|
||||
ret = wl1251_ps_set_mode(wl, STATION_IDLE);
|
||||
if (ret < 0)
|
||||
@ -895,11 +895,21 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (hw->conf.flags & IEEE80211_CONF_IDLE) {
|
||||
ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
ret = wl1251_join(wl, wl->bss_type, wl->channel,
|
||||
wl->beacon_int, wl->dtim_period);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
}
|
||||
|
||||
skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
|
||||
req->ie_len);
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto out_idle;
|
||||
}
|
||||
if (req->ie_len)
|
||||
memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
|
||||
@ -908,11 +918,11 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
|
||||
skb->len);
|
||||
dev_kfree_skb(skb);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
goto out_idle;
|
||||
|
||||
ret = wl1251_cmd_trigger_scan_to(wl, 0);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
goto out_idle;
|
||||
|
||||
wl->scanning = true;
|
||||
|
||||
@ -920,9 +930,13 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
|
||||
req->n_channels, WL1251_SCAN_NUM_PROBES);
|
||||
if (ret < 0) {
|
||||
wl->scanning = false;
|
||||
goto out_sleep;
|
||||
goto out_idle;
|
||||
}
|
||||
goto out_sleep;
|
||||
|
||||
out_idle:
|
||||
if (hw->conf.flags & IEEE80211_CONF_IDLE)
|
||||
ret = wl1251_ps_set_mode(wl, STATION_IDLE);
|
||||
out_sleep:
|
||||
wl1251_ps_elp_sleep(wl);
|
||||
|
||||
|
@ -5636,7 +5636,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
|
||||
IEEE80211_HW_AP_LINK_PS |
|
||||
IEEE80211_HW_AMPDU_AGGREGATION |
|
||||
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
|
||||
IEEE80211_HW_SCAN_WHILE_IDLE |
|
||||
IEEE80211_HW_QUEUE_CONTROL;
|
||||
|
||||
wl->hw->wiphy->cipher_suites = cipher_suites;
|
||||
|
@ -424,7 +424,7 @@ int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
|
||||
if (result)
|
||||
|
@ -535,7 +535,7 @@ struct mac_address {
|
||||
* struct cfg80211_acl_data - Access control list data
|
||||
*
|
||||
* @acl_policy: ACL policy to be applied on the station's
|
||||
entry specified by mac_addr
|
||||
* entry specified by mac_addr
|
||||
* @n_acl_entries: Number of MAC address entries passed
|
||||
* @mac_addrs: List of MAC addresses of stations to be used for ACL
|
||||
*/
|
||||
@ -666,6 +666,8 @@ struct station_parameters {
|
||||
* @STATION_INFO_INACTIVE_TIME: @inactive_time filled
|
||||
* @STATION_INFO_RX_BYTES: @rx_bytes filled
|
||||
* @STATION_INFO_TX_BYTES: @tx_bytes filled
|
||||
* @STATION_INFO_RX_BYTES64: @rx_bytes filled with 64-bit value
|
||||
* @STATION_INFO_TX_BYTES64: @tx_bytes filled with 64-bit value
|
||||
* @STATION_INFO_LLID: @llid filled
|
||||
* @STATION_INFO_PLID: @plid filled
|
||||
* @STATION_INFO_PLINK_STATE: @plink_state filled
|
||||
@ -674,8 +676,6 @@ struct station_parameters {
|
||||
* (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
|
||||
* @STATION_INFO_RX_PACKETS: @rx_packets filled with 32-bit value
|
||||
* @STATION_INFO_TX_PACKETS: @tx_packets filled with 32-bit value
|
||||
* @STATION_INFO_RX_PACKETS64: @rx_packets filled with 64-bit value
|
||||
* @STATION_INFO_TX_PACKETS64: @tx_packets filled with 64-bit value
|
||||
* @STATION_INFO_TX_RETRIES: @tx_retries filled
|
||||
* @STATION_INFO_TX_FAILED: @tx_failed filled
|
||||
* @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
|
||||
@ -1226,6 +1226,7 @@ struct cfg80211_match_set {
|
||||
* @n_match_sets: number of match sets
|
||||
* @wiphy: the wiphy this was for
|
||||
* @dev: the interface
|
||||
* @scan_start: start time of the scheduled scan
|
||||
* @channels: channels to scan
|
||||
* @rssi_thold: don't report scan results below this threshold (in s32 dBm)
|
||||
*/
|
||||
@ -1265,11 +1266,13 @@ enum cfg80211_signal_type {
|
||||
|
||||
/**
|
||||
* struct cfg80211_bss_ie_data - BSS entry IE data
|
||||
* @tsf: TSF contained in the frame that carried these IEs
|
||||
* @rcu_head: internal use, for freeing
|
||||
* @len: length of the IEs
|
||||
* @data: IE data
|
||||
*/
|
||||
struct cfg80211_bss_ies {
|
||||
u64 tsf;
|
||||
struct rcu_head rcu_head;
|
||||
int len;
|
||||
u8 data[];
|
||||
@ -1283,27 +1286,33 @@ struct cfg80211_bss_ies {
|
||||
*
|
||||
* @channel: channel this BSS is on
|
||||
* @bssid: BSSID of the BSS
|
||||
* @tsf: timestamp of last received update
|
||||
* @beacon_interval: the beacon interval as from the frame
|
||||
* @capability: the capability field in host byte order
|
||||
* @ies: the information elements (Note that there
|
||||
* is no guarantee that these are well-formed!); this is a pointer to
|
||||
* either the beacon_ies or proberesp_ies depending on whether Probe
|
||||
* Response frame has been received
|
||||
* @ies: the information elements (Note that there is no guarantee that these
|
||||
* are well-formed!); this is a pointer to either the beacon_ies or
|
||||
* proberesp_ies depending on whether Probe Response frame has been
|
||||
* received. It is always non-%NULL.
|
||||
* @beacon_ies: the information elements from the last Beacon frame
|
||||
* (implementation note: if @hidden_beacon_bss is set this struct doesn't
|
||||
* own the beacon_ies, but they're just pointers to the ones from the
|
||||
* @hidden_beacon_bss struct)
|
||||
* @proberesp_ies: the information elements from the last Probe Response frame
|
||||
* @hidden_beacon_bss: in case this BSS struct represents a probe response from
|
||||
* a BSS that hides the SSID in its beacon, this points to the BSS struct
|
||||
* that holds the beacon data. @beacon_ies is still valid, of course, and
|
||||
* points to the same data as hidden_beacon_bss->beacon_ies in that case.
|
||||
* @signal: signal strength value (type depends on the wiphy's signal_type)
|
||||
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
|
||||
*/
|
||||
struct cfg80211_bss {
|
||||
u64 tsf;
|
||||
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
const struct cfg80211_bss_ies __rcu *ies;
|
||||
const struct cfg80211_bss_ies __rcu *beacon_ies;
|
||||
const struct cfg80211_bss_ies __rcu *proberesp_ies;
|
||||
|
||||
struct cfg80211_bss *hidden_beacon_bss;
|
||||
|
||||
s32 signal;
|
||||
|
||||
u16 beacon_interval;
|
||||
@ -1404,6 +1413,8 @@ struct cfg80211_assoc_request {
|
||||
* @ie: Extra IEs to add to Deauthentication frame or %NULL
|
||||
* @ie_len: Length of ie buffer in octets
|
||||
* @reason_code: The reason code for the deauthentication
|
||||
* @local_state_change: if set, change local state only and
|
||||
* do not set a deauth frame
|
||||
*/
|
||||
struct cfg80211_deauth_request {
|
||||
const u8 *bssid;
|
||||
@ -2629,7 +2640,6 @@ struct cfg80211_cached_keys;
|
||||
* the user-set AP, monitor and WDS channel
|
||||
* @preset_chan: (private) Used by the internal configuration code to
|
||||
* track the channel to be used for AP later
|
||||
* @preset_chantype: (private) the corresponding channel type
|
||||
* @bssid: (private) Used by the internal configuration code
|
||||
* @ssid: (private) Used by the internal configuration code
|
||||
* @ssid_len: (private) Used by the internal configuration code
|
||||
@ -3166,19 +3176,21 @@ cfg80211_get_ibss(struct wiphy *wiphy,
|
||||
|
||||
/**
|
||||
* cfg80211_ref_bss - reference BSS struct
|
||||
* @wiphy: the wiphy this BSS struct belongs to
|
||||
* @bss: the BSS struct to reference
|
||||
*
|
||||
* Increments the refcount of the given BSS struct.
|
||||
*/
|
||||
void cfg80211_ref_bss(struct cfg80211_bss *bss);
|
||||
void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
|
||||
|
||||
/**
|
||||
* cfg80211_put_bss - unref BSS struct
|
||||
* @wiphy: the wiphy this BSS struct belongs to
|
||||
* @bss: the BSS struct
|
||||
*
|
||||
* Decrements the refcount of the given BSS struct.
|
||||
*/
|
||||
void cfg80211_put_bss(struct cfg80211_bss *bss);
|
||||
void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
|
||||
|
||||
/**
|
||||
* cfg80211_unlink_bss - unlink BSS from internal data structures
|
||||
|
@ -277,9 +277,16 @@ enum ieee80211_rssi_event {
|
||||
* valid in station mode only if after the driver was notified
|
||||
* with the %BSS_CHANGED_DTIM_PERIOD 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)
|
||||
* as it may have been received during scanning long ago). If the
|
||||
* HW flag %IEEE80211_HW_TIMING_BEACON_ONLY is set, then this can
|
||||
* only come from a beacon, but might not become valid until after
|
||||
* association when a beacon is received (which is notified with the
|
||||
* %BSS_CHANGED_DTIM flag.)
|
||||
* @sync_device_ts: the device timestamp corresponding to the sync_tsf,
|
||||
* the driver/device can use this to calculate synchronisation
|
||||
* (see @sync_tsf)
|
||||
* @sync_dtim_count: Only valid when %IEEE80211_HW_TIMING_BEACON_ONLY
|
||||
* is requested, see @sync_tsf/@sync_device_ts.
|
||||
* @beacon_int: beacon interval
|
||||
* @assoc_capability: capabilities taken from assoc resp
|
||||
* @basic_rates: bitmap of basic rates, each bit stands for an
|
||||
@ -331,6 +338,7 @@ struct ieee80211_bss_conf {
|
||||
u16 assoc_capability;
|
||||
u64 sync_tsf;
|
||||
u32 sync_device_ts;
|
||||
u8 sync_dtim_count;
|
||||
u32 basic_rates;
|
||||
int mcast_rate[IEEE80211_NUM_BANDS];
|
||||
u16 ht_operation_mode;
|
||||
@ -391,6 +399,9 @@ struct ieee80211_bss_conf {
|
||||
* @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
|
||||
* set by rate control algorithms to indicate probe rate, will
|
||||
* be cleared for fragmented frames (except on the last fragment)
|
||||
* @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate
|
||||
* that a frame can be transmitted while the queues are stopped for
|
||||
* off-channel operation.
|
||||
* @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
|
||||
* used to indicate that a pending frame requires TX processing before
|
||||
* it can be sent out.
|
||||
@ -456,6 +467,7 @@ enum mac80211_tx_control_flags {
|
||||
IEEE80211_TX_STAT_AMPDU = BIT(10),
|
||||
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
|
||||
IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
|
||||
IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13),
|
||||
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
|
||||
IEEE80211_TX_INTFL_RETRIED = BIT(15),
|
||||
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
|
||||
@ -1355,10 +1367,6 @@ struct ieee80211_tx_control {
|
||||
* setup strictly in HW. mac80211 should not attempt to do this in
|
||||
* software.
|
||||
*
|
||||
* @IEEE80211_HW_SCAN_WHILE_IDLE: The device can do hw scan while
|
||||
* being idle (i.e. mac80211 doesn't have to go idle-off during the
|
||||
* the scan).
|
||||
*
|
||||
* @IEEE80211_HW_WANT_MONITOR_VIF: The driver would like to be informed of
|
||||
* a virtual monitor interface when monitor interfaces are the only
|
||||
* active interfaces.
|
||||
@ -1371,6 +1379,9 @@ struct ieee80211_tx_control {
|
||||
* @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any
|
||||
* P2P Interface. This will be honoured even if more than one interface
|
||||
* is supported.
|
||||
*
|
||||
* @IEEE80211_HW_TIMING_BEACON_ONLY: Use sync timing from beacon frames
|
||||
* only, to allow getting TBTT of a DTIM beacon.
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
|
||||
@ -1397,8 +1408,8 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21,
|
||||
IEEE80211_HW_AP_LINK_PS = 1<<22,
|
||||
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23,
|
||||
IEEE80211_HW_SCAN_WHILE_IDLE = 1<<24,
|
||||
IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25,
|
||||
IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1683,15 +1694,6 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
* dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
|
||||
* enabled whenever user has enabled powersave.
|
||||
*
|
||||
* Some hardware need to toggle a single shared antenna between WLAN and
|
||||
* Bluetooth to facilitate co-existence. These types of hardware set
|
||||
* limitations on the use of host controlled dynamic powersave whenever there
|
||||
* is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the
|
||||
* driver may request temporarily going into full power save, in order to
|
||||
* enable toggling the antenna between BT and WLAN. If the driver requests
|
||||
* disabling dynamic powersave, the @dynamic_ps_timeout value will be
|
||||
* temporarily set to zero until the driver re-enables dynamic powersave.
|
||||
*
|
||||
* Driver informs U-APSD client support by enabling
|
||||
* %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
|
||||
* uapsd paramater in conf_tx() operation. Hardware needs to send the QoS
|
||||
@ -2167,6 +2169,18 @@ enum ieee80211_rate_control_changed {
|
||||
* MAC address of the device going away.
|
||||
* Hence, this callback must be implemented. It can sleep.
|
||||
*
|
||||
* @add_interface_debugfs: Drivers can use this callback to add debugfs files
|
||||
* when a vif is added to mac80211. This callback and
|
||||
* @remove_interface_debugfs should be within a CONFIG_MAC80211_DEBUGFS
|
||||
* conditional. @remove_interface_debugfs must be provided for cleanup.
|
||||
* This callback can sleep.
|
||||
*
|
||||
* @remove_interface_debugfs: Remove the debugfs files which were added using
|
||||
* @add_interface_debugfs. This callback must remove all debugfs entries
|
||||
* that were added because mac80211 only removes interface debugfs when the
|
||||
* interface is destroyed, not when it is removed from the driver.
|
||||
* This callback can sleep.
|
||||
*
|
||||
* @config: Handler for configuration requests. IEEE 802.11 code calls this
|
||||
* function to change hardware configuration, e.g., channel.
|
||||
* This function should never fail but returns a negative error code
|
||||
@ -2580,6 +2594,12 @@ struct ieee80211_ops {
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct dentry *dir);
|
||||
void (*add_interface_debugfs)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct dentry *dir);
|
||||
void (*remove_interface_debugfs)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct dentry *dir);
|
||||
#endif
|
||||
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum sta_notify_cmd, struct ieee80211_sta *sta);
|
||||
@ -3908,36 +3928,6 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif);
|
||||
*/
|
||||
void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm
|
||||
*
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
*
|
||||
* Some hardware require full power save to manage simultaneous BT traffic
|
||||
* on the WLAN frequency. Full PSM is required periodically, whenever there are
|
||||
* burst of BT traffic. The hardware gets information of BT traffic via
|
||||
* hardware co-existence lines, and consequentially requests mac80211 to
|
||||
* (temporarily) enter full psm.
|
||||
* This function will only temporarily disable dynamic PS, not enable PSM if
|
||||
* it was not already enabled.
|
||||
* The driver must make sure to re-enable dynamic PS using
|
||||
* ieee80211_enable_dyn_ps() if the driver has disabled it.
|
||||
*
|
||||
*/
|
||||
void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* ieee80211_enable_dyn_ps - restore dynamic psm after being disabled
|
||||
*
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
*
|
||||
* This function restores dynamic PS after being temporarily disabled via
|
||||
* ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must
|
||||
* be coupled with an eventual call to this function.
|
||||
*
|
||||
*/
|
||||
void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring
|
||||
* rssi threshold triggered
|
||||
|
@ -933,6 +933,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
if (err)
|
||||
return err;
|
||||
ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
|
||||
|
||||
/*
|
||||
* Apply control port protocol, this allows us to
|
||||
@ -1047,6 +1048,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
|
||||
skb_queue_purge(&sdata->u.ap.ps.bc_buf);
|
||||
|
||||
ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
|
||||
return 0;
|
||||
@ -2747,7 +2749,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN |
|
||||
IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
|
||||
if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
|
||||
IEEE80211_SKB_CB(skb)->hw_queue =
|
||||
local->hw.offchannel_tx_hw_queue;
|
||||
|
@ -91,6 +91,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
|
||||
|
||||
list_add_rcu(&ctx->list, &local->chanctx_list);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@ -110,6 +114,10 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
|
||||
|
||||
list_del_rcu(&ctx->list);
|
||||
kfree_rcu(ctx, rcu_head);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
||||
@ -128,6 +136,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
||||
ctx->refcount++;
|
||||
|
||||
ieee80211_recalc_txpower(sdata);
|
||||
sdata->vif.bss_conf.idle = false;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -175,6 +185,9 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
||||
ctx->refcount--;
|
||||
rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
|
||||
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
||||
|
||||
drv_unassign_vif_chanctx(local, sdata, ctx);
|
||||
|
||||
if (ctx->refcount > 0) {
|
||||
@ -198,15 +211,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
ctx = container_of(conf, struct ieee80211_chanctx, conf);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
struct ieee80211_sub_if_data *vlan;
|
||||
|
||||
/* for the VLAN list */
|
||||
ASSERT_RTNL();
|
||||
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||
rcu_assign_pointer(vlan->vif.chanctx_conf, NULL);
|
||||
}
|
||||
|
||||
ieee80211_unassign_vif_chanctx(sdata, ctx);
|
||||
if (ctx->refcount == 0)
|
||||
ieee80211_free_chanctx(local, ctx);
|
||||
@ -326,15 +330,6 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
struct ieee80211_sub_if_data *vlan;
|
||||
|
||||
/* for the VLAN list */
|
||||
ASSERT_RTNL();
|
||||
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||
rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf);
|
||||
}
|
||||
|
||||
ieee80211_recalc_smps_chanctx(local, ctx);
|
||||
out:
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
@ -369,6 +364,40 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
|
||||
bool clear)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_sub_if_data *vlan;
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
|
||||
return;
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
|
||||
/*
|
||||
* Check that conf exists, even when clearing this function
|
||||
* must be called with the AP's channel context still there
|
||||
* as it would otherwise cause VLANs to have an invalid
|
||||
* channel context pointer for a while, possibly pointing
|
||||
* to a channel context that has already been freed.
|
||||
*/
|
||||
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
WARN_ON(!conf);
|
||||
|
||||
if (clear)
|
||||
conf = NULL;
|
||||
|
||||
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
|
||||
rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
|
||||
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_iter_chan_contexts_atomic(
|
||||
struct ieee80211_hw *hw,
|
||||
void (*iter)(struct ieee80211_hw *hw,
|
||||
|
@ -151,8 +151,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
|
||||
sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
|
||||
if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)
|
||||
sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");
|
||||
if (local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)
|
||||
sf += snprintf(buf + sf, mxln - sf, "SCAN_WHILE_IDLE\n");
|
||||
|
||||
rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
|
||||
kfree(buf);
|
||||
|
@ -528,6 +528,43 @@ static inline void drv_sta_remove_debugfs(struct ieee80211_local *local,
|
||||
local->ops->sta_remove_debugfs(&local->hw, &sdata->vif,
|
||||
sta, dir);
|
||||
}
|
||||
|
||||
static inline
|
||||
void drv_add_interface_debugfs(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
if (!local->ops->add_interface_debugfs)
|
||||
return;
|
||||
|
||||
local->ops->add_interface_debugfs(&local->hw, &sdata->vif,
|
||||
sdata->debugfs.dir);
|
||||
}
|
||||
|
||||
static inline
|
||||
void drv_remove_interface_debugfs(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
if (!local->ops->remove_interface_debugfs)
|
||||
return;
|
||||
|
||||
local->ops->remove_interface_debugfs(&local->hw, &sdata->vif,
|
||||
sdata->debugfs.dir);
|
||||
}
|
||||
#else
|
||||
static inline
|
||||
void drv_add_interface_debugfs(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata) {}
|
||||
static inline
|
||||
void drv_remove_interface_debugfs(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata) {}
|
||||
#endif
|
||||
|
||||
static inline __must_check
|
||||
|
@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan,
|
||||
mgmt, skb->len, 0, GFP_KERNEL);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(local->hw.wiphy, bss);
|
||||
netif_carrier_on(sdata->dev);
|
||||
cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
|
||||
}
|
||||
@ -242,6 +242,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
u32 basic_rates;
|
||||
int i, j;
|
||||
u16 beacon_int = cbss->beacon_interval;
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
u64 tsf;
|
||||
|
||||
lockdep_assert_held(&sdata->u.ibss.mtx);
|
||||
|
||||
@ -265,13 +267,17 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(cbss->ies);
|
||||
tsf = ies->tsf;
|
||||
rcu_read_unlock();
|
||||
|
||||
__ieee80211_sta_join_ibss(sdata, cbss->bssid,
|
||||
beacon_int,
|
||||
cbss->channel,
|
||||
basic_rates,
|
||||
cbss->capability,
|
||||
cbss->tsf,
|
||||
false);
|
||||
tsf, false);
|
||||
}
|
||||
|
||||
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
|
||||
@ -535,8 +541,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
cbss = container_of((void *)bss, struct cfg80211_bss, priv);
|
||||
|
||||
/* was just updated in ieee80211_bss_info_update */
|
||||
beacon_timestamp = cbss->tsf;
|
||||
/* same for beacon and probe response */
|
||||
beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
|
||||
/* check if we need to merge IBSS */
|
||||
|
||||
@ -1102,10 +1108,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
mutex_unlock(&sdata->u.ibss.mtx);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
/*
|
||||
* 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is
|
||||
* reserved, but an HT STA shall protect HT transmissions as though
|
||||
@ -1159,7 +1161,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
if (cbss) {
|
||||
cfg80211_unlink_bss(local->hw.wiphy, cbss);
|
||||
cfg80211_put_bss(cbss);
|
||||
cfg80211_put_bss(local->hw.wiphy, cbss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1203,9 +1205,5 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
mutex_unlock(&sdata->u.ibss.mtx);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ struct ieee80211_fragment_entry {
|
||||
|
||||
|
||||
struct ieee80211_bss {
|
||||
u32 device_ts;
|
||||
u32 device_ts_beacon, device_ts_presp;
|
||||
|
||||
bool wmm_used;
|
||||
bool uapsd_supported;
|
||||
@ -689,9 +689,6 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
/* to detect idle changes */
|
||||
bool old_idle;
|
||||
|
||||
/* Fragment table for host-based reassembly */
|
||||
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
|
||||
unsigned int fragment_next;
|
||||
@ -812,6 +809,7 @@ enum queue_stop_reason {
|
||||
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
|
||||
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
|
||||
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MAC80211_LEDS
|
||||
@ -958,14 +956,7 @@ struct ieee80211_local {
|
||||
struct sk_buff_head skb_queue;
|
||||
struct sk_buff_head skb_queue_unreliable;
|
||||
|
||||
/*
|
||||
* Internal FIFO queue which is shared between multiple rx path
|
||||
* stages. Its main task is to provide a serialization mechanism,
|
||||
* so all rx handlers can enjoy having exclusive access to their
|
||||
* private data structures.
|
||||
*/
|
||||
struct sk_buff_head rx_skb_queue;
|
||||
bool running_rx_handler; /* protected by rx_skb_queue.lock */
|
||||
spinlock_t rx_path_lock;
|
||||
|
||||
/* Station data */
|
||||
/*
|
||||
@ -1106,8 +1097,6 @@ struct ieee80211_local {
|
||||
* this will override whatever chosen by mac80211 internally.
|
||||
*/
|
||||
int dynamic_ps_forced_timeout;
|
||||
int dynamic_ps_user_timeout;
|
||||
bool disable_dynamic_ps;
|
||||
|
||||
int user_power_level; /* in dBm, for all interfaces */
|
||||
|
||||
@ -1612,6 +1601,8 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_chanctx_mode mode);
|
||||
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
|
||||
bool clear);
|
||||
|
||||
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *chanctx);
|
||||
|
@ -78,8 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
|
||||
}
|
||||
|
||||
static u32 ieee80211_idle_off(struct ieee80211_local *local,
|
||||
const char *reason)
|
||||
static u32 ieee80211_idle_off(struct ieee80211_local *local)
|
||||
{
|
||||
if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
|
||||
return 0;
|
||||
@ -99,110 +98,45 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
|
||||
return IEEE80211_CONF_CHANGE_IDLE;
|
||||
}
|
||||
|
||||
static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int count = 0;
|
||||
bool working = false, scanning = false;
|
||||
bool working = false, scanning, active;
|
||||
unsigned int led_trig_start = 0, led_trig_stop = 0;
|
||||
struct ieee80211_roc_work *roc;
|
||||
u32 change;
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
|
||||
!lockdep_is_held(&local->iflist_mtx));
|
||||
#endif
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata)) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
sdata->old_idle = sdata->vif.bss_conf.idle;
|
||||
|
||||
/* do not count disabled managed interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!sdata->u.mgd.associated &&
|
||||
!sdata->u.mgd.auth_data &&
|
||||
!sdata->u.mgd.assoc_data) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
/* do not count unused IBSS interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
!sdata->u.ibss.ssid_len) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
continue;
|
||||
|
||||
/* count everything else */
|
||||
sdata->vif.bss_conf.idle = false;
|
||||
count++;
|
||||
}
|
||||
active = !list_empty(&local->chanctx_list);
|
||||
|
||||
if (!local->ops->remain_on_channel) {
|
||||
list_for_each_entry(roc, &local->roc_list, list) {
|
||||
working = true;
|
||||
roc->sdata->vif.bss_conf.idle = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
|
||||
scanning = true;
|
||||
sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
continue;
|
||||
if (sdata->old_idle == sdata->vif.bss_conf.idle)
|
||||
continue;
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
||||
}
|
||||
scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
|
||||
test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning);
|
||||
|
||||
if (working || scanning)
|
||||
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
else
|
||||
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
|
||||
if (count)
|
||||
if (active)
|
||||
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
|
||||
else
|
||||
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
|
||||
|
||||
ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
|
||||
|
||||
if (working)
|
||||
return ieee80211_idle_off(local, "working");
|
||||
if (scanning)
|
||||
return ieee80211_idle_off(local, "scanning");
|
||||
if (!count)
|
||||
return ieee80211_idle_on(local);
|
||||
if (working || scanning || active)
|
||||
change = ieee80211_idle_off(local);
|
||||
else
|
||||
return ieee80211_idle_off(local, "in use");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
u32 chg;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
chg = __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
if (chg)
|
||||
ieee80211_hw_config(local, chg);
|
||||
change = ieee80211_idle_on(local);
|
||||
if (change)
|
||||
ieee80211_hw_config(local, change);
|
||||
}
|
||||
|
||||
static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
|
||||
@ -621,6 +555,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
goto err_del_interface;
|
||||
}
|
||||
|
||||
drv_add_interface_debugfs(local, sdata);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||
local->fif_pspoll++;
|
||||
local->fif_probe_req++;
|
||||
@ -694,10 +630,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
if (sdata->flags & IEEE80211_SDATA_PROMISC)
|
||||
atomic_inc(&local->iff_promiscs);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
hw_reconf_flags |= __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (coming_up)
|
||||
local->open_count++;
|
||||
|
||||
@ -882,16 +814,14 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
ieee80211_free_keys(sdata);
|
||||
|
||||
drv_remove_interface_debugfs(local, sdata);
|
||||
|
||||
if (going_down)
|
||||
drv_remove_interface(local, sdata);
|
||||
}
|
||||
|
||||
sdata->bss = NULL;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
hw_reconf_flags |= __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
|
||||
if (local->open_count == 0) {
|
||||
|
@ -34,8 +34,6 @@
|
||||
#include "cfg.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
static struct lock_class_key ieee80211_rx_skb_queue_class;
|
||||
|
||||
void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||
{
|
||||
u64 mc;
|
||||
@ -613,21 +611,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
|
||||
mutex_init(&local->key_mtx);
|
||||
spin_lock_init(&local->filter_lock);
|
||||
spin_lock_init(&local->rx_path_lock);
|
||||
spin_lock_init(&local->queue_stop_reason_lock);
|
||||
|
||||
INIT_LIST_HEAD(&local->chanctx_list);
|
||||
mutex_init(&local->chanctx_mtx);
|
||||
|
||||
/*
|
||||
* The rx_skb_queue is only accessed from tasklets,
|
||||
* but other SKB queues are used from within IRQ
|
||||
* context. Therefore, this one needs a different
|
||||
* locking class so our direct, non-irq-safe use of
|
||||
* the queue's lock doesn't throw lockdep warnings.
|
||||
*/
|
||||
skb_queue_head_init_class(&local->rx_skb_queue,
|
||||
&ieee80211_rx_skb_queue_class);
|
||||
|
||||
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
|
||||
|
||||
INIT_WORK(&local->restart_work, ieee80211_restart_work);
|
||||
@ -707,9 +696,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
|
||||
return -EINVAL;
|
||||
|
||||
if (!local->use_chanctx) {
|
||||
for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
|
||||
const struct ieee80211_iface_combination *comb;
|
||||
@ -1089,7 +1075,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
||||
wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
|
||||
skb_queue_purge(&local->skb_queue);
|
||||
skb_queue_purge(&local->skb_queue_unreliable);
|
||||
skb_queue_purge(&local->rx_skb_queue);
|
||||
|
||||
destroy_workqueue(local->workqueue);
|
||||
wiphy_unregister(local->hw.wiphy);
|
||||
|
@ -149,6 +149,31 @@ u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
|
||||
return changed;
|
||||
}
|
||||
|
||||
/*
|
||||
* mesh_sta_cleanup - clean up any mesh sta state
|
||||
*
|
||||
* @sta: mesh sta to clean up.
|
||||
*/
|
||||
void mesh_sta_cleanup(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
u32 changed;
|
||||
|
||||
/*
|
||||
* maybe userspace handles peer allocation and peering, but in either
|
||||
* case the beacon is still generated by the kernel and we might need
|
||||
* an update.
|
||||
*/
|
||||
changed = mesh_accept_plinks_update(sdata);
|
||||
if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
|
||||
changed |= mesh_plink_deactivate(sta);
|
||||
del_timer_sync(&sta->plink_timer);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
}
|
||||
|
||||
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
int i;
|
||||
@ -368,8 +393,6 @@ mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
|
||||
int mesh_add_ds_params_ie(struct sk_buff *skb,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *chan;
|
||||
u8 *pos;
|
||||
@ -386,13 +409,10 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
|
||||
chan = chanctx_conf->def.chan;
|
||||
rcu_read_unlock();
|
||||
|
||||
sband = local->hw.wiphy->bands[chan->band];
|
||||
if (sband->band == IEEE80211_BAND_2GHZ) {
|
||||
pos = skb_put(skb, 2 + 1);
|
||||
*pos++ = WLAN_EID_DS_PARAMS;
|
||||
*pos++ = 1;
|
||||
*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
|
||||
}
|
||||
pos = skb_put(skb, 2 + 1);
|
||||
*pos++ = WLAN_EID_DS_PARAMS;
|
||||
*pos++ = 1;
|
||||
*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -288,12 +288,13 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
|
||||
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
|
||||
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_plink_broken(struct sta_info *sta);
|
||||
void mesh_plink_deactivate(struct sta_info *sta);
|
||||
u32 mesh_plink_deactivate(struct sta_info *sta);
|
||||
int mesh_plink_open(struct sta_info *sta);
|
||||
void mesh_plink_block(struct sta_info *sta);
|
||||
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
void mesh_sta_cleanup(struct sta_info *sta);
|
||||
|
||||
/* Private interfaces */
|
||||
/* Mesh tables */
|
||||
|
@ -214,7 +214,7 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta)
|
||||
*
|
||||
* All mesh paths with this peer as next hop will be flushed
|
||||
*/
|
||||
void mesh_plink_deactivate(struct sta_info *sta)
|
||||
u32 mesh_plink_deactivate(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
u32 changed;
|
||||
@ -227,7 +227,7 @@ void mesh_plink_deactivate(struct sta_info *sta)
|
||||
sta->reason);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
|
||||
@ -592,6 +592,13 @@ static void mesh_plink_timer(unsigned long data)
|
||||
#ifdef CONFIG_PM
|
||||
void mesh_plink_quiesce(struct sta_info *sta)
|
||||
{
|
||||
if (!ieee80211_vif_is_mesh(&sta->sdata->vif))
|
||||
return;
|
||||
|
||||
/* no kernel mesh sta timers have been initialized */
|
||||
if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
|
||||
return;
|
||||
|
||||
if (del_timer_sync(&sta->plink_timer))
|
||||
sta->plink_timer_was_running = true;
|
||||
}
|
||||
|
@ -685,7 +685,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
if (powersave)
|
||||
nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||
IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
|
||||
if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
|
||||
IEEE80211_STA_CONNECTION_POLL))
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
|
||||
@ -951,39 +952,6 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
|
||||
WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
|
||||
!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
|
||||
(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
|
||||
|
||||
local->disable_dynamic_ps = false;
|
||||
conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_enable_dyn_ps);
|
||||
|
||||
void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
|
||||
WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
|
||||
!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
|
||||
(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
|
||||
|
||||
local->disable_dynamic_ps = true;
|
||||
conf->dynamic_ps_timeout = 0;
|
||||
del_timer_sync(&local->dynamic_ps_timer);
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&local->dynamic_ps_enable_work);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_disable_dyn_ps);
|
||||
|
||||
/* powersave */
|
||||
static void ieee80211_enable_ps(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
@ -1086,7 +1054,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
||||
}
|
||||
|
||||
if (count == 1 && ieee80211_powersave_allowed(found)) {
|
||||
struct ieee80211_conf *conf = &local->hw.conf;
|
||||
s32 beaconint_us;
|
||||
|
||||
if (latency < 0)
|
||||
@ -1110,10 +1077,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
||||
else
|
||||
timeout = 100;
|
||||
}
|
||||
local->dynamic_ps_user_timeout = timeout;
|
||||
if (!local->disable_dynamic_ps)
|
||||
conf->dynamic_ps_timeout =
|
||||
local->dynamic_ps_user_timeout;
|
||||
local->hw.conf.dynamic_ps_timeout = timeout;
|
||||
|
||||
if (beaconint_us > latency) {
|
||||
local->ps_sdata = NULL;
|
||||
@ -1183,8 +1147,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS)
|
||||
return;
|
||||
|
||||
if (!local->disable_dynamic_ps &&
|
||||
local->hw.conf.dynamic_ps_timeout > 0) {
|
||||
if (local->hw.conf.dynamic_ps_timeout > 0) {
|
||||
/* don't enter PS if TX frames are pending */
|
||||
if (drv_tx_frames_pending(local)) {
|
||||
mod_timer(&local->dynamic_ps_timer, jiffies +
|
||||
@ -1746,7 +1709,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (beacon)
|
||||
mlme_dbg_ratelimited(sdata,
|
||||
"detected beacon loss from AP - sending probe request\n");
|
||||
"detected beacon loss from AP - probing\n");
|
||||
|
||||
ieee80211_cqm_rssi_notify(&sdata->vif,
|
||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
|
||||
@ -1830,7 +1793,6 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get);
|
||||
static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||||
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
@ -1850,10 +1812,6 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
|
||||
* but that's not a problem.
|
||||
*/
|
||||
cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
|
||||
@ -1934,7 +1892,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
}
|
||||
|
||||
cfg80211_put_bss(auth_data->bss);
|
||||
cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
|
||||
kfree(auth_data);
|
||||
sdata->u.mgd.auth_data = NULL;
|
||||
}
|
||||
@ -2086,10 +2044,6 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return RX_MGMT_CFG80211_DEAUTH;
|
||||
}
|
||||
|
||||
@ -2117,10 +2071,6 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return RX_MGMT_CFG80211_DISASSOC;
|
||||
}
|
||||
|
||||
@ -2263,9 +2213,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
if (elems.wmm_param)
|
||||
set_sta_flag(sta, WLAN_STA_WME);
|
||||
|
||||
err = sta_info_move_state(sta, IEEE80211_STA_AUTH);
|
||||
if (!err)
|
||||
err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
|
||||
err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
||||
if (err) {
|
||||
@ -2387,7 +2335,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
||||
if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
|
||||
/* oops -- internal error -- send timeout for now */
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
cfg80211_put_bss(*bss);
|
||||
cfg80211_put_bss(sdata->local->hw.wiphy, *bss);
|
||||
return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
|
||||
}
|
||||
sdata_info(sdata, "associated\n");
|
||||
@ -2567,6 +2515,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
ifmgd->assoc_data->have_beacon = true;
|
||||
ifmgd->assoc_data->need_beacon = false;
|
||||
if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
|
||||
sdata->vif.bss_conf.sync_tsf =
|
||||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
}
|
||||
/* continue assoc process */
|
||||
ifmgd->assoc_data->timeout = jiffies;
|
||||
run_again(ifmgd, ifmgd->assoc_data->timeout);
|
||||
@ -2641,7 +2600,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
|
||||
mlme_dbg_ratelimited(sdata,
|
||||
"cancelling probereq poll due to a received beacon\n");
|
||||
"cancelling AP probe due to a received beacon\n");
|
||||
mutex_lock(&local->mtx);
|
||||
ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
|
||||
ieee80211_run_deferred_scan(local);
|
||||
@ -2725,7 +2684,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 now.
|
||||
* DTIM period (and beacon timing if desired) now.
|
||||
*/
|
||||
if (!bss_conf->dtim_period) {
|
||||
/* a few bogus AP send dtim_period = 0 or no TIM IE */
|
||||
@ -2733,6 +2692,19 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
|
||||
else
|
||||
bss_conf->dtim_period = 1;
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
|
||||
sdata->vif.bss_conf.sync_tsf =
|
||||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
}
|
||||
|
||||
changed |= BSS_CHANGED_DTIM_PERIOD;
|
||||
}
|
||||
|
||||
@ -2853,7 +2825,6 @@ static void ieee80211_sta_timer(unsigned long data)
|
||||
static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *bssid, u8 reason, bool tx)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||||
|
||||
@ -2867,10 +2838,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
}
|
||||
|
||||
@ -3141,10 +3108,6 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
static void ieee80211_sta_bcn_mon_timer(unsigned long data)
|
||||
@ -3658,15 +3621,12 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (new_sta) {
|
||||
u32 rates = 0, basic_rates = 0;
|
||||
bool have_higher_than_11mbit;
|
||||
int min_rate = INT_MAX, min_rate_index = -1;
|
||||
struct ieee80211_supported_band *sband;
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
|
||||
sband = local->hw.wiphy->bands[cbss->channel->band];
|
||||
|
||||
@ -3710,8 +3670,34 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
/* set timing information */
|
||||
sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
|
||||
sdata->vif.bss_conf.sync_tsf = cbss->tsf;
|
||||
sdata->vif.bss_conf.sync_device_ts = bss->device_ts;
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(cbss->beacon_ies);
|
||||
if (ies) {
|
||||
const u8 *tim_ie;
|
||||
|
||||
sdata->vif.bss_conf.sync_tsf = ies->tsf;
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
bss->device_ts_beacon;
|
||||
tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
|
||||
ies->data, ies->len);
|
||||
if (tim_ie && tim_ie[1] >= 2)
|
||||
sdata->vif.bss_conf.sync_dtim_count = tim_ie[2];
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
} else if (!(local->hw.flags &
|
||||
IEEE80211_HW_TIMING_BEACON_ONLY)) {
|
||||
ies = rcu_dereference(cbss->proberesp_ies);
|
||||
/* must be non-NULL since beacon IEs were NULL */
|
||||
sdata->vif.bss_conf.sync_tsf = ies->tsf;
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
bss->device_ts_presp;
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
} else {
|
||||
sdata->vif.bss_conf.sync_tsf = 0;
|
||||
sdata->vif.bss_conf.sync_device_ts = 0;
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* tell driver about BSSID, basic rates and timing */
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
@ -3831,7 +3817,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
/* hold our own reference */
|
||||
cfg80211_ref_bss(auth_data->bss);
|
||||
cfg80211_ref_bss(local->hw.wiphy, auth_data->bss);
|
||||
err = 0;
|
||||
goto out_unlock;
|
||||
|
||||
@ -4037,13 +4023,23 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
|
||||
beacon_ies->data,
|
||||
beacon_ies->len);
|
||||
u8 dtim_count = 0;
|
||||
|
||||
if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) {
|
||||
const struct ieee80211_tim_ie *tim;
|
||||
tim = (void *)(tim_ie + 2);
|
||||
ifmgd->dtim_period = tim->dtim_period;
|
||||
dtim_count = tim->dtim_count;
|
||||
}
|
||||
assoc_data->have_beacon = true;
|
||||
assoc_data->timeout = jiffies;
|
||||
|
||||
if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
|
||||
sdata->vif.bss_conf.sync_tsf = beacon_ies->tsf;
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
bss->device_ts_beacon;
|
||||
sdata->vif.bss_conf.sync_dtim_count = dtim_count;
|
||||
}
|
||||
} else {
|
||||
assoc_data->timeout = jiffies;
|
||||
}
|
||||
@ -4115,10 +4111,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
out:
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
if (sent_frame)
|
||||
__cfg80211_send_deauth(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
@ -4159,10 +4151,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
__cfg80211_send_disassoc(sdata->dev, frame_buf,
|
||||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,15 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
|
||||
* notify the AP about us leaving the channel and stop all
|
||||
* STA interfaces.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stop queues and transmit all frames queued by the driver
|
||||
* before sending nullfunc to enable powersave at the AP.
|
||||
*/
|
||||
ieee80211_stop_queues_by_reason(&local->hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
|
||||
drv_flush(local, false);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
@ -133,12 +142,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
|
||||
sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
}
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata);
|
||||
}
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_enable(sdata);
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
@ -166,20 +172,6 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
|
||||
sdata->u.mgd.associated)
|
||||
ieee80211_offchannel_ps_disable(sdata);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
|
||||
/*
|
||||
* This may wake up queues even though the driver
|
||||
* currently has them stopped. This is not very
|
||||
* likely, since the driver won't have gotten any
|
||||
* (or hardly any) new packets while we weren't
|
||||
* on the right channel, and even if it happens
|
||||
* it will at most lead to queueing up one more
|
||||
* packet per queue in mac80211 rather than on
|
||||
* the interface qdisc.
|
||||
*/
|
||||
netif_tx_wake_all_queues(sdata->dev);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
|
||||
&sdata->state)) {
|
||||
sdata->vif.bss_conf.enable_beacon = true;
|
||||
@ -188,6 +180,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
|
||||
}
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
ieee80211_wake_queues_by_reason(&local->hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
|
||||
}
|
||||
|
||||
void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
|
||||
|
@ -231,10 +231,6 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
if (!mr->cur_tp)
|
||||
continue;
|
||||
|
||||
/* ignore the lowest rate of each single-stream group */
|
||||
if (!i && minstrel_mcs_groups[group].streams == 1)
|
||||
continue;
|
||||
|
||||
if ((mr->cur_tp > cur_prob_tp && mr->probability >
|
||||
MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
|
||||
mg->max_prob_rate = index;
|
||||
|
@ -38,8 +38,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
|
||||
|
||||
file->private_data = ms;
|
||||
p = ms->buf;
|
||||
p += sprintf(p, "type rate throughput ewma prob this prob "
|
||||
"this succ/attempt success attempts\n");
|
||||
p += sprintf(p, "type rate throughput ewma prob this prob "
|
||||
"retry this succ/attempt success attempts\n");
|
||||
for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
|
||||
char htmode = '2';
|
||||
char gimode = 'L';
|
||||
@ -64,18 +64,19 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
|
||||
*(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
|
||||
*(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
|
||||
*(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
|
||||
p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
|
||||
p += sprintf(p, " MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
|
||||
MCS_GROUP_RATES + j);
|
||||
|
||||
tp = mr->cur_tp / 10;
|
||||
prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
|
||||
eprob = MINSTREL_TRUNC(mr->probability * 1000);
|
||||
|
||||
p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
|
||||
"%3u(%3u) %8llu %8llu\n",
|
||||
p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
|
||||
"%3u %3u(%3u) %8llu %8llu\n",
|
||||
tp / 10, tp % 10,
|
||||
eprob / 10, eprob % 10,
|
||||
prob / 10, prob % 10,
|
||||
mr->retry_count,
|
||||
mr->last_success,
|
||||
mr->last_attempts,
|
||||
(unsigned long long)mr->succ_hist,
|
||||
|
@ -668,9 +668,9 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
|
||||
|
||||
static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
int index)
|
||||
int index,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
|
||||
struct ieee80211_rx_status *status;
|
||||
|
||||
@ -684,7 +684,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||
tid_agg_rx->reorder_buf[index] = NULL;
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE;
|
||||
skb_queue_tail(&local->rx_skb_queue, skb);
|
||||
__skb_queue_tail(frames, skb);
|
||||
|
||||
no_frame:
|
||||
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
|
||||
@ -692,7 +692,8 @@ no_frame:
|
||||
|
||||
static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
u16 head_seq_num)
|
||||
u16 head_seq_num,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
int index;
|
||||
|
||||
@ -701,7 +702,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
|
||||
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
|
||||
frames);
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,7 +719,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
|
||||
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
|
||||
|
||||
static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
struct tid_ampdu_rx *tid_agg_rx)
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
int index, j;
|
||||
|
||||
@ -746,7 +749,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ht_dbg_ratelimited(sdata,
|
||||
"release an RX reorder frame due to timeout on earlier frames\n");
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, j);
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, j,
|
||||
frames);
|
||||
|
||||
/*
|
||||
* Increment the head seq# also for the skipped slots.
|
||||
@ -756,7 +760,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
skipped = 0;
|
||||
}
|
||||
} else while (tid_agg_rx->reorder_buf[index]) {
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index);
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
|
||||
frames);
|
||||
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
|
||||
tid_agg_rx->buf_size;
|
||||
}
|
||||
@ -788,7 +793,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
struct sk_buff *skb)
|
||||
struct sk_buff *skb,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
@ -816,7 +822,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||
head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
|
||||
/* release stored frames up to new head to stack */
|
||||
ieee80211_release_reorder_frames(sdata, tid_agg_rx,
|
||||
head_seq_num);
|
||||
head_seq_num, frames);
|
||||
}
|
||||
|
||||
/* Now the new frame is always in the range of the reordering buffer */
|
||||
@ -846,7 +852,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||
tid_agg_rx->reorder_buf[index] = skb;
|
||||
tid_agg_rx->reorder_time[index] = jiffies;
|
||||
tid_agg_rx->stored_mpdu_num++;
|
||||
ieee80211_sta_reorder_release(sdata, tid_agg_rx);
|
||||
ieee80211_sta_reorder_release(sdata, tid_agg_rx, frames);
|
||||
|
||||
out:
|
||||
spin_unlock(&tid_agg_rx->reorder_lock);
|
||||
@ -857,7 +863,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||
* Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
|
||||
* true if the MPDU was buffered, false if it should be processed.
|
||||
*/
|
||||
static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
|
||||
static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_local *local = rx->local;
|
||||
@ -922,11 +929,12 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
|
||||
* sure that we cannot get to it any more before doing
|
||||
* anything with it.
|
||||
*/
|
||||
if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb))
|
||||
if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb,
|
||||
frames))
|
||||
return;
|
||||
|
||||
dont_reorder:
|
||||
skb_queue_tail(&local->rx_skb_queue, skb);
|
||||
__skb_queue_tail(frames, skb);
|
||||
}
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
@ -2184,7 +2192,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
|
||||
}
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
|
||||
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
|
||||
{
|
||||
struct sk_buff *skb = rx->skb;
|
||||
struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
|
||||
@ -2223,7 +2231,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
|
||||
spin_lock(&tid_agg_rx->reorder_lock);
|
||||
/* release stored frames up to start of BAR */
|
||||
ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx,
|
||||
start_seq_num);
|
||||
start_seq_num, frames);
|
||||
spin_unlock(&tid_agg_rx->reorder_lock);
|
||||
|
||||
kfree_skb(skb);
|
||||
@ -2808,7 +2816,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
|
||||
struct sk_buff_head *frames)
|
||||
{
|
||||
ieee80211_rx_result res = RX_DROP_MONITOR;
|
||||
struct sk_buff *skb;
|
||||
@ -2820,15 +2829,9 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
goto rxh_next; \
|
||||
} while (0);
|
||||
|
||||
spin_lock(&rx->local->rx_skb_queue.lock);
|
||||
if (rx->local->running_rx_handler)
|
||||
goto unlock;
|
||||
|
||||
rx->local->running_rx_handler = true;
|
||||
|
||||
while ((skb = __skb_dequeue(&rx->local->rx_skb_queue))) {
|
||||
spin_unlock(&rx->local->rx_skb_queue.lock);
|
||||
spin_lock_bh(&rx->local->rx_path_lock);
|
||||
|
||||
while ((skb = __skb_dequeue(frames))) {
|
||||
/*
|
||||
* all the other fields are valid across frames
|
||||
* that belong to an aMPDU since they are on the
|
||||
@ -2849,7 +2852,12 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
#endif
|
||||
CALL_RXH(ieee80211_rx_h_amsdu)
|
||||
CALL_RXH(ieee80211_rx_h_data)
|
||||
CALL_RXH(ieee80211_rx_h_ctrl);
|
||||
|
||||
/* special treatment -- needs the queue */
|
||||
res = ieee80211_rx_h_ctrl(rx, frames);
|
||||
if (res != RX_CONTINUE)
|
||||
goto rxh_next;
|
||||
|
||||
CALL_RXH(ieee80211_rx_h_mgmt_check)
|
||||
CALL_RXH(ieee80211_rx_h_action)
|
||||
CALL_RXH(ieee80211_rx_h_userspace_mgmt)
|
||||
@ -2858,20 +2866,20 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
|
||||
rxh_next:
|
||||
ieee80211_rx_handlers_result(rx, res);
|
||||
spin_lock(&rx->local->rx_skb_queue.lock);
|
||||
|
||||
#undef CALL_RXH
|
||||
}
|
||||
|
||||
rx->local->running_rx_handler = false;
|
||||
|
||||
unlock:
|
||||
spin_unlock(&rx->local->rx_skb_queue.lock);
|
||||
spin_unlock_bh(&rx->local->rx_path_lock);
|
||||
}
|
||||
|
||||
static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct sk_buff_head reorder_release;
|
||||
ieee80211_rx_result res = RX_DROP_MONITOR;
|
||||
|
||||
__skb_queue_head_init(&reorder_release);
|
||||
|
||||
#define CALL_RXH(rxh) \
|
||||
do { \
|
||||
res = rxh(rx); \
|
||||
@ -2881,9 +2889,9 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
|
||||
CALL_RXH(ieee80211_rx_h_check)
|
||||
|
||||
ieee80211_rx_reorder_ampdu(rx);
|
||||
ieee80211_rx_reorder_ampdu(rx, &reorder_release);
|
||||
|
||||
ieee80211_rx_handlers(rx);
|
||||
ieee80211_rx_handlers(rx, &reorder_release);
|
||||
return;
|
||||
|
||||
rxh_next:
|
||||
@ -2898,6 +2906,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
*/
|
||||
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
||||
{
|
||||
struct sk_buff_head frames;
|
||||
struct ieee80211_rx_data rx = {
|
||||
.sta = sta,
|
||||
.sdata = sta->sdata,
|
||||
@ -2913,11 +2922,13 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
||||
if (!tid_agg_rx)
|
||||
return;
|
||||
|
||||
__skb_queue_head_init(&frames);
|
||||
|
||||
spin_lock(&tid_agg_rx->reorder_lock);
|
||||
ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx);
|
||||
ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
|
||||
spin_unlock(&tid_agg_rx->reorder_lock);
|
||||
|
||||
ieee80211_rx_handlers(&rx);
|
||||
ieee80211_rx_handlers(&rx, &frames);
|
||||
}
|
||||
|
||||
/* main receive path */
|
||||
|
@ -34,7 +34,8 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local,
|
||||
{
|
||||
if (!bss)
|
||||
return;
|
||||
cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv));
|
||||
cfg80211_put_bss(local->hw.wiphy,
|
||||
container_of((void *)bss, struct cfg80211_bss, priv));
|
||||
}
|
||||
|
||||
static bool is_uapsd_supported(struct ieee802_11_elems *elems)
|
||||
@ -79,7 +80,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
|
||||
bss = (void *)cbss->priv;
|
||||
|
||||
bss->device_ts = rx_status->device_timestamp;
|
||||
if (beacon)
|
||||
bss->device_ts_beacon = rx_status->device_timestamp;
|
||||
else
|
||||
bss->device_ts_presp = rx_status->device_timestamp;
|
||||
|
||||
if (elems->parse_error) {
|
||||
if (beacon)
|
||||
@ -330,6 +334,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
||||
|
||||
ieee80211_offchannel_stop_vifs(local);
|
||||
|
||||
/* ensure nullfunc is transmitted before leaving operating channel */
|
||||
drv_flush(local, false);
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
|
||||
/* We need to set power level at maximum rate for scanning. */
|
||||
@ -378,6 +385,11 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
|
||||
int i;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
enum ieee80211_band band = local->hw.conf.channel->band;
|
||||
u32 tx_flags;
|
||||
|
||||
tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
|
||||
if (local->scan_req->no_cck)
|
||||
tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
|
||||
|
||||
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
@ -389,9 +401,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
|
||||
local->scan_req->ssids[i].ssid_len,
|
||||
local->scan_req->ie, local->scan_req->ie_len,
|
||||
local->scan_req->rates[band], false,
|
||||
local->scan_req->no_cck ?
|
||||
IEEE80211_TX_CTL_NO_CCK_RATE : 0,
|
||||
local->hw.conf.channel, true);
|
||||
tx_flags, local->hw.conf.channel, true);
|
||||
|
||||
/*
|
||||
* After sending probe requests, wait for probe responses
|
||||
|
@ -137,13 +137,8 @@ static void cleanup_single_sta(struct sta_info *sta)
|
||||
ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
mesh_accept_plinks_update(sdata);
|
||||
mesh_plink_deactivate(sta);
|
||||
del_timer_sync(&sta->plink_timer);
|
||||
}
|
||||
#endif
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
mesh_sta_cleanup(sta);
|
||||
|
||||
cancel_work_sync(&sta->drv_unblock_wk);
|
||||
|
||||
|
@ -298,6 +298,7 @@ struct sta_ampdu_mlme {
|
||||
* @beacon_loss_count: number of times beacon loss has triggered
|
||||
* @supports_40mhz: tracks whether the station advertised 40 MHz support
|
||||
* as we overwrite its HT parameters with the currently used value
|
||||
* @rcu_head: RCU head used for freeing this station struct
|
||||
*/
|
||||
struct sta_info {
|
||||
/* General information, mostly static */
|
||||
|
@ -36,7 +36,7 @@
|
||||
__entry->control_freq = (c)->chan->center_freq; \
|
||||
__entry->chan_width = (c)->width; \
|
||||
__entry->center_freq1 = (c)->center_freq1; \
|
||||
__entry->center_freq1 = (c)->center_freq2;
|
||||
__entry->center_freq2 = (c)->center_freq2;
|
||||
#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
|
||||
#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
|
||||
__entry->center_freq1, __entry->center_freq2
|
||||
@ -340,6 +340,7 @@ TRACE_EVENT(drv_bss_info_changed,
|
||||
__field(u16, assoc_cap)
|
||||
__field(u64, sync_tsf)
|
||||
__field(u32, sync_device_ts)
|
||||
__field(u8, sync_dtim_count)
|
||||
__field(u32, basic_rates)
|
||||
__array(int, mcast_rate, IEEE80211_NUM_BANDS)
|
||||
__field(u16, ht_operation_mode)
|
||||
@ -379,6 +380,7 @@ TRACE_EVENT(drv_bss_info_changed,
|
||||
__entry->assoc_cap = info->assoc_capability;
|
||||
__entry->sync_tsf = info->sync_tsf;
|
||||
__entry->sync_device_ts = info->sync_device_ts;
|
||||
__entry->sync_dtim_count = info->sync_dtim_count;
|
||||
__entry->basic_rates = info->basic_rates;
|
||||
memcpy(__entry->mcast_rate, info->mcast_rate,
|
||||
sizeof(__entry->mcast_rate));
|
||||
|
@ -1230,6 +1230,21 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
if (local->queue_stop_reasons[q] ||
|
||||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
|
||||
if (unlikely(info->flags &
|
||||
IEEE80211_TX_INTFL_OFFCHAN_TX_OK &&
|
||||
local->queue_stop_reasons[q] &
|
||||
~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL))) {
|
||||
/*
|
||||
* Drop off-channel frames if queues are stopped
|
||||
* for any reason other than off-channel
|
||||
* operation. Never queue them.
|
||||
*/
|
||||
spin_unlock_irqrestore(
|
||||
&local->queue_stop_reason_lock, flags);
|
||||
ieee80211_purge_tx_queue(&local->hw, skbs);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since queue is stopped, queue up frames for later
|
||||
* transmission from the tx-pending tasklet when the
|
||||
|
@ -715,7 +715,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
|
||||
kfree(reg);
|
||||
}
|
||||
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
|
||||
cfg80211_put_bss(&scan->pub);
|
||||
cfg80211_put_bss(&rdev->wiphy, &scan->pub);
|
||||
kfree(rdev);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/rfkill.h>
|
||||
@ -124,9 +123,10 @@ static inline void assert_cfg80211_lock(void)
|
||||
|
||||
struct cfg80211_internal_bss {
|
||||
struct list_head list;
|
||||
struct list_head hidden_list;
|
||||
struct rb_node rbn;
|
||||
unsigned long ts;
|
||||
struct kref ref;
|
||||
unsigned long refcount;
|
||||
atomic_t hold;
|
||||
|
||||
/* must be last because of priv member */
|
||||
|
@ -37,7 +37,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
|
||||
|
||||
if (wdev->current_bss) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
}
|
||||
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
@ -182,7 +182,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
|
||||
|
||||
if (wdev->current_bss) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
}
|
||||
|
||||
wdev->current_bss = NULL;
|
||||
|
@ -58,7 +58,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
|
||||
*/
|
||||
if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
|
||||
cfg80211_sme_failed_reassoc(wdev)) {
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
|
||||
* do not call connect_result() now because the
|
||||
* sme will schedule work that does it later.
|
||||
*/
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
|
||||
if (wdev->current_bss &&
|
||||
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
was_current = true;
|
||||
}
|
||||
@ -164,7 +164,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
|
||||
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(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
} else
|
||||
WARN_ON(1);
|
||||
@ -324,7 +324,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
err = rdev_auth(rdev, dev, &req);
|
||||
|
||||
out:
|
||||
cfg80211_put_bss(req.bss);
|
||||
cfg80211_put_bss(&rdev->wiphy, req.bss);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -432,7 +432,7 @@ out:
|
||||
if (err) {
|
||||
if (was_connected)
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
cfg80211_put_bss(req.bss);
|
||||
cfg80211_put_bss(&rdev->wiphy, req.bss);
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -572,7 +572,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
||||
|
||||
if (wdev->current_bss) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -4997,6 +4997,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
void *hdr;
|
||||
struct nlattr *bss;
|
||||
bool tsf = false;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
@ -5020,22 +5021,24 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(res->ies);
|
||||
if (ies && ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
|
||||
ies->len, ies->data)) {
|
||||
rcu_read_unlock();
|
||||
goto nla_put_failure;
|
||||
if (ies) {
|
||||
if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
|
||||
goto fail_unlock_rcu;
|
||||
tsf = true;
|
||||
if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
|
||||
ies->len, ies->data))
|
||||
goto fail_unlock_rcu;
|
||||
}
|
||||
ies = rcu_dereference(res->beacon_ies);
|
||||
if (ies && ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
|
||||
ies->len, ies->data)) {
|
||||
rcu_read_unlock();
|
||||
goto nla_put_failure;
|
||||
if (ies) {
|
||||
if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
|
||||
goto fail_unlock_rcu;
|
||||
if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
|
||||
ies->len, ies->data))
|
||||
goto fail_unlock_rcu;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (res->tsf &&
|
||||
nla_put_u64(msg, NL80211_BSS_TSF, res->tsf))
|
||||
goto nla_put_failure;
|
||||
if (res->beacon_interval &&
|
||||
nla_put_u16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval))
|
||||
goto nla_put_failure;
|
||||
@ -5080,6 +5083,8 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
||||
fail_unlock_rcu:
|
||||
rcu_read_unlock();
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
return -EMSGSIZE;
|
||||
|
@ -2189,10 +2189,15 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
|
||||
* However if a driver requested this specific regulatory
|
||||
* domain we keep it for its private use
|
||||
*/
|
||||
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER)
|
||||
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
|
||||
const struct ieee80211_regdomain *tmp;
|
||||
|
||||
tmp = get_wiphy_regdom(request_wiphy);
|
||||
rcu_assign_pointer(request_wiphy->regd, rd);
|
||||
else
|
||||
rcu_free_regdom(tmp);
|
||||
} else {
|
||||
kfree(rd);
|
||||
}
|
||||
|
||||
rd = NULL;
|
||||
|
||||
|
@ -19,46 +19,124 @@
|
||||
#include "wext-compat.h"
|
||||
#include "rdev-ops.h"
|
||||
|
||||
/**
|
||||
* DOC: BSS tree/list structure
|
||||
*
|
||||
* At the top level, the BSS list is kept in both a list in each
|
||||
* registered device (@bss_list) as well as an RB-tree for faster
|
||||
* lookup. In the RB-tree, entries can be looked up using their
|
||||
* channel, MESHID, MESHCONF (for MBSSes) or channel, BSSID, SSID
|
||||
* for other BSSes.
|
||||
*
|
||||
* Due to the possibility of hidden SSIDs, there's a second level
|
||||
* structure, the "hidden_list" and "hidden_beacon_bss" pointer.
|
||||
* The hidden_list connects all BSSes belonging to a single AP
|
||||
* that has a hidden SSID, and connects beacon and probe response
|
||||
* entries. For a probe response entry for a hidden SSID, the
|
||||
* hidden_beacon_bss pointer points to the BSS struct holding the
|
||||
* beacon's information.
|
||||
*
|
||||
* Reference counting is done for all these references except for
|
||||
* the hidden_list, so that a beacon BSS struct that is otherwise
|
||||
* not referenced has one reference for being on the bss_list and
|
||||
* one for each probe response entry that points to it using the
|
||||
* hidden_beacon_bss pointer. When a BSS struct that has such a
|
||||
* pointer is get/put, the refcount update is also propagated to
|
||||
* the referenced struct, this ensure that it cannot get removed
|
||||
* while somebody is using the probe response version.
|
||||
*
|
||||
* Note that the hidden_beacon_bss pointer never changes, due to
|
||||
* the reference counting. Therefore, no locking is needed for
|
||||
* it.
|
||||
*
|
||||
* Also note that the hidden_beacon_bss pointer is only relevant
|
||||
* if the driver uses something other than the IEs, e.g. private
|
||||
* data stored stored in the BSS struct, since the beacon IEs are
|
||||
* also linked into the probe response struct.
|
||||
*/
|
||||
|
||||
#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
|
||||
|
||||
static void bss_release(struct kref *ref)
|
||||
static void bss_free(struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
struct cfg80211_bss_ies *ies;
|
||||
struct cfg80211_internal_bss *bss;
|
||||
|
||||
bss = container_of(ref, struct cfg80211_internal_bss, ref);
|
||||
|
||||
if (WARN_ON(atomic_read(&bss->hold)))
|
||||
return;
|
||||
|
||||
ies = (void *)rcu_access_pointer(bss->pub.beacon_ies);
|
||||
if (ies)
|
||||
if (ies && !bss->pub.hidden_beacon_bss)
|
||||
kfree_rcu(ies, rcu_head);
|
||||
ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies);
|
||||
if (ies)
|
||||
kfree_rcu(ies, rcu_head);
|
||||
|
||||
/*
|
||||
* This happens when the module is removed, it doesn't
|
||||
* really matter any more save for completeness
|
||||
*/
|
||||
if (!list_empty(&bss->hidden_list))
|
||||
list_del(&bss->hidden_list);
|
||||
|
||||
kfree(bss);
|
||||
}
|
||||
|
||||
static inline void bss_ref_get(struct cfg80211_internal_bss *bss)
|
||||
static inline void bss_ref_get(struct cfg80211_registered_device *dev,
|
||||
struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
kref_get(&bss->ref);
|
||||
lockdep_assert_held(&dev->bss_lock);
|
||||
|
||||
bss->refcount++;
|
||||
if (bss->pub.hidden_beacon_bss) {
|
||||
bss = container_of(bss->pub.hidden_beacon_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
bss->refcount++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bss_ref_put(struct cfg80211_internal_bss *bss)
|
||||
static inline void bss_ref_put(struct cfg80211_registered_device *dev,
|
||||
struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
kref_put(&bss->ref, bss_release);
|
||||
lockdep_assert_held(&dev->bss_lock);
|
||||
|
||||
if (bss->pub.hidden_beacon_bss) {
|
||||
struct cfg80211_internal_bss *hbss;
|
||||
hbss = container_of(bss->pub.hidden_beacon_bss,
|
||||
struct cfg80211_internal_bss,
|
||||
pub);
|
||||
hbss->refcount--;
|
||||
if (hbss->refcount == 0)
|
||||
bss_free(hbss);
|
||||
}
|
||||
bss->refcount--;
|
||||
if (bss->refcount == 0)
|
||||
bss_free(bss);
|
||||
}
|
||||
|
||||
static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
|
||||
static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
|
||||
struct cfg80211_internal_bss *bss)
|
||||
{
|
||||
lockdep_assert_held(&dev->bss_lock);
|
||||
|
||||
if (!list_empty(&bss->hidden_list)) {
|
||||
/*
|
||||
* don't remove the beacon entry if it has
|
||||
* probe responses associated with it
|
||||
*/
|
||||
if (!bss->pub.hidden_beacon_bss)
|
||||
return false;
|
||||
/*
|
||||
* if it's a probe response entry break its
|
||||
* link to the other entries in the group
|
||||
*/
|
||||
list_del_init(&bss->hidden_list);
|
||||
}
|
||||
|
||||
list_del_init(&bss->list);
|
||||
rb_erase(&bss->rbn, &dev->bss_tree);
|
||||
bss_ref_put(bss);
|
||||
bss_ref_put(dev, bss);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
|
||||
@ -75,8 +153,8 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
|
||||
if (!time_after(expire_time, bss->ts))
|
||||
continue;
|
||||
|
||||
__cfg80211_unlink_bss(dev, bss);
|
||||
expired = true;
|
||||
if (__cfg80211_unlink_bss(dev, bss))
|
||||
expired = true;
|
||||
}
|
||||
|
||||
if (expired)
|
||||
@ -466,7 +544,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
|
||||
continue;
|
||||
if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
|
||||
res = bss;
|
||||
bss_ref_get(res);
|
||||
bss_ref_get(dev, res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -532,23 +610,67 @@ rb_find_bss(struct cfg80211_registered_device *dev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_hidden_ies(struct cfg80211_internal_bss *res,
|
||||
struct cfg80211_internal_bss *hidden)
|
||||
static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
|
||||
struct cfg80211_internal_bss *new)
|
||||
{
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
struct cfg80211_internal_bss *bss;
|
||||
const u8 *ie;
|
||||
int i, ssidlen;
|
||||
u8 fold = 0;
|
||||
|
||||
if (rcu_access_pointer(res->pub.beacon_ies))
|
||||
return;
|
||||
|
||||
ies = rcu_access_pointer(hidden->pub.beacon_ies);
|
||||
ies = rcu_access_pointer(new->pub.beacon_ies);
|
||||
if (WARN_ON(!ies))
|
||||
return;
|
||||
return false;
|
||||
|
||||
ies = kmemdup(ies, sizeof(*ies) + ies->len, GFP_ATOMIC);
|
||||
if (unlikely(!ies))
|
||||
return;
|
||||
rcu_assign_pointer(res->pub.beacon_ies, ies);
|
||||
ie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ie) {
|
||||
/* nothing to do */
|
||||
return true;
|
||||
}
|
||||
|
||||
ssidlen = ie[1];
|
||||
for (i = 0; i < ssidlen; i++)
|
||||
fold |= ie[2 + i];
|
||||
|
||||
if (fold) {
|
||||
/* not a hidden SSID */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This is the bad part ... */
|
||||
|
||||
list_for_each_entry(bss, &dev->bss_list, list) {
|
||||
if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
|
||||
continue;
|
||||
if (bss->pub.channel != new->pub.channel)
|
||||
continue;
|
||||
if (rcu_access_pointer(bss->pub.beacon_ies))
|
||||
continue;
|
||||
ies = rcu_access_pointer(bss->pub.ies);
|
||||
if (!ies)
|
||||
continue;
|
||||
ie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
|
||||
if (!ie)
|
||||
continue;
|
||||
if (ssidlen && ie[1] != ssidlen)
|
||||
continue;
|
||||
/* that would be odd ... */
|
||||
if (bss->pub.beacon_ies)
|
||||
continue;
|
||||
if (WARN_ON_ONCE(bss->pub.hidden_beacon_bss))
|
||||
continue;
|
||||
if (WARN_ON_ONCE(!list_empty(&bss->hidden_list)))
|
||||
list_del(&bss->hidden_list);
|
||||
/* combine them */
|
||||
list_add(&bss->hidden_list, &new->hidden_list);
|
||||
bss->pub.hidden_beacon_bss = &new->pub;
|
||||
new->refcount += bss->refcount;
|
||||
rcu_assign_pointer(bss->pub.beacon_ies,
|
||||
new->pub.beacon_ies);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct cfg80211_internal_bss *
|
||||
@ -573,7 +695,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||
|
||||
if (found) {
|
||||
found->pub.beacon_interval = tmp->pub.beacon_interval;
|
||||
found->pub.tsf = tmp->pub.tsf;
|
||||
found->pub.signal = tmp->pub.signal;
|
||||
found->pub.capability = tmp->pub.capability;
|
||||
found->ts = tmp->ts;
|
||||
@ -594,6 +715,21 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||
rcu_head);
|
||||
} else if (rcu_access_pointer(tmp->pub.beacon_ies)) {
|
||||
const struct cfg80211_bss_ies *old;
|
||||
struct cfg80211_internal_bss *bss;
|
||||
|
||||
if (found->pub.hidden_beacon_bss &&
|
||||
!list_empty(&found->hidden_list)) {
|
||||
/*
|
||||
* The found BSS struct is one of the probe
|
||||
* response members of a group, but we're
|
||||
* receiving a beacon (beacon_ies in the tmp
|
||||
* bss is used). This can only mean that the
|
||||
* AP changed its beacon from not having an
|
||||
* SSID to showing it, which is confusing so
|
||||
* drop this information.
|
||||
*/
|
||||
goto drop;
|
||||
}
|
||||
|
||||
old = rcu_access_pointer(found->pub.beacon_ies);
|
||||
|
||||
@ -605,6 +741,18 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||
rcu_assign_pointer(found->pub.ies,
|
||||
tmp->pub.beacon_ies);
|
||||
|
||||
/* Assign beacon IEs to all sub entries */
|
||||
list_for_each_entry(bss, &found->hidden_list,
|
||||
hidden_list) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
|
||||
ies = rcu_access_pointer(bss->pub.beacon_ies);
|
||||
WARN_ON(ies != old);
|
||||
|
||||
rcu_assign_pointer(bss->pub.beacon_ies,
|
||||
tmp->pub.beacon_ies);
|
||||
}
|
||||
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old,
|
||||
rcu_head);
|
||||
@ -614,24 +762,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||
struct cfg80211_internal_bss *hidden;
|
||||
struct cfg80211_bss_ies *ies;
|
||||
|
||||
/* First check if the beacon is a probe response from
|
||||
* a hidden bss. If so, copy beacon ies (with nullified
|
||||
* ssid) into the probe response bss entry (with real ssid).
|
||||
* It is required basically for PSM implementation
|
||||
* (probe responses do not contain tim ie) */
|
||||
|
||||
/* TODO: The code is not trying to update existing probe
|
||||
* response bss entries when beacon ies are
|
||||
* getting changed. */
|
||||
hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_ZLEN);
|
||||
if (hidden) {
|
||||
copy_hidden_ies(tmp, hidden);
|
||||
} else {
|
||||
hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_NUL);
|
||||
if (hidden)
|
||||
copy_hidden_ies(tmp, hidden);
|
||||
}
|
||||
|
||||
/*
|
||||
* create a copy -- the "res" variable that is passed in
|
||||
* is allocated on the stack since it's not needed in the
|
||||
@ -646,21 +776,51 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||
ies = (void *)rcu_dereference(tmp->pub.proberesp_ies);
|
||||
if (ies)
|
||||
kfree_rcu(ies, rcu_head);
|
||||
spin_unlock_bh(&dev->bss_lock);
|
||||
return NULL;
|
||||
goto drop;
|
||||
}
|
||||
memcpy(new, tmp, sizeof(*new));
|
||||
kref_init(&new->ref);
|
||||
new->refcount = 1;
|
||||
INIT_LIST_HEAD(&new->hidden_list);
|
||||
|
||||
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
|
||||
hidden = rb_find_bss(dev, tmp, BSS_CMP_HIDE_ZLEN);
|
||||
if (!hidden)
|
||||
hidden = rb_find_bss(dev, tmp,
|
||||
BSS_CMP_HIDE_NUL);
|
||||
if (hidden) {
|
||||
new->pub.hidden_beacon_bss = &hidden->pub;
|
||||
list_add(&new->hidden_list,
|
||||
&hidden->hidden_list);
|
||||
hidden->refcount++;
|
||||
rcu_assign_pointer(new->pub.beacon_ies,
|
||||
hidden->pub.beacon_ies);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Ok so we found a beacon, and don't have an entry. If
|
||||
* it's a beacon with hidden SSID, we might be in for an
|
||||
* expensive search for any probe responses that should
|
||||
* be grouped with this beacon for updates ...
|
||||
*/
|
||||
if (!cfg80211_combine_bsses(dev, new)) {
|
||||
kfree(new);
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&new->list, &dev->bss_list);
|
||||
rb_insert_bss(dev, new);
|
||||
found = new;
|
||||
}
|
||||
|
||||
dev->bss_generation++;
|
||||
bss_ref_get(dev, found);
|
||||
spin_unlock_bh(&dev->bss_lock);
|
||||
|
||||
bss_ref_get(found);
|
||||
return found;
|
||||
drop:
|
||||
spin_unlock_bh(&dev->bss_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ieee80211_channel *
|
||||
@ -719,7 +879,6 @@ cfg80211_inform_bss(struct wiphy *wiphy,
|
||||
memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
|
||||
tmp.pub.channel = channel;
|
||||
tmp.pub.signal = signal;
|
||||
tmp.pub.tsf = tsf;
|
||||
tmp.pub.beacon_interval = beacon_interval;
|
||||
tmp.pub.capability = capability;
|
||||
/*
|
||||
@ -734,6 +893,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
|
||||
if (!ies)
|
||||
return NULL;
|
||||
ies->len = ielen;
|
||||
ies->tsf = tsf;
|
||||
memcpy(ies->data, ie, ielen);
|
||||
|
||||
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
|
||||
@ -790,6 +950,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
||||
if (!ies)
|
||||
return NULL;
|
||||
ies->len = ielen;
|
||||
ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
|
||||
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control))
|
||||
@ -801,7 +962,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
||||
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
|
||||
tmp.pub.channel = channel;
|
||||
tmp.pub.signal = signal;
|
||||
tmp.pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
|
||||
|
||||
@ -818,27 +978,35 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_inform_bss_frame);
|
||||
|
||||
void cfg80211_ref_bss(struct cfg80211_bss *pub)
|
||||
void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
{
|
||||
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
|
||||
struct cfg80211_internal_bss *bss;
|
||||
|
||||
if (!pub)
|
||||
return;
|
||||
|
||||
bss = container_of(pub, struct cfg80211_internal_bss, pub);
|
||||
bss_ref_get(bss);
|
||||
|
||||
spin_lock_bh(&dev->bss_lock);
|
||||
bss_ref_get(dev, bss);
|
||||
spin_unlock_bh(&dev->bss_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_ref_bss);
|
||||
|
||||
void cfg80211_put_bss(struct cfg80211_bss *pub)
|
||||
void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
{
|
||||
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
|
||||
struct cfg80211_internal_bss *bss;
|
||||
|
||||
if (!pub)
|
||||
return;
|
||||
|
||||
bss = container_of(pub, struct cfg80211_internal_bss, pub);
|
||||
bss_ref_put(bss);
|
||||
|
||||
spin_lock_bh(&dev->bss_lock);
|
||||
bss_ref_put(dev, bss);
|
||||
spin_unlock_bh(&dev->bss_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_put_bss);
|
||||
|
||||
@ -854,8 +1022,8 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
|
||||
|
||||
spin_lock_bh(&dev->bss_lock);
|
||||
if (!list_empty(&bss->list)) {
|
||||
__cfg80211_unlink_bss(dev, bss);
|
||||
dev->bss_generation++;
|
||||
if (__cfg80211_unlink_bss(dev, bss))
|
||||
dev->bss_generation++;
|
||||
}
|
||||
spin_unlock_bh(&dev->bss_lock);
|
||||
}
|
||||
@ -1124,15 +1292,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(bss->pub.ies);
|
||||
if (ies) {
|
||||
rem = ies->len;
|
||||
ie = ies->data;
|
||||
} else {
|
||||
rem = 0;
|
||||
ie = NULL;
|
||||
}
|
||||
rem = ies->len;
|
||||
ie = ies->data;
|
||||
|
||||
while (ies && rem >= 2) {
|
||||
while (rem >= 2) {
|
||||
/* invalid data */
|
||||
if (ie[1] > rem - 2)
|
||||
break;
|
||||
@ -1245,7 +1408,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
if (buf) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf));
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
|
@ -301,7 +301,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
|
||||
|
||||
bss = cfg80211_get_conn_bss(wdev);
|
||||
if (bss) {
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(&rdev->wiphy, bss);
|
||||
} else {
|
||||
/* not found */
|
||||
if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
|
||||
@ -464,7 +464,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
|
||||
if (wdev->current_bss) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
}
|
||||
|
||||
@ -480,7 +480,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -586,7 +586,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
}
|
||||
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
@ -621,7 +621,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
|
||||
return;
|
||||
out:
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
}
|
||||
|
||||
void cfg80211_roamed(struct net_device *dev,
|
||||
@ -663,7 +663,7 @@ void cfg80211_roamed_bss(struct net_device *dev,
|
||||
|
||||
ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
|
||||
if (!ev) {
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -704,7 +704,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
|
||||
if (wdev->current_bss) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(&wdev->current_bss->pub);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
}
|
||||
|
||||
wdev->current_bss = NULL;
|
||||
@ -875,7 +875,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
if (bss) {
|
||||
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
|
||||
err = cfg80211_conn_do_work(wdev);
|
||||
cfg80211_put_bss(bss);
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
} else {
|
||||
/* otherwise we'll need to scan for the AP first */
|
||||
err = cfg80211_conn_scan(wdev);
|
||||
|
@ -1217,10 +1217,10 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
radar_required = false;
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user