For 4.11, we seem to have more than in the past few releases:
* socket owner support for connections, so when the wifi manager (e.g. wpa_supplicant) is killed, connections are torn down - wpa_supplicant is critical to managing certain operations, and can opt in to this where applicable * minstrel & minstrel_ht updates to be more efficient (time and space) * set wifi_acked/wifi_acked_valid for skb->destructor use in the kernel, which was already available to userspace * don't indicate new mesh peers that might be used if there's no room to add them * multicast-to-unicast support in mac80211, for better medium usage (since unicast frames can use *much* higher rates, by ~3 orders of magnitude) * add API to read channel (frequency) limitations from DT * add infrastructure to allow randomizing public action frames for MAC address privacy (still requires driver support) * many cleanups and small improvements/fixes across the board -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJYeKu7AAoJEGt7eEactAAdwjEP/RA4bXFMfkC7qUJ++cLrMMwY yCvjb8+ULWL2wbCzpfY37acbGJgot3DNoQJzrO2jMQPqyM9nRlTMg5aF49cI7t62 gU6daNKJaGBe/0yeG7lTJ4n5UtVCDtN45hGc06Yert+ewb9njiJf+XYrtCWetsIJ 5bOLYQKPWOz/7UyMH7uJ25zrPFaiA3y7XnXKPEudagG/EwEq9ZuUpSSfLwEAEBPi 6i/2w4fLj32vXRsQMvQT0sU6mjd+1ub8Is7w5l2F06iWwNYPzdSM0IbU+E+ie2tk sE6RA70c4ILrp8KisTAz2lJPa4XEpFkLhI3lzRRy8CVzjyyo/OJen92zvr2R7TVb /uZG9qfRQ3UitQmgeKd+wS8PsbRAyWUR/xhNxD2r7zARH2vliwyneU+zEpXLeGA1 Y4PrN1+Fk45Ye4/4XSbPO4cf1MHX7qinN4rjrpsJKPwoYD/gQ1cZvef4AbaKPvq6 oCKRVrwNoUuSB8NTcMLPqze3WCfhnJyVUhCZTyzHeW4uG81qrHwrvBvM25vcWGcm CcSWFktFIpuGML4FCU3byZfb0NkmJtpCD4n7P98WFPGjvsWIEVCMckqlC8x1F7B7 BqqjGS2mGA17Xy0uLfmN/JempesQJnZhnAnFERdyX1S1YQuKhLwEu7OsYegnStDL Cn1wFw2/qcgeTkJfBICB =UToW -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2017-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== For 4.11, we seem to have more than in the past few releases: * socket owner support for connections, so when the wifi manager (e.g. wpa_supplicant) is killed, connections are torn down - wpa_supplicant is critical to managing certain operations, and can opt in to this where applicable * minstrel & minstrel_ht updates to be more efficient (time and space) * set wifi_acked/wifi_acked_valid for skb->destructor use in the kernel, which was already available to userspace * don't indicate new mesh peers that might be used if there's no room to add them * multicast-to-unicast support in mac80211, for better medium usage (since unicast frames can use *much* higher rates, by ~3 orders of magnitude) * add API to read channel (frequency) limitations from DT * add infrastructure to allow randomizing public action frames for MAC address privacy (still requires driver support) * many cleanups and small improvements/fixes across the board ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
bb60b8b35a
24
Documentation/devicetree/bindings/net/wireless/ieee80211.txt
Normal file
24
Documentation/devicetree/bindings/net/wireless/ieee80211.txt
Normal file
|
@ -0,0 +1,24 @@
|
|||
Common IEEE 802.11 properties
|
||||
|
||||
This provides documentation of common properties that are valid for all wireless
|
||||
devices.
|
||||
|
||||
Optional properties:
|
||||
- ieee80211-freq-limit : list of supported frequency ranges in KHz. This can be
|
||||
used for devices that in a given config support less channels than
|
||||
normally. It may happen chipset supports a wide wireless band but it is
|
||||
limited to some part of it due to used antennas or power amplifier.
|
||||
An example case for this can be tri-band wireless router with two
|
||||
identical chipsets used for two different 5 GHz subbands. Using them
|
||||
incorrectly could not work or decrease performance noticeably.
|
||||
|
||||
Example:
|
||||
|
||||
pcie@0,0 {
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
wifi@0,0 {
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
ieee80211-freq-limit = <2402000 2482000>,
|
||||
<5170000 5250000>;
|
||||
};
|
||||
};
|
|
@ -44,6 +44,9 @@ Device registration
|
|||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: wiphy_new
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: wiphy_read_of_freq_limits
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: wiphy_register
|
||||
|
||||
|
|
|
@ -156,12 +156,12 @@ struct ieee80211_regdomain mydriver_jp_regdom = {
|
|||
//.alpha2 = "99", /* If I have no alpha2 to map it to */
|
||||
.reg_rules = {
|
||||
/* IEEE 802.11b/g, channels 1..14 */
|
||||
REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
|
||||
REG_RULE(2412-10, 2484+10, 40, 6, 20, 0),
|
||||
/* IEEE 802.11a, channels 34..48 */
|
||||
REG_RULE(5170-20, 5240+20, 40, 6, 20,
|
||||
REG_RULE(5170-10, 5240+10, 40, 6, 20,
|
||||
NL80211_RRF_NO_IR),
|
||||
/* IEEE 802.11a, channels 52..64 */
|
||||
REG_RULE(5260-20, 5320+20, 40, 6, 20,
|
||||
REG_RULE(5260-10, 5320+10, 40, 6, 20,
|
||||
NL80211_RRF_NO_IR|
|
||||
NL80211_RRF_DFS),
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ the data in regdb.c as an alternative to using CRDA.
|
|||
The file net/wireless/db.txt should be kept up-to-date with the db.txt
|
||||
file available in the git repository here:
|
||||
|
||||
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
|
||||
git://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
|
||||
|
||||
Again, most users in most situations should be using the CRDA package
|
||||
provided with their distribution, and in most other situations users
|
||||
|
|
|
@ -2451,8 +2451,7 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
|||
u32 phymode = __le32_to_cpu(resp->chan_change.phymode);
|
||||
u32 freq = __le32_to_cpu(resp->chan_change.freq);
|
||||
|
||||
ar->tgt_oper_chan =
|
||||
__ieee80211_get_channel(ar->hw->wiphy, freq);
|
||||
ar->tgt_oper_chan = ieee80211_get_channel(ar->hw->wiphy, freq);
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt chan change freq %u phymode %s\n",
|
||||
freq, ath10k_wmi_phymode_str(phymode));
|
||||
|
|
|
@ -2078,7 +2078,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
|
|||
ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
|
||||
|
||||
band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
|
||||
chan = __ieee80211_get_channel(priv->wdev.wiphy,
|
||||
chan = ieee80211_get_channel(priv->wdev.wiphy,
|
||||
ieee80211_channel_to_frequency(bss_info.bss_chan,
|
||||
band));
|
||||
|
||||
|
|
|
@ -185,6 +185,8 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
|
|||
|
||||
/* number of user priorities 802.11 uses */
|
||||
#define IEEE80211_NUM_UPS 8
|
||||
/* number of ACs */
|
||||
#define IEEE80211_NUM_ACS 4
|
||||
|
||||
#define IEEE80211_QOS_CTL_LEN 2
|
||||
/* 1d tag mask */
|
||||
|
|
|
@ -311,6 +311,34 @@ struct ieee80211_supported_band {
|
|||
struct ieee80211_sta_vht_cap vht_cap;
|
||||
};
|
||||
|
||||
/**
|
||||
* wiphy_read_of_freq_limits - read frequency limits from device tree
|
||||
*
|
||||
* @wiphy: the wireless device to get extra limits for
|
||||
*
|
||||
* Some devices may have extra limitations specified in DT. This may be useful
|
||||
* for chipsets that normally support more bands but are limited due to board
|
||||
* design (e.g. by antennas or external power amplifier).
|
||||
*
|
||||
* This function reads info from DT and uses it to *modify* channels (disable
|
||||
* unavailable ones). It's usually a *bad* idea to use it in drivers with
|
||||
* shared channel data as DT limitations are device specific. You should make
|
||||
* sure to call it only if channels in wiphy are copied and can be modified
|
||||
* without affecting other devices.
|
||||
*
|
||||
* As this function access device node it has to be called after set_wiphy_dev.
|
||||
* It also modifies channels so they have to be set first.
|
||||
* If using this helper, call it before wiphy_register().
|
||||
*/
|
||||
#ifdef CONFIG_OF
|
||||
void wiphy_read_of_freq_limits(struct wiphy *wiphy);
|
||||
#else /* CONFIG_OF */
|
||||
static inline void wiphy_read_of_freq_limits(struct wiphy *wiphy)
|
||||
{
|
||||
}
|
||||
#endif /* !CONFIG_OF */
|
||||
|
||||
|
||||
/*
|
||||
* Wireless hardware/device configuration structures and methods
|
||||
*/
|
||||
|
@ -1591,6 +1619,17 @@ struct cfg80211_sched_scan_plan {
|
|||
u32 iterations;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment.
|
||||
*
|
||||
* @band: band of BSS which should match for RSSI level adjustment.
|
||||
* @delta: value of RSSI level adjustment.
|
||||
*/
|
||||
struct cfg80211_bss_select_adjust {
|
||||
enum nl80211_band band;
|
||||
s8 delta;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_sched_scan_request - scheduled scan request description
|
||||
*
|
||||
|
@ -1626,6 +1665,16 @@ struct cfg80211_sched_scan_plan {
|
|||
* cycle. The driver may ignore this parameter and start
|
||||
* immediately (or at any other time), if this feature is not
|
||||
* supported.
|
||||
* @relative_rssi_set: Indicates whether @relative_rssi is set or not.
|
||||
* @relative_rssi: Relative RSSI threshold in dB to restrict scan result
|
||||
* reporting in connected state to cases where a matching BSS is determined
|
||||
* to have better or slightly worse RSSI than the current connected BSS.
|
||||
* The relative RSSI threshold values are ignored in disconnected state.
|
||||
* @rssi_adjust: delta dB of RSSI preference to be given to the BSSs that belong
|
||||
* to the specified band while deciding whether a better BSS is reported
|
||||
* using @relative_rssi. If delta is a negative number, the BSSs that
|
||||
* belong to the specified band will be penalized by delta dB in relative
|
||||
* comparisions.
|
||||
*/
|
||||
struct cfg80211_sched_scan_request {
|
||||
struct cfg80211_ssid *ssids;
|
||||
|
@ -1645,6 +1694,10 @@ struct cfg80211_sched_scan_request {
|
|||
u8 mac_addr[ETH_ALEN] __aligned(2);
|
||||
u8 mac_addr_mask[ETH_ALEN] __aligned(2);
|
||||
|
||||
bool relative_rssi_set;
|
||||
s8 relative_rssi;
|
||||
struct cfg80211_bss_select_adjust rssi_adjust;
|
||||
|
||||
/* internal */
|
||||
struct wiphy *wiphy;
|
||||
struct net_device *dev;
|
||||
|
@ -1952,17 +2005,6 @@ struct cfg80211_ibss_params {
|
|||
struct ieee80211_ht_cap ht_capa_mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_bss_select_adjust - BSS selection with RSSI adjustment.
|
||||
*
|
||||
* @band: band of BSS which should match for RSSI level adjustment.
|
||||
* @delta: value of RSSI level adjustment.
|
||||
*/
|
||||
struct cfg80211_bss_select_adjust {
|
||||
enum nl80211_band band;
|
||||
s8 delta;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_bss_selection - connection parameters for BSS selection.
|
||||
*
|
||||
|
@ -3837,6 +3879,9 @@ struct cfg80211_cached_keys;
|
|||
* @conn: (private) cfg80211 software SME connection state machine data
|
||||
* @connect_keys: (private) keys to set after connection is established
|
||||
* @conn_bss_type: connecting/connected BSS type
|
||||
* @conn_owner_nlportid: (private) connection owner socket port ID
|
||||
* @disconnect_wk: (private) auto-disconnect work
|
||||
* @disconnect_bssid: (private) the BSSID to use for auto-disconnect
|
||||
* @ibss_fixed: (private) IBSS is using fixed BSSID
|
||||
* @ibss_dfs_possible: (private) IBSS may change to a DFS channel
|
||||
* @event_list: (private) list for internal event processing
|
||||
|
@ -3868,6 +3913,10 @@ struct wireless_dev {
|
|||
struct cfg80211_conn *conn;
|
||||
struct cfg80211_cached_keys *connect_keys;
|
||||
enum ieee80211_bss_type conn_bss_type;
|
||||
u32 conn_owner_nlportid;
|
||||
|
||||
struct work_struct disconnect_wk;
|
||||
u8 disconnect_bssid[ETH_ALEN];
|
||||
|
||||
struct list_head event_list;
|
||||
spinlock_t event_lock;
|
||||
|
@ -3955,26 +4004,15 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band);
|
|||
*/
|
||||
int ieee80211_frequency_to_channel(int freq);
|
||||
|
||||
/*
|
||||
* Name indirection necessary because the ieee80211 code also has
|
||||
* a function named "ieee80211_get_channel", so if you include
|
||||
* cfg80211's header file you get cfg80211's version, if you try
|
||||
* to include both header files you'll (rightfully!) get a symbol
|
||||
* clash.
|
||||
*/
|
||||
struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
|
||||
int freq);
|
||||
/**
|
||||
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
|
||||
*
|
||||
* @wiphy: the struct wiphy to get the channel for
|
||||
* @freq: the center frequency of the channel
|
||||
*
|
||||
* Return: The channel struct from @wiphy at @freq.
|
||||
*/
|
||||
static inline struct ieee80211_channel *
|
||||
ieee80211_get_channel(struct wiphy *wiphy, int freq)
|
||||
{
|
||||
return __ieee80211_get_channel(wiphy, freq);
|
||||
}
|
||||
struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq);
|
||||
|
||||
/**
|
||||
* ieee80211_get_response_rate - get basic rate for a given rate
|
||||
|
@ -5048,20 +5086,32 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
|||
* @req_ie_len: association request IEs length
|
||||
* @resp_ie: association response IEs (may be %NULL)
|
||||
* @resp_ie_len: assoc response IEs length
|
||||
* @status: status code, 0 for successful connection, use
|
||||
* %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
|
||||
* the real status code for failures.
|
||||
* @status: status code, %WLAN_STATUS_SUCCESS for successful connection, use
|
||||
* %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
|
||||
* the real status code for failures. If this call is used to report a
|
||||
* failure due to a timeout (e.g., not receiving an Authentication frame
|
||||
* from the AP) instead of an explicit rejection by the AP, -1 is used to
|
||||
* indicate that this is a failure, but without a status code.
|
||||
* @timeout_reason is used to report the reason for the timeout in that
|
||||
* case.
|
||||
* @gfp: allocation flags
|
||||
* @timeout_reason: reason for connection timeout. This is used when the
|
||||
* connection fails due to a timeout instead of an explicit rejection from
|
||||
* the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is
|
||||
* not known. This value is used only if @status < 0 to indicate that the
|
||||
* failure is due to a timeout and not due to explicit rejection by the AP.
|
||||
* This value is ignored in other cases (@status >= 0).
|
||||
*
|
||||
* It should be called by the underlying driver whenever connect() has
|
||||
* succeeded. This is similar to cfg80211_connect_result(), but with the
|
||||
* option of identifying the exact bss entry for the connection. Only one of
|
||||
* these functions should be called.
|
||||
* It should be called by the underlying driver once execution of the connection
|
||||
* request from connect() has been completed. This is similar to
|
||||
* cfg80211_connect_result(), but with the option of identifying the exact bss
|
||||
* entry for the connection. Only one of these functions should be called.
|
||||
*/
|
||||
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, int status, gfp_t gfp);
|
||||
size_t resp_ie_len, int status, gfp_t gfp,
|
||||
enum nl80211_timeout_reason timeout_reason);
|
||||
|
||||
/**
|
||||
* cfg80211_connect_result - notify cfg80211 of connection result
|
||||
|
@ -5072,13 +5122,15 @@ void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
|||
* @req_ie_len: association request IEs length
|
||||
* @resp_ie: association response IEs (may be %NULL)
|
||||
* @resp_ie_len: assoc response IEs length
|
||||
* @status: status code, 0 for successful connection, use
|
||||
* @status: status code, %WLAN_STATUS_SUCCESS for successful connection, use
|
||||
* %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
|
||||
* the real status code for failures.
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* It should be called by the underlying driver whenever connect() has
|
||||
* succeeded.
|
||||
* It should be called by the underlying driver once execution of the connection
|
||||
* request from connect() has been completed. This is similar to
|
||||
* cfg80211_connect_bss() which allows the exact bss entry to be specified. Only
|
||||
* one of these functions should be called.
|
||||
*/
|
||||
static inline void
|
||||
cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
|
@ -5087,7 +5139,8 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
u16 status, gfp_t gfp)
|
||||
{
|
||||
cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie,
|
||||
resp_ie_len, status, gfp);
|
||||
resp_ie_len, status, gfp,
|
||||
NL80211_TIMEOUT_UNSPECIFIED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5098,6 +5151,7 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
* @req_ie: association request IEs (maybe be %NULL)
|
||||
* @req_ie_len: association request IEs length
|
||||
* @gfp: allocation flags
|
||||
* @timeout_reason: reason for connection timeout.
|
||||
*
|
||||
* It should be called by the underlying driver whenever connect() has failed
|
||||
* in a sequence where no explicit authentication/association rejection was
|
||||
|
@ -5107,10 +5161,11 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
*/
|
||||
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)
|
||||
const u8 *req_ie, size_t req_ie_len, gfp_t gfp,
|
||||
enum nl80211_timeout_reason timeout_reason)
|
||||
{
|
||||
cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, NULL, 0, -1,
|
||||
gfp);
|
||||
gfp, timeout_reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -505,25 +505,8 @@ static inline int iwe_stream_event_len_adjust(struct iw_request_info *info,
|
|||
/*
|
||||
* Wrapper to add an Wireless Event to a stream of events.
|
||||
*/
|
||||
static inline char *
|
||||
iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends,
|
||||
struct iw_event *iwe, int event_len)
|
||||
{
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
event_len = iwe_stream_event_len_adjust(info, event_len);
|
||||
|
||||
/* Check if it's possible */
|
||||
if(likely((stream + event_len) < ends)) {
|
||||
iwe->len = event_len;
|
||||
/* Beware of alignement issues on 64 bits */
|
||||
memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + lcp_len, &iwe->u,
|
||||
event_len - lcp_len);
|
||||
stream += event_len;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
char *iwe_stream_add_event(struct iw_request_info *info, char *stream,
|
||||
char *ends, struct iw_event *iwe, int event_len);
|
||||
|
||||
static inline char *
|
||||
iwe_stream_add_event_check(struct iw_request_info *info, char *stream,
|
||||
|
@ -541,26 +524,8 @@ iwe_stream_add_event_check(struct iw_request_info *info, char *stream,
|
|||
* Wrapper to add an short Wireless Event containing a pointer to a
|
||||
* stream of events.
|
||||
*/
|
||||
static inline char *
|
||||
iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends,
|
||||
struct iw_event *iwe, char *extra)
|
||||
{
|
||||
int event_len = iwe_stream_point_len(info) + iwe->u.data.length;
|
||||
int point_len = iwe_stream_point_len(info);
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
/* Check if it's possible */
|
||||
if(likely((stream + event_len) < ends)) {
|
||||
iwe->len = event_len;
|
||||
memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + lcp_len,
|
||||
((char *) &iwe->u) + IW_EV_POINT_OFF,
|
||||
IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + point_len, extra, iwe->u.data.length);
|
||||
stream += event_len;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
char *iwe_stream_add_point(struct iw_request_info *info, char *stream,
|
||||
char *ends, struct iw_event *iwe, char *extra);
|
||||
|
||||
static inline char *
|
||||
iwe_stream_add_point_check(struct iw_request_info *info, char *stream,
|
||||
|
@ -579,25 +544,8 @@ iwe_stream_add_point_check(struct iw_request_info *info, char *stream,
|
|||
* Be careful, this one is tricky to use properly :
|
||||
* At the first run, you need to have (value = event + IW_EV_LCP_LEN).
|
||||
*/
|
||||
static inline char *
|
||||
iwe_stream_add_value(struct iw_request_info *info, char *event, char *value,
|
||||
char *ends, struct iw_event *iwe, int event_len)
|
||||
{
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
/* Don't duplicate LCP */
|
||||
event_len -= IW_EV_LCP_LEN;
|
||||
|
||||
/* Check if it's possible */
|
||||
if(likely((value + event_len) < ends)) {
|
||||
/* Add new value */
|
||||
memcpy(value, &iwe->u, event_len);
|
||||
value += event_len;
|
||||
/* Patch LCP */
|
||||
iwe->len = value - event;
|
||||
memcpy(event, (char *) iwe, lcp_len);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
char *iwe_stream_add_value(struct iw_request_info *info, char *event,
|
||||
char *value, char *ends, struct iw_event *iwe,
|
||||
int event_len);
|
||||
|
||||
#endif /* _IW_HANDLER_H */
|
||||
|
|
|
@ -147,7 +147,6 @@ enum ieee80211_ac_numbers {
|
|||
IEEE80211_AC_BE = 2,
|
||||
IEEE80211_AC_BK = 3,
|
||||
};
|
||||
#define IEEE80211_NUM_ACS 4
|
||||
|
||||
/**
|
||||
* struct ieee80211_tx_queue_params - transmit queue configuration
|
||||
|
@ -1018,7 +1017,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
|||
* @RX_FLAG_DECRYPTED: This frame was decrypted in hardware.
|
||||
* @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame,
|
||||
* verification has been done by the hardware.
|
||||
* @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame.
|
||||
* @RX_FLAG_IV_STRIPPED: The IV and ICV are stripped from this frame.
|
||||
* If this flag is set, the stack cannot do any replay detection
|
||||
* hence the driver or hardware will have to do that.
|
||||
* @RX_FLAG_PN_VALIDATED: Currently only valid for CCMP/GCMP frames, this
|
||||
|
@ -1089,6 +1088,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
|||
* @RX_FLAG_ALLOW_SAME_PN: Allow the same PN as same packet before.
|
||||
* This is used for AMSDU subframes which can have the same PN as
|
||||
* the first subframe.
|
||||
* @RX_FLAG_ICV_STRIPPED: The ICV is stripped from this frame. CRC checking must
|
||||
* be done in the hardware.
|
||||
*/
|
||||
enum mac80211_rx_flags {
|
||||
RX_FLAG_MMIC_ERROR = BIT(0),
|
||||
|
@ -1124,6 +1125,7 @@ enum mac80211_rx_flags {
|
|||
RX_FLAG_RADIOTAP_VENDOR_DATA = BIT(31),
|
||||
RX_FLAG_MIC_STRIPPED = BIT_ULL(32),
|
||||
RX_FLAG_ALLOW_SAME_PN = BIT_ULL(33),
|
||||
RX_FLAG_ICV_STRIPPED = BIT_ULL(34),
|
||||
};
|
||||
|
||||
#define RX_FLAG_STBC_SHIFT 26
|
||||
|
|
|
@ -1820,6 +1820,8 @@ enum nl80211_commands {
|
|||
* and remove functions. NAN notifications will be sent in unicast to that
|
||||
* socket. Without this attribute, any socket can add functions and the
|
||||
* notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
|
||||
* If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
|
||||
* station will deauthenticate when the socket is closed.
|
||||
*
|
||||
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
|
||||
* the TDLS link initiator.
|
||||
|
@ -1980,6 +1982,24 @@ enum nl80211_commands {
|
|||
* @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also
|
||||
* used in various commands/events for specifying the BSSID.
|
||||
*
|
||||
* @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which
|
||||
* other BSSs has to be better or slightly worse than the current
|
||||
* connected BSS so that they get reported to user space.
|
||||
* This will give an opportunity to userspace to consider connecting to
|
||||
* other matching BSSs which have better or slightly worse RSSI than
|
||||
* the current connected BSS by using an offloaded operation to avoid
|
||||
* unnecessary wakeups.
|
||||
*
|
||||
* @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in
|
||||
* the specified band is to be adjusted before doing
|
||||
* %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out
|
||||
* better BSSs. The attribute value is a packed structure
|
||||
* value as specified by &struct nl80211_bss_select_rssi_adjust.
|
||||
*
|
||||
* @NL80211_ATTR_TIMEOUT_REASON: The reason for which an operation timed out.
|
||||
* u32 attribute with an &enum nl80211_timeout_reason value. This is used,
|
||||
* e.g., with %NL80211_CMD_CONNECT event.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -2386,6 +2406,11 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_BSSID,
|
||||
|
||||
NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
|
||||
NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
|
||||
|
||||
NL80211_ATTR_TIMEOUT_REASON,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -3078,6 +3103,13 @@ enum nl80211_reg_rule_attr {
|
|||
* how this API was implemented in the past. Also, due to the same problem,
|
||||
* the only way to create a matchset with only an RSSI filter (with this
|
||||
* attribute) is if there's only a single matchset with the RSSI attribute.
|
||||
* @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether
|
||||
* %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or
|
||||
* relative to current bss's RSSI.
|
||||
* @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for
|
||||
* BSS-es in the specified band is to be adjusted before doing
|
||||
* RSSI-based BSS selection. The attribute value is a packed structure
|
||||
* value as specified by &struct nl80211_bss_select_rssi_adjust.
|
||||
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
|
||||
* attribute number currently defined
|
||||
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
|
||||
|
@ -3087,6 +3119,8 @@ enum nl80211_sched_scan_match_attr {
|
|||
|
||||
NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
|
||||
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
|
||||
NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
|
||||
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
|
||||
|
@ -4697,6 +4731,13 @@ enum nl80211_feature_flags {
|
|||
* configuration (AP/mesh) with VHT rates.
|
||||
* @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup
|
||||
* with user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
|
||||
* @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA: This driver supports randomized TA
|
||||
* in @NL80211_CMD_FRAME while not associated.
|
||||
* @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports
|
||||
* randomized TA in @NL80211_CMD_FRAME while associated.
|
||||
* @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
|
||||
* for reporting BSSs with better RSSI than the current connected BSS
|
||||
* (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
|
@ -4712,6 +4753,9 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_BEACON_RATE_HT,
|
||||
NL80211_EXT_FEATURE_BEACON_RATE_VHT,
|
||||
NL80211_EXT_FEATURE_FILS_STA,
|
||||
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
|
||||
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
|
||||
NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
@ -4750,6 +4794,21 @@ enum nl80211_connect_failed_reason {
|
|||
NL80211_CONN_FAIL_BLOCKED_CLIENT,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_timeout_reason - timeout reasons
|
||||
*
|
||||
* @NL80211_TIMEOUT_UNSPECIFIED: Timeout reason unspecified.
|
||||
* @NL80211_TIMEOUT_SCAN: Scan (AP discovery) timed out.
|
||||
* @NL80211_TIMEOUT_AUTH: Authentication timed out.
|
||||
* @NL80211_TIMEOUT_ASSOC: Association timed out.
|
||||
*/
|
||||
enum nl80211_timeout_reason {
|
||||
NL80211_TIMEOUT_UNSPECIFIED,
|
||||
NL80211_TIMEOUT_SCAN,
|
||||
NL80211_TIMEOUT_AUTH,
|
||||
NL80211_TIMEOUT_ASSOC,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_scan_flags - scan request control flags
|
||||
*
|
||||
|
@ -4964,8 +5023,9 @@ enum nl80211_sched_scan_plan {
|
|||
/**
|
||||
* struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters.
|
||||
*
|
||||
* @band: band of BSS that must match for RSSI value adjustment.
|
||||
* @delta: value used to adjust the RSSI value of matching BSS.
|
||||
* @band: band of BSS that must match for RSSI value adjustment. The value
|
||||
* of this field is according to &enum nl80211_band.
|
||||
* @delta: value used to adjust the RSSI value of matching BSS in dB.
|
||||
*/
|
||||
struct nl80211_bss_select_rssi_adjust {
|
||||
__u8 band;
|
||||
|
|
|
@ -3563,6 +3563,17 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_nan_func_match);
|
||||
|
||||
static int ieee80211_set_multicast_to_unicast(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
const bool enabled)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
sdata->u.ap.multicast_to_unicast = enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
|
@ -3653,4 +3664,5 @@ const struct cfg80211_ops mac80211_config_ops = {
|
|||
.nan_change_conf = ieee80211_nan_change_conf,
|
||||
.add_nan_func = ieee80211_add_nan_func,
|
||||
.del_nan_func = ieee80211_del_nan_func,
|
||||
.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
|
||||
};
|
||||
|
|
|
@ -1270,7 +1270,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
|
|||
struct ieee80211_sub_if_data *sdata, *sdata_tmp;
|
||||
struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
|
||||
struct ieee80211_chanctx *new_ctx = NULL;
|
||||
int i, err, n_assigned, n_reserved, n_ready;
|
||||
int err, n_assigned, n_reserved, n_ready;
|
||||
int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
@ -1391,8 +1391,6 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
|
|||
* Update all structures, values and pointers to point to new channel
|
||||
* context(s).
|
||||
*/
|
||||
|
||||
i = 0;
|
||||
list_for_each_entry(ctx, &local->chanctx_list, list) {
|
||||
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
|
||||
continue;
|
||||
|
|
|
@ -243,6 +243,31 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
|
|||
return rv;
|
||||
}
|
||||
|
||||
static ssize_t misc_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
/* Max len of each line is 16 characters, plus 9 for 'pending:\n' */
|
||||
size_t bufsz = IEEE80211_MAX_QUEUES * 16 + 9;
|
||||
char *buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
char *pos = buf, *end = buf + bufsz - 1;
|
||||
ssize_t rv;
|
||||
int i;
|
||||
int ln;
|
||||
|
||||
pos += scnprintf(pos, end - pos, "pending:\n");
|
||||
|
||||
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
|
||||
ln = skb_queue_len(&local->pending[i]);
|
||||
pos += scnprintf(pos, end - pos, "[%i] %d\n",
|
||||
i, ln);
|
||||
}
|
||||
|
||||
rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
|
||||
kfree(buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static ssize_t queues_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -263,6 +288,7 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
|
|||
|
||||
DEBUGFS_READONLY_FILE_OPS(hwflags);
|
||||
DEBUGFS_READONLY_FILE_OPS(queues);
|
||||
DEBUGFS_READONLY_FILE_OPS(misc);
|
||||
|
||||
/* statistics stuff */
|
||||
|
||||
|
@ -331,6 +357,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
|||
DEBUGFS_ADD(total_ps_buffered);
|
||||
DEBUGFS_ADD(wep_iv);
|
||||
DEBUGFS_ADD(queues);
|
||||
DEBUGFS_ADD(misc);
|
||||
#ifdef CONFIG_PM
|
||||
DEBUGFS_ADD_MODE(reset, 0200);
|
||||
#endif
|
||||
|
|
|
@ -519,6 +519,8 @@ static ssize_t ieee80211_if_fmt_aqm(
|
|||
}
|
||||
IEEE80211_IF_FILE_R(aqm);
|
||||
|
||||
IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
|
||||
|
||||
/* IBSS attributes */
|
||||
static ssize_t ieee80211_if_fmt_tsf(
|
||||
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
|
||||
|
@ -683,6 +685,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
|
|||
DEBUGFS_ADD(dtim_count);
|
||||
DEBUGFS_ADD(num_buffered_multicast);
|
||||
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
|
||||
DEBUGFS_ADD_MODE(multicast_to_unicast, 0600);
|
||||
}
|
||||
|
||||
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
|
||||
|
|
|
@ -297,6 +297,7 @@ struct ieee80211_if_ap {
|
|||
driver_smps_mode; /* smps mode request */
|
||||
|
||||
struct work_struct request_smps_work;
|
||||
bool multicast_to_unicast;
|
||||
};
|
||||
|
||||
struct ieee80211_if_wds {
|
||||
|
@ -624,8 +625,8 @@ struct ieee80211_mesh_sync_ops {
|
|||
struct ieee80211_rx_status *rx_status);
|
||||
|
||||
/* should be called with beacon_data under RCU read lock */
|
||||
void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata,
|
||||
struct beacon_data *beacon);
|
||||
void (*adjust_tsf)(struct ieee80211_sub_if_data *sdata,
|
||||
struct beacon_data *beacon);
|
||||
/* add other framework functions here */
|
||||
};
|
||||
|
||||
|
@ -688,7 +689,6 @@ struct ieee80211_if_mesh {
|
|||
const struct ieee80211_mesh_sync_ops *sync_ops;
|
||||
s64 sync_offset_clockdrift_max;
|
||||
spinlock_t sync_offset_lock;
|
||||
bool adjusting_tbtt;
|
||||
/* mesh power save */
|
||||
enum nl80211_mesh_power_mode nonpeer_pm;
|
||||
int ps_peers_light_sleep;
|
||||
|
|
|
@ -279,10 +279,6 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
|
|||
/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
|
||||
*pos |= ifmsh->ps_peers_deep_sleep ?
|
||||
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00;
|
||||
*pos++ |= ifmsh->adjusting_tbtt ?
|
||||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
|
||||
*pos++ = 0x00;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -850,7 +846,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
|||
ifmsh->mesh_cc_id = 0; /* Disabled */
|
||||
/* register sync ops from extensible synchronization framework */
|
||||
ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
|
||||
ifmsh->adjusting_tbtt = false;
|
||||
ifmsh->sync_offset_clockdrift_max = 0;
|
||||
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
|
||||
ieee80211_mesh_root_setup(ifmsh);
|
||||
|
@ -1349,7 +1344,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
|||
ieee80211_mesh_rootpath(sdata);
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
|
||||
mesh_sync_adjust_tbtt(sdata);
|
||||
mesh_sync_adjust_tsf(sdata);
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
|
||||
mesh_bss_info_changed(sdata);
|
||||
|
|
|
@ -341,7 +341,7 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
|
||||
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
|
||||
void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211s_stop(void);
|
||||
#else
|
||||
static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
|
||||
|
|
|
@ -505,12 +505,14 @@ mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr,
|
|||
|
||||
/* Userspace handles station allocation */
|
||||
if (sdata->u.mesh.user_mpm ||
|
||||
sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
|
||||
cfg80211_notify_new_peer_candidate(sdata->dev, addr,
|
||||
elems->ie_start,
|
||||
elems->total_len,
|
||||
GFP_KERNEL);
|
||||
else
|
||||
sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
|
||||
if (mesh_peer_accepts_plinks(elems) &&
|
||||
mesh_plink_availables(sdata))
|
||||
cfg80211_notify_new_peer_candidate(sdata->dev, addr,
|
||||
elems->ie_start,
|
||||
elems->total_len,
|
||||
GFP_KERNEL);
|
||||
} else
|
||||
sta = __mesh_sta_info_alloc(sdata, addr);
|
||||
|
||||
return sta;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "mesh.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
/* This is not in the standard. It represents a tolerable tbtt drift below
|
||||
/* This is not in the standard. It represents a tolerable tsf drift below
|
||||
* which we do no TSF adjustment.
|
||||
*/
|
||||
#define TOFFSET_MINIMUM_ADJUSTMENT 10
|
||||
|
@ -46,7 +46,7 @@ static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
|
|||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
|
||||
}
|
||||
|
||||
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
|
||||
void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
@ -57,12 +57,12 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
spin_lock_bh(&ifmsh->sync_offset_lock);
|
||||
if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) {
|
||||
msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n",
|
||||
msync_dbg(sdata, "TSF : max clockdrift=%lld; adjusting\n",
|
||||
(long long) ifmsh->sync_offset_clockdrift_max);
|
||||
tsfdelta = -ifmsh->sync_offset_clockdrift_max;
|
||||
ifmsh->sync_offset_clockdrift_max = 0;
|
||||
} else {
|
||||
msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting by %llu\n",
|
||||
msync_dbg(sdata, "TSF : max clockdrift=%lld; adjusting by %llu\n",
|
||||
(long long) ifmsh->sync_offset_clockdrift_max,
|
||||
(unsigned long long) beacon_int_fraction);
|
||||
tsfdelta = -beacon_int_fraction;
|
||||
|
@ -123,7 +123,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
|
||||
if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
|
||||
clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
|
||||
msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
|
||||
sta->sta.addr);
|
||||
goto no_sync;
|
||||
|
@ -168,15 +167,13 @@ no_sync:
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata,
|
||||
static void mesh_sync_offset_adjust_tsf(struct ieee80211_sub_if_data *sdata,
|
||||
struct beacon_data *beacon)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u8 cap;
|
||||
|
||||
WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
|
||||
WARN_ON(!rcu_read_lock_held());
|
||||
cap = beacon->meshconf->meshconf_cap;
|
||||
|
||||
spin_lock_bh(&ifmsh->sync_offset_lock);
|
||||
|
||||
|
@ -187,24 +184,16 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata,
|
|||
* the tsf adjustment to the mesh tasklet
|
||||
*/
|
||||
msync_dbg(sdata,
|
||||
"TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n",
|
||||
"TSF : kicking off TSF adjustment with clockdrift_max=%lld\n",
|
||||
ifmsh->sync_offset_clockdrift_max);
|
||||
set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags);
|
||||
|
||||
ifmsh->adjusting_tbtt = true;
|
||||
} else {
|
||||
msync_dbg(sdata,
|
||||
"TBTT : max clockdrift=%lld; too small to adjust\n",
|
||||
"TSF : max clockdrift=%lld; too small to adjust\n",
|
||||
(long long)ifmsh->sync_offset_clockdrift_max);
|
||||
ifmsh->sync_offset_clockdrift_max = 0;
|
||||
|
||||
ifmsh->adjusting_tbtt = false;
|
||||
}
|
||||
spin_unlock_bh(&ifmsh->sync_offset_lock);
|
||||
|
||||
beacon->meshconf->meshconf_cap = ifmsh->adjusting_tbtt ?
|
||||
IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING | cap :
|
||||
~IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING & cap;
|
||||
}
|
||||
|
||||
static const struct sync_method sync_methods[] = {
|
||||
|
@ -212,7 +201,7 @@ static const struct sync_method sync_methods[] = {
|
|||
.method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
|
||||
.ops = {
|
||||
.rx_bcn_presp = &mesh_sync_offset_rx_bcn_presp,
|
||||
.adjust_tbtt = &mesh_sync_offset_adjust_tbtt,
|
||||
.adjust_tsf = &mesh_sync_offset_adjust_tsf,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1486,10 +1486,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local)
|
|||
|
||||
if (count == 1 && ieee80211_powersave_allowed(found)) {
|
||||
u8 dtimper = found->u.mgd.dtim_period;
|
||||
s32 beaconint_us;
|
||||
|
||||
beaconint_us = ieee80211_tu_to_usec(
|
||||
found->vif.bss_conf.beacon_int);
|
||||
|
||||
timeout = local->dynamic_ps_forced_timeout;
|
||||
if (timeout < 0)
|
||||
|
|
|
@ -159,21 +159,23 @@ minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
|||
void
|
||||
minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
|
||||
{
|
||||
unsigned int cur_prob;
|
||||
|
||||
if (unlikely(mrs->attempts > 0)) {
|
||||
mrs->sample_skipped = 0;
|
||||
mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
|
||||
cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
|
||||
if (unlikely(!mrs->att_hist)) {
|
||||
mrs->prob_ewma = mrs->cur_prob;
|
||||
mrs->prob_ewma = cur_prob;
|
||||
} else {
|
||||
/* update exponential weighted moving variance */
|
||||
mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd,
|
||||
mrs->cur_prob,
|
||||
mrs->prob_ewma,
|
||||
EWMA_LEVEL);
|
||||
mrs->prob_ewmv = minstrel_ewmv(mrs->prob_ewmv,
|
||||
cur_prob,
|
||||
mrs->prob_ewma,
|
||||
EWMA_LEVEL);
|
||||
|
||||
/*update exponential weighted moving avarage */
|
||||
mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
|
||||
mrs->cur_prob,
|
||||
cur_prob,
|
||||
EWMA_LEVEL);
|
||||
}
|
||||
mrs->att_hist += mrs->attempts;
|
||||
|
@ -365,6 +367,11 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
|
|||
return;
|
||||
#endif
|
||||
|
||||
/* Don't use EAPOL frames for sampling on non-mrr hw */
|
||||
if (mp->hw->max_rates == 1 &&
|
||||
(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
|
||||
return;
|
||||
|
||||
delta = (mi->total_packets * sampling_ratio / 100) -
|
||||
(mi->sample_packets + mi->sample_deferred / 2);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#define SAMPLE_COLUMNS 10 /* number of columns in sample table */
|
||||
|
||||
/* scaled fraction values */
|
||||
#define MINSTREL_SCALE 16
|
||||
#define MINSTREL_SCALE 12
|
||||
#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
|
||||
#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
|
||||
|
||||
|
@ -36,21 +36,16 @@ minstrel_ewma(int old, int new, int weight)
|
|||
}
|
||||
|
||||
/*
|
||||
* Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation
|
||||
* Perform EWMV (Exponentially Weighted Moving Variance) calculation
|
||||
*/
|
||||
static inline int
|
||||
minstrel_ewmsd(int old_ewmsd, int cur_prob, int prob_ewma, int weight)
|
||||
minstrel_ewmv(int old_ewmv, int cur_prob, int prob_ewma, int weight)
|
||||
{
|
||||
int diff, incr, tmp_var;
|
||||
int diff, incr;
|
||||
|
||||
/* calculate exponential weighted moving variance */
|
||||
diff = MINSTREL_TRUNC((cur_prob - prob_ewma) * 1000000);
|
||||
diff = cur_prob - prob_ewma;
|
||||
incr = (EWMA_DIV - weight) * diff / EWMA_DIV;
|
||||
tmp_var = old_ewmsd * old_ewmsd;
|
||||
tmp_var = weight * (tmp_var + diff * incr / 1000000) / EWMA_DIV;
|
||||
|
||||
/* return standard deviation */
|
||||
return (u16) int_sqrt(tmp_var);
|
||||
return weight * (old_ewmv + MINSTREL_TRUNC(diff * incr)) / EWMA_DIV;
|
||||
}
|
||||
|
||||
struct minstrel_rate_stats {
|
||||
|
@ -59,15 +54,13 @@ struct minstrel_rate_stats {
|
|||
u16 success, last_success;
|
||||
|
||||
/* total attempts/success counters */
|
||||
u64 att_hist, succ_hist;
|
||||
u32 att_hist, succ_hist;
|
||||
|
||||
/* statistis of packet delivery probability
|
||||
* cur_prob - current prob within last update intervall
|
||||
* prob_ewma - exponential weighted moving average of prob
|
||||
* prob_ewmsd - exp. weighted moving standard deviation of prob */
|
||||
unsigned int cur_prob;
|
||||
unsigned int prob_ewma;
|
||||
u16 prob_ewmsd;
|
||||
u16 prob_ewma;
|
||||
u16 prob_ewmv;
|
||||
|
||||
/* maximum retry counts */
|
||||
u8 retry_count;
|
||||
|
@ -153,6 +146,14 @@ struct minstrel_debugfs_info {
|
|||
char buf[];
|
||||
};
|
||||
|
||||
/* Get EWMSD (Exponentially Weighted Moving Standard Deviation) * 10 */
|
||||
static inline int
|
||||
minstrel_get_ewmsd10(struct minstrel_rate_stats *mrs)
|
||||
{
|
||||
unsigned int ewmv = mrs->prob_ewmv;
|
||||
return int_sqrt(MINSTREL_TRUNC(ewmv * 1000 * 1000));
|
||||
}
|
||||
|
||||
extern const struct rate_control_ops mac80211_minstrel;
|
||||
void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
|
||||
void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
|
||||
|
|
|
@ -75,7 +75,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
struct minstrel_sta_info *mi = inode->i_private;
|
||||
struct minstrel_debugfs_info *ms;
|
||||
unsigned int i, tp_max, tp_avg, prob, eprob;
|
||||
unsigned int i, tp_max, tp_avg, eprob;
|
||||
char *p;
|
||||
|
||||
ms = kmalloc(2048, GFP_KERNEL);
|
||||
|
@ -86,13 +86,14 @@ minstrel_stats_open(struct inode *inode, struct file *file)
|
|||
p = ms->buf;
|
||||
p += sprintf(p, "\n");
|
||||
p += sprintf(p,
|
||||
"best __________rate_________ ________statistics________ ________last_______ ______sum-of________\n");
|
||||
"best __________rate_________ ________statistics________ ____last_____ ______sum-of________\n");
|
||||
p += sprintf(p,
|
||||
"rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n");
|
||||
"rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [retry|suc|att] [#success | #attempts]\n");
|
||||
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
struct minstrel_rate *mr = &mi->r[i];
|
||||
struct minstrel_rate_stats *mrs = &mi->r[i].stats;
|
||||
unsigned int prob_ewmsd;
|
||||
|
||||
*(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' ';
|
||||
*(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' ';
|
||||
|
@ -107,17 +108,16 @@ minstrel_stats_open(struct inode *inode, struct file *file)
|
|||
|
||||
tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
|
||||
tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
|
||||
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
|
||||
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
|
||||
prob_ewmsd = minstrel_get_ewmsd10(mrs);
|
||||
|
||||
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
|
||||
" %3u.%1u %3u %3u %-3u "
|
||||
" %3u %3u %-3u "
|
||||
"%9llu %-9llu\n",
|
||||
tp_max / 10, tp_max % 10,
|
||||
tp_avg / 10, tp_avg % 10,
|
||||
eprob / 10, eprob % 10,
|
||||
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
|
||||
prob / 10, prob % 10,
|
||||
prob_ewmsd / 10, prob_ewmsd % 10,
|
||||
mrs->retry_count,
|
||||
mrs->last_success,
|
||||
mrs->last_attempts,
|
||||
|
@ -148,7 +148,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
struct minstrel_sta_info *mi = inode->i_private;
|
||||
struct minstrel_debugfs_info *ms;
|
||||
unsigned int i, tp_max, tp_avg, prob, eprob;
|
||||
unsigned int i, tp_max, tp_avg, eprob;
|
||||
char *p;
|
||||
|
||||
ms = kmalloc(2048, GFP_KERNEL);
|
||||
|
@ -161,6 +161,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
|
|||
for (i = 0; i < mi->n_rates; i++) {
|
||||
struct minstrel_rate *mr = &mi->r[i];
|
||||
struct minstrel_rate_stats *mrs = &mi->r[i].stats;
|
||||
unsigned int prob_ewmsd;
|
||||
|
||||
p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : ""));
|
||||
p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : ""));
|
||||
|
@ -175,16 +176,15 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
|
|||
|
||||
tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
|
||||
tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
|
||||
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
|
||||
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
|
||||
prob_ewmsd = minstrel_get_ewmsd10(mrs);
|
||||
|
||||
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,"
|
||||
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,"
|
||||
"%llu,%llu,%d,%d\n",
|
||||
tp_max / 10, tp_max % 10,
|
||||
tp_avg / 10, tp_avg % 10,
|
||||
eprob / 10, eprob % 10,
|
||||
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
|
||||
prob / 10, prob % 10,
|
||||
prob_ewmsd / 10, prob_ewmsd % 10,
|
||||
mrs->retry_count,
|
||||
mrs->last_success,
|
||||
mrs->last_attempts,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "rate.h"
|
||||
#include "sta_info.h"
|
||||
#include "rc80211_minstrel.h"
|
||||
#include "rc80211_minstrel_ht.h"
|
||||
|
||||
|
@ -154,67 +155,47 @@ MODULE_PARM_DESC(minstrel_vht_only,
|
|||
const struct mcs_group minstrel_mcs_groups[] = {
|
||||
MCS_GROUP(1, 0, BW_20),
|
||||
MCS_GROUP(2, 0, BW_20),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
MCS_GROUP(3, 0, BW_20),
|
||||
#endif
|
||||
|
||||
MCS_GROUP(1, 1, BW_20),
|
||||
MCS_GROUP(2, 1, BW_20),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
MCS_GROUP(3, 1, BW_20),
|
||||
#endif
|
||||
|
||||
MCS_GROUP(1, 0, BW_40),
|
||||
MCS_GROUP(2, 0, BW_40),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
MCS_GROUP(3, 0, BW_40),
|
||||
#endif
|
||||
|
||||
MCS_GROUP(1, 1, BW_40),
|
||||
MCS_GROUP(2, 1, BW_40),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
MCS_GROUP(3, 1, BW_40),
|
||||
#endif
|
||||
|
||||
CCK_GROUP,
|
||||
|
||||
#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
|
||||
VHT_GROUP(1, 0, BW_20),
|
||||
VHT_GROUP(2, 0, BW_20),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
VHT_GROUP(3, 0, BW_20),
|
||||
#endif
|
||||
|
||||
VHT_GROUP(1, 1, BW_20),
|
||||
VHT_GROUP(2, 1, BW_20),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
VHT_GROUP(3, 1, BW_20),
|
||||
#endif
|
||||
|
||||
VHT_GROUP(1, 0, BW_40),
|
||||
VHT_GROUP(2, 0, BW_40),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
VHT_GROUP(3, 0, BW_40),
|
||||
#endif
|
||||
|
||||
VHT_GROUP(1, 1, BW_40),
|
||||
VHT_GROUP(2, 1, BW_40),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
VHT_GROUP(3, 1, BW_40),
|
||||
#endif
|
||||
|
||||
VHT_GROUP(1, 0, BW_80),
|
||||
VHT_GROUP(2, 0, BW_80),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
VHT_GROUP(3, 0, BW_80),
|
||||
#endif
|
||||
|
||||
VHT_GROUP(1, 1, BW_80),
|
||||
VHT_GROUP(2, 1, BW_80),
|
||||
#if MINSTREL_MAX_STREAMS >= 3
|
||||
VHT_GROUP(3, 1, BW_80),
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
|
||||
|
@ -301,7 +282,7 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
|||
break;
|
||||
|
||||
/* short preamble */
|
||||
if (!(mi->groups[group].supported & BIT(idx)))
|
||||
if (!(mi->supported[group] & BIT(idx)))
|
||||
idx += 4;
|
||||
}
|
||||
return &mi->groups[group].rates[idx];
|
||||
|
@ -486,7 +467,7 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
|
|||
MCS_GROUP_RATES].streams;
|
||||
for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
|
||||
mg = &mi->groups[group];
|
||||
if (!mg->supported || group == MINSTREL_CCK_GROUP)
|
||||
if (!mi->supported[group] || group == MINSTREL_CCK_GROUP)
|
||||
continue;
|
||||
|
||||
tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
|
||||
|
@ -540,7 +521,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
|||
for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
|
||||
|
||||
mg = &mi->groups[group];
|
||||
if (!mg->supported)
|
||||
if (!mi->supported[group])
|
||||
continue;
|
||||
|
||||
mi->sample_count++;
|
||||
|
@ -550,7 +531,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
|||
tmp_group_tp_rate[j] = group;
|
||||
|
||||
for (i = 0; i < MCS_GROUP_RATES; i++) {
|
||||
if (!(mg->supported & BIT(i)))
|
||||
if (!(mi->supported[group] & BIT(i)))
|
||||
continue;
|
||||
|
||||
index = MCS_GROUP_RATES * group + i;
|
||||
|
@ -636,7 +617,7 @@ minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi)
|
|||
mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups);
|
||||
mg = &mi->groups[mi->sample_group];
|
||||
|
||||
if (!mg->supported)
|
||||
if (!mi->supported[mi->sample_group])
|
||||
continue;
|
||||
|
||||
if (++mg->index >= MCS_GROUP_RATES) {
|
||||
|
@ -657,7 +638,7 @@ minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
|
|||
while (group > 0) {
|
||||
group--;
|
||||
|
||||
if (!mi->groups[group].supported)
|
||||
if (!mi->supported[group])
|
||||
continue;
|
||||
|
||||
if (minstrel_mcs_groups[group].streams >
|
||||
|
@ -994,7 +975,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
|||
sample_idx = sample_table[mg->column][mg->index];
|
||||
minstrel_set_next_sample_idx(mi);
|
||||
|
||||
if (!(mg->supported & BIT(sample_idx)))
|
||||
if (!(mi->supported[sample_group] & BIT(sample_idx)))
|
||||
return -1;
|
||||
|
||||
mrs = &mg->rates[sample_idx];
|
||||
|
@ -1048,22 +1029,6 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
|||
return sample_idx;
|
||||
}
|
||||
|
||||
static void
|
||||
minstrel_ht_check_cck_shortpreamble(struct minstrel_priv *mp,
|
||||
struct minstrel_ht_sta *mi, bool val)
|
||||
{
|
||||
u8 supported = mi->groups[MINSTREL_CCK_GROUP].supported;
|
||||
|
||||
if (!supported || !mi->cck_supported_short)
|
||||
return;
|
||||
|
||||
if (supported & (mi->cck_supported_short << (val * 4)))
|
||||
return;
|
||||
|
||||
supported ^= mi->cck_supported_short | (mi->cck_supported_short << 4);
|
||||
mi->groups[MINSTREL_CCK_GROUP].supported = supported;
|
||||
}
|
||||
|
||||
static void
|
||||
minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct ieee80211_tx_rate_control *txrc)
|
||||
|
@ -1087,7 +1052,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|||
minstrel_aggr_check(sta, txrc->skb);
|
||||
|
||||
info->flags |= mi->tx_flags;
|
||||
minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
if (mp->fixed_rate_idx != -1)
|
||||
|
@ -1154,7 +1118,7 @@ minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
|||
mi->cck_supported_short |= BIT(i);
|
||||
}
|
||||
|
||||
mi->groups[MINSTREL_CCK_GROUP].supported = mi->cck_supported;
|
||||
mi->supported[MINSTREL_CCK_GROUP] = mi->cck_supported;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1168,6 +1132,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
|
|||
struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
|
||||
u16 sta_cap = sta->ht_cap.cap;
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
|
||||
struct sta_info *sinfo = container_of(sta, struct sta_info, sta);
|
||||
int use_vht;
|
||||
int n_supported = 0;
|
||||
int ack_dur;
|
||||
|
@ -1224,7 +1189,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
|
|||
u32 gflags = minstrel_mcs_groups[i].flags;
|
||||
int bw, nss;
|
||||
|
||||
mi->groups[i].supported = 0;
|
||||
mi->supported[i] = 0;
|
||||
if (i == MINSTREL_CCK_GROUP) {
|
||||
minstrel_ht_update_cck(mp, mi, sband, sta);
|
||||
continue;
|
||||
|
@ -1256,8 +1221,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
|
|||
if (use_vht && minstrel_vht_only)
|
||||
continue;
|
||||
#endif
|
||||
mi->groups[i].supported = mcs->rx_mask[nss - 1];
|
||||
if (mi->groups[i].supported)
|
||||
mi->supported[i] = mcs->rx_mask[nss - 1];
|
||||
if (mi->supported[i])
|
||||
n_supported++;
|
||||
continue;
|
||||
}
|
||||
|
@ -1283,16 +1248,19 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
|
|||
else
|
||||
bw = BW_20;
|
||||
|
||||
mi->groups[i].supported = minstrel_get_valid_vht_rates(bw, nss,
|
||||
mi->supported[i] = minstrel_get_valid_vht_rates(bw, nss,
|
||||
vht_cap->vht_mcs.tx_mcs_map);
|
||||
|
||||
if (mi->groups[i].supported)
|
||||
if (mi->supported[i])
|
||||
n_supported++;
|
||||
}
|
||||
|
||||
if (!n_supported)
|
||||
goto use_legacy;
|
||||
|
||||
if (test_sta_flag(sinfo, WLAN_STA_SHORT_PREAMBLE))
|
||||
mi->cck_supported_short |= mi->cck_supported_short << 4;
|
||||
|
||||
/* create an initial rate table with the lowest supported rates */
|
||||
minstrel_ht_update_stats(mp, mi);
|
||||
minstrel_ht_update_rates(mp, mi);
|
||||
|
|
|
@ -52,9 +52,6 @@ struct minstrel_mcs_group_data {
|
|||
u8 index;
|
||||
u8 column;
|
||||
|
||||
/* bitfield of supported MCS rates of this group */
|
||||
u16 supported;
|
||||
|
||||
/* sorted rate set within a MCS group*/
|
||||
u16 max_group_tp_rate[MAX_THR_RATES];
|
||||
u16 max_group_prob_rate;
|
||||
|
@ -101,6 +98,9 @@ struct minstrel_ht_sta {
|
|||
u8 cck_supported;
|
||||
u8 cck_supported_short;
|
||||
|
||||
/* Bitfield of supported MCS rates of all groups */
|
||||
u16 supported[MINSTREL_GROUPS_NB];
|
||||
|
||||
/* MCS rate group info and statistics */
|
||||
struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB];
|
||||
};
|
||||
|
|
|
@ -19,12 +19,12 @@ static char *
|
|||
minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
|
||||
{
|
||||
const struct mcs_group *mg;
|
||||
unsigned int j, tp_max, tp_avg, prob, eprob, tx_time;
|
||||
unsigned int j, tp_max, tp_avg, eprob, tx_time;
|
||||
char htmode = '2';
|
||||
char gimode = 'L';
|
||||
u32 gflags;
|
||||
|
||||
if (!mi->groups[i].supported)
|
||||
if (!mi->supported[i])
|
||||
return p;
|
||||
|
||||
mg = &minstrel_mcs_groups[i];
|
||||
|
@ -41,8 +41,9 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
|
|||
struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
|
||||
static const int bitrates[4] = { 10, 20, 55, 110 };
|
||||
int idx = i * MCS_GROUP_RATES + j;
|
||||
unsigned int prob_ewmsd;
|
||||
|
||||
if (!(mi->groups[i].supported & BIT(j)))
|
||||
if (!(mi->supported[i] & BIT(j)))
|
||||
continue;
|
||||
|
||||
if (gflags & IEEE80211_TX_RC_MCS) {
|
||||
|
@ -83,17 +84,16 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
|
|||
|
||||
tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
|
||||
tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
|
||||
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
|
||||
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
|
||||
prob_ewmsd = minstrel_get_ewmsd10(mrs);
|
||||
|
||||
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
|
||||
" %3u.%1u %3u %3u %-3u "
|
||||
" %3u %3u %-3u "
|
||||
"%9llu %-9llu\n",
|
||||
tp_max / 10, tp_max % 10,
|
||||
tp_avg / 10, tp_avg % 10,
|
||||
eprob / 10, eprob % 10,
|
||||
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
|
||||
prob / 10, prob % 10,
|
||||
prob_ewmsd / 10, prob_ewmsd % 10,
|
||||
mrs->retry_count,
|
||||
mrs->last_success,
|
||||
mrs->last_attempts,
|
||||
|
@ -130,9 +130,9 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
|
|||
|
||||
p += sprintf(p, "\n");
|
||||
p += sprintf(p,
|
||||
" best ____________rate__________ ________statistics________ ________last_______ ______sum-of________\n");
|
||||
" best ____________rate__________ ________statistics________ _____last____ ______sum-of________\n");
|
||||
p += sprintf(p,
|
||||
"mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [prob.|retry|suc|att] [#success | #attempts]\n");
|
||||
"mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob) sd(prob)] [retry|suc|att] [#success | #attempts]\n");
|
||||
|
||||
p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
|
||||
for (i = 0; i < MINSTREL_CCK_GROUP; i++)
|
||||
|
@ -165,12 +165,12 @@ static char *
|
|||
minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
|
||||
{
|
||||
const struct mcs_group *mg;
|
||||
unsigned int j, tp_max, tp_avg, prob, eprob, tx_time;
|
||||
unsigned int j, tp_max, tp_avg, eprob, tx_time;
|
||||
char htmode = '2';
|
||||
char gimode = 'L';
|
||||
u32 gflags;
|
||||
|
||||
if (!mi->groups[i].supported)
|
||||
if (!mi->supported[i])
|
||||
return p;
|
||||
|
||||
mg = &minstrel_mcs_groups[i];
|
||||
|
@ -187,8 +187,9 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
|
|||
struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
|
||||
static const int bitrates[4] = { 10, 20, 55, 110 };
|
||||
int idx = i * MCS_GROUP_RATES + j;
|
||||
unsigned int prob_ewmsd;
|
||||
|
||||
if (!(mi->groups[i].supported & BIT(j)))
|
||||
if (!(mi->supported[i] & BIT(j)))
|
||||
continue;
|
||||
|
||||
if (gflags & IEEE80211_TX_RC_MCS) {
|
||||
|
@ -226,16 +227,15 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
|
|||
|
||||
tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
|
||||
tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
|
||||
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
|
||||
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
|
||||
prob_ewmsd = minstrel_get_ewmsd10(mrs);
|
||||
|
||||
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,"
|
||||
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,"
|
||||
"%u,%llu,%llu,",
|
||||
tp_max / 10, tp_max % 10,
|
||||
tp_avg / 10, tp_avg % 10,
|
||||
eprob / 10, eprob % 10,
|
||||
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
|
||||
prob / 10, prob % 10,
|
||||
prob_ewmsd / 10, prob_ewmsd % 10,
|
||||
mrs->retry_count,
|
||||
mrs->last_success,
|
||||
mrs->last_attempts,
|
||||
|
|
|
@ -1908,7 +1908,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
|||
unsigned int frag, seq;
|
||||
struct ieee80211_fragment_entry *entry;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_rx_status *status;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
fc = hdr->frame_control;
|
||||
|
@ -2034,9 +2033,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
|||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* Complete frame has been reassembled - process it now */
|
||||
status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
|
||||
out:
|
||||
ieee80211_led_rx(rx->local);
|
||||
out_no_led:
|
||||
|
|
|
@ -1120,7 +1120,6 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
|||
u32 rate_masks[NUM_NL80211_BANDS] = {};
|
||||
u8 bands_used = 0;
|
||||
u8 *ie;
|
||||
size_t len;
|
||||
|
||||
iebufsz = local->scan_ies_len + req->ie_len;
|
||||
|
||||
|
@ -1145,10 +1144,9 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
|
||||
|
||||
len = ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
|
||||
&sched_scan_ies, req->ie,
|
||||
req->ie_len, bands_used,
|
||||
rate_masks, &chandef);
|
||||
ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
|
||||
&sched_scan_ies, req->ie,
|
||||
req->ie_len, bands_used, rate_masks, &chandef);
|
||||
|
||||
ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
|
||||
if (ret == 0) {
|
||||
|
|
|
@ -513,23 +513,23 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
|
|||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct station_info *sinfo;
|
||||
struct station_info *sinfo = NULL;
|
||||
int err = 0;
|
||||
|
||||
lockdep_assert_held(&local->sta_mtx);
|
||||
|
||||
sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
|
||||
if (!sinfo) {
|
||||
err = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* check if STA exists already */
|
||||
if (sta_info_get_bss(sdata, sta->sta.addr)) {
|
||||
err = -EEXIST;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
|
||||
if (!sinfo) {
|
||||
err = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
local->num_sta++;
|
||||
local->sta_generation++;
|
||||
smp_mb();
|
||||
|
@ -2051,16 +2051,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct rate_control_ref *ref = NULL;
|
||||
u32 thr = 0;
|
||||
int i, ac, cpu;
|
||||
struct ieee80211_sta_rx_stats *last_rxstats;
|
||||
|
||||
last_rxstats = sta_get_last_rx_stats(sta);
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
|
||||
ref = local->rate_ctrl;
|
||||
|
||||
sinfo->generation = sdata->local->sta_generation;
|
||||
|
||||
/* do before driver, so beacon filtering drivers have a
|
||||
|
|
|
@ -541,6 +541,11 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
|
|||
} else if (info->ack_frame_id) {
|
||||
ieee80211_report_ack_skb(local, info, acked, dropped);
|
||||
}
|
||||
|
||||
if (!dropped && skb->destructor) {
|
||||
skb->wifi_acked_valid = 1;
|
||||
skb->wifi_acked = acked;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -633,10 +638,9 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
|
|||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_supported_band *sband;
|
||||
int retry_count;
|
||||
int rates_idx;
|
||||
bool acked, noack_success;
|
||||
|
||||
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
|
||||
ieee80211_tx_get_rates(hw, info, &retry_count);
|
||||
|
||||
sband = hw->wiphy->bands[info->band];
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
@ -63,6 +64,10 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
|||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
u32 rate_flags = 0;
|
||||
|
||||
/* assume HW handles this */
|
||||
if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(tx->sdata->vif.chanctx_conf);
|
||||
if (chanctx_conf) {
|
||||
|
@ -71,10 +76,6 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
|||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* assume HW handles this */
|
||||
if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
|
||||
return 0;
|
||||
|
||||
/* uh huh? */
|
||||
if (WARN_ON_ONCE(tx->rate.idx < 0))
|
||||
return 0;
|
||||
|
@ -3574,6 +3575,115 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int ieee80211_change_da(struct sk_buff *skb, struct sta_info *sta)
|
||||
{
|
||||
struct ethhdr *eth;
|
||||
int err;
|
||||
|
||||
err = skb_ensure_writable(skb, ETH_HLEN);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
eth = (void *)skb->data;
|
||||
ether_addr_copy(eth->h_dest, sta->sta.addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ieee80211_multicast_to_unicast(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
const struct ethhdr *eth = (void *)skb->data;
|
||||
const struct vlan_ethhdr *ethvlan = (void *)skb->data;
|
||||
__be16 ethertype;
|
||||
|
||||
if (likely(!is_multicast_ether_addr(eth->h_dest)))
|
||||
return false;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
if (sdata->u.vlan.sta)
|
||||
return false;
|
||||
if (sdata->wdev.use_4addr)
|
||||
return false;
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_AP:
|
||||
/* check runtime toggle for this bss */
|
||||
if (!sdata->bss->multicast_to_unicast)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* multicast to unicast conversion only for some payload */
|
||||
ethertype = eth->h_proto;
|
||||
if (ethertype == htons(ETH_P_8021Q) && skb->len >= VLAN_ETH_HLEN)
|
||||
ethertype = ethvlan->h_vlan_encapsulated_proto;
|
||||
switch (ethertype) {
|
||||
case htons(ETH_P_ARP):
|
||||
case htons(ETH_P_IP):
|
||||
case htons(ETH_P_IPV6):
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_convert_to_unicast(struct sk_buff *skb, struct net_device *dev,
|
||||
struct sk_buff_head *queue)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
const struct ethhdr *eth = (struct ethhdr *)skb->data;
|
||||
struct sta_info *sta, *first = NULL;
|
||||
struct sk_buff *cloned_skb;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sdata != sta->sdata)
|
||||
/* AP-VLAN mismatch */
|
||||
continue;
|
||||
if (unlikely(ether_addr_equal(eth->h_source, sta->sta.addr)))
|
||||
/* do not send back to source */
|
||||
continue;
|
||||
if (!first) {
|
||||
first = sta;
|
||||
continue;
|
||||
}
|
||||
cloned_skb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!cloned_skb)
|
||||
goto multicast;
|
||||
if (unlikely(ieee80211_change_da(cloned_skb, sta))) {
|
||||
dev_kfree_skb(cloned_skb);
|
||||
goto multicast;
|
||||
}
|
||||
__skb_queue_tail(queue, cloned_skb);
|
||||
}
|
||||
|
||||
if (likely(first)) {
|
||||
if (unlikely(ieee80211_change_da(skb, first)))
|
||||
goto multicast;
|
||||
__skb_queue_tail(queue, skb);
|
||||
} else {
|
||||
/* no STA connected, drop */
|
||||
kfree_skb(skb);
|
||||
skb = NULL;
|
||||
}
|
||||
|
||||
goto out;
|
||||
multicast:
|
||||
__skb_queue_purge(queue);
|
||||
__skb_queue_tail(queue, skb);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs
|
||||
* @skb: packet to be sent
|
||||
|
@ -3584,7 +3694,17 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0);
|
||||
if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) {
|
||||
struct sk_buff_head queue;
|
||||
|
||||
__skb_queue_head_init(&queue);
|
||||
ieee80211_convert_to_unicast(skb, dev, &queue);
|
||||
while ((skb = __skb_dequeue(&queue)))
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0);
|
||||
} else {
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0);
|
||||
}
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
|
@ -4077,7 +4197,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
if (ifmsh->sync_ops)
|
||||
ifmsh->sync_ops->adjust_tbtt(sdata, beacon);
|
||||
ifmsh->sync_ops->adjust_tsf(sdata, beacon);
|
||||
|
||||
skb = dev_alloc_skb(local->tx_headroom +
|
||||
beacon->head_len +
|
||||
|
|
|
@ -436,14 +436,10 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
|
|||
struct sta_info *sta, u8 opmode,
|
||||
enum nl80211_band band)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
enum ieee80211_sta_rx_bandwidth new_bw;
|
||||
u32 changed = 0;
|
||||
u8 nss;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
||||
/* ignore - no support for BF yet */
|
||||
if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)
|
||||
return 0;
|
||||
|
|
|
@ -293,7 +293,8 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
|
|||
return RX_DROP_UNUSABLE;
|
||||
ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
|
||||
/* remove ICV */
|
||||
if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
|
||||
if (!(status->flag & RX_FLAG_ICV_STRIPPED) &&
|
||||
pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
|
|||
return RX_DROP_UNUSABLE;
|
||||
|
||||
/* Trim ICV */
|
||||
skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
|
||||
if (!(status->flag & RX_FLAG_ICV_STRIPPED))
|
||||
skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
|
||||
|
||||
/* Remove IV */
|
||||
memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen);
|
||||
|
|
|
@ -176,6 +176,50 @@ static void rfkill_led_trigger_unregister(struct rfkill *rfkill)
|
|||
{
|
||||
led_trigger_unregister(&rfkill->led_trigger);
|
||||
}
|
||||
|
||||
static struct led_trigger rfkill_any_led_trigger;
|
||||
static struct work_struct rfkill_any_work;
|
||||
|
||||
static void rfkill_any_led_trigger_worker(struct work_struct *work)
|
||||
{
|
||||
enum led_brightness brightness = LED_OFF;
|
||||
struct rfkill *rfkill;
|
||||
|
||||
mutex_lock(&rfkill_global_mutex);
|
||||
list_for_each_entry(rfkill, &rfkill_list, node) {
|
||||
if (!(rfkill->state & RFKILL_BLOCK_ANY)) {
|
||||
brightness = LED_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&rfkill_global_mutex);
|
||||
|
||||
led_trigger_event(&rfkill_any_led_trigger, brightness);
|
||||
}
|
||||
|
||||
static void rfkill_any_led_trigger_event(void)
|
||||
{
|
||||
schedule_work(&rfkill_any_work);
|
||||
}
|
||||
|
||||
static void rfkill_any_led_trigger_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
rfkill_any_led_trigger_event();
|
||||
}
|
||||
|
||||
static int rfkill_any_led_trigger_register(void)
|
||||
{
|
||||
INIT_WORK(&rfkill_any_work, rfkill_any_led_trigger_worker);
|
||||
rfkill_any_led_trigger.name = "rfkill-any";
|
||||
rfkill_any_led_trigger.activate = rfkill_any_led_trigger_activate;
|
||||
return led_trigger_register(&rfkill_any_led_trigger);
|
||||
}
|
||||
|
||||
static void rfkill_any_led_trigger_unregister(void)
|
||||
{
|
||||
led_trigger_unregister(&rfkill_any_led_trigger);
|
||||
cancel_work_sync(&rfkill_any_work);
|
||||
}
|
||||
#else
|
||||
static void rfkill_led_trigger_event(struct rfkill *rfkill)
|
||||
{
|
||||
|
@ -189,6 +233,19 @@ static inline int rfkill_led_trigger_register(struct rfkill *rfkill)
|
|||
static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill)
|
||||
{
|
||||
}
|
||||
|
||||
static void rfkill_any_led_trigger_event(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int rfkill_any_led_trigger_register(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rfkill_any_led_trigger_unregister(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_RFKILL_LEDS */
|
||||
|
||||
static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill,
|
||||
|
@ -297,6 +354,7 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
|||
spin_unlock_irqrestore(&rfkill->lock, flags);
|
||||
|
||||
rfkill_led_trigger_event(rfkill);
|
||||
rfkill_any_led_trigger_event();
|
||||
|
||||
if (prev != curr)
|
||||
rfkill_event(rfkill);
|
||||
|
@ -477,11 +535,9 @@ bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
|
|||
spin_unlock_irqrestore(&rfkill->lock, flags);
|
||||
|
||||
rfkill_led_trigger_event(rfkill);
|
||||
rfkill_any_led_trigger_event();
|
||||
|
||||
if (!rfkill->registered)
|
||||
return ret;
|
||||
|
||||
if (prev != blocked)
|
||||
if (rfkill->registered && prev != blocked)
|
||||
schedule_work(&rfkill->uevent_work);
|
||||
|
||||
return ret;
|
||||
|
@ -523,6 +579,7 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
|
|||
schedule_work(&rfkill->uevent_work);
|
||||
|
||||
rfkill_led_trigger_event(rfkill);
|
||||
rfkill_any_led_trigger_event();
|
||||
|
||||
return blocked;
|
||||
}
|
||||
|
@ -572,6 +629,7 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
|
|||
schedule_work(&rfkill->uevent_work);
|
||||
|
||||
rfkill_led_trigger_event(rfkill);
|
||||
rfkill_any_led_trigger_event();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(rfkill_set_states);
|
||||
|
@ -988,6 +1046,7 @@ int __must_check rfkill_register(struct rfkill *rfkill)
|
|||
#endif
|
||||
}
|
||||
|
||||
rfkill_any_led_trigger_event();
|
||||
rfkill_send_events(rfkill, RFKILL_OP_ADD);
|
||||
|
||||
mutex_unlock(&rfkill_global_mutex);
|
||||
|
@ -1020,6 +1079,7 @@ void rfkill_unregister(struct rfkill *rfkill)
|
|||
mutex_lock(&rfkill_global_mutex);
|
||||
rfkill_send_events(rfkill, RFKILL_OP_DEL);
|
||||
list_del_init(&rfkill->node);
|
||||
rfkill_any_led_trigger_event();
|
||||
mutex_unlock(&rfkill_global_mutex);
|
||||
|
||||
rfkill_led_trigger_unregister(rfkill);
|
||||
|
@ -1266,24 +1326,33 @@ static int __init rfkill_init(void)
|
|||
|
||||
error = class_register(&rfkill_class);
|
||||
if (error)
|
||||
goto out;
|
||||
goto error_class;
|
||||
|
||||
error = misc_register(&rfkill_miscdev);
|
||||
if (error) {
|
||||
class_unregister(&rfkill_class);
|
||||
goto out;
|
||||
}
|
||||
if (error)
|
||||
goto error_misc;
|
||||
|
||||
error = rfkill_any_led_trigger_register();
|
||||
if (error)
|
||||
goto error_led_trigger;
|
||||
|
||||
#ifdef CONFIG_RFKILL_INPUT
|
||||
error = rfkill_handler_init();
|
||||
if (error) {
|
||||
misc_deregister(&rfkill_miscdev);
|
||||
class_unregister(&rfkill_class);
|
||||
goto out;
|
||||
}
|
||||
if (error)
|
||||
goto error_input;
|
||||
#endif
|
||||
|
||||
out:
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_RFKILL_INPUT
|
||||
error_input:
|
||||
rfkill_any_led_trigger_unregister();
|
||||
#endif
|
||||
error_led_trigger:
|
||||
misc_deregister(&rfkill_miscdev);
|
||||
error_misc:
|
||||
class_unregister(&rfkill_class);
|
||||
error_class:
|
||||
return error;
|
||||
}
|
||||
subsys_initcall(rfkill_init);
|
||||
|
@ -1293,6 +1362,7 @@ static void __exit rfkill_exit(void)
|
|||
#ifdef CONFIG_RFKILL_INPUT
|
||||
rfkill_handler_exit();
|
||||
#endif
|
||||
rfkill_any_led_trigger_unregister();
|
||||
misc_deregister(&rfkill_miscdev);
|
||||
class_unregister(&rfkill_class);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
|
|||
|
||||
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
|
||||
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
|
||||
cfg80211-$(CONFIG_OF) += of.o
|
||||
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
|
||||
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
|
||||
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
|
||||
|
|
|
@ -1142,6 +1142,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
|||
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
|
||||
dev->priv_flags |= IFF_DONT_BRIDGE;
|
||||
|
||||
INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
|
||||
|
||||
nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
|
||||
break;
|
||||
case NETDEV_GOING_DOWN:
|
||||
|
@ -1230,6 +1232,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
|||
#ifdef CONFIG_CFG80211_WEXT
|
||||
kzfree(wdev->wext.keys);
|
||||
#endif
|
||||
flush_work(&wdev->disconnect_wk);
|
||||
}
|
||||
/*
|
||||
* synchronise (so that we won't find this netdev
|
||||
|
|
|
@ -228,6 +228,7 @@ struct cfg80211_event {
|
|||
size_t resp_ie_len;
|
||||
struct cfg80211_bss *bss;
|
||||
int status; /* -1 = failed; 0..65535 = status code */
|
||||
enum nl80211_timeout_reason timeout_reason;
|
||||
} cr;
|
||||
struct {
|
||||
const u8 *req_ie;
|
||||
|
@ -388,7 +389,8 @@ 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,
|
||||
int status, bool wextev,
|
||||
struct cfg80211_bss *bss);
|
||||
struct cfg80211_bss *bss,
|
||||
enum nl80211_timeout_reason timeout_reason);
|
||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
size_t ie_len, u16 reason, bool from_ap);
|
||||
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
||||
|
@ -400,6 +402,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
|
|||
const u8 *resp_ie, size_t resp_ie_len);
|
||||
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
void cfg80211_autodisconnect_wk(struct work_struct *work);
|
||||
|
||||
/* SME implementation */
|
||||
void cfg80211_conn_work(struct work_struct *work);
|
||||
|
@ -430,6 +433,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
||||
void cfg80211_process_wdev_events(struct wireless_dev *wdev);
|
||||
|
||||
bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
|
||||
u32 center_freq_khz, u32 bw_khz);
|
||||
|
||||
/**
|
||||
* cfg80211_chandef_dfs_usable - checks if chandef is DFS usable
|
||||
* @wiphy: the wiphy to validate against
|
||||
|
|
|
@ -48,7 +48,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
|||
/* update current_bss etc., consumes the bss reference */
|
||||
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
|
||||
status_code,
|
||||
status_code == WLAN_STATUS_SUCCESS, bss);
|
||||
status_code == WLAN_STATUS_SUCCESS, bss,
|
||||
NL80211_TIMEOUT_UNSPECIFIED);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
|
||||
|
||||
|
@ -345,6 +346,11 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
|
|||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
|
||||
return 0;
|
||||
|
||||
if (ether_addr_equal(wdev->disconnect_bssid, bssid) ||
|
||||
(wdev->current_bss &&
|
||||
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
|
||||
return rdev_deauth(rdev, dev, &req);
|
||||
}
|
||||
|
||||
|
@ -657,8 +663,25 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!ether_addr_equal(mgmt->sa, wdev_address(wdev)))
|
||||
return -EINVAL;
|
||||
if (!ether_addr_equal(mgmt->sa, wdev_address(wdev))) {
|
||||
/* Allow random TA to be used with Public Action frames if the
|
||||
* driver has indicated support for this. Otherwise, only allow
|
||||
* the local address to be used.
|
||||
*/
|
||||
if (!ieee80211_is_action(mgmt->frame_control) ||
|
||||
mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
|
||||
return -EINVAL;
|
||||
if (!wdev->current_bss &&
|
||||
!wiphy_ext_feature_isset(
|
||||
&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
|
||||
return -EINVAL;
|
||||
if (wdev->current_bss &&
|
||||
!wiphy_ext_feature_isset(
|
||||
&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Transmit the Action frame as requested by user space */
|
||||
return rdev_mgmt_tx(rdev, wdev, params, cookie);
|
||||
|
|
|
@ -405,6 +405,11 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
[NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
|
||||
[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
|
||||
[NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
|
||||
[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
|
||||
[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
|
||||
.len = sizeof(struct nl80211_bss_select_rssi_adjust)
|
||||
},
|
||||
[NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
@ -6775,13 +6780,10 @@ nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
|
|||
|
||||
/*
|
||||
* If scan plans are not specified,
|
||||
* %NL80211_ATTR_SCHED_SCAN_INTERVAL must be specified. In this
|
||||
* %NL80211_ATTR_SCHED_SCAN_INTERVAL will be specified. In this
|
||||
* case one scan plan will be set with the specified scan
|
||||
* interval and infinite number of iterations.
|
||||
*/
|
||||
if (!attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
|
||||
return -EINVAL;
|
||||
|
||||
interval = nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
|
||||
if (!interval)
|
||||
return -EINVAL;
|
||||
|
@ -6953,6 +6955,12 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
if (!n_plans || n_plans > wiphy->max_sched_scan_plans)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!wiphy_ext_feature_isset(
|
||||
wiphy, NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI) &&
|
||||
(attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] ||
|
||||
attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
request = kzalloc(sizeof(*request)
|
||||
+ sizeof(*request->ssids) * n_ssids
|
||||
+ sizeof(*request->match_sets) * n_match_sets
|
||||
|
@ -7159,6 +7167,26 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
request->delay =
|
||||
nla_get_u32(attrs[NL80211_ATTR_SCHED_SCAN_DELAY]);
|
||||
|
||||
if (attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]) {
|
||||
request->relative_rssi = nla_get_s8(
|
||||
attrs[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI]);
|
||||
request->relative_rssi_set = true;
|
||||
}
|
||||
|
||||
if (request->relative_rssi_set &&
|
||||
attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]) {
|
||||
struct nl80211_bss_select_rssi_adjust *rssi_adjust;
|
||||
|
||||
rssi_adjust = nla_data(
|
||||
attrs[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST]);
|
||||
request->rssi_adjust.band = rssi_adjust->band;
|
||||
request->rssi_adjust.delta = rssi_adjust->delta;
|
||||
if (!is_band_valid(wiphy, request->rssi_adjust.band)) {
|
||||
err = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
err = nl80211_parse_sched_scan_plans(wiphy, n_plans, request, attrs);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
@ -8053,8 +8081,17 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
|||
err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
|
||||
if (!err) {
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
|
||||
err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
|
||||
ssid, ssid_len, &req);
|
||||
|
||||
if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
|
||||
dev->ieee80211_ptr->conn_owner_nlportid =
|
||||
info->snd_portid;
|
||||
memcpy(dev->ieee80211_ptr->disconnect_bssid,
|
||||
bssid, ETH_ALEN);
|
||||
}
|
||||
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
}
|
||||
|
||||
|
@ -8773,11 +8810,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
|
||||
err = cfg80211_connect(rdev, dev, &connect, connkeys,
|
||||
connect.prev_bssid);
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
if (err)
|
||||
kzfree(connkeys);
|
||||
|
||||
if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
|
||||
dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
|
||||
if (connect.bssid)
|
||||
memcpy(dev->ieee80211_ptr->disconnect_bssid,
|
||||
connect.bssid, ETH_ALEN);
|
||||
else
|
||||
memset(dev->ieee80211_ptr->disconnect_bssid,
|
||||
0, ETH_ALEN);
|
||||
}
|
||||
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -9673,6 +9723,20 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
|
|||
if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (req->relative_rssi_set) {
|
||||
struct nl80211_bss_select_rssi_adjust rssi_adjust;
|
||||
|
||||
if (nla_put_s8(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
|
||||
req->relative_rssi))
|
||||
return -ENOBUFS;
|
||||
|
||||
rssi_adjust.band = req->rssi_adjust.band;
|
||||
rssi_adjust.delta = req->rssi_adjust.delta;
|
||||
if (nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
|
||||
sizeof(rssi_adjust), &rssi_adjust))
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
|
||||
if (!freqs)
|
||||
return -ENOBUFS;
|
||||
|
@ -11807,9 +11871,6 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
|
|||
const struct nlattr *nla;
|
||||
bool enabled;
|
||||
|
||||
if (netif_running(dev))
|
||||
return -EBUSY;
|
||||
|
||||
if (!rdev->ops->set_multicast_to_unicast)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
@ -12810,7 +12871,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
|
|||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int nl80211_send_scan_msg(struct sk_buff *msg,
|
||||
static int nl80211_prep_scan_msg(struct sk_buff *msg,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
u32 portid, u32 seq, int flags,
|
||||
|
@ -12841,7 +12902,7 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
|
|||
}
|
||||
|
||||
static int
|
||||
nl80211_send_sched_scan_msg(struct sk_buff *msg,
|
||||
nl80211_prep_sched_scan_msg(struct sk_buff *msg,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
u32 portid, u32 seq, int flags, u32 cmd)
|
||||
|
@ -12873,7 +12934,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
|
|||
if (!msg)
|
||||
return;
|
||||
|
||||
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
|
||||
if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
|
||||
NL80211_CMD_TRIGGER_SCAN) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
|
@ -12892,7 +12953,7 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
|
|||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
|
||||
if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
|
||||
aborted ? NL80211_CMD_SCAN_ABORTED :
|
||||
NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
|
||||
nlmsg_free(msg);
|
||||
|
@ -12902,8 +12963,9 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
|
|||
return msg;
|
||||
}
|
||||
|
||||
void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
|
||||
struct sk_buff *msg)
|
||||
/* send message created by nl80211_build_scan_msg() */
|
||||
void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
|
||||
struct sk_buff *msg)
|
||||
{
|
||||
if (!msg)
|
||||
return;
|
||||
|
@ -12912,25 +12974,6 @@ void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
|
|||
NL80211_MCGRP_SCAN, GFP_KERNEL);
|
||||
}
|
||||
|
||||
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
|
||||
NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
||||
NL80211_MCGRP_SCAN, GFP_KERNEL);
|
||||
}
|
||||
|
||||
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u32 cmd)
|
||||
{
|
||||
|
@ -12940,7 +12983,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
|||
if (!msg)
|
||||
return;
|
||||
|
||||
if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
|
||||
if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
@ -13042,7 +13085,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
|
|||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
msg = nlmsg_new(100 + len, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -13189,12 +13232,14 @@ 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,
|
||||
int status, gfp_t gfp)
|
||||
int status,
|
||||
enum nl80211_timeout_reason timeout_reason,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -13210,7 +13255,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
|||
nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
|
||||
status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
|
||||
status) ||
|
||||
(status < 0 && nla_put_flag(msg, NL80211_ATTR_TIMED_OUT)) ||
|
||||
(status < 0 &&
|
||||
(nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
|
||||
(req_ie &&
|
||||
nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
|
||||
(resp_ie &&
|
||||
|
@ -13236,7 +13283,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
|||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -13273,7 +13320,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
|
|||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
msg = nlmsg_new(100 + ie_len, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -13349,7 +13396,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
|
|||
|
||||
trace_cfg80211_notify_new_peer_candidate(dev, addr);
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
msg = nlmsg_new(100 + ie_len, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -13720,7 +13767,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
|
|||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
msg = nlmsg_new(100 + len, gfp);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -13764,7 +13811,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
|||
|
||||
trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
|
||||
msg = nlmsg_new(100 + len, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -14519,6 +14566,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|||
|
||||
if (wdev->owner_nlportid == notify->portid)
|
||||
schedule_destroy_work = true;
|
||||
else if (wdev->conn_owner_nlportid == notify->portid)
|
||||
schedule_work(&wdev->disconnect_wk);
|
||||
}
|
||||
|
||||
spin_lock_bh(&rdev->beacon_registrations_lock);
|
||||
|
@ -14573,7 +14622,7 @@ void cfg80211_ft_event(struct net_device *netdev,
|
|||
if (!ft_event->target_ap)
|
||||
return;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
|
|
@ -14,12 +14,10 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
|
|||
struct wireless_dev *wdev);
|
||||
struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, bool aborted);
|
||||
void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
|
||||
struct sk_buff *msg);
|
||||
void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
|
||||
struct sk_buff *msg);
|
||||
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u32 cmd);
|
||||
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev);
|
||||
void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
|
||||
struct regulatory_request *request);
|
||||
|
||||
|
@ -58,7 +56,9 @@ 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,
|
||||
int status, gfp_t gfp);
|
||||
int status,
|
||||
enum nl80211_timeout_reason timeout_reason,
|
||||
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,
|
||||
|
|
138
net/wireless/of.c
Normal file
138
net/wireless/of.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "core.h"
|
||||
|
||||
static bool wiphy_freq_limits_valid_chan(struct wiphy *wiphy,
|
||||
struct ieee80211_freq_range *freq_limits,
|
||||
unsigned int n_freq_limits,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
u32 bw = MHZ_TO_KHZ(20);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_freq_limits; i++) {
|
||||
struct ieee80211_freq_range *limit = &freq_limits[i];
|
||||
|
||||
if (cfg80211_does_bw_fit_range(limit,
|
||||
MHZ_TO_KHZ(chan->center_freq),
|
||||
bw))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void wiphy_freq_limits_apply(struct wiphy *wiphy,
|
||||
struct ieee80211_freq_range *freq_limits,
|
||||
unsigned int n_freq_limits)
|
||||
{
|
||||
enum nl80211_band band;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(!n_freq_limits))
|
||||
return;
|
||||
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband = wiphy->bands[band];
|
||||
|
||||
if (!sband)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
struct ieee80211_channel *chan = &sband->channels[i];
|
||||
|
||||
if (chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
continue;
|
||||
|
||||
if (!wiphy_freq_limits_valid_chan(wiphy, freq_limits,
|
||||
n_freq_limits,
|
||||
chan)) {
|
||||
pr_debug("Disabling freq %d MHz as it's out of OF limits\n",
|
||||
chan->center_freq);
|
||||
chan->flags |= IEEE80211_CHAN_DISABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wiphy_read_of_freq_limits(struct wiphy *wiphy)
|
||||
{
|
||||
struct device *dev = wiphy_dev(wiphy);
|
||||
struct device_node *np;
|
||||
struct property *prop;
|
||||
struct ieee80211_freq_range *freq_limits;
|
||||
unsigned int n_freq_limits;
|
||||
const __be32 *p;
|
||||
int len, i;
|
||||
int err = 0;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
np = dev_of_node(dev);
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
prop = of_find_property(np, "ieee80211-freq-limit", &len);
|
||||
if (!prop)
|
||||
return;
|
||||
|
||||
if (!len || len % sizeof(u32) || len / sizeof(u32) % 2) {
|
||||
dev_err(dev, "ieee80211-freq-limit wrong format");
|
||||
return;
|
||||
}
|
||||
n_freq_limits = len / sizeof(u32) / 2;
|
||||
|
||||
freq_limits = kcalloc(n_freq_limits, sizeof(*freq_limits), GFP_KERNEL);
|
||||
if (!freq_limits) {
|
||||
err = -ENOMEM;
|
||||
goto out_kfree;
|
||||
}
|
||||
|
||||
p = NULL;
|
||||
for (i = 0; i < n_freq_limits; i++) {
|
||||
struct ieee80211_freq_range *limit = &freq_limits[i];
|
||||
|
||||
p = of_prop_next_u32(prop, p, &limit->start_freq_khz);
|
||||
if (!p) {
|
||||
err = -EINVAL;
|
||||
goto out_kfree;
|
||||
}
|
||||
|
||||
p = of_prop_next_u32(prop, p, &limit->end_freq_khz);
|
||||
if (!p) {
|
||||
err = -EINVAL;
|
||||
goto out_kfree;
|
||||
}
|
||||
|
||||
if (!limit->start_freq_khz ||
|
||||
!limit->end_freq_khz ||
|
||||
limit->start_freq_khz >= limit->end_freq_khz) {
|
||||
err = -EINVAL;
|
||||
goto out_kfree;
|
||||
}
|
||||
}
|
||||
|
||||
wiphy_freq_limits_apply(wiphy, freq_limits, n_freq_limits);
|
||||
|
||||
out_kfree:
|
||||
kfree(freq_limits);
|
||||
if (err)
|
||||
dev_err(dev, "Failed to get limits: %d\n", err);
|
||||
}
|
||||
EXPORT_SYMBOL(wiphy_read_of_freq_limits);
|
|
@ -748,21 +748,6 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range,
|
||||
u32 center_freq_khz, u32 bw_khz)
|
||||
{
|
||||
u32 start_freq_khz, end_freq_khz;
|
||||
|
||||
start_freq_khz = center_freq_khz - (bw_khz/2);
|
||||
end_freq_khz = center_freq_khz + (bw_khz/2);
|
||||
|
||||
if (start_freq_khz >= freq_range->start_freq_khz &&
|
||||
end_freq_khz <= freq_range->end_freq_khz)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* freq_in_rule_band - tells us if a frequency is in a frequency band
|
||||
* @freq_range: frequency rule we want to query
|
||||
|
@ -1070,7 +1055,7 @@ freq_reg_info_regd(u32 center_freq,
|
|||
if (!band_rule_found)
|
||||
band_rule_found = freq_in_rule_band(fr, center_freq);
|
||||
|
||||
bw_fits = reg_does_bw_fit(fr, center_freq, bw);
|
||||
bw_fits = cfg80211_does_bw_fit_range(fr, center_freq, bw);
|
||||
|
||||
if (band_rule_found && bw_fits)
|
||||
return rr;
|
||||
|
@ -1138,11 +1123,13 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
|
|||
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
|
||||
|
||||
/* If we get a reg_rule we can assume that at least 5Mhz fit */
|
||||
if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
|
||||
MHZ_TO_KHZ(10)))
|
||||
if (!cfg80211_does_bw_fit_range(freq_range,
|
||||
MHZ_TO_KHZ(chan->center_freq),
|
||||
MHZ_TO_KHZ(10)))
|
||||
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
|
||||
if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
|
||||
MHZ_TO_KHZ(20)))
|
||||
if (!cfg80211_does_bw_fit_range(freq_range,
|
||||
MHZ_TO_KHZ(chan->center_freq),
|
||||
MHZ_TO_KHZ(20)))
|
||||
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
|
||||
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
|
||||
|
|
|
@ -227,7 +227,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
|
|||
ASSERT_RTNL();
|
||||
|
||||
if (rdev->scan_msg) {
|
||||
nl80211_send_scan_result(rdev, rdev->scan_msg);
|
||||
nl80211_send_scan_msg(rdev, rdev->scan_msg);
|
||||
rdev->scan_msg = NULL;
|
||||
return;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
|
|||
if (!send_message)
|
||||
rdev->scan_msg = msg;
|
||||
else
|
||||
nl80211_send_scan_result(rdev, msg);
|
||||
nl80211_send_scan_msg(rdev, msg);
|
||||
}
|
||||
|
||||
void __cfg80211_scan_done(struct work_struct *wk)
|
||||
|
@ -321,7 +321,8 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
|
|||
spin_unlock_bh(&rdev->bss_lock);
|
||||
request->scan_start = jiffies;
|
||||
}
|
||||
nl80211_send_sched_scan_results(rdev, request->dev);
|
||||
nl80211_send_sched_scan(rdev, request->dev,
|
||||
NL80211_CMD_SCHED_SCAN_RESULTS);
|
||||
}
|
||||
|
||||
rtnl_unlock();
|
||||
|
@ -1147,7 +1148,7 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
|||
else
|
||||
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
|
||||
rcu_assign_pointer(tmp.pub.ies, ies);
|
||||
|
||||
|
||||
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
|
||||
tmp.pub.channel = channel;
|
||||
tmp.pub.scan_width = data->scan_width;
|
||||
|
|
|
@ -34,10 +34,11 @@ struct cfg80211_conn {
|
|||
CFG80211_CONN_SCAN_AGAIN,
|
||||
CFG80211_CONN_AUTHENTICATE_NEXT,
|
||||
CFG80211_CONN_AUTHENTICATING,
|
||||
CFG80211_CONN_AUTH_FAILED,
|
||||
CFG80211_CONN_AUTH_FAILED_TIMEOUT,
|
||||
CFG80211_CONN_ASSOCIATE_NEXT,
|
||||
CFG80211_CONN_ASSOCIATING,
|
||||
CFG80211_CONN_ASSOC_FAILED,
|
||||
CFG80211_CONN_ASSOC_FAILED_TIMEOUT,
|
||||
CFG80211_CONN_DEAUTH,
|
||||
CFG80211_CONN_ABANDON,
|
||||
CFG80211_CONN_CONNECTED,
|
||||
|
@ -140,7 +141,8 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
||||
static int cfg80211_conn_do_work(struct wireless_dev *wdev,
|
||||
enum nl80211_timeout_reason *treason)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_connect_params *params;
|
||||
|
@ -171,7 +173,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
|||
NULL, 0,
|
||||
params->key, params->key_len,
|
||||
params->key_idx, NULL, 0);
|
||||
case CFG80211_CONN_AUTH_FAILED:
|
||||
case CFG80211_CONN_AUTH_FAILED_TIMEOUT:
|
||||
*treason = NL80211_TIMEOUT_AUTH;
|
||||
return -ENOTCONN;
|
||||
case CFG80211_CONN_ASSOCIATE_NEXT:
|
||||
if (WARN_ON(!rdev->ops->assoc))
|
||||
|
@ -198,6 +201,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
|||
WLAN_REASON_DEAUTH_LEAVING,
|
||||
false);
|
||||
return err;
|
||||
case CFG80211_CONN_ASSOC_FAILED_TIMEOUT:
|
||||
*treason = NL80211_TIMEOUT_ASSOC;
|
||||
/* fall through */
|
||||
case CFG80211_CONN_ASSOC_FAILED:
|
||||
cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
|
||||
NULL, 0,
|
||||
|
@ -223,6 +229,7 @@ void cfg80211_conn_work(struct work_struct *work)
|
|||
container_of(work, struct cfg80211_registered_device, conn_work);
|
||||
struct wireless_dev *wdev;
|
||||
u8 bssid_buf[ETH_ALEN], *bssid = NULL;
|
||||
enum nl80211_timeout_reason treason;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
|
@ -244,10 +251,12 @@ void cfg80211_conn_work(struct work_struct *work)
|
|||
memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
|
||||
bssid = bssid_buf;
|
||||
}
|
||||
if (cfg80211_conn_do_work(wdev)) {
|
||||
treason = NL80211_TIMEOUT_UNSPECIFIED;
|
||||
if (cfg80211_conn_do_work(wdev, &treason)) {
|
||||
__cfg80211_connect_result(
|
||||
wdev->netdev, bssid,
|
||||
NULL, 0, NULL, 0, -1, false, NULL);
|
||||
NULL, 0, NULL, 0, -1, false, NULL,
|
||||
treason);
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
|
@ -352,7 +361,8 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
|
|||
} else if (status_code != WLAN_STATUS_SUCCESS) {
|
||||
__cfg80211_connect_result(wdev->netdev, mgmt->bssid,
|
||||
NULL, 0, NULL, 0,
|
||||
status_code, false, NULL);
|
||||
status_code, false, NULL,
|
||||
NL80211_TIMEOUT_UNSPECIFIED);
|
||||
} else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
|
||||
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
|
@ -400,7 +410,7 @@ void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
|
|||
if (!wdev->conn)
|
||||
return;
|
||||
|
||||
wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
|
||||
wdev->conn->state = CFG80211_CONN_AUTH_FAILED_TIMEOUT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
}
|
||||
|
||||
|
@ -422,7 +432,7 @@ void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
|
|||
if (!wdev->conn)
|
||||
return;
|
||||
|
||||
wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
|
||||
wdev->conn->state = CFG80211_CONN_ASSOC_FAILED_TIMEOUT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
}
|
||||
|
||||
|
@ -564,7 +574,9 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
|
|||
|
||||
/* we're good if we have a matching bss struct */
|
||||
if (bss) {
|
||||
err = cfg80211_conn_do_work(wdev);
|
||||
enum nl80211_timeout_reason treason;
|
||||
|
||||
err = cfg80211_conn_do_work(wdev, &treason);
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
} else {
|
||||
/* otherwise we'll need to scan for the AP first */
|
||||
|
@ -661,7 +673,8 @@ 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,
|
||||
int status, bool wextev,
|
||||
struct cfg80211_bss *bss)
|
||||
struct cfg80211_bss *bss,
|
||||
enum nl80211_timeout_reason timeout_reason)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
const u8 *country_ie;
|
||||
|
@ -680,7 +693,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev,
|
||||
bssid, req_ie, req_ie_len,
|
||||
resp_ie, resp_ie_len,
|
||||
status, GFP_KERNEL);
|
||||
status, timeout_reason, GFP_KERNEL);
|
||||
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
if (wextev) {
|
||||
|
@ -727,6 +740,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
kzfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
if (bss) {
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
|
@ -770,7 +784,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
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, int status, gfp_t gfp)
|
||||
size_t resp_ie_len, int status, gfp_t gfp,
|
||||
enum nl80211_timeout_reason timeout_reason)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
|
@ -810,6 +825,7 @@ void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
|||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
ev->cr.bss = bss;
|
||||
ev->cr.status = status;
|
||||
ev->cr.timeout_reason = timeout_reason;
|
||||
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
list_add_tail(&ev->list, &wdev->event_list);
|
||||
|
@ -955,6 +971,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
|||
|
||||
wdev->current_bss = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
|
||||
nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
|
||||
|
||||
|
@ -1098,6 +1115,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
|||
kzfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
|
||||
if (wdev->conn)
|
||||
err = cfg80211_sme_disconnect(wdev, reason);
|
||||
else if (!rdev->ops->disconnect)
|
||||
|
@ -1107,3 +1126,32 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
|||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to clean up after the connection / connection attempt owner socket
|
||||
* disconnects
|
||||
*/
|
||||
void cfg80211_autodisconnect_wk(struct work_struct *work)
|
||||
{
|
||||
struct wireless_dev *wdev =
|
||||
container_of(work, struct wireless_dev, disconnect_wk);
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
|
||||
wdev_lock(wdev);
|
||||
|
||||
if (wdev->conn_owner_nlportid) {
|
||||
/*
|
||||
* Use disconnect_bssid if still connecting and ops->disconnect
|
||||
* not implemented. Otherwise we can use cfg80211_disconnect.
|
||||
*/
|
||||
if (rdev->ops->disconnect || wdev->current_bss)
|
||||
cfg80211_disconnect(rdev, wdev->netdev,
|
||||
WLAN_REASON_DEAUTH_LEAVING, true);
|
||||
else
|
||||
cfg80211_mlme_deauth(rdev, wdev->netdev,
|
||||
wdev->disconnect_bssid, NULL, 0,
|
||||
WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
}
|
||||
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
|
|
|
@ -39,9 +39,11 @@ SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
|
|||
|
||||
static ssize_t name_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf) {
|
||||
char *buf)
|
||||
{
|
||||
struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
|
||||
return sprintf(buf, "%s\n", dev_name(&wiphy->dev));
|
||||
|
||||
return sprintf(buf, "%s\n", wiphy_name(wiphy));
|
||||
}
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
|
|
|
@ -114,8 +114,7 @@ int ieee80211_frequency_to_channel(int freq)
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
|
||||
|
||||
struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
|
||||
int freq)
|
||||
struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
|
||||
{
|
||||
enum nl80211_band band;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
@ -135,14 +134,13 @@ struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
|
|||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(__ieee80211_get_channel);
|
||||
EXPORT_SYMBOL(ieee80211_get_channel);
|
||||
|
||||
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
|
||||
enum nl80211_band band)
|
||||
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
|
||||
{
|
||||
int i, want;
|
||||
|
||||
switch (band) {
|
||||
switch (sband->band) {
|
||||
case NL80211_BAND_5GHZ:
|
||||
want = 3;
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
|
@ -192,6 +190,7 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
|
|||
WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e);
|
||||
break;
|
||||
case NUM_NL80211_BANDS:
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
@ -203,7 +202,7 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
|
|||
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++)
|
||||
if (wiphy->bands[band])
|
||||
set_mandatory_flags_band(wiphy->bands[band], band);
|
||||
set_mandatory_flags_band(wiphy->bands[band]);
|
||||
}
|
||||
|
||||
bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher)
|
||||
|
@ -952,7 +951,7 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
|
|||
ev->cr.resp_ie, ev->cr.resp_ie_len,
|
||||
ev->cr.status,
|
||||
ev->cr.status == WLAN_STATUS_SUCCESS,
|
||||
ev->cr.bss);
|
||||
ev->cr.bss, ev->cr.timeout_reason);
|
||||
break;
|
||||
case EVENT_ROAMED:
|
||||
__cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
|
||||
|
@ -1848,6 +1847,21 @@ void cfg80211_free_nan_func(struct cfg80211_nan_func *f)
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_free_nan_func);
|
||||
|
||||
bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
|
||||
u32 center_freq_khz, u32 bw_khz)
|
||||
{
|
||||
u32 start_freq_khz, end_freq_khz;
|
||||
|
||||
start_freq_khz = center_freq_khz - (bw_khz / 2);
|
||||
end_freq_khz = center_freq_khz + (bw_khz / 2);
|
||||
|
||||
if (start_freq_khz >= freq_range->start_freq_khz &&
|
||||
end_freq_khz <= freq_range->end_freq_khz)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||
const unsigned char rfc1042_header[] __aligned(2) =
|
||||
|
|
|
@ -1119,3 +1119,70 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
|
|||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *iwe_stream_add_event(struct iw_request_info *info, char *stream,
|
||||
char *ends, struct iw_event *iwe, int event_len)
|
||||
{
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
event_len = iwe_stream_event_len_adjust(info, event_len);
|
||||
|
||||
/* Check if it's possible */
|
||||
if (likely((stream + event_len) < ends)) {
|
||||
iwe->len = event_len;
|
||||
/* Beware of alignement issues on 64 bits */
|
||||
memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + lcp_len, &iwe->u,
|
||||
event_len - lcp_len);
|
||||
stream += event_len;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
EXPORT_SYMBOL(iwe_stream_add_event);
|
||||
|
||||
char *iwe_stream_add_point(struct iw_request_info *info, char *stream,
|
||||
char *ends, struct iw_event *iwe, char *extra)
|
||||
{
|
||||
int event_len = iwe_stream_point_len(info) + iwe->u.data.length;
|
||||
int point_len = iwe_stream_point_len(info);
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
/* Check if it's possible */
|
||||
if (likely((stream + event_len) < ends)) {
|
||||
iwe->len = event_len;
|
||||
memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
|
||||
memcpy(stream + lcp_len,
|
||||
((char *) &iwe->u) + IW_EV_POINT_OFF,
|
||||
IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
|
||||
if (iwe->u.data.length && extra)
|
||||
memcpy(stream + point_len, extra, iwe->u.data.length);
|
||||
stream += event_len;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
EXPORT_SYMBOL(iwe_stream_add_point);
|
||||
|
||||
char *iwe_stream_add_value(struct iw_request_info *info, char *event,
|
||||
char *value, char *ends, struct iw_event *iwe,
|
||||
int event_len)
|
||||
{
|
||||
int lcp_len = iwe_stream_lcp_len(info);
|
||||
|
||||
/* Don't duplicate LCP */
|
||||
event_len -= IW_EV_LCP_LEN;
|
||||
|
||||
/* Check if it's possible */
|
||||
if (likely((value + event_len) < ends)) {
|
||||
/* Add new value */
|
||||
memcpy(value, &iwe->u, event_len);
|
||||
value += event_len;
|
||||
/* Patch LCP */
|
||||
iwe->len = value - event;
|
||||
memcpy(event, (char *) iwe, lcp_len);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL(iwe_stream_add_value);
|
||||
|
|
|
@ -105,30 +105,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
|
||||
wdev->wext.connect.channel = chan;
|
||||
|
||||
/*
|
||||
* SSID is not set, we just want to switch monitor channel,
|
||||
* this is really just backward compatibility, if the SSID
|
||||
* is set then we use the channel to select the BSS to use
|
||||
* to connect to instead. If we were connected on another
|
||||
* channel we disconnected above and reconnect below.
|
||||
*/
|
||||
if (chan && !wdev->wext.connect.ssid_len) {
|
||||
struct cfg80211_chan_def chandef = {
|
||||
.width = NL80211_CHAN_WIDTH_20_NOHT,
|
||||
.center_freq1 = freq,
|
||||
};
|
||||
|
||||
chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
|
||||
if (chandef.chan)
|
||||
err = cfg80211_set_monitor_channel(rdev, &chandef);
|
||||
else
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = cfg80211_mgd_wext_connect(rdev, wdev);
|
||||
out:
|
||||
wdev_unlock(wdev);
|
||||
|
|
Loading…
Reference in a new issue