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:
David S. Miller 2017-01-14 12:02:15 -05:00
commit bb60b8b35a
49 changed files with 1015 additions and 426 deletions

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
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,
}
},
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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