You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'mac80211-next-for-davem-2016-06-09' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says: ==================== For the next cycle, we have the following: * the biggest change is Michał's work on integrating FQ/codel with the mac80211 internal software queues * cfg80211 connect result gets clarified for the "no connection at all" case * advertisement of per-interface type capabilities, in case they differ (which makes a lot of sense for some capabilities) * most of the nl80211 & hwsim unprivileged namespace operation changes * human-readable VHT capabilities in debugfs * some other cleanups, like spelling ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -136,6 +136,7 @@
|
||||
!Finclude/net/cfg80211.h cfg80211_ibss_joined
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_result
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_bss
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_timeout
|
||||
!Finclude/net/cfg80211.h cfg80211_roamed
|
||||
!Finclude/net/cfg80211.h cfg80211_disconnected
|
||||
!Finclude/net/cfg80211.h cfg80211_ready_on_channel
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
#include "mac80211_hwsim.h"
|
||||
|
||||
#define WARN_QUEUE 100
|
||||
@@ -250,6 +252,28 @@ static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c)
|
||||
cp->magic = 0;
|
||||
}
|
||||
|
||||
static unsigned int hwsim_net_id;
|
||||
|
||||
static int hwsim_netgroup;
|
||||
|
||||
struct hwsim_net {
|
||||
int netgroup;
|
||||
};
|
||||
|
||||
static inline int hwsim_net_get_netgroup(struct net *net)
|
||||
{
|
||||
struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
|
||||
|
||||
return hwsim_net->netgroup;
|
||||
}
|
||||
|
||||
static inline void hwsim_net_set_netgroup(struct net *net)
|
||||
{
|
||||
struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
|
||||
|
||||
hwsim_net->netgroup = hwsim_netgroup++;
|
||||
}
|
||||
|
||||
static struct class *hwsim_class;
|
||||
|
||||
static struct net_device *hwsim_mon; /* global monitor netdev */
|
||||
@@ -526,6 +550,9 @@ struct mac80211_hwsim_data {
|
||||
*/
|
||||
u64 group;
|
||||
|
||||
/* group shared by radios created in the same netns */
|
||||
int netgroup;
|
||||
|
||||
int power_level;
|
||||
|
||||
/* difference between this hw's clock and the real clock, in usecs */
|
||||
@@ -568,6 +595,7 @@ static struct genl_family hwsim_genl_family = {
|
||||
.name = "MAC80211_HWSIM",
|
||||
.version = 1,
|
||||
.maxattr = HWSIM_ATTR_MAX,
|
||||
.netnsok = true,
|
||||
};
|
||||
|
||||
enum hwsim_multicast_groups {
|
||||
@@ -1202,6 +1230,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
|
||||
if (!(data->group & data2->group))
|
||||
continue;
|
||||
|
||||
if (data->netgroup != data2->netgroup)
|
||||
continue;
|
||||
|
||||
if (!hwsim_chans_compat(chan, data2->tmp_chan) &&
|
||||
!hwsim_chans_compat(chan, data2->channel)) {
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
@@ -2349,6 +2380,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
struct ieee80211_hw *hw;
|
||||
enum nl80211_band band;
|
||||
const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
|
||||
struct net *net;
|
||||
int idx;
|
||||
|
||||
if (WARN_ON(param->channels > 1 && !param->use_chanctx))
|
||||
@@ -2366,6 +2398,13 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
err = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (info)
|
||||
net = genl_info_net(info);
|
||||
else
|
||||
net = &init_net;
|
||||
wiphy_net_set(hw->wiphy, net);
|
||||
|
||||
data = hw->priv;
|
||||
data->hw = hw;
|
||||
|
||||
@@ -2541,6 +2580,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
data->group = 1;
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
data->netgroup = hwsim_net_get_netgroup(net);
|
||||
|
||||
/* Enable frame retransmissions for lossy channels */
|
||||
hw->max_rates = 4;
|
||||
hw->max_rate_tries = 11;
|
||||
@@ -3014,6 +3055,9 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info)))
|
||||
continue;
|
||||
|
||||
list_del(&data->list);
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
|
||||
@@ -3040,6 +3084,9 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
||||
if (data->idx != idx)
|
||||
continue;
|
||||
|
||||
if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info)))
|
||||
continue;
|
||||
|
||||
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
res = -ENOMEM;
|
||||
@@ -3079,6 +3126,9 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb,
|
||||
if (data->idx < idx)
|
||||
continue;
|
||||
|
||||
if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk)))
|
||||
continue;
|
||||
|
||||
res = mac80211_hwsim_get_radio(skb, data,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, cb,
|
||||
@@ -3118,13 +3168,13 @@ static const struct genl_ops hwsim_ops[] = {
|
||||
.cmd = HWSIM_CMD_NEW_RADIO,
|
||||
.policy = hwsim_genl_policy,
|
||||
.doit = hwsim_new_radio_nl,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = HWSIM_CMD_DEL_RADIO,
|
||||
.policy = hwsim_genl_policy,
|
||||
.doit = hwsim_del_radio_nl,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = HWSIM_CMD_GET_RADIO,
|
||||
@@ -3206,6 +3256,40 @@ failure:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static __net_init int hwsim_init_net(struct net *net)
|
||||
{
|
||||
hwsim_net_set_netgroup(net);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __net_exit hwsim_exit_net(struct net *net)
|
||||
{
|
||||
struct mac80211_hwsim_data *data, *tmp;
|
||||
|
||||
spin_lock_bh(&hwsim_radio_lock);
|
||||
list_for_each_entry_safe(data, tmp, &hwsim_radios, list) {
|
||||
if (!net_eq(wiphy_net(data->hw->wiphy), net))
|
||||
continue;
|
||||
|
||||
/* Radios created in init_net are returned to init_net. */
|
||||
if (data->netgroup == hwsim_net_get_netgroup(&init_net))
|
||||
continue;
|
||||
|
||||
list_del(&data->list);
|
||||
INIT_WORK(&data->destroy_work, destroy_radio);
|
||||
schedule_work(&data->destroy_work);
|
||||
}
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
}
|
||||
|
||||
static struct pernet_operations hwsim_net_ops = {
|
||||
.init = hwsim_init_net,
|
||||
.exit = hwsim_exit_net,
|
||||
.id = &hwsim_net_id,
|
||||
.size = sizeof(struct hwsim_net),
|
||||
};
|
||||
|
||||
static void hwsim_exit_netlink(void)
|
||||
{
|
||||
/* unregister the notifier */
|
||||
@@ -3242,10 +3326,14 @@ static int __init init_mac80211_hwsim(void)
|
||||
spin_lock_init(&hwsim_radio_lock);
|
||||
INIT_LIST_HEAD(&hwsim_radios);
|
||||
|
||||
err = platform_driver_register(&mac80211_hwsim_driver);
|
||||
err = register_pernet_device(&hwsim_net_ops);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = platform_driver_register(&mac80211_hwsim_driver);
|
||||
if (err)
|
||||
goto out_unregister_pernet;
|
||||
|
||||
hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
|
||||
if (IS_ERR(hwsim_class)) {
|
||||
err = PTR_ERR(hwsim_class);
|
||||
@@ -3363,6 +3451,8 @@ out_free_radios:
|
||||
mac80211_hwsim_free();
|
||||
out_unregister_driver:
|
||||
platform_driver_unregister(&mac80211_hwsim_driver);
|
||||
out_unregister_pernet:
|
||||
unregister_pernet_device(&hwsim_net_ops);
|
||||
return err;
|
||||
}
|
||||
module_init(init_mac80211_hwsim);
|
||||
@@ -3376,5 +3466,6 @@ static void __exit exit_mac80211_hwsim(void)
|
||||
mac80211_hwsim_free();
|
||||
unregister_netdev(hwsim_mon);
|
||||
platform_driver_unregister(&mac80211_hwsim_driver);
|
||||
unregister_pernet_device(&hwsim_net_ops);
|
||||
}
|
||||
module_exit(exit_mac80211_hwsim);
|
||||
|
||||
+67
-14
@@ -2367,19 +2367,23 @@ struct cfg80211_qos_map {
|
||||
* (invoked with the wireless_dev mutex held)
|
||||
*
|
||||
* @connect: Connect to the ESS with the specified parameters. When connected,
|
||||
* call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS.
|
||||
* If the connection fails for some reason, call cfg80211_connect_result()
|
||||
* with the status from the AP. The driver is allowed to roam to other
|
||||
* BSSes within the ESS when the other BSS matches the connect parameters.
|
||||
* When such roaming is initiated by the driver, the driver is expected to
|
||||
* verify that the target matches the configured security parameters and
|
||||
* to use Reassociation Request frame instead of Association Request frame.
|
||||
* The connect function can also be used to request the driver to perform
|
||||
* a specific roam when connected to an ESS. In that case, the prev_bssid
|
||||
* call cfg80211_connect_result()/cfg80211_connect_bss() with status code
|
||||
* %WLAN_STATUS_SUCCESS. If the connection fails for some reason, call
|
||||
* cfg80211_connect_result()/cfg80211_connect_bss() with the status code
|
||||
* from the AP or cfg80211_connect_timeout() if no frame with status code
|
||||
* was received.
|
||||
* The driver is allowed to roam to other BSSes within the ESS when the
|
||||
* other BSS matches the connect parameters. When such roaming is initiated
|
||||
* by the driver, the driver is expected to verify that the target matches
|
||||
* the configured security parameters and to use Reassociation Request
|
||||
* frame instead of Association Request frame.
|
||||
* The connect function can also be used to request the driver to perform a
|
||||
* specific roam when connected to an ESS. In that case, the prev_bssid
|
||||
* parameter is set to the BSSID of the currently associated BSS as an
|
||||
* indication of requesting reassociation. In both the driver-initiated and
|
||||
* new connect() call initiated roaming cases, the result of roaming is
|
||||
* indicated with a call to cfg80211_roamed() or cfg80211_roamed_bss().
|
||||
* indication of requesting reassociation.
|
||||
* In both the driver-initiated and new connect() call initiated roaming
|
||||
* cases, the result of roaming is indicated with a call to
|
||||
* cfg80211_roamed() or cfg80211_roamed_bss().
|
||||
* (invoked with the wireless_dev mutex held)
|
||||
* @disconnect: Disconnect from the BSS/ESS.
|
||||
* (invoked with the wireless_dev mutex held)
|
||||
@@ -3079,6 +3083,24 @@ struct wiphy_vendor_command {
|
||||
unsigned long *storage);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wiphy_iftype_ext_capab - extended capabilities per interface type
|
||||
* @iftype: interface type
|
||||
* @extended_capabilities: extended capabilities supported by the driver,
|
||||
* additional capabilities might be supported by userspace; these are the
|
||||
* 802.11 extended capabilities ("Extended Capabilities element") and are
|
||||
* in the same format as in the information element. See IEEE Std
|
||||
* 802.11-2012 8.4.2.29 for the defined fields.
|
||||
* @extended_capabilities_mask: mask of the valid values
|
||||
* @extended_capabilities_len: length of the extended capabilities
|
||||
*/
|
||||
struct wiphy_iftype_ext_capab {
|
||||
enum nl80211_iftype iftype;
|
||||
const u8 *extended_capabilities;
|
||||
const u8 *extended_capabilities_mask;
|
||||
u8 extended_capabilities_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wiphy - wireless hardware description
|
||||
* @reg_notifier: the driver's regulatory notification callback,
|
||||
@@ -3199,9 +3221,14 @@ struct wiphy_vendor_command {
|
||||
* additional capabilities might be supported by userspace; these are
|
||||
* the 802.11 extended capabilities ("Extended Capabilities element")
|
||||
* and are in the same format as in the information element. See
|
||||
* 802.11-2012 8.4.2.29 for the defined fields.
|
||||
* 802.11-2012 8.4.2.29 for the defined fields. These are the default
|
||||
* extended capabilities to be used if the capabilities are not specified
|
||||
* for a specific interface type in iftype_ext_capab.
|
||||
* @extended_capabilities_mask: mask of the valid values
|
||||
* @extended_capabilities_len: length of the extended capabilities
|
||||
* @iftype_ext_capab: array of extended capabilities per interface type
|
||||
* @num_iftype_ext_capab: number of interface types for which extended
|
||||
* capabilities are specified separately.
|
||||
* @coalesce: packet coalescing support information
|
||||
*
|
||||
* @vendor_commands: array of vendor commands supported by the hardware
|
||||
@@ -3301,6 +3328,9 @@ struct wiphy {
|
||||
const u8 *extended_capabilities, *extended_capabilities_mask;
|
||||
u8 extended_capabilities_len;
|
||||
|
||||
const struct wiphy_iftype_ext_capab *iftype_ext_capab;
|
||||
unsigned int num_iftype_ext_capab;
|
||||
|
||||
/* If multiple wiphys are registered and you're handed e.g.
|
||||
* a regular netdev with assigned ieee80211_ptr, you won't
|
||||
* know whether it points to a wiphy your driver has registered
|
||||
@@ -4680,7 +4710,7 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
||||
void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
||||
struct cfg80211_bss *bss, const u8 *req_ie,
|
||||
size_t req_ie_len, const u8 *resp_ie,
|
||||
size_t resp_ie_len, u16 status, gfp_t gfp);
|
||||
size_t resp_ie_len, int status, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_connect_result - notify cfg80211 of connection result
|
||||
@@ -4709,6 +4739,29 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
resp_ie_len, status, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_connect_timeout - notify cfg80211 of connection timeout
|
||||
*
|
||||
* @dev: network device
|
||||
* @bssid: the BSSID of the AP
|
||||
* @req_ie: association request IEs (maybe be %NULL)
|
||||
* @req_ie_len: association request IEs length
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* It should be called by the underlying driver whenever connect() has failed
|
||||
* in a sequence where no explicit authentication/association rejection was
|
||||
* received from the AP. This could happen, e.g., due to not being able to send
|
||||
* out the Authentication or Association Request frame or timing out while
|
||||
* waiting for the response.
|
||||
*/
|
||||
static inline void
|
||||
cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len, gfp_t gfp)
|
||||
{
|
||||
cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, NULL, 0, -1,
|
||||
gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_roamed - notify cfg80211 of roaming
|
||||
*
|
||||
|
||||
+13
-5
@@ -21,6 +21,7 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/codel.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/**
|
||||
@@ -895,7 +896,18 @@ struct ieee80211_tx_info {
|
||||
unsigned long jiffies;
|
||||
};
|
||||
/* NB: vif can be NULL for injected frames */
|
||||
struct ieee80211_vif *vif;
|
||||
union {
|
||||
/* NB: vif can be NULL for injected frames */
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
/* When packets are enqueued on txq it's easy
|
||||
* to re-construct the vif pointer. There's no
|
||||
* more space in tx_info so it can be used to
|
||||
* store the necessary enqueue time for packet
|
||||
* sojourn time computation.
|
||||
*/
|
||||
codel_time_t enqueue_time;
|
||||
};
|
||||
struct ieee80211_key_conf *hw_key;
|
||||
u32 flags;
|
||||
/* 4 bytes free */
|
||||
@@ -2147,9 +2159,6 @@ enum ieee80211_hw_flags {
|
||||
* @n_cipher_schemes: a size of an array of cipher schemes definitions.
|
||||
* @cipher_schemes: a pointer to an array of cipher scheme definitions
|
||||
* supported by HW.
|
||||
*
|
||||
* @txq_ac_max_pending: maximum number of frames per AC pending in all txq
|
||||
* entries for a vif.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
@@ -2180,7 +2189,6 @@ struct ieee80211_hw {
|
||||
u8 uapsd_max_sp_len;
|
||||
u8 n_cipher_schemes;
|
||||
const struct ieee80211_cipher_scheme *cipher_schemes;
|
||||
int txq_ac_max_pending;
|
||||
};
|
||||
|
||||
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
|
||||
|
||||
@@ -493,7 +493,12 @@
|
||||
* This attribute is ignored if driver does not support roam scan.
|
||||
* It is also sent as an event, with the BSSID and response IEs when the
|
||||
* connection is established or failed to be established. This can be
|
||||
* determined by the STATUS_CODE attribute.
|
||||
* determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success,
|
||||
* non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the
|
||||
* event, the connection attempt failed due to not being able to initiate
|
||||
* authentication/association or not receiving a response from the AP.
|
||||
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
|
||||
* well to remain backwards compatible.
|
||||
* @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
|
||||
* sent as an event when the card/driver roamed by itself.
|
||||
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
|
||||
@@ -1819,6 +1824,11 @@ enum nl80211_commands {
|
||||
*
|
||||
* @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
|
||||
*
|
||||
* @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes:
|
||||
* %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA,
|
||||
* %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
|
||||
* interface type.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -2201,6 +2211,8 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_PAD,
|
||||
|
||||
NL80211_ATTR_IFTYPE_EXT_CAPA,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
||||
@@ -670,8 +670,7 @@
|
||||
/*
|
||||
* Generic format for most parameters that fit in an int
|
||||
*/
|
||||
struct iw_param
|
||||
{
|
||||
struct iw_param {
|
||||
__s32 value; /* The value of the parameter itself */
|
||||
__u8 fixed; /* Hardware should not use auto select */
|
||||
__u8 disabled; /* Disable the feature */
|
||||
@@ -682,8 +681,7 @@ struct iw_param
|
||||
* For all data larger than 16 octets, we need to use a
|
||||
* pointer to memory allocated in user space.
|
||||
*/
|
||||
struct iw_point
|
||||
{
|
||||
struct iw_point {
|
||||
void __user *pointer; /* Pointer to the data (in user space) */
|
||||
__u16 length; /* number of fields or size in bytes */
|
||||
__u16 flags; /* Optional params */
|
||||
@@ -698,8 +696,7 @@ struct iw_point
|
||||
* of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
|
||||
* The power of 10 is in 'e', the result of the division is in 'm'.
|
||||
*/
|
||||
struct iw_freq
|
||||
{
|
||||
struct iw_freq {
|
||||
__s32 m; /* Mantissa */
|
||||
__s16 e; /* Exponent */
|
||||
__u8 i; /* List index (when in range struct) */
|
||||
@@ -709,8 +706,7 @@ struct iw_freq
|
||||
/*
|
||||
* Quality of the link
|
||||
*/
|
||||
struct iw_quality
|
||||
{
|
||||
struct iw_quality {
|
||||
__u8 qual; /* link quality (%retries, SNR,
|
||||
%missed beacons or better...) */
|
||||
__u8 level; /* signal level (dBm) */
|
||||
@@ -725,8 +721,7 @@ struct iw_quality
|
||||
* is already pretty exhaustive, and you should use that first.
|
||||
* This is only additional stats...
|
||||
*/
|
||||
struct iw_discarded
|
||||
{
|
||||
struct iw_discarded {
|
||||
__u32 nwid; /* Rx : Wrong nwid/essid */
|
||||
__u32 code; /* Rx : Unable to code/decode (WEP) */
|
||||
__u32 fragment; /* Rx : Can't perform MAC reassembly */
|
||||
@@ -738,16 +733,14 @@ struct iw_discarded
|
||||
* Packet/Time period missed in the wireless adapter due to
|
||||
* "wireless" specific problems...
|
||||
*/
|
||||
struct iw_missed
|
||||
{
|
||||
struct iw_missed {
|
||||
__u32 beacon; /* Missed beacons/superframe */
|
||||
};
|
||||
|
||||
/*
|
||||
* Quality range (for spy threshold)
|
||||
*/
|
||||
struct iw_thrspy
|
||||
{
|
||||
struct iw_thrspy {
|
||||
struct sockaddr addr; /* Source address (hw/mac) */
|
||||
struct iw_quality qual; /* Quality of the link */
|
||||
struct iw_quality low; /* Low threshold */
|
||||
@@ -765,8 +758,7 @@ struct iw_thrspy
|
||||
* Especially, scan results are required to include an entry for the
|
||||
* current BSS if the driver is in Managed mode and associated with an AP.
|
||||
*/
|
||||
struct iw_scan_req
|
||||
{
|
||||
struct iw_scan_req {
|
||||
__u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
|
||||
__u8 essid_len;
|
||||
__u8 num_channels; /* num entries in channel_list;
|
||||
@@ -827,8 +819,7 @@ struct iw_scan_req
|
||||
* RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
|
||||
* debugging/testing.
|
||||
*/
|
||||
struct iw_encode_ext
|
||||
{
|
||||
struct iw_encode_ext {
|
||||
__u32 ext_flags; /* IW_ENCODE_EXT_* */
|
||||
__u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
|
||||
__u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
|
||||
@@ -841,8 +832,7 @@ struct iw_encode_ext
|
||||
};
|
||||
|
||||
/* SIOCSIWMLME data */
|
||||
struct iw_mlme
|
||||
{
|
||||
struct iw_mlme {
|
||||
__u16 cmd; /* IW_MLME_* */
|
||||
__u16 reason_code;
|
||||
struct sockaddr addr;
|
||||
@@ -855,16 +845,14 @@ struct iw_mlme
|
||||
|
||||
#define IW_PMKID_LEN 16
|
||||
|
||||
struct iw_pmksa
|
||||
{
|
||||
struct iw_pmksa {
|
||||
__u32 cmd; /* IW_PMKSA_* */
|
||||
struct sockaddr bssid;
|
||||
__u8 pmkid[IW_PMKID_LEN];
|
||||
};
|
||||
|
||||
/* IWEVMICHAELMICFAILURE data */
|
||||
struct iw_michaelmicfailure
|
||||
{
|
||||
struct iw_michaelmicfailure {
|
||||
__u32 flags;
|
||||
struct sockaddr src_addr;
|
||||
__u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
|
||||
@@ -872,8 +860,7 @@ struct iw_michaelmicfailure
|
||||
|
||||
/* IWEVPMKIDCAND data */
|
||||
#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */
|
||||
struct iw_pmkid_cand
|
||||
{
|
||||
struct iw_pmkid_cand {
|
||||
__u32 flags; /* IW_PMKID_CAND_* */
|
||||
__u32 index; /* the smaller the index, the higher the
|
||||
* priority */
|
||||
@@ -884,8 +871,7 @@ struct iw_pmkid_cand
|
||||
/*
|
||||
* Wireless statistics (used for /proc/net/wireless)
|
||||
*/
|
||||
struct iw_statistics
|
||||
{
|
||||
struct iw_statistics {
|
||||
__u16 status; /* Status
|
||||
* - device dependent for now */
|
||||
|
||||
@@ -897,7 +883,7 @@ struct iw_statistics
|
||||
|
||||
/* ------------------------ IOCTL REQUEST ------------------------ */
|
||||
/*
|
||||
* This structure defines the payload of an ioctl, and is used
|
||||
* This structure defines the payload of an ioctl, and is used
|
||||
* below.
|
||||
*
|
||||
* Note that this structure should fit on the memory footprint
|
||||
@@ -906,8 +892,7 @@ struct iw_statistics
|
||||
* You should check this when increasing the structures defined
|
||||
* above in this file...
|
||||
*/
|
||||
union iwreq_data
|
||||
{
|
||||
union iwreq_data {
|
||||
/* Config - generic */
|
||||
char name[IFNAMSIZ];
|
||||
/* Name : used to verify the presence of wireless extensions.
|
||||
@@ -944,15 +929,14 @@ union iwreq_data
|
||||
* convenience...
|
||||
* Do I need to remind you about structure size (32 octets) ?
|
||||
*/
|
||||
struct iwreq
|
||||
{
|
||||
struct iwreq {
|
||||
union
|
||||
{
|
||||
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
|
||||
} ifr_ifrn;
|
||||
|
||||
/* Data part (defined just above) */
|
||||
union iwreq_data u;
|
||||
union iwreq_data u;
|
||||
};
|
||||
|
||||
/* -------------------------- IOCTL DATA -------------------------- */
|
||||
@@ -965,8 +949,7 @@ struct iwreq
|
||||
* Range of parameters
|
||||
*/
|
||||
|
||||
struct iw_range
|
||||
{
|
||||
struct iw_range {
|
||||
/* Informative stuff (to choose between different interface) */
|
||||
__u32 throughput; /* To give an idea... */
|
||||
/* In theory this value should be the maximum benchmarked
|
||||
@@ -1069,9 +1052,8 @@ struct iw_range
|
||||
/*
|
||||
* Private ioctl interface information
|
||||
*/
|
||||
|
||||
struct iw_priv_args
|
||||
{
|
||||
|
||||
struct iw_priv_args {
|
||||
__u32 cmd; /* Number of the ioctl to issue */
|
||||
__u16 set_args; /* Type and number of args */
|
||||
__u16 get_args; /* Type and number of args */
|
||||
@@ -1088,8 +1070,7 @@ struct iw_priv_args
|
||||
/*
|
||||
* A Wireless Event. Contains basically the same data as the ioctl...
|
||||
*/
|
||||
struct iw_event
|
||||
{
|
||||
struct iw_event {
|
||||
__u16 len; /* Real length of this stuff */
|
||||
__u16 cmd; /* Wireless IOCTL */
|
||||
union iwreq_data u; /* IOCTL fixed payload */
|
||||
|
||||
@@ -194,17 +194,21 @@ static void
|
||||
ieee80211_agg_stop_txq(struct sta_info *sta, int tid)
|
||||
{
|
||||
struct ieee80211_txq *txq = sta->sta.txq[tid];
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct fq *fq;
|
||||
struct txq_info *txqi;
|
||||
|
||||
if (!txq)
|
||||
return;
|
||||
|
||||
txqi = to_txq_info(txq);
|
||||
sdata = vif_to_sdata(txq->vif);
|
||||
fq = &sdata->local->fq;
|
||||
|
||||
/* Lock here to protect against further seqno updates on dequeue */
|
||||
spin_lock_bh(&txqi->queue.lock);
|
||||
spin_lock_bh(&fq->lock);
|
||||
set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||
spin_unlock_bh(&txqi->queue.lock);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
#include "rate.h"
|
||||
@@ -70,6 +71,177 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
|
||||
DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
|
||||
local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
|
||||
|
||||
struct aqm_info {
|
||||
struct ieee80211_local *local;
|
||||
size_t size;
|
||||
size_t len;
|
||||
unsigned char buf[0];
|
||||
};
|
||||
|
||||
#define AQM_HDR_LEN 200
|
||||
#define AQM_HW_ENTRY_LEN 40
|
||||
#define AQM_TXQ_ENTRY_LEN 110
|
||||
|
||||
static int aqm_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ieee80211_local *local = inode->i_private;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
struct txq_info *txqi;
|
||||
struct fq *fq = &local->fq;
|
||||
struct aqm_info *info = NULL;
|
||||
int len = 0;
|
||||
int i;
|
||||
|
||||
if (!local->ops->wake_tx_queue)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
len += AQM_HDR_LEN;
|
||||
len += 6 * AQM_HW_ENTRY_LEN;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
len += AQM_TXQ_ENTRY_LEN;
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list)
|
||||
len += AQM_TXQ_ENTRY_LEN * ARRAY_SIZE(sta->sta.txq);
|
||||
rcu_read_unlock();
|
||||
|
||||
info = vmalloc(len);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_bh(&local->fq.lock);
|
||||
rcu_read_lock();
|
||||
|
||||
file->private_data = info;
|
||||
info->local = local;
|
||||
info->size = len;
|
||||
len = 0;
|
||||
|
||||
len += scnprintf(info->buf + len, info->size - len,
|
||||
"* hw\n"
|
||||
"access name value\n"
|
||||
"R fq_flows_cnt %u\n"
|
||||
"R fq_backlog %u\n"
|
||||
"R fq_overlimit %u\n"
|
||||
"R fq_collisions %u\n"
|
||||
"RW fq_limit %u\n"
|
||||
"RW fq_quantum %u\n",
|
||||
fq->flows_cnt,
|
||||
fq->backlog,
|
||||
fq->overlimit,
|
||||
fq->collisions,
|
||||
fq->limit,
|
||||
fq->quantum);
|
||||
|
||||
len += scnprintf(info->buf + len,
|
||||
info->size - len,
|
||||
"* vif\n"
|
||||
"ifname addr ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
txqi = to_txq_info(sdata->vif.txq);
|
||||
len += scnprintf(info->buf + len, info->size - len,
|
||||
"%s %pM %u %u %u %u %u %u %u %u\n",
|
||||
sdata->name,
|
||||
sdata->vif.addr,
|
||||
txqi->txq.ac,
|
||||
txqi->tin.backlog_bytes,
|
||||
txqi->tin.backlog_packets,
|
||||
txqi->tin.flows,
|
||||
txqi->tin.overlimit,
|
||||
txqi->tin.collisions,
|
||||
txqi->tin.tx_bytes,
|
||||
txqi->tin.tx_packets);
|
||||
}
|
||||
|
||||
len += scnprintf(info->buf + len,
|
||||
info->size - len,
|
||||
"* sta\n"
|
||||
"ifname addr tid ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
|
||||
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
sdata = sta->sdata;
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
txqi = to_txq_info(sta->sta.txq[i]);
|
||||
len += scnprintf(info->buf + len, info->size - len,
|
||||
"%s %pM %d %d %u %u %u %u %u %u %u\n",
|
||||
sdata->name,
|
||||
sta->sta.addr,
|
||||
txqi->txq.tid,
|
||||
txqi->txq.ac,
|
||||
txqi->tin.backlog_bytes,
|
||||
txqi->tin.backlog_packets,
|
||||
txqi->tin.flows,
|
||||
txqi->tin.overlimit,
|
||||
txqi->tin.collisions,
|
||||
txqi->tin.tx_bytes,
|
||||
txqi->tin.tx_packets);
|
||||
}
|
||||
}
|
||||
|
||||
info->len = len;
|
||||
|
||||
rcu_read_unlock();
|
||||
spin_unlock_bh(&local->fq.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aqm_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
vfree(file->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t aqm_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct aqm_info *info = file->private_data;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
info->buf, info->len);
|
||||
}
|
||||
|
||||
static ssize_t aqm_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct aqm_info *info = file->private_data;
|
||||
struct ieee80211_local *local = info->local;
|
||||
char buf[100];
|
||||
size_t len;
|
||||
|
||||
if (count > sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
len = strlen(buf);
|
||||
if (len > 0 && buf[len-1] == '\n')
|
||||
buf[len-1] = 0;
|
||||
|
||||
if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1)
|
||||
return count;
|
||||
else if (sscanf(buf, "fq_quantum %u", &local->fq.quantum) == 1)
|
||||
return count;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct file_operations aqm_ops = {
|
||||
.write = aqm_write,
|
||||
.read = aqm_read,
|
||||
.open = aqm_open,
|
||||
.release = aqm_release,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static ssize_t reset_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@@ -256,6 +428,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
||||
DEBUGFS_ADD(hwflags);
|
||||
DEBUGFS_ADD(user_power);
|
||||
DEBUGFS_ADD(power);
|
||||
DEBUGFS_ADD_MODE(aqm, 0600);
|
||||
|
||||
statsd = debugfs_create_dir("statistics", phyd);
|
||||
|
||||
|
||||
@@ -328,14 +328,88 @@ STA_OPS(ht_capa);
|
||||
static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[128], *p = buf;
|
||||
char buf[512], *p = buf;
|
||||
struct sta_info *sta = file->private_data;
|
||||
struct ieee80211_sta_vht_cap *vhtc = &sta->sta.vht_cap;
|
||||
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n",
|
||||
vhtc->vht_supported ? "" : "not ");
|
||||
if (vhtc->vht_supported) {
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.8x\n", vhtc->cap);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, "cap: %#.8x\n",
|
||||
vhtc->cap);
|
||||
#define PFLAG(a, b) \
|
||||
do { \
|
||||
if (vhtc->cap & IEEE80211_VHT_CAP_ ## a) \
|
||||
p += scnprintf(p, sizeof(buf) + buf - p, \
|
||||
"\t\t%s\n", b); \
|
||||
} while (0)
|
||||
|
||||
switch (vhtc->cap & 0x3) {
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tMAX-MPDU-3895\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tMAX-MPDU-7991\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tMAX-MPDU-11454\n");
|
||||
break;
|
||||
default:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tMAX-MPDU-UNKNOWN\n");
|
||||
};
|
||||
switch (vhtc->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||
case 0:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\t80Mhz\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\t160Mhz\n");
|
||||
break;
|
||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\t80+80Mhz\n");
|
||||
break;
|
||||
default:
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tUNKNOWN-MHZ: 0x%x\n",
|
||||
(vhtc->cap >> 2) & 0x3);
|
||||
};
|
||||
PFLAG(RXLDPC, "RXLDPC");
|
||||
PFLAG(SHORT_GI_80, "SHORT-GI-80");
|
||||
PFLAG(SHORT_GI_160, "SHORT-GI-160");
|
||||
PFLAG(TXSTBC, "TXSTBC");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tRXSTBC_%d\n", (vhtc->cap >> 8) & 0x7);
|
||||
PFLAG(SU_BEAMFORMER_CAPABLE, "SU-BEAMFORMER-CAPABLE");
|
||||
PFLAG(SU_BEAMFORMEE_CAPABLE, "SU-BEAMFORMEE-CAPABLE");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tBEAMFORMEE-STS: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK) >>
|
||||
IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tSOUNDING-DIMENSIONS: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK)
|
||||
>> IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT);
|
||||
PFLAG(MU_BEAMFORMER_CAPABLE, "MU-BEAMFORMER-CAPABLE");
|
||||
PFLAG(MU_BEAMFORMEE_CAPABLE, "MU-BEAMFORMEE-CAPABLE");
|
||||
PFLAG(VHT_TXOP_PS, "TXOP-PS");
|
||||
PFLAG(HTC_VHT, "HTC-VHT");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tMPDU-LENGTH-EXPONENT: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
|
||||
PFLAG(VHT_LINK_ADAPTATION_VHT_UNSOL_MFB,
|
||||
"LINK-ADAPTATION-VHT-UNSOL-MFB");
|
||||
p += scnprintf(p, sizeof(buf) + buf - p,
|
||||
"\t\tLINK-ADAPTATION-VHT-MRQ-MFB: 0x%x\n",
|
||||
(vhtc->cap & IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB) >> 26);
|
||||
PFLAG(RX_ANTENNA_PATTERN, "RX-ANTENNA-PATTERN");
|
||||
PFLAG(TX_ANTENNA_PATTERN, "TX-ANTENNA-PATTERN");
|
||||
|
||||
p += scnprintf(p, sizeof(buf)+buf-p, "RX MCS: %.4x\n",
|
||||
le16_to_cpu(vhtc->vht_mcs.rx_mcs_map));
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/fq.h>
|
||||
#include "key.h"
|
||||
#include "sta_info.h"
|
||||
#include "debug.h"
|
||||
@@ -805,10 +806,19 @@ enum txq_info_flags {
|
||||
IEEE80211_TXQ_NO_AMSDU,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct txq_info - per tid queue
|
||||
*
|
||||
* @tin: contains packets split into multiple flows
|
||||
* @def_flow: used as a fallback flow when a packet destined to @tin hashes to
|
||||
* a fq_flow which is already owned by a different tin
|
||||
* @def_cvars: codel vars for @def_flow
|
||||
*/
|
||||
struct txq_info {
|
||||
struct sk_buff_head queue;
|
||||
struct fq_tin tin;
|
||||
struct fq_flow def_flow;
|
||||
struct codel_vars def_cvars;
|
||||
unsigned long flags;
|
||||
unsigned long byte_cnt;
|
||||
|
||||
/* keep last! */
|
||||
struct ieee80211_txq txq;
|
||||
@@ -856,7 +866,7 @@ struct ieee80211_sub_if_data {
|
||||
bool control_port_no_encrypt;
|
||||
int encrypt_headroom;
|
||||
|
||||
atomic_t txqs_len[IEEE80211_NUM_ACS];
|
||||
atomic_t num_tx_queued;
|
||||
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
|
||||
struct mac80211_qos_map __rcu *qos_map;
|
||||
|
||||
@@ -1099,6 +1109,11 @@ struct ieee80211_local {
|
||||
* it first anyway so they become a no-op */
|
||||
struct ieee80211_hw hw;
|
||||
|
||||
struct fq fq;
|
||||
struct codel_vars *cvars;
|
||||
struct codel_params cparams;
|
||||
struct codel_stats cstats;
|
||||
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/*
|
||||
@@ -1931,9 +1946,13 @@ static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct txq_info *txq, int tid);
|
||||
int ieee80211_txq_setup_flows(struct ieee80211_local *local);
|
||||
void ieee80211_txq_teardown_flows(struct ieee80211_local *local);
|
||||
void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct txq_info *txq, int tid);
|
||||
void ieee80211_txq_purge(struct ieee80211_local *local,
|
||||
struct txq_info *txqi);
|
||||
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||
u16 transaction, u16 auth_alg, u16 status,
|
||||
const u8 *extra, size_t extra_len, const u8 *bssid,
|
||||
|
||||
+18
-8
@@ -779,6 +779,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
bool going_down)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct fq *fq = &local->fq;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb, *tmp;
|
||||
u32 hw_reconf_flags = 0;
|
||||
@@ -977,12 +978,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
if (sdata->vif.txq) {
|
||||
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
|
||||
|
||||
spin_lock_bh(&txqi->queue.lock);
|
||||
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
||||
txqi->byte_cnt = 0;
|
||||
spin_unlock_bh(&txqi->queue.lock);
|
||||
|
||||
atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_purge(local, txqi);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
|
||||
if (local->open_count == 0)
|
||||
@@ -1198,6 +1196,12 @@ static void ieee80211_if_setup(struct net_device *dev)
|
||||
dev->destructor = ieee80211_if_free;
|
||||
}
|
||||
|
||||
static void ieee80211_if_setup_no_queue(struct net_device *dev)
|
||||
{
|
||||
ieee80211_if_setup(dev);
|
||||
dev->priv_flags |= IFF_NO_QUEUE;
|
||||
}
|
||||
|
||||
static void ieee80211_iface_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
@@ -1707,6 +1711,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
struct net_device *ndev = NULL;
|
||||
struct ieee80211_sub_if_data *sdata = NULL;
|
||||
struct txq_info *txqi;
|
||||
void (*if_setup)(struct net_device *dev);
|
||||
int ret, i;
|
||||
int txqs = 1;
|
||||
|
||||
@@ -1734,12 +1739,17 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
txq_size += sizeof(struct txq_info) +
|
||||
local->hw.txq_data_size;
|
||||
|
||||
if (local->ops->wake_tx_queue)
|
||||
if_setup = ieee80211_if_setup_no_queue;
|
||||
else
|
||||
if_setup = ieee80211_if_setup;
|
||||
|
||||
if (local->hw.queues >= IEEE80211_NUM_ACS)
|
||||
txqs = IEEE80211_NUM_ACS;
|
||||
|
||||
ndev = alloc_netdev_mqs(size + txq_size,
|
||||
name, name_assign_type,
|
||||
ieee80211_if_setup, txqs, 1);
|
||||
if_setup, txqs, 1);
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
|
||||
@@ -1780,7 +1790,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
|
||||
if (txq_size) {
|
||||
txqi = netdev_priv(ndev) + size;
|
||||
ieee80211_init_tx_queue(sdata, NULL, txqi, 0);
|
||||
ieee80211_txq_init(sdata, NULL, txqi, 0);
|
||||
}
|
||||
|
||||
sdata->dev = ndev;
|
||||
|
||||
+7
-3
@@ -1055,9 +1055,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
|
||||
local->dynamic_ps_forced_timeout = -1;
|
||||
|
||||
if (!local->hw.txq_ac_max_pending)
|
||||
local->hw.txq_ac_max_pending = 64;
|
||||
|
||||
result = ieee80211_wep_init(local);
|
||||
if (result < 0)
|
||||
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
|
||||
@@ -1089,6 +1086,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
result = ieee80211_txq_setup_flows(local);
|
||||
if (result)
|
||||
goto fail_flows;
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
|
||||
result = register_inetaddr_notifier(&local->ifa_notifier);
|
||||
@@ -1114,6 +1115,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
|
||||
fail_ifa:
|
||||
#endif
|
||||
ieee80211_txq_teardown_flows(local);
|
||||
fail_flows:
|
||||
rtnl_lock();
|
||||
rate_control_deinitialize(local);
|
||||
ieee80211_remove_interfaces(local);
|
||||
@@ -1172,6 +1175,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
||||
skb_queue_purge(&local->skb_queue);
|
||||
skb_queue_purge(&local->skb_queue_unreliable);
|
||||
skb_queue_purge(&local->skb_queue_tdls_chsw);
|
||||
ieee80211_txq_teardown_flows(local);
|
||||
|
||||
destroy_workqueue(local->workqueue);
|
||||
wiphy_unregister(local->hw.wiphy);
|
||||
|
||||
+1
-1
@@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info *sta)
|
||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
||||
|
||||
if (!skb_queue_len(&txqi->queue))
|
||||
if (!txqi->tin.backlog_packets)
|
||||
set_bit(tid, &sta->txq_buffered_tids);
|
||||
else
|
||||
clear_bit(tid, &sta->txq_buffered_tids);
|
||||
|
||||
@@ -90,6 +90,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct fq *fq = &local->fq;
|
||||
struct ps_data *ps;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
|
||||
@@ -113,11 +114,10 @@ static void __cleanup_single_sta(struct sta_info *sta)
|
||||
if (sta->sta.txq[0]) {
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
int n = skb_queue_len(&txqi->queue);
|
||||
|
||||
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
||||
atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
|
||||
txqi->byte_cnt = 0;
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_purge(local, txqi);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txq = txq_data + i * size;
|
||||
|
||||
ieee80211_init_tx_queue(sdata, sta, txq, i);
|
||||
ieee80211_txq_init(sdata, sta, txq, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1211,7 +1211,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
|
||||
if (!skb_queue_len(&txqi->queue))
|
||||
if (!txqi->tin.backlog_packets)
|
||||
continue;
|
||||
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
@@ -1648,7 +1648,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
||||
|
||||
if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue))
|
||||
if (!(tids & BIT(tid)) || txqi->tin.backlog_packets)
|
||||
continue;
|
||||
|
||||
sta_info_recalc_tim(sta);
|
||||
|
||||
+252
-40
@@ -24,7 +24,10 @@
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/codel.h>
|
||||
#include <net/codel_impl.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <net/fq_impl.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
@@ -1236,27 +1239,21 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static void ieee80211_drv_tx(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *pubsta,
|
||||
struct sk_buff *skb)
|
||||
static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *pubsta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_control control = {
|
||||
.sta = pubsta,
|
||||
};
|
||||
struct ieee80211_txq *txq = NULL;
|
||||
struct txq_info *txqi;
|
||||
u8 ac;
|
||||
|
||||
if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
|
||||
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
|
||||
goto tx_normal;
|
||||
return NULL;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
goto tx_normal;
|
||||
return NULL;
|
||||
|
||||
if (pubsta) {
|
||||
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
@@ -1267,51 +1264,230 @@ static void ieee80211_drv_tx(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
if (!txq)
|
||||
goto tx_normal;
|
||||
return NULL;
|
||||
|
||||
ac = txq->ac;
|
||||
txqi = to_txq_info(txq);
|
||||
atomic_inc(&sdata->txqs_len[ac]);
|
||||
if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending)
|
||||
netif_stop_subqueue(sdata->dev, ac);
|
||||
return to_txq_info(txq);
|
||||
}
|
||||
|
||||
spin_lock_bh(&txqi->queue.lock);
|
||||
txqi->byte_cnt += skb->len;
|
||||
__skb_queue_tail(&txqi->queue, skb);
|
||||
spin_unlock_bh(&txqi->queue.lock);
|
||||
static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
|
||||
{
|
||||
IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
|
||||
}
|
||||
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
static void ieee80211_set_skb_vif(struct sk_buff *skb, struct txq_info *txqi)
|
||||
{
|
||||
IEEE80211_SKB_CB(skb)->control.vif = txqi->txq.vif;
|
||||
}
|
||||
|
||||
return;
|
||||
static u32 codel_skb_len_func(const struct sk_buff *skb)
|
||||
{
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
tx_normal:
|
||||
drv_tx(local, &control, skb);
|
||||
static codel_time_t codel_skb_time_func(const struct sk_buff *skb)
|
||||
{
|
||||
const struct ieee80211_tx_info *info;
|
||||
|
||||
info = (const struct ieee80211_tx_info *)skb->cb;
|
||||
return info->control.enqueue_time;
|
||||
}
|
||||
|
||||
static struct sk_buff *codel_dequeue_func(struct codel_vars *cvars,
|
||||
void *ctx)
|
||||
{
|
||||
struct ieee80211_local *local;
|
||||
struct txq_info *txqi;
|
||||
struct fq *fq;
|
||||
struct fq_flow *flow;
|
||||
|
||||
txqi = ctx;
|
||||
local = vif_to_sdata(txqi->txq.vif)->local;
|
||||
fq = &local->fq;
|
||||
|
||||
if (cvars == &txqi->def_cvars)
|
||||
flow = &txqi->def_flow;
|
||||
else
|
||||
flow = &fq->flows[cvars - local->cvars];
|
||||
|
||||
return fq_flow_dequeue(fq, flow);
|
||||
}
|
||||
|
||||
static void codel_drop_func(struct sk_buff *skb,
|
||||
void *ctx)
|
||||
{
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_hw *hw;
|
||||
struct txq_info *txqi;
|
||||
|
||||
txqi = ctx;
|
||||
local = vif_to_sdata(txqi->txq.vif)->local;
|
||||
hw = &local->hw;
|
||||
|
||||
ieee80211_free_txskb(hw, skb);
|
||||
}
|
||||
|
||||
static struct sk_buff *fq_tin_dequeue_func(struct fq *fq,
|
||||
struct fq_tin *tin,
|
||||
struct fq_flow *flow)
|
||||
{
|
||||
struct ieee80211_local *local;
|
||||
struct txq_info *txqi;
|
||||
struct codel_vars *cvars;
|
||||
struct codel_params *cparams;
|
||||
struct codel_stats *cstats;
|
||||
|
||||
local = container_of(fq, struct ieee80211_local, fq);
|
||||
txqi = container_of(tin, struct txq_info, tin);
|
||||
cparams = &local->cparams;
|
||||
cstats = &local->cstats;
|
||||
|
||||
if (flow == &txqi->def_flow)
|
||||
cvars = &txqi->def_cvars;
|
||||
else
|
||||
cvars = &local->cvars[flow - fq->flows];
|
||||
|
||||
return codel_dequeue(txqi,
|
||||
&flow->backlog,
|
||||
cparams,
|
||||
cvars,
|
||||
cstats,
|
||||
codel_skb_len_func,
|
||||
codel_skb_time_func,
|
||||
codel_drop_func,
|
||||
codel_dequeue_func);
|
||||
}
|
||||
|
||||
static void fq_skb_free_func(struct fq *fq,
|
||||
struct fq_tin *tin,
|
||||
struct fq_flow *flow,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local;
|
||||
|
||||
local = container_of(fq, struct ieee80211_local, fq);
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
}
|
||||
|
||||
static struct fq_flow *fq_flow_get_default_func(struct fq *fq,
|
||||
struct fq_tin *tin,
|
||||
int idx,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct txq_info *txqi;
|
||||
|
||||
txqi = container_of(tin, struct txq_info, tin);
|
||||
return &txqi->def_flow;
|
||||
}
|
||||
|
||||
static void ieee80211_txq_enqueue(struct ieee80211_local *local,
|
||||
struct txq_info *txqi,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
|
||||
ieee80211_set_skb_enqueue_time(skb);
|
||||
fq_tin_enqueue(fq, tin, skb,
|
||||
fq_skb_free_func,
|
||||
fq_flow_get_default_func);
|
||||
}
|
||||
|
||||
void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct txq_info *txqi, int tid)
|
||||
{
|
||||
fq_tin_init(&txqi->tin);
|
||||
fq_flow_init(&txqi->def_flow);
|
||||
codel_vars_init(&txqi->def_cvars);
|
||||
|
||||
txqi->txq.vif = &sdata->vif;
|
||||
|
||||
if (sta) {
|
||||
txqi->txq.sta = &sta->sta;
|
||||
sta->sta.txq[tid] = &txqi->txq;
|
||||
txqi->txq.tid = tid;
|
||||
txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
|
||||
} else {
|
||||
sdata->vif.txq = &txqi->txq;
|
||||
txqi->txq.tid = 0;
|
||||
txqi->txq.ac = IEEE80211_AC_BE;
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_txq_purge(struct ieee80211_local *local,
|
||||
struct txq_info *txqi)
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
|
||||
fq_tin_reset(fq, tin, fq_skb_free_func);
|
||||
}
|
||||
|
||||
int ieee80211_txq_setup_flows(struct ieee80211_local *local)
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!local->ops->wake_tx_queue)
|
||||
return 0;
|
||||
|
||||
ret = fq_init(fq, 4096);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
codel_params_init(&local->cparams);
|
||||
codel_stats_init(&local->cstats);
|
||||
local->cparams.interval = MS2TIME(100);
|
||||
local->cparams.target = MS2TIME(20);
|
||||
local->cparams.ecn = true;
|
||||
|
||||
local->cvars = kcalloc(fq->flows_cnt, sizeof(local->cvars[0]),
|
||||
GFP_KERNEL);
|
||||
if (!local->cvars) {
|
||||
fq_reset(fq, fq_skb_free_func);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < fq->flows_cnt; i++)
|
||||
codel_vars_init(&local->cvars[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
|
||||
if (!local->ops->wake_tx_queue)
|
||||
return;
|
||||
|
||||
kfree(local->cvars);
|
||||
local->cvars = NULL;
|
||||
|
||||
fq_reset(fq, fq_skb_free_func);
|
||||
}
|
||||
|
||||
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
|
||||
struct txq_info *txqi = container_of(txq, struct txq_info, txq);
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb = NULL;
|
||||
u8 ac = txq->ac;
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
|
||||
spin_lock_bh(&txqi->queue.lock);
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
|
||||
goto out;
|
||||
|
||||
skb = __skb_dequeue(&txqi->queue);
|
||||
skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
txqi->byte_cnt -= skb->len;
|
||||
|
||||
atomic_dec(&sdata->txqs_len[ac]);
|
||||
if (__netif_subqueue_stopped(sdata->dev, ac))
|
||||
ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
|
||||
ieee80211_set_skb_vif(skb, txqi);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
@@ -1327,7 +1503,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&txqi->queue.lock);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
if (skb && skb_has_frag_list(skb) &&
|
||||
!ieee80211_hw_check(&local->hw, TX_FRAG_LIST))
|
||||
@@ -1343,7 +1519,10 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
struct sk_buff_head *skbs,
|
||||
bool txpending)
|
||||
{
|
||||
struct ieee80211_tx_control control = {};
|
||||
struct fq *fq = &local->fq;
|
||||
struct sk_buff *skb, *tmp;
|
||||
struct txq_info *txqi;
|
||||
unsigned long flags;
|
||||
|
||||
skb_queue_walk_safe(skbs, skb, tmp) {
|
||||
@@ -1358,6 +1537,21 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
}
|
||||
#endif
|
||||
|
||||
txqi = ieee80211_get_txq(local, vif, sta, skb);
|
||||
if (txqi) {
|
||||
info->control.vif = vif;
|
||||
|
||||
__skb_unlink(skb, skbs);
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_enqueue(local, txqi, skb);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
if (local->queue_stop_reasons[q] ||
|
||||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
|
||||
@@ -1400,9 +1594,10 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
info->control.vif = vif;
|
||||
control.sta = sta;
|
||||
|
||||
__skb_unlink(skb, skbs);
|
||||
ieee80211_drv_tx(local, vif, sta, skb);
|
||||
drv_tx(local, &control, skb);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2882,6 +3077,9 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin;
|
||||
struct fq_flow *flow;
|
||||
u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
struct ieee80211_txq *txq = sta->sta.txq[tid];
|
||||
struct txq_info *txqi;
|
||||
@@ -2893,6 +3091,7 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
__be16 len;
|
||||
void *data;
|
||||
bool ret = false;
|
||||
unsigned int orig_len;
|
||||
int n = 1, nfrags;
|
||||
|
||||
if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
|
||||
@@ -2909,12 +3108,20 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
max_amsdu_len = min_t(int, max_amsdu_len,
|
||||
sta->sta.max_rc_amsdu_len);
|
||||
|
||||
spin_lock_bh(&txqi->queue.lock);
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
head = skb_peek_tail(&txqi->queue);
|
||||
/* TODO: Ideally aggregation should be done on dequeue to remain
|
||||
* responsive to environment changes.
|
||||
*/
|
||||
|
||||
tin = &txqi->tin;
|
||||
flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
|
||||
head = skb_peek_tail(&flow->queue);
|
||||
if (!head)
|
||||
goto out;
|
||||
|
||||
orig_len = head->len;
|
||||
|
||||
if (skb->len + head->len > max_amsdu_len)
|
||||
goto out;
|
||||
|
||||
@@ -2953,8 +3160,13 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
head->data_len += skb->len;
|
||||
*frag_tail = skb;
|
||||
|
||||
flow->backlog += head->len - orig_len;
|
||||
tin->backlog_bytes += head->len - orig_len;
|
||||
|
||||
fq_recalc_backlog(fq, tin, flow);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&txqi->queue.lock);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+8
-26
@@ -244,6 +244,9 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int n_acs = IEEE80211_NUM_ACS;
|
||||
|
||||
if (local->ops->wake_tx_queue)
|
||||
return;
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
n_acs = 1;
|
||||
|
||||
@@ -260,11 +263,6 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
|
||||
for (ac = 0; ac < n_acs; ac++) {
|
||||
int ac_queue = sdata->vif.hw_queue[ac];
|
||||
|
||||
if (local->ops->wake_tx_queue &&
|
||||
(atomic_read(&sdata->txqs_len[ac]) >
|
||||
local->hw.txq_ac_max_pending))
|
||||
continue;
|
||||
|
||||
if (ac_queue == queue ||
|
||||
(sdata->vif.cab_queue == queue &&
|
||||
local->queue_stop_reasons[ac_queue] == 0 &&
|
||||
@@ -352,6 +350,9 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
|
||||
if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
|
||||
return;
|
||||
|
||||
if (local->ops->wake_tx_queue)
|
||||
return;
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
n_acs = 1;
|
||||
|
||||
@@ -3388,25 +3389,6 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo)
|
||||
return buf;
|
||||
}
|
||||
|
||||
void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct txq_info *txqi, int tid)
|
||||
{
|
||||
skb_queue_head_init(&txqi->queue);
|
||||
txqi->txq.vif = &sdata->vif;
|
||||
|
||||
if (sta) {
|
||||
txqi->txq.sta = &sta->sta;
|
||||
sta->sta.txq[tid] = &txqi->txq;
|
||||
txqi->txq.tid = tid;
|
||||
txqi->txq.ac = ieee802_1d_to_ac[tid & 7];
|
||||
} else {
|
||||
sdata->vif.txq = &txqi->txq;
|
||||
txqi->txq.tid = 0;
|
||||
txqi->txq.ac = IEEE80211_AC_BE;
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
|
||||
unsigned long *frame_cnt,
|
||||
unsigned long *byte_cnt)
|
||||
@@ -3414,9 +3396,9 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
|
||||
struct txq_info *txqi = to_txq_info(txq);
|
||||
|
||||
if (frame_cnt)
|
||||
*frame_cnt = txqi->queue.qlen;
|
||||
*frame_cnt = txqi->tin.backlog_packets;
|
||||
|
||||
if (byte_cnt)
|
||||
*byte_cnt = txqi->byte_cnt;
|
||||
*byte_cnt = txqi->tin.backlog_bytes;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_txq_get_depth);
|
||||
|
||||
@@ -748,6 +748,36 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
nl80211_send_reg_change_event(&request);
|
||||
}
|
||||
|
||||
/* Check that nobody globally advertises any capabilities they do not
|
||||
* advertise on all possible interface types.
|
||||
*/
|
||||
if (wiphy->extended_capabilities_len &&
|
||||
wiphy->num_iftype_ext_capab &&
|
||||
wiphy->iftype_ext_capab) {
|
||||
u8 supported_on_all, j;
|
||||
const struct wiphy_iftype_ext_capab *capab;
|
||||
|
||||
capab = wiphy->iftype_ext_capab;
|
||||
for (j = 0; j < wiphy->extended_capabilities_len; j++) {
|
||||
if (capab[0].extended_capabilities_len > j)
|
||||
supported_on_all =
|
||||
capab[0].extended_capabilities[j];
|
||||
else
|
||||
supported_on_all = 0x00;
|
||||
for (i = 1; i < wiphy->num_iftype_ext_capab; i++) {
|
||||
if (j >= capab[i].extended_capabilities_len) {
|
||||
supported_on_all = 0x00;
|
||||
break;
|
||||
}
|
||||
supported_on_all &=
|
||||
capab[i].extended_capabilities[j];
|
||||
}
|
||||
if (WARN_ON(wiphy->extended_capabilities[j] &
|
||||
~supported_on_all))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rdev->wiphy.registered = true;
|
||||
rtnl_unlock();
|
||||
|
||||
|
||||
+2
-2
@@ -214,7 +214,7 @@ struct cfg80211_event {
|
||||
size_t req_ie_len;
|
||||
size_t resp_ie_len;
|
||||
struct cfg80211_bss *bss;
|
||||
u16 status;
|
||||
int status; /* -1 = failed; 0..65535 = status code */
|
||||
} cr;
|
||||
struct {
|
||||
const u8 *req_ie;
|
||||
@@ -374,7 +374,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
u16 status, bool wextev,
|
||||
int status, bool wextev,
|
||||
struct cfg80211_bss *bss);
|
||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
size_t ie_len, u16 reason, bool from_ap);
|
||||
|
||||
+136
-96
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
u16 status, gfp_t gfp);
|
||||
int status, gfp_t gfp);
|
||||
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user