Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

This commit is contained in:
John W. Linville 2013-02-12 11:06:52 -05:00
commit 4fe0c75eed
49 changed files with 720 additions and 522 deletions

View File

@ -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,

View File

@ -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

View File

@ -341,7 +341,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
}
out:
cfg80211_put_bss(bss);
cfg80211_put_bss(wiphy, bss);
return rc;
}

View File

@ -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");
}

View File

@ -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:

View File

@ -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;

View File

@ -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 |

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -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",

View File

@ -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,

View File

@ -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);
}
/*

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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));

View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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: