Merge mac80211-next into ath-next
Patch "ath10k: introduce basic tdls functionality" depends on this mac80211
patch:
c23e31cf7b
mac80211: initialize rate control earlier for tdls station
This commit is contained in:
commit
23d6660d7f
|
@ -1632,7 +1632,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
|
|||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan,
|
||||
info->bssid, NULL, 0, 0, 0);
|
||||
info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (bss) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
|
||||
|
|
|
@ -686,20 +686,21 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
|
|||
{
|
||||
struct ath6kl *ar = vif->ar;
|
||||
struct cfg80211_bss *bss;
|
||||
u16 cap_mask, cap_val;
|
||||
u16 cap_val;
|
||||
enum ieee80211_bss_type bss_type;
|
||||
u8 *ie;
|
||||
|
||||
if (nw_type & ADHOC_NETWORK) {
|
||||
cap_mask = WLAN_CAPABILITY_IBSS;
|
||||
cap_val = WLAN_CAPABILITY_IBSS;
|
||||
bss_type = IEEE80211_BSS_TYPE_IBSS;
|
||||
} else {
|
||||
cap_mask = WLAN_CAPABILITY_ESS;
|
||||
cap_val = WLAN_CAPABILITY_ESS;
|
||||
bss_type = IEEE80211_BSS_TYPE_ESS;
|
||||
}
|
||||
|
||||
bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
|
||||
vif->ssid, vif->ssid_len,
|
||||
cap_mask, cap_val);
|
||||
bss_type, IEEE80211_PRIVACY_ANY);
|
||||
if (bss == NULL) {
|
||||
/*
|
||||
* Since cfg80211 may not yet know about the BSS,
|
||||
|
|
|
@ -409,7 +409,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
|||
|
||||
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
|
||||
sme->ssid, sme->ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
||||
if (!bss) {
|
||||
wil_err(wil, "Unable to find BSS\n");
|
||||
return -ENOENT;
|
||||
|
|
|
@ -1240,8 +1240,8 @@ static void cw1200_do_join(struct cw1200_common *priv)
|
|||
|
||||
bssid = priv->vif->bss_conf.bssid;
|
||||
|
||||
bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel,
|
||||
bssid, NULL, 0, 0, 0);
|
||||
bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, bssid, NULL, 0,
|
||||
IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
|
||||
|
||||
if (!bss && !conf->ibss_joined) {
|
||||
wsm_unlock_tx(priv);
|
||||
|
|
|
@ -66,7 +66,7 @@ config IPW2100_DEBUG
|
|||
config IPW2200
|
||||
tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
|
||||
depends on PCI && CFG80211
|
||||
select CFG80211_WEXT
|
||||
select CFG80211_WEXT_EXPORT
|
||||
select WIRELESS_EXT
|
||||
select WEXT_SPY
|
||||
select WEXT_PRIV
|
||||
|
|
|
@ -1356,8 +1356,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
/* Find the BSS we want using available scan results */
|
||||
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
|
||||
sme->ssid, sme->ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
sme->ssid, sme->ssid_len, IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (!bss) {
|
||||
wiphy_err(wiphy, "assoc: bss %pM not in scan results\n",
|
||||
sme->bssid);
|
||||
|
@ -2000,7 +2000,7 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
|
|||
* bss list is populated already */
|
||||
bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid,
|
||||
params->ssid, params->ssid_len,
|
||||
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
|
||||
IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
|
||||
|
||||
if (bss) {
|
||||
ret = lbs_ibss_join_existing(priv, params, bss);
|
||||
|
|
|
@ -330,6 +330,83 @@ static const struct ieee80211_rate hwsim_rates[] = {
|
|||
{ .bitrate = 540 }
|
||||
};
|
||||
|
||||
#define OUI_QCA 0x001374
|
||||
#define QCA_NL80211_SUBCMD_TEST 1
|
||||
enum qca_nl80211_vendor_subcmds {
|
||||
QCA_WLAN_VENDOR_ATTR_TEST = 8,
|
||||
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_TEST
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
hwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = {
|
||||
[QCA_WLAN_VENDOR_ATTR_MAX] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
|
||||
int err;
|
||||
u32 val;
|
||||
|
||||
err = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len,
|
||||
hwsim_vendor_test_policy);
|
||||
if (err)
|
||||
return err;
|
||||
if (!tb[QCA_WLAN_VENDOR_ATTR_TEST])
|
||||
return -EINVAL;
|
||||
val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]);
|
||||
wiphy_debug(wiphy, "%s: test=%u\n", __func__, val);
|
||||
|
||||
/* Send a vendor event as a test. Note that this would not normally be
|
||||
* done within a command handler, but rather, based on some other
|
||||
* trigger. For simplicity, this command is used to trigger the event
|
||||
* here.
|
||||
*
|
||||
* event_idx = 0 (index in mac80211_hwsim_vendor_commands)
|
||||
*/
|
||||
skb = cfg80211_vendor_event_alloc(wiphy, wdev, 100, 0, GFP_KERNEL);
|
||||
if (skb) {
|
||||
/* skb_put() or nla_put() will fill up data within
|
||||
* NL80211_ATTR_VENDOR_DATA.
|
||||
*/
|
||||
|
||||
/* Add vendor data */
|
||||
nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1);
|
||||
|
||||
/* Send the event - this will call nla_nest_end() */
|
||||
cfg80211_vendor_event(skb, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/* Send a response to the command */
|
||||
skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 10);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
/* skb_put() or nla_put() will fill up data within
|
||||
* NL80211_ATTR_VENDOR_DATA
|
||||
*/
|
||||
nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 2);
|
||||
|
||||
return cfg80211_vendor_cmd_reply(skb);
|
||||
}
|
||||
|
||||
static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = {
|
||||
{
|
||||
.info = { .vendor_id = OUI_QCA,
|
||||
.subcmd = QCA_NL80211_SUBCMD_TEST },
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_NETDEV,
|
||||
.doit = mac80211_hwsim_vendor_cmd_test,
|
||||
}
|
||||
};
|
||||
|
||||
/* Advertise support vendor specific events */
|
||||
static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = {
|
||||
{ .vendor_id = OUI_QCA, .subcmd = 1 },
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit hwsim_if_limits[] = {
|
||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
|
||||
{ .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
|
||||
|
@ -906,8 +983,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
|||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
|
||||
ETH_ALEN, data->addresses[1].addr))
|
||||
if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* We get the skb->data */
|
||||
|
@ -1519,21 +1595,16 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
|||
vp->aid = info->aid;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||
wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int);
|
||||
data->beacon_int = info->beacon_int * 1024;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon);
|
||||
wiphy_debug(hw->wiphy, " BCN EN: %d (BI=%u)\n",
|
||||
info->enable_beacon, info->beacon_int);
|
||||
vp->bcn_en = info->enable_beacon;
|
||||
if (data->started &&
|
||||
!hrtimer_is_queued(&data->beacon_timer.timer) &&
|
||||
info->enable_beacon) {
|
||||
u64 tsf, until_tbtt;
|
||||
u32 bcn_int;
|
||||
if (WARN_ON(!data->beacon_int))
|
||||
data->beacon_int = 1000 * 1024;
|
||||
data->beacon_int = info->beacon_int * 1024;
|
||||
tsf = mac80211_hwsim_get_tsf(hw, vif);
|
||||
bcn_int = data->beacon_int;
|
||||
until_tbtt = bcn_int - do_div(tsf, bcn_int);
|
||||
|
@ -1547,8 +1618,10 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
|||
mac80211_hwsim_bcn_en_iter, &count);
|
||||
wiphy_debug(hw->wiphy, " beaconing vifs remaining: %u",
|
||||
count);
|
||||
if (count == 0)
|
||||
if (count == 0) {
|
||||
tasklet_hrtimer_cancel(&data->beacon_timer);
|
||||
data->beacon_int = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2417,6 +2490,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
hw->max_rates = 4;
|
||||
hw->max_rate_tries = 11;
|
||||
|
||||
hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands;
|
||||
hw->wiphy->n_vendor_commands =
|
||||
ARRAY_SIZE(mac80211_hwsim_vendor_commands);
|
||||
hw->wiphy->vendor_events = mac80211_hwsim_vendor_events;
|
||||
hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events);
|
||||
|
||||
if (param->reg_strict)
|
||||
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
|
||||
if (param->regd) {
|
||||
|
@ -2608,7 +2687,7 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
|
|||
|
||||
spin_lock_bh(&hwsim_radio_lock);
|
||||
list_for_each_entry(data, &hwsim_radios, list) {
|
||||
if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) {
|
||||
if (mac80211_hwsim_addr_match(data, addr)) {
|
||||
_found = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1954,13 +1954,13 @@ done:
|
|||
if (mode == NL80211_IFTYPE_ADHOC)
|
||||
bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
|
||||
bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_IBSS,
|
||||
WLAN_CAPABILITY_IBSS);
|
||||
IEEE80211_BSS_TYPE_IBSS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
else
|
||||
bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
|
||||
bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
|
||||
if (!bss) {
|
||||
if (is_scanning_required) {
|
||||
|
|
|
@ -2,7 +2,7 @@ config HERMES
|
|||
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
|
||||
depends on (PPC_PMAC || PCI || PCMCIA)
|
||||
depends on CFG80211
|
||||
select CFG80211_WEXT
|
||||
select CFG80211_WEXT_EXPORT
|
||||
select WIRELESS_EXT
|
||||
select WEXT_SPY
|
||||
select WEXT_PRIV
|
||||
|
|
|
@ -77,7 +77,7 @@ static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel,
|
|||
wl1271_debug(DEBUG_EVENT,
|
||||
"SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)",
|
||||
freq, sync_channel, sync_band);
|
||||
skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, 20,
|
||||
skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, 20,
|
||||
WLCORE_VENDOR_EVENT_SC_SYNC,
|
||||
GFP_KERNEL);
|
||||
|
||||
|
@ -98,7 +98,7 @@ static int wlcore_smart_config_decode_event(struct wl1271 *wl,
|
|||
wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID");
|
||||
wl1271_dump_ascii(DEBUG_EVENT, "SSID:", ssid, ssid_len);
|
||||
|
||||
skb = cfg80211_vendor_event_alloc(wl->hw->wiphy,
|
||||
skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL,
|
||||
ssid_len + pwd_len + 20,
|
||||
WLCORE_VENDOR_EVENT_SC_DECODE,
|
||||
GFP_KERNEL);
|
||||
|
|
|
@ -214,6 +214,39 @@ enum ieee80211_rate_flags {
|
|||
IEEE80211_RATE_SUPPORTS_10MHZ = 1<<6,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_bss_type - BSS type filter
|
||||
*
|
||||
* @IEEE80211_BSS_TYPE_ESS: Infrastructure BSS
|
||||
* @IEEE80211_BSS_TYPE_PBSS: Personal BSS
|
||||
* @IEEE80211_BSS_TYPE_IBSS: Independent BSS
|
||||
* @IEEE80211_BSS_TYPE_MBSS: Mesh BSS
|
||||
* @IEEE80211_BSS_TYPE_ANY: Wildcard value for matching any BSS type
|
||||
*/
|
||||
enum ieee80211_bss_type {
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_BSS_TYPE_PBSS,
|
||||
IEEE80211_BSS_TYPE_IBSS,
|
||||
IEEE80211_BSS_TYPE_MBSS,
|
||||
IEEE80211_BSS_TYPE_ANY
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ieee80211_privacy - BSS privacy filter
|
||||
*
|
||||
* @IEEE80211_PRIVACY_ON: privacy bit set
|
||||
* @IEEE80211_PRIVACY_OFF: privacy bit clear
|
||||
* @IEEE80211_PRIVACY_ANY: Wildcard value for matching any privacy setting
|
||||
*/
|
||||
enum ieee80211_privacy {
|
||||
IEEE80211_PRIVACY_ON,
|
||||
IEEE80211_PRIVACY_OFF,
|
||||
IEEE80211_PRIVACY_ANY
|
||||
};
|
||||
|
||||
#define IEEE80211_PRIVACY(x) \
|
||||
((x) ? IEEE80211_PRIVACY_ON : IEEE80211_PRIVACY_OFF)
|
||||
|
||||
/**
|
||||
* struct ieee80211_rate - bitrate definition
|
||||
*
|
||||
|
@ -4012,14 +4045,16 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
|
|||
struct ieee80211_channel *channel,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
u16 capa_mask, u16 capa_val);
|
||||
enum ieee80211_bss_type bss_type,
|
||||
enum ieee80211_privacy);
|
||||
static inline struct cfg80211_bss *
|
||||
cfg80211_get_ibss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
|
||||
IEEE80211_BSS_TYPE_IBSS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4260,6 +4295,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
|
|||
int approxlen);
|
||||
|
||||
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
int vendor_event_idx,
|
||||
|
@ -4314,6 +4350,7 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
|
|||
/**
|
||||
* cfg80211_vendor_event_alloc - allocate vendor-specific event skb
|
||||
* @wiphy: the wiphy
|
||||
* @wdev: the wireless device
|
||||
* @event_idx: index of the vendor event in the wiphy's vendor_events
|
||||
* @approxlen: an upper bound of the length of the data that will
|
||||
* be put into the skb
|
||||
|
@ -4322,16 +4359,20 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
|
|||
* This function allocates and pre-fills an skb for an event on the
|
||||
* vendor-specific multicast group.
|
||||
*
|
||||
* If wdev != NULL, both the ifindex and identifier of the specified
|
||||
* wireless device are added to the event message before the vendor data
|
||||
* attribute.
|
||||
*
|
||||
* When done filling the skb, call cfg80211_vendor_event() with the
|
||||
* skb to send the event.
|
||||
*
|
||||
* Return: An allocated and pre-filled skb. %NULL if any errors happen.
|
||||
*/
|
||||
static inline struct sk_buff *
|
||||
cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
|
||||
int event_idx, gfp_t gfp)
|
||||
cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
int approxlen, int event_idx, gfp_t gfp)
|
||||
{
|
||||
return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
|
||||
return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
|
||||
NL80211_ATTR_VENDOR_DATA,
|
||||
event_idx, approxlen, gfp);
|
||||
}
|
||||
|
@ -4432,7 +4473,7 @@ static inline int cfg80211_testmode_reply(struct sk_buff *skb)
|
|||
static inline struct sk_buff *
|
||||
cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
|
||||
{
|
||||
return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
|
||||
return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE,
|
||||
NL80211_ATTR_TESTDATA, -1,
|
||||
approxlen, gfp);
|
||||
}
|
||||
|
|
|
@ -519,6 +519,17 @@ iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends,
|
|||
return stream;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
iwe_stream_add_event_check(struct iw_request_info *info, char *stream,
|
||||
char *ends, struct iw_event *iwe, int event_len)
|
||||
{
|
||||
char *res = iwe_stream_add_event(info, stream, ends, iwe, event_len);
|
||||
|
||||
if (res == stream)
|
||||
return ERR_PTR(-E2BIG);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
* Wrapper to add an short Wireless Event containing a pointer to a
|
||||
|
@ -545,6 +556,17 @@ iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends,
|
|||
return stream;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
iwe_stream_add_point_check(struct iw_request_info *info, char *stream,
|
||||
char *ends, struct iw_event *iwe, char *extra)
|
||||
{
|
||||
char *res = iwe_stream_add_point(info, stream, ends, iwe, extra);
|
||||
|
||||
if (res == stream)
|
||||
return ERR_PTR(-E2BIG);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
* Wrapper to add a value to a Wireless Event in a stream of events.
|
||||
|
|
|
@ -337,12 +337,15 @@ enum ieee80211_rssi_event {
|
|||
* 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.)
|
||||
* %BSS_CHANGED_DTIM flag.). See also sync_dtim_count important notice.
|
||||
* @sync_device_ts: the device timestamp corresponding to the sync_tsf,
|
||||
* the driver/device can use this to calculate synchronisation
|
||||
* (see @sync_tsf)
|
||||
* (see @sync_tsf). See also sync_dtim_count important notice.
|
||||
* @sync_dtim_count: Only valid when %IEEE80211_HW_TIMING_BEACON_ONLY
|
||||
* is requested, see @sync_tsf/@sync_device_ts.
|
||||
* IMPORTANT: These three sync_* parameters would possibly be out of sync
|
||||
* by the time the driver will use them. The synchronized view is currently
|
||||
* guaranteed only in certain callbacks.
|
||||
* @beacon_int: beacon interval
|
||||
* @assoc_capability: capabilities taken from assoc resp
|
||||
* @basic_rates: bitmap of basic rates, each bit stands for an
|
||||
|
@ -1278,6 +1281,19 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
|
|||
*/
|
||||
struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
|
||||
|
||||
/**
|
||||
* ieee80211_vif_to_wdev - return a wdev struct from a vif
|
||||
* @vif: the vif to get the wdev for
|
||||
*
|
||||
* This can be used by mac80211 drivers with direct cfg80211 APIs
|
||||
* (like the vendor commands) that needs to get the wdev for a vif.
|
||||
*
|
||||
* Note that this function may return %NULL if the given wdev isn't
|
||||
* associated with a vif that the driver knows about (e.g. monitor
|
||||
* or AP_VLAN interfaces.)
|
||||
*/
|
||||
struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif);
|
||||
|
||||
/**
|
||||
* enum ieee80211_key_flags - key flags
|
||||
*
|
||||
|
@ -1488,6 +1504,7 @@ struct ieee80211_sta_rates {
|
|||
* @tdls: indicates whether the STA is a TDLS peer
|
||||
* @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
|
||||
* valid if the STA is a TDLS peer in the first place.
|
||||
* @mfp: indicates whether the STA uses management frame protection or not.
|
||||
*/
|
||||
struct ieee80211_sta {
|
||||
u32 supp_rates[IEEE80211_NUM_BANDS];
|
||||
|
@ -1504,6 +1521,7 @@ struct ieee80211_sta {
|
|||
struct ieee80211_sta_rates __rcu *rates;
|
||||
bool tdls;
|
||||
bool tdls_initiator;
|
||||
bool mfp;
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
|
@ -4343,12 +4361,32 @@ void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
|
|||
* haven't been re-added to the driver yet.
|
||||
* @IEEE80211_IFACE_ITER_RESUME_ALL: During resume, iterate over all
|
||||
* interfaces, even if they haven't been re-added to the driver yet.
|
||||
* @IEEE80211_IFACE_ITER_ACTIVE: Iterate only active interfaces (netdev is up).
|
||||
*/
|
||||
enum ieee80211_interface_iteration_flags {
|
||||
IEEE80211_IFACE_ITER_NORMAL = 0,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL = BIT(0),
|
||||
IEEE80211_IFACE_ITER_ACTIVE = BIT(1),
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_iterate_interfaces - iterate interfaces
|
||||
*
|
||||
* This function iterates over the interfaces associated with a given
|
||||
* hardware and calls the callback for them. This includes active as well as
|
||||
* inactive interfaces. This function allows the iterator function to sleep.
|
||||
* Will iterate over a new interface during add_interface().
|
||||
*
|
||||
* @hw: the hardware struct of which the interfaces should be iterated over
|
||||
* @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
|
||||
* @iterator: the iterator function to call
|
||||
* @data: first argument of the iterator function
|
||||
*/
|
||||
void ieee80211_iterate_interfaces(struct ieee80211_hw *hw, u32 iter_flags,
|
||||
void (*iterator)(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif),
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* ieee80211_iterate_active_interfaces - iterate active interfaces
|
||||
*
|
||||
|
@ -4364,11 +4402,16 @@ enum ieee80211_interface_iteration_flags {
|
|||
* @iterator: the iterator function to call
|
||||
* @data: first argument of the iterator function
|
||||
*/
|
||||
void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
|
||||
u32 iter_flags,
|
||||
static inline void
|
||||
ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, u32 iter_flags,
|
||||
void (*iterator)(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif),
|
||||
void *data);
|
||||
void *data)
|
||||
{
|
||||
ieee80211_iterate_interfaces(hw,
|
||||
iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
|
||||
iterator, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_iterate_active_interfaces_atomic - iterate active interfaces
|
||||
|
|
|
@ -25,6 +25,19 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header file defines the userspace API to the wireless stack. Please
|
||||
* be careful not to break things - i.e. don't move anything around or so
|
||||
* unless you can demonstrate that it breaks neither API nor ABI.
|
||||
*
|
||||
* Additions to the API should be accompanied by actual implementations in
|
||||
* an upstream driver, so that example implementations exist in case there
|
||||
* are ever concerns about the precise semantics of the API or changes are
|
||||
* needed, and to ensure that code for dead (no longer implemented) API
|
||||
* can actually be identified and removed.
|
||||
* Nonetheless, semantics should also be documented carefully in this file.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define NL80211_GENL_NAME "nl80211"
|
||||
|
@ -1684,6 +1697,10 @@ enum nl80211_commands {
|
|||
* If set during scheduled scan start then the new scan req will be
|
||||
* owned by the netlink socket that created it and the scheduled scan will
|
||||
* be stopped when the socket is closed.
|
||||
* If set during configuration of regulatory indoor operation then the
|
||||
* regulatory indoor configuration would be owned by the netlink socket
|
||||
* that configured the indoor setting, and the indoor operation would be
|
||||
* cleared when the socket is closed.
|
||||
*
|
||||
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
|
||||
* the TDLS link initiator.
|
||||
|
@ -1739,6 +1756,9 @@ enum nl80211_commands {
|
|||
*
|
||||
* @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
|
||||
* WoWLAN net-detect scan) is started, u32 in seconds.
|
||||
|
||||
* @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
|
||||
* is operating in an indoor environment.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
|
@ -2107,6 +2127,8 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_SCHED_SCAN_DELAY,
|
||||
|
||||
NL80211_ATTR_REG_INDOOR,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -3092,7 +3114,8 @@ enum nl80211_mesh_power_mode {
|
|||
*
|
||||
* @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've
|
||||
* established peering with for longer than this time (in seconds), then
|
||||
* remove it from the STA's list of peers. Default is 30 minutes.
|
||||
* remove it from the STA's list of peers. You may set this to 0 to disable
|
||||
* the removal of the STA. Default is 30 minutes.
|
||||
*
|
||||
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -3694,6 +3717,8 @@ struct nl80211_pattern_support {
|
|||
* @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
|
||||
* the chip into a special state -- works best with chips that have
|
||||
* support for low-power operation already (flag)
|
||||
* Note that this mode is incompatible with all of the others, if
|
||||
* any others are even supported by the device.
|
||||
* @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
|
||||
* is detected is implementation-specific (flag)
|
||||
* @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
|
||||
|
@ -4327,11 +4352,13 @@ enum nl80211_feature_flags {
|
|||
|
||||
/**
|
||||
* enum nl80211_ext_feature_index - bit index of extended features.
|
||||
* @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
enum nl80211_ext_feature_index {
|
||||
NL80211_EXT_FEATURE_VHT_IBSS,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
|
|
@ -977,6 +977,14 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
|
|||
if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
|
||||
set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
|
||||
!test_sta_flag(sta, WLAN_STA_ASSOC)) {
|
||||
/*
|
||||
* When peer becomes associated, init rate control as
|
||||
* well. Some drivers require rate control initialized
|
||||
* before drv_sta_state() is called.
|
||||
*/
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1068,6 +1076,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
|||
sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
|
||||
|
||||
if (mask & BIT(NL80211_STA_FLAG_MFP)) {
|
||||
sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP));
|
||||
if (set & BIT(NL80211_STA_FLAG_MFP))
|
||||
set_sta_flag(sta, WLAN_STA_MFP);
|
||||
else
|
||||
|
@ -1377,11 +1386,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
|
|||
if (err)
|
||||
goto out_err;
|
||||
|
||||
/* When peer becomes authorized, init rate control as well */
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
|
||||
test_sta_flag(sta, WLAN_STA_AUTHORIZED))
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
|
@ -2273,7 +2277,6 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct sta_info *sta;
|
||||
enum ieee80211_smps_mode old_req;
|
||||
int i;
|
||||
|
||||
if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP))
|
||||
return -EINVAL;
|
||||
|
@ -2301,12 +2304,7 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
|
|||
smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
|
||||
|
||||
mutex_lock(&sdata->local->sta_mtx);
|
||||
for (i = 0; i < STA_HASH_SIZE; i++) {
|
||||
for (sta = rcu_dereference_protected(sdata->local->sta_hash[i],
|
||||
lockdep_is_held(&sdata->local->sta_mtx));
|
||||
sta;
|
||||
sta = rcu_dereference_protected(sta->hnext,
|
||||
lockdep_is_held(&sdata->local->sta_mtx))) {
|
||||
list_for_each_entry(sta, &sdata->local->sta_list, list) {
|
||||
/*
|
||||
* Only stations associated to our AP and
|
||||
* associated VLANs
|
||||
|
@ -2325,8 +2323,7 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
|
|||
if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
|
||||
!ieee80211_smps_is_restrictive(sta->known_smps_mode,
|
||||
smps_mode)) {
|
||||
ht_dbg(sdata,
|
||||
"Won't send SMPS to sleeping STA %pM\n",
|
||||
ht_dbg(sdata, "Won't send SMPS to sleeping STA %pM\n",
|
||||
sta->sta.addr);
|
||||
continue;
|
||||
}
|
||||
|
@ -2339,11 +2336,9 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
|
|||
continue;
|
||||
|
||||
ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
|
||||
ieee80211_send_smps_action(sdata, smps_mode,
|
||||
sta->sta.addr,
|
||||
ieee80211_send_smps_action(sdata, smps_mode, sta->sta.addr,
|
||||
sdata->vif.bss_conf.bssid);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
|
||||
sdata->smps_mode = smps_mode;
|
||||
|
@ -3581,7 +3576,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
|
|||
nullfunc->qos_ctrl = cpu_to_le16(7);
|
||||
|
||||
local_bh_disable();
|
||||
ieee80211_xmit(sdata, skb);
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
local_bh_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
|
@ -18,172 +18,6 @@
|
|||
|
||||
#define DEBUGFS_FORMAT_BUFFER_SIZE 100
|
||||
|
||||
#define TX_LATENCY_BIN_DELIMTER_C ','
|
||||
#define TX_LATENCY_BIN_DELIMTER_S ","
|
||||
#define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n"
|
||||
#define TX_LATENCY_DISABLED "disable\n"
|
||||
|
||||
|
||||
/*
|
||||
* Display if Tx latency statistics & bins are enabled/disabled
|
||||
*/
|
||||
static ssize_t sta_tx_latency_stat_read(struct file *file,
|
||||
char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
struct ieee80211_tx_latency_bin_ranges *tx_latency;
|
||||
char *buf;
|
||||
int bufsz, i, ret;
|
||||
int pos = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
tx_latency = rcu_dereference(local->tx_latency);
|
||||
|
||||
if (tx_latency && tx_latency->n_ranges) {
|
||||
bufsz = tx_latency->n_ranges * 15;
|
||||
buf = kzalloc(bufsz, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < tx_latency->n_ranges; i++)
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%d,",
|
||||
tx_latency->ranges[i]);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
} else if (tx_latency) {
|
||||
bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1;
|
||||
buf = kzalloc(bufsz, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
goto err;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
|
||||
TX_LATENCY_BINS_DISABLED);
|
||||
} else {
|
||||
bufsz = sizeof(TX_LATENCY_DISABLED) + 1;
|
||||
buf = kzalloc(bufsz, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
goto err;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
|
||||
TX_LATENCY_DISABLED);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
|
||||
return ret;
|
||||
err:
|
||||
rcu_read_unlock();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive input from user regarding Tx latency statistics
|
||||
* The input should indicate if Tx latency statistics and bins are
|
||||
* enabled/disabled.
|
||||
* If bins are enabled input should indicate the amount of different bins and
|
||||
* their ranges. Each bin will count how many Tx frames transmitted within the
|
||||
* appropriate latency.
|
||||
* Legal input is:
|
||||
* a) "enable(bins disabled)" - to enable only general statistics
|
||||
* b) "a,b,c,d,...z" - to enable general statistics and bins, where all are
|
||||
* numbers and a < b < c < d.. < z
|
||||
* c) "disable" - disable all statistics
|
||||
* NOTE: must configure Tx latency statistics bins before stations connected.
|
||||
*/
|
||||
|
||||
static ssize_t sta_tx_latency_stat_write(struct file *file,
|
||||
const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
char buf[128] = {};
|
||||
char *bins = buf;
|
||||
char *token;
|
||||
int buf_size, i, alloc_size;
|
||||
int prev_bin = 0;
|
||||
int n_ranges = 0;
|
||||
int ret = count;
|
||||
struct ieee80211_tx_latency_bin_ranges *tx_latency;
|
||||
|
||||
if (sizeof(buf) <= count)
|
||||
return -EINVAL;
|
||||
buf_size = count;
|
||||
if (copy_from_user(buf, userbuf, buf_size))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
/* cannot change config once we have stations */
|
||||
if (local->num_sta)
|
||||
goto unlock;
|
||||
|
||||
tx_latency =
|
||||
rcu_dereference_protected(local->tx_latency,
|
||||
lockdep_is_held(&local->sta_mtx));
|
||||
|
||||
/* disable Tx statistics */
|
||||
if (!strcmp(buf, TX_LATENCY_DISABLED)) {
|
||||
if (!tx_latency)
|
||||
goto unlock;
|
||||
RCU_INIT_POINTER(local->tx_latency, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(tx_latency);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Tx latency already enabled */
|
||||
if (tx_latency)
|
||||
goto unlock;
|
||||
|
||||
if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) {
|
||||
/* check how many bins and between what ranges user requested */
|
||||
token = buf;
|
||||
while (*token != '\0') {
|
||||
if (*token == TX_LATENCY_BIN_DELIMTER_C)
|
||||
n_ranges++;
|
||||
token++;
|
||||
}
|
||||
n_ranges++;
|
||||
}
|
||||
|
||||
alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) +
|
||||
n_ranges * sizeof(u32);
|
||||
tx_latency = kzalloc(alloc_size, GFP_ATOMIC);
|
||||
if (!tx_latency) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
tx_latency->n_ranges = n_ranges;
|
||||
for (i = 0; i < n_ranges; i++) { /* setting bin ranges */
|
||||
token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S);
|
||||
sscanf(token, "%d", &tx_latency->ranges[i]);
|
||||
/* bins values should be in ascending order */
|
||||
if (prev_bin >= tx_latency->ranges[i]) {
|
||||
ret = -EINVAL;
|
||||
kfree(tx_latency);
|
||||
goto unlock;
|
||||
}
|
||||
prev_bin = tx_latency->ranges[i];
|
||||
}
|
||||
rcu_assign_pointer(local->tx_latency, tx_latency);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations stats_tx_latency_ops = {
|
||||
.write = sta_tx_latency_stat_write,
|
||||
.read = sta_tx_latency_stat_read,
|
||||
.open = simple_open,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
int mac80211_format_buffer(char __user *userbuf, size_t count,
|
||||
loff_t *ppos, char *fmt, ...)
|
||||
{
|
||||
|
@ -440,8 +274,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
|||
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted,
|
||||
local->tx_handlers_drop_unencrypted);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
|
||||
local->tx_handlers_drop_fragment);
|
||||
DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
|
||||
|
@ -475,6 +307,4 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
|||
DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
|
||||
DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
|
||||
DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
|
||||
|
||||
DEBUGFS_DEVSTATS_ADD(tx_latency);
|
||||
}
|
||||
|
|
|
@ -177,7 +177,6 @@ static ssize_t ieee80211_if_write_##name(struct file *file, \
|
|||
IEEE80211_IF_FILE_R(name)
|
||||
|
||||
/* common attributes */
|
||||
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
|
||||
IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
|
||||
HEX);
|
||||
IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
|
||||
|
@ -562,7 +561,6 @@ IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
|
|||
|
||||
static void add_common_files(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
DEBUGFS_ADD(drop_unencrypted);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_2ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mask_5ghz);
|
||||
DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
|
||||
|
|
|
@ -39,13 +39,6 @@ static const struct file_operations sta_ ##name## _ops = { \
|
|||
.llseek = generic_file_llseek, \
|
||||
}
|
||||
|
||||
#define STA_OPS_W(name) \
|
||||
static const struct file_operations sta_ ##name## _ops = { \
|
||||
.write = sta_##name##_write, \
|
||||
.open = simple_open, \
|
||||
.llseek = generic_file_llseek, \
|
||||
}
|
||||
|
||||
#define STA_OPS_RW(name) \
|
||||
static const struct file_operations sta_ ##name## _ops = { \
|
||||
.read = sta_##name##_read, \
|
||||
|
@ -398,131 +391,6 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf,
|
|||
}
|
||||
STA_OPS(last_rx_rate);
|
||||
|
||||
static int
|
||||
sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency,
|
||||
char *buf, int pos, int bufsz)
|
||||
{
|
||||
int i;
|
||||
int range_count = tx_latency->n_ranges;
|
||||
u32 *bin_ranges = tx_latency->ranges;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Station\t\t\tTID\tMax\tAvg");
|
||||
if (range_count) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\t<=%d", bin_ranges[0]);
|
||||
for (i = 0; i < range_count - 1; i++)
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d",
|
||||
bin_ranges[i], bin_ranges[i+1]);
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\t%d<", bin_ranges[range_count - 1]);
|
||||
}
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int
|
||||
sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range,
|
||||
struct ieee80211_tx_latency_stat *tx_lat,
|
||||
char *buf, int pos, int bufsz, int tid)
|
||||
{
|
||||
u32 avg = 0;
|
||||
int j;
|
||||
int bin_count = tx_lat->bin_count;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid);
|
||||
/* make sure you don't divide in 0 */
|
||||
if (tx_lat->counter)
|
||||
avg = tx_lat->sum / tx_lat->counter;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d",
|
||||
tx_lat->max, avg);
|
||||
|
||||
if (tx_lat_range->n_ranges && tx_lat->bins)
|
||||
for (j = 0; j < bin_count; j++)
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"\t%d", tx_lat->bins[j]);
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "\n");
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output Tx latency statistics station && restart all statistics information
|
||||
*/
|
||||
static ssize_t sta_tx_latency_stat_read(struct file *file,
|
||||
char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_tx_latency_bin_ranges *tx_latency;
|
||||
char *buf;
|
||||
int bufsz, ret, i;
|
||||
int pos = 0;
|
||||
|
||||
bufsz = 20 * IEEE80211_NUM_TIDS *
|
||||
sizeof(struct ieee80211_tx_latency_stat);
|
||||
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
tx_latency = rcu_dereference(local->tx_latency);
|
||||
|
||||
if (!sta->tx_lat) {
|
||||
pos += scnprintf(buf + pos, bufsz - pos,
|
||||
"Tx latency statistics are not enabled\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr);
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
|
||||
pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i],
|
||||
buf, pos, bufsz, i);
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
|
||||
kfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
STA_OPS(tx_latency_stat);
|
||||
|
||||
static ssize_t sta_tx_latency_stat_reset_write(struct file *file,
|
||||
const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u32 *bins;
|
||||
int bin_count;
|
||||
struct sta_info *sta = file->private_data;
|
||||
int i;
|
||||
|
||||
if (!sta->tx_lat)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
bins = sta->tx_lat[i].bins;
|
||||
bin_count = sta->tx_lat[i].bin_count;
|
||||
|
||||
sta->tx_lat[i].max = 0;
|
||||
sta->tx_lat[i].sum = 0;
|
||||
sta->tx_lat[i].counter = 0;
|
||||
|
||||
if (bin_count)
|
||||
memset(bins, 0, bin_count * sizeof(u32));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
STA_OPS_W(tx_latency_stat_reset);
|
||||
|
||||
#define DEBUGFS_ADD(name) \
|
||||
debugfs_create_file(#name, 0400, \
|
||||
sta->debugfs.dir, sta, &sta_ ##name## _ops);
|
||||
|
@ -576,8 +444,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
|
|||
DEBUGFS_ADD(last_ack_signal);
|
||||
DEBUGFS_ADD(current_tx_rate);
|
||||
DEBUGFS_ADD(last_rx_rate);
|
||||
DEBUGFS_ADD(tx_latency_stat);
|
||||
DEBUGFS_ADD(tx_latency_stat_reset);
|
||||
|
||||
DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
|
||||
DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
|
||||
|
|
|
@ -249,8 +249,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
if (presp)
|
||||
kfree_rcu(presp, rcu_head);
|
||||
|
||||
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
||||
|
||||
/* make a copy of the chandef, it could be modified below. */
|
||||
chandef = *req_chandef;
|
||||
chan = chandef.chan;
|
||||
|
@ -470,22 +468,19 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
struct beacon_data *presp, *old_presp;
|
||||
struct cfg80211_bss *cbss;
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
u16 capability;
|
||||
u16 capability = 0;
|
||||
u64 tsf;
|
||||
int ret = 0;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
capability = WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
|
||||
ifibss->bssid, ifibss->ssid,
|
||||
ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
||||
WLAN_CAPABILITY_PRIVACY,
|
||||
capability);
|
||||
ifibss->ssid_len, IEEE80211_BSS_TYPE_IBSS,
|
||||
IEEE80211_PRIVACY(ifibss->privacy));
|
||||
|
||||
if (WARN_ON(!cbss)) {
|
||||
ret = -EINVAL;
|
||||
|
@ -525,23 +520,17 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
|
|||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct cfg80211_bss *cbss;
|
||||
int err, changed = 0;
|
||||
u16 capability;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
/* update cfg80211 bss information with the new channel */
|
||||
if (!is_zero_ether_addr(ifibss->bssid)) {
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
|
||||
ifibss->chandef.chan,
|
||||
ifibss->bssid, ifibss->ssid,
|
||||
ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
||||
WLAN_CAPABILITY_PRIVACY,
|
||||
capability);
|
||||
ifibss->ssid_len,
|
||||
IEEE80211_BSS_TYPE_IBSS,
|
||||
IEEE80211_PRIVACY(ifibss->privacy));
|
||||
/* XXX: should not really modify cfg80211 data */
|
||||
if (cbss) {
|
||||
cbss->channel = sdata->csa_chandef.chan;
|
||||
|
@ -682,19 +671,13 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
|
|||
struct cfg80211_bss *cbss;
|
||||
struct beacon_data *presp;
|
||||
struct sta_info *sta;
|
||||
u16 capability;
|
||||
|
||||
if (!is_zero_ether_addr(ifibss->bssid)) {
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
|
||||
ifibss->bssid, ifibss->ssid,
|
||||
ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
||||
WLAN_CAPABILITY_PRIVACY,
|
||||
capability);
|
||||
ifibss->ssid_len,
|
||||
IEEE80211_BSS_TYPE_IBSS,
|
||||
IEEE80211_PRIVACY(ifibss->privacy));
|
||||
|
||||
if (cbss) {
|
||||
cfg80211_unlink_bss(local->hw.wiphy, cbss);
|
||||
|
@ -980,29 +963,25 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee802_11_elems *elems)
|
||||
struct ieee802_11_elems *elems,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct cfg80211_bss *cbss;
|
||||
struct ieee80211_bss *bss;
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_channel *channel;
|
||||
u64 beacon_timestamp, rx_timestamp;
|
||||
u32 supp_rates = 0;
|
||||
enum ieee80211_band band = rx_status->band;
|
||||
enum nl80211_bss_scan_width scan_width;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
|
||||
bool rates_updated = false;
|
||||
u32 supp_rates = 0;
|
||||
|
||||
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
|
||||
if (!channel)
|
||||
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
return;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) {
|
||||
if (!ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(sdata, mgmt->sa);
|
||||
|
@ -1022,8 +1001,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
scan_width = NL80211_BSS_CHAN_WIDTH_10;
|
||||
|
||||
sta->sta.supp_rates[band] = supp_rates |
|
||||
ieee80211_mandatory_rates(sband,
|
||||
scan_width);
|
||||
ieee80211_mandatory_rates(sband, scan_width);
|
||||
if (sta->sta.supp_rates[band] != prev_rates) {
|
||||
ibss_dbg(sdata,
|
||||
"updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
|
||||
|
@ -1059,13 +1037,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
* fall back to HT20 if we don't use or use
|
||||
* the other extension channel
|
||||
*/
|
||||
if (chandef.center_freq1 !=
|
||||
sdata->u.ibss.chandef.center_freq1)
|
||||
if (chandef.center_freq1 != sdata->u.ibss.chandef.center_freq1)
|
||||
htcap_ie.cap_info &=
|
||||
cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
|
||||
|
||||
rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(
|
||||
sdata, sband, &htcap_ie, sta);
|
||||
rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
&htcap_ie,
|
||||
sta);
|
||||
}
|
||||
|
||||
if (sta && rates_updated) {
|
||||
|
@ -1084,6 +1062,25 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct ieee802_11_elems *elems)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct cfg80211_bss *cbss;
|
||||
struct ieee80211_bss *bss;
|
||||
struct ieee80211_channel *channel;
|
||||
u64 beacon_timestamp, rx_timestamp;
|
||||
u32 supp_rates = 0;
|
||||
enum ieee80211_band band = rx_status->band;
|
||||
|
||||
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
ieee80211_update_sta_info(sdata, mgmt, len, rx_status, elems, channel);
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
|
||||
channel);
|
||||
if (!bss)
|
||||
|
@ -1304,8 +1301,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
else
|
||||
sdata->drop_unencrypted = 0;
|
||||
|
||||
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
|
||||
&ifibss->chandef, ifibss->basic_rates,
|
||||
|
@ -1325,7 +1320,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
const u8 *bssid = NULL;
|
||||
enum nl80211_bss_scan_width scan_width;
|
||||
int active_ibss;
|
||||
u16 capability;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
|
@ -1335,9 +1329,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
if (active_ibss)
|
||||
return;
|
||||
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
if (ifibss->fixed_bssid)
|
||||
bssid = ifibss->bssid;
|
||||
if (ifibss->fixed_channel)
|
||||
|
@ -1346,8 +1337,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
bssid = ifibss->bssid;
|
||||
cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
|
||||
ifibss->ssid, ifibss->ssid_len,
|
||||
WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY,
|
||||
capability);
|
||||
IEEE80211_BSS_TYPE_IBSS,
|
||||
IEEE80211_PRIVACY(ifibss->privacy));
|
||||
|
||||
if (cbss) {
|
||||
struct ieee80211_bss *bss;
|
||||
|
|
|
@ -818,8 +818,6 @@ struct ieee80211_sub_if_data {
|
|||
|
||||
unsigned long state;
|
||||
|
||||
int drop_unencrypted;
|
||||
|
||||
char name[IFNAMSIZ];
|
||||
|
||||
/* Fragment table for host-based reassembly */
|
||||
|
@ -1030,24 +1028,6 @@ struct tpt_led_trigger {
|
|||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges
|
||||
*
|
||||
* Measuring Tx latency statistics. Counts how many Tx frames transmitted in a
|
||||
* certain latency range (in Milliseconds). Each station that uses these
|
||||
* ranges will have bins to count the amount of frames received in that range.
|
||||
* The user can configure the ranges via debugfs.
|
||||
* If ranges is NULL then Tx latency statistics bins are disabled for all
|
||||
* stations.
|
||||
*
|
||||
* @n_ranges: number of ranges that are taken in account
|
||||
* @ranges: the ranges that the user requested or NULL if disabled.
|
||||
*/
|
||||
struct ieee80211_tx_latency_bin_ranges {
|
||||
int n_ranges;
|
||||
u32 ranges[];
|
||||
};
|
||||
|
||||
/**
|
||||
* mac80211 scan flags - currently active scan mode
|
||||
*
|
||||
|
@ -1199,12 +1179,6 @@ struct ieee80211_local {
|
|||
struct timer_list sta_cleanup;
|
||||
int sta_generation;
|
||||
|
||||
/*
|
||||
* Tx latency statistics parameters for all stations.
|
||||
* Can enable via debugfs (NULL when disabled).
|
||||
*/
|
||||
struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;
|
||||
|
||||
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
|
||||
struct tasklet_struct tx_pending_tasklet;
|
||||
|
||||
|
@ -1286,7 +1260,6 @@ struct ieee80211_local {
|
|||
/* TX/RX handler statistics */
|
||||
unsigned int tx_handlers_drop;
|
||||
unsigned int tx_handlers_queued;
|
||||
unsigned int tx_handlers_drop_unencrypted;
|
||||
unsigned int tx_handlers_drop_fragment;
|
||||
unsigned int tx_handlers_drop_wep;
|
||||
unsigned int tx_handlers_drop_not_assoc;
|
||||
|
@ -1772,7 +1745,8 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
|
|||
gfp_t gfp);
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
bool bss_notify);
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb);
|
||||
|
||||
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid,
|
||||
|
@ -1967,6 +1941,8 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
|||
u16 prot_mode);
|
||||
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
u32 cap);
|
||||
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
const struct cfg80211_chan_def *chandef);
|
||||
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
|
||||
const struct ieee80211_supported_band *sband,
|
||||
const u8 *srates, int srates_len, u32 *rates);
|
||||
|
|
|
@ -1508,7 +1508,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
/* reset some values that shouldn't be kept across type changes */
|
||||
sdata->drop_unencrypted = 0;
|
||||
if (type == NL80211_IFTYPE_STATION)
|
||||
sdata->u.mgd.use_4addr = false;
|
||||
|
||||
|
|
|
@ -492,6 +492,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
|||
for (j = 0; j < len; j++)
|
||||
key->u.gen.rx_pn[i][j] =
|
||||
seq[len - j - 1];
|
||||
key->flags |= KEY_FLAG_CIPHER_SCHEME;
|
||||
}
|
||||
}
|
||||
memcpy(key->conf.key, key_data, key_len);
|
||||
|
|
|
@ -30,10 +30,12 @@ struct sta_info;
|
|||
* @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
|
||||
* in the hardware for TX crypto hardware acceleration.
|
||||
* @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped.
|
||||
* @KEY_FLAG_CIPHER_SCHEME: This key is for a hardware cipher scheme
|
||||
*/
|
||||
enum ieee80211_internal_key_flags {
|
||||
KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
|
||||
KEY_FLAG_TAINTED = BIT(1),
|
||||
KEY_FLAG_CIPHER_SCHEME = BIT(2),
|
||||
};
|
||||
|
||||
enum ieee80211_internal_tkip_state {
|
||||
|
|
|
@ -1201,8 +1201,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
|
|||
ieee80211_free_ack_frame, NULL);
|
||||
idr_destroy(&local->ack_status_frames);
|
||||
|
||||
kfree(rcu_access_pointer(local->tx_latency));
|
||||
|
||||
sta_info_stop(local);
|
||||
|
||||
wiphy_free(local->hw.wiphy);
|
||||
|
|
|
@ -574,6 +574,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
|
|||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u32 changed;
|
||||
|
||||
if (ifmsh->mshcfg.plink_timeout > 0)
|
||||
ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
|
||||
mesh_path_expire(sdata);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#define PLINK_GET_PLID(p) (p + 4)
|
||||
|
||||
#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
|
||||
jiffies + HZ * t / 1000))
|
||||
jiffies + msecs_to_jiffies(t)))
|
||||
|
||||
enum plink_event {
|
||||
PLINK_UNDEFINED,
|
||||
|
@ -621,9 +621,9 @@ static void mesh_plink_timer(unsigned long data)
|
|||
sta->llid, sta->plid, reason);
|
||||
}
|
||||
|
||||
static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
|
||||
static inline void mesh_plink_timer_set(struct sta_info *sta, u32 timeout)
|
||||
{
|
||||
sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
|
||||
sta->plink_timer.expires = jiffies + msecs_to_jiffies(timeout);
|
||||
sta->plink_timer.data = (unsigned long) sta;
|
||||
sta->plink_timer.function = mesh_plink_timer;
|
||||
sta->plink_timeout = timeout;
|
||||
|
|
|
@ -1157,11 +1157,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
if (!conf) {
|
||||
sdata_info(sdata,
|
||||
"no channel context assigned to vif?, disconnecting\n");
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
goto drop_connection;
|
||||
}
|
||||
|
||||
chanctx = container_of(conf, struct ieee80211_chanctx, conf);
|
||||
|
@ -1170,11 +1166,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
!(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
|
||||
sdata_info(sdata,
|
||||
"driver doesn't support chan-switch with channel contexts\n");
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
goto drop_connection;
|
||||
}
|
||||
|
||||
ch_switch.timestamp = timestamp;
|
||||
|
@ -1186,11 +1178,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
if (drv_pre_channel_switch(sdata, &ch_switch)) {
|
||||
sdata_info(sdata,
|
||||
"preparing for channel switch failed, disconnecting\n");
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
goto drop_connection;
|
||||
}
|
||||
|
||||
res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
|
||||
|
@ -1199,11 +1187,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
sdata_info(sdata,
|
||||
"failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
|
||||
res);
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
goto drop_connection;
|
||||
}
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
|
||||
|
@ -1232,6 +1216,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
mod_timer(&ifmgd->chswitch_timer,
|
||||
TU_TO_EXP_TIME((csa_ie.count - 1) *
|
||||
cbss->beacon_interval));
|
||||
return;
|
||||
drop_connection:
|
||||
ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
|
||||
mutex_unlock(&local->chanctx_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -1621,9 +1610,6 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
|
|||
{
|
||||
struct ieee80211_local *local = (void *) data;
|
||||
|
||||
if (local->quiescing || local->suspended)
|
||||
return;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
|
||||
}
|
||||
|
||||
|
@ -2969,8 +2955,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
|
||||
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
|
||||
set_sta_flag(sta, WLAN_STA_MFP);
|
||||
sta->sta.mfp = true;
|
||||
} else {
|
||||
sta->sta.mfp = false;
|
||||
}
|
||||
|
||||
sta->sta.wme = elems.wmm_param;
|
||||
|
||||
|
@ -3419,6 +3409,26 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
if (ifmgd->csa_waiting_bcn)
|
||||
ieee80211_chswitch_post_beacon(sdata);
|
||||
|
||||
/*
|
||||
* Update beacon timing and dtim count on every beacon appearance. This
|
||||
* will allow the driver to use the most updated values. Do it before
|
||||
* comparing this one with last received beacon.
|
||||
* IMPORTANT: These parameters would possibly be out of sync by the time
|
||||
* the driver will use them. The synchronized view is currently
|
||||
* guaranteed only in certain callbacks.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
|
||||
return;
|
||||
ifmgd->beacon_crc = ncrc;
|
||||
|
@ -3446,18 +3456,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
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_BEACON_INFO;
|
||||
ifmgd->have_beacon = true;
|
||||
|
||||
|
@ -3891,12 +3889,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
(struct ieee80211_sub_if_data *) data;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
if (local->quiescing)
|
||||
return;
|
||||
|
||||
if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
|
||||
return;
|
||||
|
||||
|
@ -3912,9 +3906,6 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
|
|||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (local->quiescing)
|
||||
return;
|
||||
|
||||
if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
|
||||
return;
|
||||
|
||||
|
@ -3977,6 +3968,34 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
|
|||
IEEE80211_DEAUTH_FRAME_LEN);
|
||||
}
|
||||
|
||||
/* This is a bit of a hack - we should find a better and more generic
|
||||
* solution to this. Normally when suspending, cfg80211 will in fact
|
||||
* deauthenticate. However, it doesn't (and cannot) stop an ongoing
|
||||
* auth (not so important) or assoc (this is the problem) process.
|
||||
*
|
||||
* As a consequence, it can happen that we are in the process of both
|
||||
* associating and suspending, and receive an association response
|
||||
* after cfg80211 has checked if it needs to disconnect, but before
|
||||
* we actually set the flag to drop incoming frames. This will then
|
||||
* cause the workqueue flush to process the association response in
|
||||
* the suspend, resulting in a successful association just before it
|
||||
* tries to remove the interface from the driver, which now though
|
||||
* has a channel context assigned ... this results in issues.
|
||||
*
|
||||
* To work around this (for now) simply deauth here again if we're
|
||||
* now connected.
|
||||
*/
|
||||
if (ifmgd->associated && !sdata->local->wowlan) {
|
||||
u8 bssid[ETH_ALEN];
|
||||
struct cfg80211_deauth_request req = {
|
||||
.reason_code = WLAN_REASON_DEAUTH_LEAVING,
|
||||
.bssid = bssid,
|
||||
};
|
||||
|
||||
memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
|
||||
ieee80211_mgd_deauth(sdata, &req);
|
||||
}
|
||||
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,9 +59,26 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
cancel_work_sync(&local->dynamic_ps_enable_work);
|
||||
del_timer_sync(&local->dynamic_ps_timer);
|
||||
|
||||
local->wowlan = wowlan && local->open_count;
|
||||
local->wowlan = wowlan;
|
||||
if (local->wowlan) {
|
||||
int err = drv_suspend(local, wowlan);
|
||||
int err;
|
||||
|
||||
/* Drivers don't expect to suspend while some operations like
|
||||
* authenticating or associating are in progress. It doesn't
|
||||
* make sense anyway to accept that, since the authentication
|
||||
* or association would never finish since the driver can't do
|
||||
* that on its own.
|
||||
* Thus, clean up in-progress auth/assoc first.
|
||||
*/
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
continue;
|
||||
ieee80211_mgd_quiesce(sdata);
|
||||
}
|
||||
|
||||
err = drv_suspend(local, wowlan);
|
||||
if (err < 0) {
|
||||
local->quiescing = false;
|
||||
local->wowlan = false;
|
||||
|
@ -80,6 +97,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
return err;
|
||||
} else if (err > 0) {
|
||||
WARN_ON(err != 1);
|
||||
/* cfg80211 will call back into mac80211 to disconnect
|
||||
* all interfaces, allow that to proceed properly
|
||||
*/
|
||||
ieee80211_wake_queues_by_reason(hw,
|
||||
IEEE80211_MAX_QUEUE_MAP,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
|
||||
false);
|
||||
return err;
|
||||
} else {
|
||||
goto suspend;
|
||||
|
|
|
@ -17,10 +17,11 @@
|
|||
#include "rc80211_minstrel.h"
|
||||
#include "rc80211_minstrel_ht.h"
|
||||
|
||||
#define AVG_AMPDU_SIZE 16
|
||||
#define AVG_PKT_SIZE 1200
|
||||
|
||||
/* Number of bits for an average sized packet */
|
||||
#define MCS_NBITS (AVG_PKT_SIZE << 3)
|
||||
#define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3)
|
||||
|
||||
/* Number of symbols for a packet with (bps) bits per symbol */
|
||||
#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps))
|
||||
|
@ -33,7 +34,8 @@
|
|||
)
|
||||
|
||||
/* Transmit duration for the raw data part of an average sized packet */
|
||||
#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
|
||||
#define MCS_DURATION(streams, sgi, bps) \
|
||||
(MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) / AVG_AMPDU_SIZE)
|
||||
|
||||
#define BW_20 0
|
||||
#define BW_40 1
|
||||
|
|
|
@ -1912,8 +1912,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
|
|||
/* Drop unencrypted frames if key is set. */
|
||||
if (unlikely(!ieee80211_has_protected(fc) &&
|
||||
!ieee80211_is_nullfunc(fc) &&
|
||||
ieee80211_is_data(fc) &&
|
||||
(rx->key || rx->sdata->drop_unencrypted)))
|
||||
ieee80211_is_data(fc) && rx->key))
|
||||
return -EACCES;
|
||||
|
||||
return 0;
|
||||
|
@ -2043,6 +2042,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
|||
struct sta_info *dsta;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += rx->skb->len;
|
||||
|
||||
skb = rx->skb;
|
||||
xmit_skb = NULL;
|
||||
|
||||
|
@ -2173,8 +2175,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
|||
dev_kfree_skb(rx->skb);
|
||||
continue;
|
||||
}
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += rx->skb->len;
|
||||
|
||||
ieee80211_deliver_skb(rx);
|
||||
}
|
||||
|
@ -2397,9 +2397,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
|
|||
|
||||
rx->skb->dev = dev;
|
||||
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += rx->skb->len;
|
||||
|
||||
if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
|
||||
!is_multicast_ether_addr(
|
||||
((struct ethhdr *)rx->skb->data)->h_dest) &&
|
||||
|
@ -3125,6 +3122,12 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
|
|||
goto rxh_next; \
|
||||
} while (0);
|
||||
|
||||
/* Lock here to avoid hitting all of the data used in the RX
|
||||
* path (e.g. key data, station data, ...) concurrently when
|
||||
* a frame is released from the reorder buffer due to timeout
|
||||
* from the timer, potentially concurrently with RX from the
|
||||
* driver.
|
||||
*/
|
||||
spin_lock_bh(&rx->local->rx_path_lock);
|
||||
|
||||
while ((skb = __skb_dequeue(frames))) {
|
||||
|
|
|
@ -229,17 +229,9 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sta->rate_ctrl)
|
||||
rate_control_free_sta(sta);
|
||||
|
||||
if (sta->tx_lat) {
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
|
||||
kfree(sta->tx_lat[i].bins);
|
||||
kfree(sta->tx_lat);
|
||||
}
|
||||
|
||||
sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
|
||||
|
||||
kfree(rcu_dereference_raw(sta->sta.rates));
|
||||
|
@ -295,42 +287,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
struct timespec uptime;
|
||||
struct ieee80211_tx_latency_bin_ranges *tx_latency;
|
||||
int i;
|
||||
|
||||
sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
|
||||
if (!sta)
|
||||
return NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
tx_latency = rcu_dereference(local->tx_latency);
|
||||
/* init stations Tx latency statistics && TID bins */
|
||||
if (tx_latency) {
|
||||
sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
|
||||
sizeof(struct ieee80211_tx_latency_stat),
|
||||
GFP_ATOMIC);
|
||||
if (!sta->tx_lat) {
|
||||
rcu_read_unlock();
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (tx_latency->n_ranges) {
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
/* size of bins is size of the ranges +1 */
|
||||
sta->tx_lat[i].bin_count =
|
||||
tx_latency->n_ranges + 1;
|
||||
sta->tx_lat[i].bins =
|
||||
kcalloc(sta->tx_lat[i].bin_count,
|
||||
sizeof(u32), GFP_ATOMIC);
|
||||
if (!sta->tx_lat[i].bins) {
|
||||
rcu_read_unlock();
|
||||
goto free;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_lock_init(&sta->lock);
|
||||
spin_lock_init(&sta->ps_lock);
|
||||
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
|
||||
|
@ -359,8 +321,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
|
||||
ewma_init(&sta->chain_signal_avg[i], 1024, 8);
|
||||
|
||||
if (sta_prepare_rate_control(local, sta, gfp))
|
||||
goto free;
|
||||
if (sta_prepare_rate_control(local, sta, gfp)) {
|
||||
kfree(sta);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
/*
|
||||
|
@ -405,16 +369,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
|
||||
return sta;
|
||||
|
||||
free:
|
||||
if (sta->tx_lat) {
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
|
||||
kfree(sta->tx_lat[i].bins);
|
||||
kfree(sta->tx_lat);
|
||||
}
|
||||
kfree(sta);
|
||||
return NULL;
|
||||
return sta;
|
||||
}
|
||||
|
||||
static int sta_info_insert_check(struct sta_info *sta)
|
||||
|
@ -1275,7 +1231,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
info->band = chanctx_conf->def.chan->band;
|
||||
ieee80211_xmit(sdata, skb);
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
|
@ -234,25 +234,6 @@ struct sta_ampdu_mlme {
|
|||
u8 dialog_token_allocator;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct ieee80211_tx_latency_stat - Tx latency statistics
|
||||
*
|
||||
* Measures TX latency and jitter for a station per TID.
|
||||
*
|
||||
* @max: worst case latency
|
||||
* @sum: sum of all latencies
|
||||
* @counter: amount of Tx frames sent from interface
|
||||
* @bins: each bin counts how many frames transmitted within a certain
|
||||
* latency range. when disabled it is NULL.
|
||||
* @bin_count: amount of bins.
|
||||
*/
|
||||
struct ieee80211_tx_latency_stat {
|
||||
u32 max;
|
||||
u32 sum;
|
||||
u32 counter;
|
||||
u32 *bins;
|
||||
u32 bin_count;
|
||||
};
|
||||
|
||||
/* Value to indicate no TID reservation */
|
||||
#define IEEE80211_TID_UNRESERVED 0xff
|
||||
|
@ -314,7 +295,6 @@ struct ieee80211_tx_latency_stat {
|
|||
* @tid_seq: per-TID sequence numbers for sending to this STA
|
||||
* @ampdu_mlme: A-MPDU state machine state
|
||||
* @timer_to_tid: identity mapping to ID timers
|
||||
* @tx_lat: Tx latency statistics
|
||||
* @llid: Local link ID
|
||||
* @plid: Peer link ID
|
||||
* @reason: Cancel reason on PLINK_HOLDING state
|
||||
|
@ -435,8 +415,6 @@ struct sta_info {
|
|||
struct sta_ampdu_mlme ampdu_mlme;
|
||||
u8 timer_to_tid[IEEE80211_NUM_TIDS];
|
||||
|
||||
struct ieee80211_tx_latency_stat *tx_lat;
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
/*
|
||||
* Mesh peer link attributes
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/time.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "ieee80211_i.h"
|
||||
|
@ -514,73 +513,6 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Measure Tx frame completion and removal time for Tx latency statistics
|
||||
* calculation. A single Tx frame latency should be measured from when it
|
||||
* is entering the Kernel until we receive Tx complete confirmation indication
|
||||
* and remove the skb.
|
||||
*/
|
||||
static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
|
||||
struct sk_buff *skb,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_hdr *hdr)
|
||||
{
|
||||
u32 msrmnt;
|
||||
u16 tid;
|
||||
u8 *qc;
|
||||
int i, bin_range_count;
|
||||
u32 *bin_ranges;
|
||||
__le16 fc;
|
||||
struct ieee80211_tx_latency_stat *tx_lat;
|
||||
struct ieee80211_tx_latency_bin_ranges *tx_latency;
|
||||
ktime_t skb_arv = skb->tstamp;
|
||||
|
||||
tx_latency = rcu_dereference(local->tx_latency);
|
||||
|
||||
/* assert Tx latency stats are enabled & frame arrived when enabled */
|
||||
if (!tx_latency || !ktime_to_ns(skb_arv))
|
||||
return;
|
||||
|
||||
fc = hdr->frame_control;
|
||||
|
||||
if (!ieee80211_is_data(fc)) /* make sure it is a data frame */
|
||||
return;
|
||||
|
||||
/* get frame tid */
|
||||
if (ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||
} else {
|
||||
tid = 0;
|
||||
}
|
||||
|
||||
tx_lat = &sta->tx_lat[tid];
|
||||
|
||||
/* Calculate the latency */
|
||||
msrmnt = ktime_to_ms(ktime_sub(ktime_get(), skb_arv));
|
||||
|
||||
if (tx_lat->max < msrmnt) /* update stats */
|
||||
tx_lat->max = msrmnt;
|
||||
tx_lat->counter++;
|
||||
tx_lat->sum += msrmnt;
|
||||
|
||||
if (!tx_lat->bins) /* bins not activated */
|
||||
return;
|
||||
|
||||
/* count how many Tx frames transmitted with the appropriate latency */
|
||||
bin_range_count = tx_latency->n_ranges;
|
||||
bin_ranges = tx_latency->ranges;
|
||||
|
||||
for (i = 0; i < bin_range_count; i++) {
|
||||
if (msrmnt <= bin_ranges[i]) {
|
||||
tx_lat->bins[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == bin_range_count) /* msrmnt is bigger than the biggest range */
|
||||
tx_lat->bins[i]++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a static threshold for now, best value to be determined
|
||||
* by testing ...
|
||||
|
@ -853,12 +785,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
|
||||
if (acked)
|
||||
sta->last_ack_signal = info->status.ack_signal;
|
||||
|
||||
/*
|
||||
* Measure frame removal for tx latency
|
||||
* statistics calculation
|
||||
*/
|
||||
ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -193,6 +193,17 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
u8 *pos = (void *)skb_put(skb, 4);
|
||||
|
||||
*pos++ = WLAN_EID_AID;
|
||||
*pos++ = 2; /* len */
|
||||
put_unaligned_le16(ifmgd->aid, pos);
|
||||
}
|
||||
|
||||
/* translate numbering in the WMM parameter IE to the mac80211 notation */
|
||||
static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac)
|
||||
{
|
||||
|
@ -271,21 +282,11 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
struct ieee80211_sta_vht_cap vht_cap;
|
||||
struct sta_info *sta = NULL;
|
||||
size_t offset = 0, noffset;
|
||||
u8 *pos;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* we should have the peer STA if we're already responding */
|
||||
if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
|
||||
sta = sta_info_get(sdata, peer);
|
||||
if (WARN_ON_ONCE(!sta)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ieee80211_add_srates_ie(sdata, skb, false, band);
|
||||
ieee80211_add_ext_srates_ie(sdata, skb, false, band);
|
||||
ieee80211_tdls_add_supp_channels(sdata, skb);
|
||||
|
@ -338,6 +339,17 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
|
|||
offset = noffset;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* we should have the peer STA if we're already responding */
|
||||
if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
|
||||
sta = sta_info_get(sdata, peer);
|
||||
if (WARN_ON_ONCE(!sta)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* with TDLS we can switch channels, and HT-caps are not necessarily
|
||||
* the same on all bands. The specification limits the setup to a
|
||||
|
@ -368,12 +380,60 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ht_cap.ht_supported &&
|
||||
(ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
|
||||
ieee80211_tdls_add_bss_coex_ie(skb);
|
||||
|
||||
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
|
||||
|
||||
/* add any custom IEs that go before VHT capabilities */
|
||||
if (extra_ies_len) {
|
||||
static const u8 before_vht_cap[] = {
|
||||
WLAN_EID_SUPP_RATES,
|
||||
WLAN_EID_COUNTRY,
|
||||
WLAN_EID_EXT_SUPP_RATES,
|
||||
WLAN_EID_SUPPORTED_CHANNELS,
|
||||
WLAN_EID_RSN,
|
||||
WLAN_EID_EXT_CAPABILITY,
|
||||
WLAN_EID_QOS_CAPA,
|
||||
WLAN_EID_FAST_BSS_TRANSITION,
|
||||
WLAN_EID_TIMEOUT_INTERVAL,
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
|
||||
WLAN_EID_MULTI_BAND,
|
||||
};
|
||||
noffset = ieee80211_ie_split(extra_ies, extra_ies_len,
|
||||
before_vht_cap,
|
||||
ARRAY_SIZE(before_vht_cap),
|
||||
offset);
|
||||
pos = skb_put(skb, noffset - offset);
|
||||
memcpy(pos, extra_ies + offset, noffset - offset);
|
||||
offset = noffset;
|
||||
}
|
||||
|
||||
/* build the VHT-cap similarly to the HT-cap */
|
||||
memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
|
||||
if (action_code == WLAN_TDLS_SETUP_REQUEST && vht_cap.vht_supported) {
|
||||
ieee80211_apply_vhtcap_overrides(sdata, &vht_cap);
|
||||
|
||||
/* the AID is present only when VHT is implemented */
|
||||
ieee80211_tdls_add_aid(sdata, skb);
|
||||
|
||||
pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
|
||||
ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap);
|
||||
} else if (action_code == WLAN_TDLS_SETUP_RESPONSE &&
|
||||
vht_cap.vht_supported && sta->sta.vht_cap.vht_supported) {
|
||||
/* the peer caps are already intersected with our own */
|
||||
memcpy(&vht_cap, &sta->sta.vht_cap, sizeof(vht_cap));
|
||||
|
||||
/* the AID is present only when VHT is implemented */
|
||||
ieee80211_tdls_add_aid(sdata, skb);
|
||||
|
||||
pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
|
||||
ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* add any remaining IEs */
|
||||
if (extra_ies_len) {
|
||||
noffset = extra_ies_len;
|
||||
|
@ -381,7 +441,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(pos, extra_ies + offset, noffset - offset);
|
||||
}
|
||||
|
||||
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -394,6 +453,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
size_t offset = 0, noffset;
|
||||
struct sta_info *sta, *ap_sta;
|
||||
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
|
||||
u8 *pos;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -453,6 +513,21 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
|
||||
|
||||
/* only include VHT-operation if not on the 2.4GHz band */
|
||||
if (band != IEEE80211_BAND_2GHZ && !ap_sta->sta.vht_cap.vht_supported &&
|
||||
sta->sta.vht_cap.vht_supported) {
|
||||
struct ieee80211_chanctx_conf *chanctx_conf =
|
||||
rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!WARN_ON(!chanctx_conf)) {
|
||||
pos = skb_put(skb, 2 +
|
||||
sizeof(struct ieee80211_vht_operation));
|
||||
ieee80211_ie_build_vht_oper(pos, &sta->sta.vht_cap,
|
||||
&chanctx_conf->def);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* add any remaining IEs */
|
||||
|
@ -461,8 +536,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
|
|||
pos = skb_put(skb, noffset - offset);
|
||||
memcpy(pos, extra_ies + offset, noffset - offset);
|
||||
}
|
||||
|
||||
ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -708,8 +781,11 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
|
|||
26 + /* max(WMM-info, WMM-param) */
|
||||
2 + max(sizeof(struct ieee80211_ht_cap),
|
||||
sizeof(struct ieee80211_ht_operation)) +
|
||||
2 + max(sizeof(struct ieee80211_vht_cap),
|
||||
sizeof(struct ieee80211_vht_operation)) +
|
||||
50 + /* supported channels */
|
||||
3 + /* 40/20 BSS coex */
|
||||
4 + /* AID */
|
||||
extra_ies_len +
|
||||
sizeof(struct ieee80211_tdls_lnkie));
|
||||
if (!skb)
|
||||
|
@ -907,7 +983,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) &&
|
||||
!ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) {
|
||||
ret = -EBUSY;
|
||||
goto exit;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -922,27 +998,34 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (!sta_info_get(sdata, peer)) {
|
||||
rcu_read_unlock();
|
||||
ret = -ENOLINK;
|
||||
goto exit;
|
||||
goto out_unlock;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
ieee80211_flush_queues(local, sdata, false);
|
||||
memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
/* we cannot take the mutex while preparing the setup packet */
|
||||
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
|
||||
dialog_token, status_code,
|
||||
peer_capability, initiator,
|
||||
extra_ies, extra_ies_len, 0,
|
||||
NULL);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
if (ret < 0) {
|
||||
mutex_lock(&local->mtx);
|
||||
eth_zero_addr(sdata->u.mgd.tdls_peer);
|
||||
mutex_unlock(&local->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN);
|
||||
ieee80211_queue_delayed_work(&sdata->local->hw,
|
||||
&sdata->u.mgd.tdls_peer_del_work,
|
||||
TDLS_PEER_SETUP_TIMEOUT);
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
out_unlock:
|
||||
mutex_unlock(&local->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/bitmap.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/time.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
@ -594,23 +593,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
else if (!is_multicast_ether_addr(hdr->addr1) &&
|
||||
(key = rcu_dereference(tx->sdata->default_unicast_key)))
|
||||
tx->key = key;
|
||||
else if (info->flags & IEEE80211_TX_CTL_INJECTED)
|
||||
else
|
||||
tx->key = NULL;
|
||||
else if (!tx->sdata->drop_unencrypted)
|
||||
tx->key = NULL;
|
||||
else if (tx->skb->protocol == tx->sdata->control_port_protocol)
|
||||
tx->key = NULL;
|
||||
else if (ieee80211_is_robust_mgmt_frame(tx->skb) &&
|
||||
!(ieee80211_is_action(hdr->frame_control) &&
|
||||
tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
|
||||
tx->key = NULL;
|
||||
else if (ieee80211_is_mgmt(hdr->frame_control) &&
|
||||
!ieee80211_is_robust_mgmt_frame(tx->skb))
|
||||
tx->key = NULL;
|
||||
else {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
|
||||
return TX_DROP;
|
||||
}
|
||||
|
||||
if (tx->key) {
|
||||
bool skip_hw = false;
|
||||
|
@ -1136,11 +1120,13 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
|
|||
|
||||
/*
|
||||
* initialises @tx
|
||||
* pass %NULL for the station if unknown, a valid pointer if known
|
||||
* or an ERR_PTR() if the station is known not to exist
|
||||
*/
|
||||
static ieee80211_tx_result
|
||||
ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_tx_data *tx,
|
||||
struct sk_buff *skb)
|
||||
struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
@ -1163,17 +1149,22 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
|
||||
if (likely(sta)) {
|
||||
if (!IS_ERR(sta))
|
||||
tx->sta = sta;
|
||||
} else {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||
tx->sta = rcu_dereference(sdata->u.vlan.sta);
|
||||
if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
|
||||
if (!tx->sta && sdata->wdev.use_4addr)
|
||||
return TX_DROP;
|
||||
} else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
|
||||
IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
|
||||
} else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
|
||||
IEEE80211_TX_CTL_INJECTED) ||
|
||||
tx->sdata->control_port_protocol == tx->skb->protocol) {
|
||||
tx->sta = sta_info_get_bss(sdata, hdr->addr1);
|
||||
}
|
||||
if (!tx->sta)
|
||||
if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
|
||||
tx->sta = sta_info_get(sdata, hdr->addr1);
|
||||
}
|
||||
|
||||
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
|
||||
!ieee80211_is_qos_nullfunc(hdr->frame_control) &&
|
||||
|
@ -1421,8 +1412,9 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
|||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_data tx;
|
||||
struct sk_buff *skb2;
|
||||
|
||||
if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP)
|
||||
if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
|
||||
return false;
|
||||
|
||||
info->band = band;
|
||||
|
@ -1439,6 +1431,14 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
|||
*sta = NULL;
|
||||
}
|
||||
|
||||
/* this function isn't suitable for fragmented data frames */
|
||||
skb2 = __skb_dequeue(&tx.skbs);
|
||||
if (WARN_ON(skb2 != skb || !skb_queue_empty(&tx.skbs))) {
|
||||
ieee80211_free_txskb(hw, skb2);
|
||||
ieee80211_purge_tx_queue(hw, &tx.skbs);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
|
||||
|
@ -1447,7 +1447,8 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
|
|||
* Returns false if the frame couldn't be transmitted but was queued instead.
|
||||
*/
|
||||
static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, bool txpending)
|
||||
struct sta_info *sta, struct sk_buff *skb,
|
||||
bool txpending)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_data tx;
|
||||
|
@ -1463,7 +1464,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* initialises tx */
|
||||
led_len = skb->len;
|
||||
res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
|
||||
res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
|
||||
|
||||
if (unlikely(res_prepare == TX_DROP)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
|
@ -1519,7 +1520,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
@ -1554,7 +1556,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
ieee80211_set_qos_hdr(sdata, skb);
|
||||
ieee80211_tx(sdata, skb, false);
|
||||
ieee80211_tx(sdata, sta, skb, false);
|
||||
}
|
||||
|
||||
static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
|
||||
|
@ -1775,7 +1777,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
|||
goto fail_rcu;
|
||||
|
||||
info->band = chandef->chan->band;
|
||||
ieee80211_xmit(sdata, skb);
|
||||
ieee80211_xmit(sdata, NULL, skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
@ -1787,23 +1789,6 @@ fail:
|
|||
return NETDEV_TX_OK; /* meaning, we dealt with the skb */
|
||||
}
|
||||
|
||||
/*
|
||||
* Measure Tx frame arrival time for Tx latency statistics calculation
|
||||
* A single Tx frame latency should be measured from when it is entering the
|
||||
* Kernel until we receive Tx complete confirmation indication and the skb is
|
||||
* freed.
|
||||
*/
|
||||
static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_latency_bin_ranges *tx_latency;
|
||||
|
||||
tx_latency = rcu_dereference(local->tx_latency);
|
||||
if (!tx_latency)
|
||||
return;
|
||||
skb->tstamp = ktime_get();
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_build_hdr - build 802.11 header in the given frame
|
||||
* @sdata: virtual interface to build the header for
|
||||
|
@ -1823,7 +1808,8 @@ static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
|
|||
* Returns: the (possibly reallocated) skb or an ERR_PTR() code
|
||||
*/
|
||||
static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, u32 info_flags)
|
||||
struct sk_buff *skb, u32 info_flags,
|
||||
struct sta_info **sta_out)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info;
|
||||
|
@ -1840,6 +1826,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
bool wme_sta = false, authorized = false, tdls_auth = false;
|
||||
bool tdls_peer = false, tdls_setup_frame = false;
|
||||
bool multicast;
|
||||
bool have_station = false;
|
||||
u16 info_id = 0;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_sub_if_data *ap_sdata;
|
||||
|
@ -1864,6 +1851,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
hdrlen = 30;
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
have_station = true;
|
||||
*sta_out = sta;
|
||||
} else if (sdata->wdev.use_4addr) {
|
||||
ret = -ENOLINK;
|
||||
goto free;
|
||||
}
|
||||
ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
|
||||
u.ap);
|
||||
|
@ -1980,9 +1972,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
|
||||
sta = sta_info_get(sdata, skb->data);
|
||||
if (sta) {
|
||||
authorized = test_sta_flag(sta,
|
||||
WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
tdls_peer = test_sta_flag(sta,
|
||||
WLAN_STA_TDLS_PEER);
|
||||
tdls_auth = test_sta_flag(sta,
|
||||
|
@ -2014,6 +2003,10 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
have_station = true;
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
*sta_out = sta;
|
||||
} else if (sdata->u.mgd.use_4addr &&
|
||||
cpu_to_be16(ethertype) != sdata->control_port_protocol) {
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
|
||||
|
@ -2071,17 +2064,24 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
/*
|
||||
* There's no need to try to look up the destination
|
||||
* if it is a multicast address (which can only happen
|
||||
* in AP mode)
|
||||
* There's no need to try to look up the destination station
|
||||
* if it is a multicast address. In mesh, there's no need to
|
||||
* look up the station at all as it always must be QoS capable
|
||||
* and mesh mode checks authorization later.
|
||||
*/
|
||||
multicast = is_multicast_ether_addr(hdr.addr1);
|
||||
if (!multicast) {
|
||||
if (multicast) {
|
||||
*sta_out = ERR_PTR(-ENOENT);
|
||||
} else if (!have_station && !ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
if (sdata->control_port_protocol == skb->protocol)
|
||||
sta = sta_info_get_bss(sdata, hdr.addr1);
|
||||
else
|
||||
sta = sta_info_get(sdata, hdr.addr1);
|
||||
if (sta) {
|
||||
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
wme_sta = sta->sta.wme;
|
||||
}
|
||||
*sta_out = sta ?: ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
/* For mesh, the use of the QoS header is mandatory */
|
||||
|
@ -2259,7 +2259,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
u32 info_flags)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta = NULL;
|
||||
|
||||
if (unlikely(skb->len < ETH_HLEN)) {
|
||||
kfree_skb(skb);
|
||||
|
@ -2268,10 +2268,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Measure frame arrival for Tx latency statistics calculation */
|
||||
ieee80211_tx_latency_start_msrmnt(local, skb);
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags);
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
|
@ -2279,7 +2276,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
dev->stats.tx_bytes += skb->len;
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
ieee80211_xmit(sdata, skb);
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -2307,10 +2304,11 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
|
|||
.local = sdata->local,
|
||||
.sdata = sdata,
|
||||
};
|
||||
struct sta_info *sta_ignore;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags);
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta_ignore);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
|
@ -2368,7 +2366,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
|
|||
return true;
|
||||
}
|
||||
info->band = chanctx_conf->def.chan->band;
|
||||
result = ieee80211_tx(sdata, skb, true);
|
||||
result = ieee80211_tx(sdata, NULL, skb, true);
|
||||
} else {
|
||||
struct sk_buff_head skbs;
|
||||
|
||||
|
@ -3106,7 +3104,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
|
|||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
|
||||
if (!ieee80211_tx_prepare(sdata, &tx, skb))
|
||||
if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
|
||||
break;
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
@ -3238,6 +3236,6 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
local_bh_disable();
|
||||
IEEE80211_SKB_CB(skb)->band = band;
|
||||
ieee80211_xmit(sdata, skb);
|
||||
ieee80211_xmit(sdata, NULL, skb);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
|
|
@ -625,13 +625,14 @@ void ieee80211_wake_vif_queues(struct ieee80211_local *local,
|
|||
reason, true);
|
||||
}
|
||||
|
||||
static void __iterate_active_interfaces(struct ieee80211_local *local,
|
||||
static void __iterate_interfaces(struct ieee80211_local *local,
|
||||
u32 iter_flags,
|
||||
void (*iterator)(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif),
|
||||
void *data)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
switch (sdata->vif.type) {
|
||||
|
@ -645,9 +646,9 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
|
|||
break;
|
||||
}
|
||||
if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
|
||||
!(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
|
||||
active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
|
||||
continue;
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
if (ieee80211_sdata_running(sdata) || !active_only)
|
||||
iterator(data, sdata->vif.addr,
|
||||
&sdata->vif);
|
||||
}
|
||||
|
@ -656,12 +657,12 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
|
|||
lockdep_is_held(&local->iflist_mtx) ||
|
||||
lockdep_rtnl_is_held());
|
||||
if (sdata &&
|
||||
(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
|
||||
(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
|
||||
sdata->flags & IEEE80211_SDATA_IN_DRIVER))
|
||||
iterator(data, sdata->vif.addr, &sdata->vif);
|
||||
}
|
||||
|
||||
void ieee80211_iterate_active_interfaces(
|
||||
void ieee80211_iterate_interfaces(
|
||||
struct ieee80211_hw *hw, u32 iter_flags,
|
||||
void (*iterator)(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif),
|
||||
|
@ -670,10 +671,10 @@ void ieee80211_iterate_active_interfaces(
|
|||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
__iterate_active_interfaces(local, iter_flags, iterator, data);
|
||||
__iterate_interfaces(local, iter_flags, iterator, data);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
|
||||
EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces);
|
||||
|
||||
void ieee80211_iterate_active_interfaces_atomic(
|
||||
struct ieee80211_hw *hw, u32 iter_flags,
|
||||
|
@ -684,7 +685,8 @@ void ieee80211_iterate_active_interfaces_atomic(
|
|||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
rcu_read_lock();
|
||||
__iterate_active_interfaces(local, iter_flags, iterator, data);
|
||||
__iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
|
||||
iterator, data);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
|
||||
|
@ -699,7 +701,8 @@ void ieee80211_iterate_active_interfaces_rtnl(
|
|||
|
||||
ASSERT_RTNL();
|
||||
|
||||
__iterate_active_interfaces(local, iter_flags, iterator, data);
|
||||
__iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
|
||||
iterator, data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
|
||||
|
||||
|
@ -742,6 +745,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
|
||||
|
||||
struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
|
||||
if (!ieee80211_sdata_running(sdata) ||
|
||||
!(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
|
||||
return NULL;
|
||||
|
||||
return &sdata->wdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev);
|
||||
|
||||
/*
|
||||
* Nothing should have been stuffed into the workqueue during
|
||||
* the suspend->resume cycle. Since we can't check each caller
|
||||
|
@ -1811,8 +1826,25 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
ieee80211_sdata_running(sdata))
|
||||
ieee80211_sdata_running(sdata)) {
|
||||
res = drv_add_interface(local, sdata);
|
||||
if (WARN_ON(res))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If adding any of the interfaces failed above, roll back and
|
||||
* report failure.
|
||||
*/
|
||||
if (res) {
|
||||
list_for_each_entry_continue_reverse(sdata, &local->interfaces,
|
||||
list)
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
ieee80211_sdata_running(sdata))
|
||||
drv_remove_interface(local, sdata);
|
||||
ieee80211_handle_reconfig_failure(local);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* add channel contexts */
|
||||
|
@ -2344,6 +2376,41 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
|||
return pos + sizeof(struct ieee80211_ht_operation);
|
||||
}
|
||||
|
||||
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
const struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_vht_operation *vht_oper;
|
||||
|
||||
*pos++ = WLAN_EID_VHT_OPERATION;
|
||||
*pos++ = sizeof(struct ieee80211_vht_operation);
|
||||
vht_oper = (struct ieee80211_vht_operation *)pos;
|
||||
vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(
|
||||
chandef->center_freq1);
|
||||
if (chandef->center_freq2)
|
||||
vht_oper->center_freq_seg2_idx =
|
||||
ieee80211_frequency_to_channel(chandef->center_freq2);
|
||||
|
||||
switch (chandef->width) {
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
||||
break;
|
||||
default:
|
||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* don't require special VHT peer rates */
|
||||
vht_oper->basic_mcs_set = cpu_to_le16(0xffff);
|
||||
|
||||
return pos + sizeof(struct ieee80211_vht_operation);
|
||||
}
|
||||
|
||||
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
||||
const struct ieee80211_ht_operation *ht_oper,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
|
|
|
@ -129,10 +129,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
|||
if (!vht_cap_ie || !sband->vht_cap.vht_supported)
|
||||
return;
|
||||
|
||||
/* don't support VHT for TDLS peers for now */
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
|
||||
return;
|
||||
|
||||
/*
|
||||
* A VHT STA must support 40 MHz, but if we verify that here
|
||||
* then we break a few things - some APs (e.g. Netgear R6300v2
|
||||
|
|
|
@ -780,9 +780,8 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
|
|||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_key *key = tx->key;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme;
|
||||
int hdrlen;
|
||||
u8 *pos;
|
||||
u8 *pos, iv_len = key->conf.iv_len;
|
||||
|
||||
if (info->control.hw_key &&
|
||||
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
|
||||
|
@ -790,14 +789,14 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
|
|||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
if (unlikely(skb_headroom(skb) < cs->hdr_len &&
|
||||
pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC)))
|
||||
if (unlikely(skb_headroom(skb) < iv_len &&
|
||||
pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC)))
|
||||
return TX_DROP;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
pos = skb_push(skb, cs->hdr_len);
|
||||
memmove(pos, pos + cs->hdr_len, hdrlen);
|
||||
pos = skb_push(skb, iv_len);
|
||||
memmove(pos, pos + iv_len, hdrlen);
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
@ -1217,7 +1216,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
|
|||
if (!info->control.hw_key)
|
||||
return TX_DROP;
|
||||
|
||||
if (tx->key->sta->cipher_scheme) {
|
||||
if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) {
|
||||
res = ieee80211_crypto_cs_encrypt(tx, skb);
|
||||
if (res != TX_CONTINUE)
|
||||
return res;
|
||||
|
|
|
@ -178,10 +178,18 @@ config CFG80211_WEXT
|
|||
bool "cfg80211 wireless extensions compatibility"
|
||||
depends on CFG80211
|
||||
select WEXT_CORE
|
||||
default y if CFG80211_WEXT_EXPORT
|
||||
help
|
||||
Enable this option if you need old userspace for wireless
|
||||
extensions with cfg80211-based drivers.
|
||||
|
||||
config CFG80211_WEXT_EXPORT
|
||||
bool
|
||||
depends on CFG80211
|
||||
help
|
||||
Drivers should select this option if they require cfg80211's
|
||||
wext compatibility symbols to be exported.
|
||||
|
||||
config LIB80211
|
||||
tristate
|
||||
default n
|
||||
|
|
|
@ -30,7 +30,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
|
|||
return;
|
||||
|
||||
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
|
||||
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
|
||||
IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
|
||||
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
|
|
|
@ -229,7 +229,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
|||
return -EALREADY;
|
||||
|
||||
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (!req.bss)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -296,7 +297,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
|||
rdev->wiphy.vht_capa_mod_mask);
|
||||
|
||||
req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (!req->bss)
|
||||
return -ENOENT;
|
||||
|
||||
|
|
|
@ -399,6 +399,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
@ -4958,7 +4959,10 @@ static int parse_reg_rule(struct nlattr *tb[],
|
|||
static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
char *data = NULL;
|
||||
bool is_indoor;
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type;
|
||||
u32 owner_nlportid;
|
||||
|
||||
|
||||
/*
|
||||
* You should only get this when cfg80211 hasn't yet initialized
|
||||
|
@ -4984,7 +4988,15 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
|||
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
|
||||
return regulatory_hint_user(data, user_reg_hint_type);
|
||||
case NL80211_USER_REG_HINT_INDOOR:
|
||||
return regulatory_hint_indoor_user();
|
||||
if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
|
||||
owner_nlportid = info->snd_portid;
|
||||
is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
|
||||
} else {
|
||||
owner_nlportid = 0;
|
||||
is_indoor = true;
|
||||
}
|
||||
|
||||
return regulatory_hint_indoor(is_indoor, owner_nlportid);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -5265,7 +5277,7 @@ do { \
|
|||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
|
||||
0, 65535, mask,
|
||||
NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff,
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
|
||||
mask, NL80211_MESHCONF_PLINK_TIMEOUT,
|
||||
nla_get_u32);
|
||||
if (mask_out)
|
||||
|
@ -7265,7 +7277,17 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
|||
break;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
|
||||
if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
|
||||
return -EINVAL;
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_VHT_IBSS))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -7379,8 +7401,8 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
static struct sk_buff *
|
||||
__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
||||
int approxlen, u32 portid, u32 seq,
|
||||
enum nl80211_commands cmd,
|
||||
struct wireless_dev *wdev, int approxlen,
|
||||
u32 portid, u32 seq, enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
const struct nl80211_vendor_cmd_info *info,
|
||||
gfp_t gfp)
|
||||
|
@ -7411,6 +7433,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
|||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
if (wdev) {
|
||||
if (nla_put_u64(skb, NL80211_ATTR_WDEV,
|
||||
wdev_id(wdev)))
|
||||
goto nla_put_failure;
|
||||
if (wdev->netdev &&
|
||||
nla_put_u32(skb, NL80211_ATTR_IFINDEX,
|
||||
wdev->netdev->ifindex))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
data = nla_nest_start(skb, attr);
|
||||
|
||||
((void **)skb->cb)[0] = rdev;
|
||||
|
@ -7425,6 +7457,7 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
|
||||
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
int vendor_event_idx,
|
||||
|
@ -7450,7 +7483,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
|
||||
return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
|
||||
cmd, attr, info, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
|
||||
|
@ -9084,6 +9117,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|||
const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
|
||||
int err, i;
|
||||
bool prev_enabled = rdev->wiphy.wowlan_config;
|
||||
bool regular = false;
|
||||
|
||||
if (!wowlan)
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -9111,12 +9145,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
|
||||
return -EINVAL;
|
||||
new_triggers.disconnect = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
|
||||
return -EINVAL;
|
||||
new_triggers.magic_pkt = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
|
||||
|
@ -9126,24 +9162,28 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
|
||||
return -EINVAL;
|
||||
new_triggers.gtk_rekey_failure = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
|
||||
return -EINVAL;
|
||||
new_triggers.eap_identity_req = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
|
||||
return -EINVAL;
|
||||
new_triggers.four_way_handshake = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
|
||||
return -EINVAL;
|
||||
new_triggers.rfkill_release = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
|
||||
|
@ -9152,6 +9192,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|||
int rem, pat_len, mask_len, pkt_offset;
|
||||
struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
|
||||
|
||||
regular = true;
|
||||
|
||||
nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
|
||||
rem)
|
||||
n_patterns++;
|
||||
|
@ -9213,6 +9255,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
|
||||
regular = true;
|
||||
err = nl80211_parse_wowlan_tcp(
|
||||
rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
|
||||
&new_triggers);
|
||||
|
@ -9221,6 +9264,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
|
||||
regular = true;
|
||||
err = nl80211_parse_wowlan_nd(
|
||||
rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
|
||||
&new_triggers);
|
||||
|
@ -9228,6 +9272,17 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* The 'any' trigger means the device continues operating more or less
|
||||
* as in its normal operation mode and wakes up the host on most of the
|
||||
* normal interrupts (like packet RX, ...)
|
||||
* It therefore makes little sense to combine with the more constrained
|
||||
* wakeup trigger modes.
|
||||
*/
|
||||
if (new_triggers.any && regular) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
|
||||
if (!ntrig) {
|
||||
err = -ENOMEM;
|
||||
|
@ -9896,7 +9951,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
|
|||
if (WARN_ON(!rdev->cur_cmd_info))
|
||||
return NULL;
|
||||
|
||||
return __cfg80211_alloc_vendor_skb(rdev, approxlen,
|
||||
return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
|
||||
rdev->cur_cmd_info->snd_portid,
|
||||
rdev->cur_cmd_info->snd_seq,
|
||||
cmd, attr, NULL, GFP_KERNEL);
|
||||
|
@ -12767,6 +12822,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|||
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* It is possible that the user space process that is controlling the
|
||||
* indoor setting disappeared, so notify the regulatory core.
|
||||
*/
|
||||
regulatory_netlink_notify(notify->portid);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,17 +82,12 @@
|
|||
* be intersected with the current one.
|
||||
* @REG_REQ_ALREADY_SET: the regulatory request will not change the current
|
||||
* regulatory settings, and no further processing is required.
|
||||
* @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
|
||||
* further processing is required, i.e., not need to update last_request
|
||||
* etc. This should be used for user hints that do not provide an alpha2
|
||||
* but some other type of regulatory hint, i.e., indoor operation.
|
||||
*/
|
||||
enum reg_request_treatment {
|
||||
REG_REQ_OK,
|
||||
REG_REQ_IGNORE,
|
||||
REG_REQ_INTERSECT,
|
||||
REG_REQ_ALREADY_SET,
|
||||
REG_REQ_USER_HINT_HANDLED,
|
||||
};
|
||||
|
||||
static struct regulatory_request core_request_world = {
|
||||
|
@ -133,9 +128,12 @@ static int reg_num_devs_support_basehint;
|
|||
* State variable indicating if the platform on which the devices
|
||||
* are attached is operating in an indoor environment. The state variable
|
||||
* is relevant for all registered devices.
|
||||
* (protected by RTNL)
|
||||
*/
|
||||
static bool reg_is_indoor;
|
||||
static spinlock_t reg_indoor_lock;
|
||||
|
||||
/* Used to track the userspace process controlling the indoor setting */
|
||||
static u32 reg_is_indoor_portid;
|
||||
|
||||
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
|
||||
{
|
||||
|
@ -554,6 +552,9 @@ reg_call_crda(struct regulatory_request *request)
|
|||
{
|
||||
if (call_crda(request->alpha2))
|
||||
return REG_REQ_IGNORE;
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
®_timeout, msecs_to_jiffies(3142));
|
||||
return REG_REQ_OK;
|
||||
}
|
||||
|
||||
|
@ -1248,13 +1249,6 @@ static bool reg_request_cell_base(struct regulatory_request *request)
|
|||
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
|
||||
}
|
||||
|
||||
static bool reg_request_indoor(struct regulatory_request *request)
|
||||
{
|
||||
if (request->initiator != NL80211_REGDOM_SET_BY_USER)
|
||||
return false;
|
||||
return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
|
||||
}
|
||||
|
||||
bool reg_last_request_cell_base(void)
|
||||
{
|
||||
return reg_request_cell_base(get_last_request());
|
||||
|
@ -1800,7 +1794,6 @@ static void reg_set_request_processed(void)
|
|||
need_more_processing = true;
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
|
||||
cancel_delayed_work(®_timeout);
|
||||
|
||||
if (need_more_processing)
|
||||
|
@ -1833,11 +1826,6 @@ __reg_process_hint_user(struct regulatory_request *user_request)
|
|||
{
|
||||
struct regulatory_request *lr = get_last_request();
|
||||
|
||||
if (reg_request_indoor(user_request)) {
|
||||
reg_is_indoor = true;
|
||||
return REG_REQ_USER_HINT_HANDLED;
|
||||
}
|
||||
|
||||
if (reg_request_cell_base(user_request))
|
||||
return reg_ignore_cell_hint(user_request);
|
||||
|
||||
|
@ -1885,8 +1873,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
|
|||
|
||||
treatment = __reg_process_hint_user(user_request);
|
||||
if (treatment == REG_REQ_IGNORE ||
|
||||
treatment == REG_REQ_ALREADY_SET ||
|
||||
treatment == REG_REQ_USER_HINT_HANDLED) {
|
||||
treatment == REG_REQ_ALREADY_SET) {
|
||||
reg_free_request(user_request);
|
||||
return treatment;
|
||||
}
|
||||
|
@ -1947,7 +1934,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
|
|||
case REG_REQ_OK:
|
||||
break;
|
||||
case REG_REQ_IGNORE:
|
||||
case REG_REQ_USER_HINT_HANDLED:
|
||||
reg_free_request(driver_request);
|
||||
return treatment;
|
||||
case REG_REQ_INTERSECT:
|
||||
|
@ -2047,7 +2033,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
|
|||
case REG_REQ_OK:
|
||||
break;
|
||||
case REG_REQ_IGNORE:
|
||||
case REG_REQ_USER_HINT_HANDLED:
|
||||
/* fall through */
|
||||
case REG_REQ_ALREADY_SET:
|
||||
reg_free_request(country_ie_request);
|
||||
|
@ -2086,11 +2071,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
|||
case NL80211_REGDOM_SET_BY_USER:
|
||||
treatment = reg_process_hint_user(reg_request);
|
||||
if (treatment == REG_REQ_IGNORE ||
|
||||
treatment == REG_REQ_ALREADY_SET ||
|
||||
treatment == REG_REQ_USER_HINT_HANDLED)
|
||||
treatment == REG_REQ_ALREADY_SET)
|
||||
return;
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
®_timeout, msecs_to_jiffies(3142));
|
||||
return;
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
if (!wiphy)
|
||||
|
@ -2177,6 +2159,13 @@ static void reg_process_pending_hints(void)
|
|||
}
|
||||
|
||||
reg_process_hint(reg_request);
|
||||
|
||||
lr = get_last_request();
|
||||
|
||||
spin_lock(®_requests_lock);
|
||||
if (!list_empty(®_requests_list) && lr && lr->processed)
|
||||
schedule_work(®_work);
|
||||
spin_unlock(®_requests_lock);
|
||||
}
|
||||
|
||||
/* Processes beacon hints -- this has nothing to do with country IEs */
|
||||
|
@ -2309,22 +2298,50 @@ int regulatory_hint_user(const char *alpha2,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int regulatory_hint_indoor_user(void)
|
||||
int regulatory_hint_indoor(bool is_indoor, u32 portid)
|
||||
{
|
||||
struct regulatory_request *request;
|
||||
spin_lock(®_indoor_lock);
|
||||
|
||||
request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
|
||||
if (!request)
|
||||
return -ENOMEM;
|
||||
/* It is possible that more than one user space process is trying to
|
||||
* configure the indoor setting. To handle such cases, clear the indoor
|
||||
* setting in case that some process does not think that the device
|
||||
* is operating in an indoor environment. In addition, if a user space
|
||||
* process indicates that it is controlling the indoor setting, save its
|
||||
* portid, i.e., make it the owner.
|
||||
*/
|
||||
reg_is_indoor = is_indoor;
|
||||
if (reg_is_indoor) {
|
||||
if (!reg_is_indoor_portid)
|
||||
reg_is_indoor_portid = portid;
|
||||
} else {
|
||||
reg_is_indoor_portid = 0;
|
||||
}
|
||||
|
||||
request->wiphy_idx = WIPHY_IDX_INVALID;
|
||||
request->initiator = NL80211_REGDOM_SET_BY_USER;
|
||||
request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
|
||||
queue_regulatory_request(request);
|
||||
spin_unlock(®_indoor_lock);
|
||||
|
||||
if (!is_indoor)
|
||||
reg_check_channels();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void regulatory_netlink_notify(u32 portid)
|
||||
{
|
||||
spin_lock(®_indoor_lock);
|
||||
|
||||
if (reg_is_indoor_portid != portid) {
|
||||
spin_unlock(®_indoor_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
reg_is_indoor = false;
|
||||
reg_is_indoor_portid = 0;
|
||||
|
||||
spin_unlock(®_indoor_lock);
|
||||
|
||||
reg_check_channels();
|
||||
}
|
||||
|
||||
/* Driver hints */
|
||||
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
|
||||
{
|
||||
|
@ -2486,13 +2503,22 @@ static void restore_regulatory_settings(bool reset_user)
|
|||
char alpha2[2];
|
||||
char world_alpha2[2];
|
||||
struct reg_beacon *reg_beacon, *btmp;
|
||||
struct regulatory_request *reg_request, *tmp;
|
||||
LIST_HEAD(tmp_reg_req_list);
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
/*
|
||||
* Clear the indoor setting in case that it is not controlled by user
|
||||
* space, as otherwise there is no guarantee that the device is still
|
||||
* operating in an indoor environment.
|
||||
*/
|
||||
spin_lock(®_indoor_lock);
|
||||
if (reg_is_indoor && !reg_is_indoor_portid) {
|
||||
reg_is_indoor = false;
|
||||
reg_check_channels();
|
||||
}
|
||||
spin_unlock(®_indoor_lock);
|
||||
|
||||
reset_regdomains(true, &world_regdom);
|
||||
restore_alpha2(alpha2, reset_user);
|
||||
|
@ -2504,11 +2530,7 @@ static void restore_regulatory_settings(bool reset_user)
|
|||
* settings.
|
||||
*/
|
||||
spin_lock(®_requests_lock);
|
||||
list_for_each_entry_safe(reg_request, tmp, ®_requests_list, list) {
|
||||
if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER)
|
||||
continue;
|
||||
list_move_tail(®_request->list, &tmp_reg_req_list);
|
||||
}
|
||||
list_splice_tail_init(®_requests_list, &tmp_reg_req_list);
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
/* Clear beacon hints */
|
||||
|
@ -3089,6 +3111,7 @@ int __init regulatory_init(void)
|
|||
|
||||
spin_lock_init(®_requests_lock);
|
||||
spin_lock_init(®_pending_beacons_lock);
|
||||
spin_lock_init(®_indoor_lock);
|
||||
|
||||
reg_regdb_size_check();
|
||||
|
||||
|
|
|
@ -25,7 +25,20 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
|
|||
|
||||
int regulatory_hint_user(const char *alpha2,
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type);
|
||||
int regulatory_hint_indoor_user(void);
|
||||
|
||||
/**
|
||||
* regulatory_hint_indoor - hint operation in indoor env. or not
|
||||
* @is_indoor: if true indicates that user space thinks that the
|
||||
* device is operating in an indoor environment.
|
||||
* @portid: the netlink port ID on which the hint was given.
|
||||
*/
|
||||
int regulatory_hint_indoor(bool is_indoor, u32 portid);
|
||||
|
||||
/**
|
||||
* regulatory_netlink_notify - notify on released netlink socket
|
||||
* @portid: the netlink socket port ID
|
||||
*/
|
||||
void regulatory_netlink_notify(u32 portid);
|
||||
|
||||
void wiphy_regulatory_register(struct wiphy *wiphy);
|
||||
void wiphy_regulatory_deregister(struct wiphy *wiphy);
|
||||
|
|
|
@ -531,24 +531,78 @@ static int cmp_bss(struct cfg80211_bss *a,
|
|||
}
|
||||
}
|
||||
|
||||
static bool cfg80211_bss_type_match(u16 capability,
|
||||
enum ieee80211_band band,
|
||||
enum ieee80211_bss_type bss_type)
|
||||
{
|
||||
bool ret = true;
|
||||
u16 mask, val;
|
||||
|
||||
if (bss_type == IEEE80211_BSS_TYPE_ANY)
|
||||
return ret;
|
||||
|
||||
if (band == IEEE80211_BAND_60GHZ) {
|
||||
mask = WLAN_CAPABILITY_DMG_TYPE_MASK;
|
||||
switch (bss_type) {
|
||||
case IEEE80211_BSS_TYPE_ESS:
|
||||
val = WLAN_CAPABILITY_DMG_TYPE_AP;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_PBSS:
|
||||
val = WLAN_CAPABILITY_DMG_TYPE_PBSS;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_IBSS:
|
||||
val = WLAN_CAPABILITY_DMG_TYPE_IBSS;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
mask = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS;
|
||||
switch (bss_type) {
|
||||
case IEEE80211_BSS_TYPE_ESS:
|
||||
val = WLAN_CAPABILITY_ESS;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_IBSS:
|
||||
val = WLAN_CAPABILITY_IBSS;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_MBSS:
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ((capability & mask) == val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
u16 capa_mask, u16 capa_val)
|
||||
enum ieee80211_bss_type bss_type,
|
||||
enum ieee80211_privacy privacy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_internal_bss *bss, *res = NULL;
|
||||
unsigned long now = jiffies;
|
||||
int bss_privacy;
|
||||
|
||||
trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
|
||||
capa_val);
|
||||
trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, bss_type,
|
||||
privacy);
|
||||
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
|
||||
list_for_each_entry(bss, &rdev->bss_list, list) {
|
||||
if ((bss->pub.capability & capa_mask) != capa_val)
|
||||
if (!cfg80211_bss_type_match(bss->pub.capability,
|
||||
bss->pub.channel->band, bss_type))
|
||||
continue;
|
||||
|
||||
bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY);
|
||||
if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) ||
|
||||
(privacy == IEEE80211_PRIVACY_OFF && bss_privacy))
|
||||
continue;
|
||||
if (channel && bss->pub.channel != channel)
|
||||
continue;
|
||||
|
@ -896,6 +950,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
|
|||
struct cfg80211_bss_ies *ies;
|
||||
struct ieee80211_channel *channel;
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
int bss_type;
|
||||
bool signal_valid;
|
||||
|
||||
if (WARN_ON(!wiphy))
|
||||
|
@ -950,8 +1005,15 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
|
|||
if (!res)
|
||||
return NULL;
|
||||
|
||||
if (channel->band == IEEE80211_BAND_60GHZ) {
|
||||
bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
|
||||
if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
|
||||
bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
} else {
|
||||
if (res->pub.capability & WLAN_CAPABILITY_ESS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
/* cfg80211_bss_update gives us a referenced result */
|
||||
|
@ -973,6 +1035,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
|||
bool signal_valid;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
int bss_type;
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
|
||||
offsetof(struct ieee80211_mgmt, u.beacon.variable));
|
||||
|
@ -1025,8 +1088,15 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
|||
if (!res)
|
||||
return NULL;
|
||||
|
||||
if (channel->band == IEEE80211_BAND_60GHZ) {
|
||||
bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
|
||||
if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
|
||||
bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
} else {
|
||||
if (res->pub.capability & WLAN_CAPABILITY_ESS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
/* cfg80211_bss_update gives us a referenced result */
|
||||
|
@ -1237,17 +1307,17 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
|||
kfree(creq);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
|
||||
|
||||
static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
static char *ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
const struct cfg80211_bss_ies *ies,
|
||||
char **current_ev, char *end_buf)
|
||||
char *current_ev, char *end_buf)
|
||||
{
|
||||
const u8 *pos, *end, *next;
|
||||
struct iw_event iwe;
|
||||
|
||||
if (!ies)
|
||||
return;
|
||||
return current_ev;
|
||||
|
||||
/*
|
||||
* If needed, fragment the IEs buffer (at IE boundaries) into short
|
||||
|
@ -1264,10 +1334,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
|||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = next - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
pos = next;
|
||||
}
|
||||
|
||||
|
@ -1275,10 +1346,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
|||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = end - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -1289,7 +1364,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
const struct cfg80211_bss_ies *ies;
|
||||
struct iw_event iwe;
|
||||
const u8 *ie;
|
||||
u8 *buf, *cfg, *p;
|
||||
u8 buf[50];
|
||||
u8 *cfg, *p, *tmp;
|
||||
int rem, i, sig;
|
||||
bool ismesh = false;
|
||||
|
||||
|
@ -1297,22 +1373,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
|
||||
iwe.u.freq.e = 0;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = bss->pub.channel->center_freq;
|
||||
iwe.u.freq.e = 6;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -1341,8 +1423,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
/* not reached */
|
||||
break;
|
||||
}
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
IW_EV_QUAL_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
|
@ -1352,8 +1437,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
|
||||
&iwe, "");
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(bss->pub.ies);
|
||||
|
@ -1371,66 +1458,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = ie[1];
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, (u8 *)ie + 2);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf, &iwe,
|
||||
(u8 *)ie + 2);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_MESH_ID:
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = ie[1];
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, (u8 *)ie + 2);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf, &iwe,
|
||||
(u8 *)ie + 2);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_MESH_CONFIG:
|
||||
ismesh = true;
|
||||
if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
|
||||
break;
|
||||
buf = kmalloc(50, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
break;
|
||||
cfg = (u8 *)ie + 2;
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "Mesh Network Path Selection Protocol ID: "
|
||||
"0x%02X", cfg[0]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Path Selection Metric ID: 0x%02X",
|
||||
cfg[1]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Congestion Control Mode ID: 0x%02X",
|
||||
cfg[2]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
kfree(buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_SUPP_RATES:
|
||||
case WLAN_EID_EXT_SUPP_RATES:
|
||||
|
@ -1445,8 +1557,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
for (i = 0; i < ie[1]; i++) {
|
||||
iwe.u.bitrate.value =
|
||||
((ie[i + 2] & 0x7f) * 500000);
|
||||
tmp = p;
|
||||
p = iwe_stream_add_value(info, current_ev, p,
|
||||
end_buf, &iwe, IW_EV_PARAM_LEN);
|
||||
end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
if (p == tmp) {
|
||||
current_ev = ERR_PTR(-E2BIG);
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
current_ev = p;
|
||||
break;
|
||||
|
@ -1465,31 +1583,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
|||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
IW_EV_UINT_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
buf = kmalloc(31, GFP_ATOMIC);
|
||||
if (buf) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
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,
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, " Last beacon: %ums ago",
|
||||
elapsed_jiffies_msecs(bss->ts));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
|
||||
ieee80211_scan_add_ies(info, ies, ¤t_ev, end_buf);
|
||||
current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
|
@ -1501,19 +1623,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
|
|||
char *current_ev = buf;
|
||||
char *end_buf = buf + len;
|
||||
struct cfg80211_internal_bss *bss;
|
||||
int err = 0;
|
||||
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
cfg80211_bss_expire(rdev);
|
||||
|
||||
list_for_each_entry(bss, &rdev->bss_list, list) {
|
||||
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
return -E2BIG;
|
||||
err = -E2BIG;
|
||||
break;
|
||||
}
|
||||
current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
|
||||
current_ev, end_buf);
|
||||
if (IS_ERR(current_ev)) {
|
||||
err = PTR_ERR(current_ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
return current_ev - buf;
|
||||
}
|
||||
|
||||
|
@ -1545,5 +1675,5 @@ int cfg80211_wext_giwscan(struct net_device *dev,
|
|||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwscan);
|
||||
#endif
|
||||
|
|
|
@ -257,19 +257,15 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
|
|||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_bss *bss;
|
||||
u16 capa = WLAN_CAPABILITY_ESS;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->conn->params.privacy)
|
||||
capa |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
|
||||
wdev->conn->params.bssid,
|
||||
wdev->conn->params.ssid,
|
||||
wdev->conn->params.ssid_len,
|
||||
WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
|
||||
capa);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY(wdev->conn->params.privacy));
|
||||
if (!bss)
|
||||
return NULL;
|
||||
|
||||
|
@ -637,8 +633,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
|
||||
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||||
wdev->ssid, wdev->ssid_len,
|
||||
WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (bss)
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
}
|
||||
|
@ -795,8 +791,8 @@ void cfg80211_roamed(struct net_device *dev,
|
|||
struct cfg80211_bss *bss;
|
||||
|
||||
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
|
||||
wdev->ssid_len, WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
wdev->ssid_len,
|
||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
|
||||
|
|
|
@ -627,6 +627,7 @@ DECLARE_EVENT_CLASS(station_add_change,
|
|||
__field(u8, plink_state)
|
||||
__field(u8, uapsd_queues)
|
||||
__array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap))
|
||||
__array(char, vlan, IFNAMSIZ)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
|
@ -644,16 +645,19 @@ DECLARE_EVENT_CLASS(station_add_change,
|
|||
if (params->ht_capa)
|
||||
memcpy(__entry->ht_capa, params->ht_capa,
|
||||
sizeof(struct ieee80211_ht_cap));
|
||||
memset(__entry->vlan, 0, sizeof(__entry->vlan));
|
||||
if (params->vlan)
|
||||
memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
|
||||
", station flags mask: %u, station flags set: %u, "
|
||||
"station modify mask: %u, listen interval: %d, aid: %u, "
|
||||
"plink action: %u, plink state: %u, uapsd queues: %u",
|
||||
"plink action: %u, plink state: %u, uapsd queues: %u, vlan:%s",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
|
||||
__entry->sta_flags_mask, __entry->sta_flags_set,
|
||||
__entry->sta_modify_mask, __entry->listen_interval,
|
||||
__entry->aid, __entry->plink_action, __entry->plink_state,
|
||||
__entry->uapsd_queues)
|
||||
__entry->uapsd_queues, __entry->vlan)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(station_add_change, rdev_add_station,
|
||||
|
@ -2636,28 +2640,30 @@ DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_stopped,
|
|||
TRACE_EVENT(cfg80211_get_bss,
|
||||
TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
|
||||
const u8 *bssid, const u8 *ssid, size_t ssid_len,
|
||||
u16 capa_mask, u16 capa_val),
|
||||
TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val),
|
||||
enum ieee80211_bss_type bss_type,
|
||||
enum ieee80211_privacy privacy),
|
||||
TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, bss_type, privacy),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
CHAN_ENTRY
|
||||
MAC_ENTRY(bssid)
|
||||
__dynamic_array(u8, ssid, ssid_len)
|
||||
__field(u16, capa_mask)
|
||||
__field(u16, capa_val)
|
||||
__field(enum ieee80211_bss_type, bss_type)
|
||||
__field(enum ieee80211_privacy, privacy)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
CHAN_ASSIGN(channel);
|
||||
MAC_ASSIGN(bssid, bssid);
|
||||
memcpy(__get_dynamic_array(ssid), ssid, ssid_len);
|
||||
__entry->capa_mask = capa_mask;
|
||||
__entry->capa_val = capa_val;
|
||||
__entry->bss_type = bss_type;
|
||||
__entry->privacy = privacy;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, "
|
||||
"capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG,
|
||||
MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0],
|
||||
__entry->capa_mask, __entry->capa_val)
|
||||
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT
|
||||
", buf: %#.2x, bss_type: %d, privacy: %d",
|
||||
WIPHY_PR_ARG, CHAN_PR_ARG, MAC_PR_ARG(bssid),
|
||||
((u8 *)__get_dynamic_array(ssid))[0], __entry->bss_type,
|
||||
__entry->privacy)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_inform_bss_width_frame,
|
||||
|
|
|
@ -1296,6 +1296,7 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
|
|||
switch (operating_class) {
|
||||
case 112:
|
||||
case 115 ... 127:
|
||||
case 128 ... 130:
|
||||
*band = IEEE80211_BAND_5GHZ;
|
||||
return true;
|
||||
case 81:
|
||||
|
|
|
@ -63,7 +63,7 @@ int cfg80211_wext_giwname(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwname);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwname);
|
||||
|
||||
int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
u32 *mode, char *extra)
|
||||
|
@ -99,7 +99,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
|
|||
|
||||
return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode);
|
||||
|
||||
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
u32 *mode, char *extra)
|
||||
|
@ -134,7 +134,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwmode);
|
||||
|
||||
|
||||
int cfg80211_wext_giwrange(struct net_device *dev,
|
||||
|
@ -248,7 +248,7 @@ int cfg80211_wext_giwrange(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwrange);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -303,7 +303,7 @@ int cfg80211_wext_siwrts(struct net_device *dev,
|
|||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts);
|
||||
|
||||
int cfg80211_wext_giwrts(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
|
@ -317,7 +317,7 @@ int cfg80211_wext_giwrts(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwrts);
|
||||
|
||||
int cfg80211_wext_siwfrag(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
|
@ -343,7 +343,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev,
|
|||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwfrag);
|
||||
|
||||
int cfg80211_wext_giwfrag(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
|
@ -357,7 +357,7 @@ int cfg80211_wext_giwfrag(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwfrag);
|
||||
|
||||
static int cfg80211_wext_siwretry(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
|
@ -427,7 +427,7 @@ int cfg80211_wext_giwretry(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwretry);
|
||||
|
||||
static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, bool pairwise,
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
#include <net/iw_handler.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#ifdef CONFIG_CFG80211_WEXT_EXPORT
|
||||
#define EXPORT_WEXT_HANDLER(h) EXPORT_SYMBOL_GPL(h)
|
||||
#else
|
||||
#define EXPORT_WEXT_HANDLER(h)
|
||||
#endif /* CONFIG_CFG80211_WEXT_EXPORT */
|
||||
|
||||
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_freq *freq, char *extra);
|
||||
|
|
Loading…
Reference in New Issue