We have a fair number of patches, but many of them are from the
first bullet here: * EAPoL-over-nl80211 from Denis - this will let us fix some long-standing issues with bridging, races with encryption and more * DFS offload support from the qtnfmac folks * regulatory database changes for the new ETSI adaptivity requirements * various other fixes and small enhancements -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAlq85QQACgkQB8qZga/f l8Sdbg//bc8C/4F1TUdJqZWGK1j9Lwd6nZpP0iFqH5Ees3MMnti5XdV2dCL31ivz c8DOuRAU8ZG/RLPgSTHVZHwh+f7S5/TxSKg8WOBvrYk7a0C1uvVVhe5XZQEmqE7g eqM0+UQ5DyzUYnu0kSUrFKPV7BqDa2YzVDdK8e8iozqZmAnvGN9k8H7EDEeUxtxk LEl+bEcmhDSfIssU2Iaksl+9qoZP6BkoVGAOmDzIL654WV4XVKorxRX6vndqSQGu 0cCz2Occ+/0hfvszONBRR4M/gtI/Yyn3u+D1Q0YD3X40Q9gJE11fcodmMT61l5C7 rGcu94RIGilvRvjZScK3giiU2L7DD+VETUa+YGnjd8gLpmrYd6cURxlm4yuHbw8C UScLCApAUuY+skmPLeuyHW9mnzHaC336vzVjk8OhdNRhX23/rB8nk1yIywgqETVW g/iub8/Xp6TRfdyh76I18wlfqCp1It2JAeICgKH5NPlwUA6U0xFR0/ddSR8FuAcK ZLY8mgsc2kIH6r4x5sjeH+Yb6tGi/Z3HMZM2hna+t4vSpn6Q5+GPsA6yuHuBUhJb 8QswMiLDSux8I4guKgQyROiHaCzE3zOigJ4o1z9XITKsgluZVxnKr+ETKdr88WFp II8U0qH/kejXIfxUjbv5Wla70J9wi/hjxR6vOfSkEtYNvIApdfc= =hI0F -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2018-03-29' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== We have a fair number of patches, but many of them are from the first bullet here: * EAPoL-over-nl80211 from Denis - this will let us fix some long-standing issues with bridging, races with encryption and more * DFS offload support from the qtnfmac folks * regulatory database changes for the new ETSI adaptivity requirements * various other fixes and small enhancements ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e15f20ea33
@ -2584,8 +2584,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
addr[4] = idx;
|
||||
memcpy(data->addresses[0].addr, addr, ETH_ALEN);
|
||||
/* Why need here second address ? */
|
||||
data->addresses[1].addr[0] |= 0x40;
|
||||
memcpy(data->addresses[1].addr, addr, ETH_ALEN);
|
||||
data->addresses[1].addr[0] |= 0x40;
|
||||
hw->wiphy->n_addresses = 2;
|
||||
hw->wiphy->addresses = data->addresses;
|
||||
/* possible address clash is checked at hash table insertion */
|
||||
@ -3529,8 +3529,12 @@ static void __net_exit hwsim_exit_net(struct net *net)
|
||||
list_del(&data->list);
|
||||
rhashtable_remove_fast(&hwsim_radios_rht, &data->rht,
|
||||
hwsim_rht_params);
|
||||
INIT_WORK(&data->destroy_work, destroy_radio);
|
||||
queue_work(hwsim_wq, &data->destroy_work);
|
||||
hwsim_radios_generation++;
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
mac80211_hwsim_del_radio(data,
|
||||
wiphy_name(data->hw->wiphy),
|
||||
NULL);
|
||||
spin_lock_bh(&hwsim_radio_lock);
|
||||
}
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -646,6 +647,8 @@ struct survey_info {
|
||||
* allowed through even on unauthorized ports
|
||||
* @control_port_no_encrypt: TRUE to prevent encryption of control port
|
||||
* protocol frames.
|
||||
* @control_port_over_nl80211: TRUE if userspace expects to exchange control
|
||||
* port frames over NL80211 instead of the network interface.
|
||||
* @wep_keys: static WEP keys, if not NULL points to an array of
|
||||
* CFG80211_MAX_WEP_KEYS WEP keys
|
||||
* @wep_tx_key: key index (0..3) of the default TX static WEP key
|
||||
@ -661,6 +664,7 @@ struct cfg80211_crypto_settings {
|
||||
bool control_port;
|
||||
__be16 control_port_ethertype;
|
||||
bool control_port_no_encrypt;
|
||||
bool control_port_over_nl80211;
|
||||
struct key_params *wep_keys;
|
||||
int wep_tx_key;
|
||||
const u8 *psk;
|
||||
@ -1450,6 +1454,8 @@ struct mesh_config {
|
||||
* @userspace_handles_dfs: whether user space controls DFS operation, i.e.
|
||||
* changes the channel when a radar is detected. This is required
|
||||
* to operate on DFS channels.
|
||||
* @control_port_over_nl80211: TRUE if userspace expects to exchange control
|
||||
* port frames over NL80211 instead of the network interface.
|
||||
*
|
||||
* These parameters are fixed when the mesh is created.
|
||||
*/
|
||||
@ -1472,6 +1478,7 @@ struct mesh_setup {
|
||||
u32 basic_rates;
|
||||
struct cfg80211_bitrate_mask beacon_rate;
|
||||
bool userspace_handles_dfs;
|
||||
bool control_port_over_nl80211;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2030,6 +2037,8 @@ struct cfg80211_disassoc_request {
|
||||
* sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
|
||||
* required to assume that the port is unauthorized until authorized by
|
||||
* user space. Otherwise, port is marked authorized by default.
|
||||
* @control_port_over_nl80211: TRUE if userspace expects to exchange control
|
||||
* port frames over NL80211 instead of the network interface.
|
||||
* @userspace_handles_dfs: whether user space controls DFS operation, i.e.
|
||||
* changes the channel when a radar is detected. This is required
|
||||
* to operate on DFS channels.
|
||||
@ -2053,6 +2062,7 @@ struct cfg80211_ibss_params {
|
||||
bool channel_fixed;
|
||||
bool privacy;
|
||||
bool control_port;
|
||||
bool control_port_over_nl80211;
|
||||
bool userspace_handles_dfs;
|
||||
int mcast_rate[NUM_NL80211_BANDS];
|
||||
struct ieee80211_ht_cap ht_capa;
|
||||
@ -2960,6 +2970,9 @@ struct cfg80211_external_auth_params {
|
||||
*
|
||||
* @external_auth: indicates result of offloaded authentication processing from
|
||||
* user space
|
||||
*
|
||||
* @tx_control_port: TX a control port frame (EAPoL). The noencrypt parameter
|
||||
* tells the driver that the frame should not be encrypted.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||
@ -3255,6 +3268,12 @@ struct cfg80211_ops {
|
||||
const u8 *aa);
|
||||
int (*external_auth)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_external_auth_params *params);
|
||||
|
||||
int (*tx_control_port)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
const u8 *buf, size_t len,
|
||||
const u8 *dest, const __be16 proto,
|
||||
const bool noencrypt);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -3572,15 +3591,15 @@ enum wiphy_opmode_flag {
|
||||
/**
|
||||
* struct sta_opmode_info - Station's ht/vht operation mode information
|
||||
* @changed: contains value from &enum wiphy_opmode_flag
|
||||
* @smps_mode: New SMPS mode of a station
|
||||
* @bw: new max bandwidth value of a station
|
||||
* @smps_mode: New SMPS mode value from &enum nl80211_smps_mode of a station
|
||||
* @bw: new max bandwidth value from &enum nl80211_chan_width of a station
|
||||
* @rx_nss: new rx_nss value of a station
|
||||
*/
|
||||
|
||||
struct sta_opmode_info {
|
||||
u32 changed;
|
||||
u8 smps_mode;
|
||||
u8 bw;
|
||||
enum nl80211_smps_mode smps_mode;
|
||||
enum nl80211_chan_width bw;
|
||||
u8 rx_nss;
|
||||
};
|
||||
|
||||
@ -4657,6 +4676,33 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
|
||||
*/
|
||||
const char *reg_initiator_name(enum nl80211_reg_initiator initiator);
|
||||
|
||||
/**
|
||||
* DOC: Internal regulatory db functions
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* reg_query_regdb_wmm - Query internal regulatory db for wmm rule
|
||||
* Regulatory self-managed driver can use it to proactively
|
||||
*
|
||||
* @alpha2: the ISO/IEC 3166 alpha2 wmm rule to be queried.
|
||||
* @freq: the freqency(in MHz) to be queried.
|
||||
* @ptr: pointer where the regdb wmm data is to be stored (or %NULL if
|
||||
* irrelevant). This can be used later for deduplication.
|
||||
* @rule: pointer to store the wmm rule from the regulatory db.
|
||||
*
|
||||
* Self-managed wireless drivers can use this function to query
|
||||
* the internal regulatory database to check whether the given
|
||||
* ISO/IEC 3166 alpha2 country and freq have wmm rule limitations.
|
||||
*
|
||||
* Drivers should check the return value, its possible you can get
|
||||
* an -ENODATA.
|
||||
*
|
||||
* Return: 0 on success. -ENODATA.
|
||||
*/
|
||||
int reg_query_regdb_wmm(char *alpha2, int freq, u32 *ptr,
|
||||
struct ieee80211_wmm_rule *rule);
|
||||
|
||||
/*
|
||||
* callbacks for asynchronous cfg80211 methods, notification
|
||||
* functions and BSS handling helpers
|
||||
@ -5693,6 +5739,28 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||
const u8 *buf, size_t len, bool ack, gfp_t gfp);
|
||||
|
||||
|
||||
/**
|
||||
* cfg80211_rx_control_port - notification about a received control port frame
|
||||
* @dev: The device the frame matched to
|
||||
* @buf: control port frame
|
||||
* @len: length of the frame data
|
||||
* @addr: The peer from which the frame was received
|
||||
* @proto: frame protocol, typically PAE or Pre-authentication
|
||||
* @unencrypted: Whether the frame was received unencrypted
|
||||
*
|
||||
* This function is used to inform userspace about a received control port
|
||||
* frame. It should only be used if userspace indicated it wants to receive
|
||||
* control port frames over nl80211.
|
||||
*
|
||||
* The frame is the data portion of the 802.3 or 802.11 data frame with all
|
||||
* network layer headers removed (e.g. the raw EAPoL frame).
|
||||
*
|
||||
* Return: %true if the frame was passed to userspace
|
||||
*/
|
||||
bool cfg80211_rx_control_port(struct net_device *dev,
|
||||
const u8 *buf, size_t len,
|
||||
const u8 *addr, u16 proto, bool unencrypted);
|
||||
|
||||
/**
|
||||
* cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
|
||||
* @dev: network device
|
||||
|
@ -302,6 +302,8 @@ struct ieee80211_vif_chanctx_switch {
|
||||
* @BSS_CHANGED_MU_GROUPS: VHT MU-MIMO group id or user position changed
|
||||
* @BSS_CHANGED_KEEP_ALIVE: keep alive options (idle period or protected
|
||||
* keep alive) changed.
|
||||
* @BSS_CHANGED_MCAST_RATE: Multicast Rate setting changed for this interface
|
||||
*
|
||||
*/
|
||||
enum ieee80211_bss_change {
|
||||
BSS_CHANGED_ASSOC = 1<<0,
|
||||
@ -329,6 +331,7 @@ enum ieee80211_bss_change {
|
||||
BSS_CHANGED_OCB = 1<<22,
|
||||
BSS_CHANGED_MU_GROUPS = 1<<23,
|
||||
BSS_CHANGED_KEEP_ALIVE = 1<<24,
|
||||
BSS_CHANGED_MCAST_RATE = 1<<25,
|
||||
|
||||
/* when adding here, make sure to change ieee80211_reconfig */
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
* regulatory support structures
|
||||
*
|
||||
* Copyright 2008-2009 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -188,9 +189,35 @@ struct ieee80211_power_rule {
|
||||
u32 max_eirp;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_wmm_ac - used to store per ac wmm regulatory limitation
|
||||
*
|
||||
* The information provided in this structure is required for QoS
|
||||
* transmit queue configuration. Cf. IEEE 802.11 7.3.2.29.
|
||||
*
|
||||
* @cw_min: minimum contention window [a value of the form
|
||||
* 2^n-1 in the range 1..32767]
|
||||
* @cw_max: maximum contention window [like @cw_min]
|
||||
* @cot: maximum burst time in units of 32 usecs, 0 meaning disabled
|
||||
* @aifsn: arbitration interframe space [0..255]
|
||||
*
|
||||
*/
|
||||
struct ieee80211_wmm_ac {
|
||||
u16 cw_min;
|
||||
u16 cw_max;
|
||||
u16 cot;
|
||||
u8 aifsn;
|
||||
};
|
||||
|
||||
struct ieee80211_wmm_rule {
|
||||
struct ieee80211_wmm_ac client[IEEE80211_NUM_ACS];
|
||||
struct ieee80211_wmm_ac ap[IEEE80211_NUM_ACS];
|
||||
};
|
||||
|
||||
struct ieee80211_reg_rule {
|
||||
struct ieee80211_freq_range freq_range;
|
||||
struct ieee80211_power_rule power_rule;
|
||||
struct ieee80211_wmm_rule *wmm_rule;
|
||||
u32 flags;
|
||||
u32 dfs_cac_ms;
|
||||
};
|
||||
@ -198,6 +225,7 @@ struct ieee80211_reg_rule {
|
||||
struct ieee80211_regdomain {
|
||||
struct rcu_head rcu_head;
|
||||
u32 n_reg_rules;
|
||||
u32 n_wmm_rules;
|
||||
char alpha2[3];
|
||||
enum nl80211_dfs_regions dfs_region;
|
||||
struct ieee80211_reg_rule reg_rules[];
|
||||
|
@ -542,7 +542,8 @@
|
||||
* IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
|
||||
* %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
|
||||
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
|
||||
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
|
||||
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
|
||||
* %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
|
||||
* %NL80211_ATTR_WIPHY_FREQ_HINT.
|
||||
* If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
|
||||
* restrictions on BSS selection, i.e., they effectively prevent roaming
|
||||
@ -990,6 +991,17 @@
|
||||
* &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
|
||||
* &NL80211_CMD_DISCONNECT should be indicated instead.
|
||||
*
|
||||
* @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
|
||||
* and RX notification. This command is used both as a request to transmit
|
||||
* a control port frame and as a notification that a control port frame
|
||||
* has been received. %NL80211_ATTR_FRAME is used to specify the
|
||||
* frame contents. The frame is the raw EAPoL data, without ethernet or
|
||||
* 802.11 headers.
|
||||
* When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
|
||||
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
|
||||
* indicating the protocol type of the received frame; whether the frame
|
||||
* was received unencrypted and the MAC address of the peer respectively.
|
||||
*
|
||||
* @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
|
||||
*
|
||||
* @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
|
||||
@ -1228,6 +1240,8 @@ enum nl80211_commands {
|
||||
|
||||
NL80211_CMD_STA_OPMODE_CHANGED,
|
||||
|
||||
NL80211_CMD_CONTROL_PORT_FRAME,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@ -1475,6 +1489,15 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
|
||||
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
|
||||
* ethertype frames used for key negotiation must not be encrypted.
|
||||
* @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control
|
||||
* port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
|
||||
* will be sent directly to the network interface or sent via the NL80211
|
||||
* socket. If this attribute is missing, then legacy behavior of sending
|
||||
* control port frames directly to the network interface is used. If the
|
||||
* flag is included, then control port frames are sent over NL80211 instead
|
||||
* using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is
|
||||
* to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
|
||||
* flag.
|
||||
*
|
||||
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
|
||||
* We recommend using nested, driver-specific attributes within this.
|
||||
@ -1962,6 +1985,12 @@ enum nl80211_commands {
|
||||
* multicast group.
|
||||
* If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
|
||||
* station will deauthenticate when the socket is closed.
|
||||
* If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically
|
||||
* torn down when the socket is closed.
|
||||
* If set during %NL80211_CMD_JOIN_MESH the mesh setup will be
|
||||
* automatically torn down when the socket is closed.
|
||||
* If set during %NL80211_CMD_START_AP the AP will be automatically
|
||||
* disabled when the socket is closed.
|
||||
*
|
||||
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
|
||||
* the TDLS link initiator.
|
||||
@ -2628,6 +2657,8 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_NSS,
|
||||
NL80211_ATTR_ACK_SIGNAL,
|
||||
|
||||
NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@ -4999,6 +5030,14 @@ enum nl80211_feature_flags {
|
||||
* @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
|
||||
* @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
|
||||
* @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
|
||||
* @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions.
|
||||
* Device or driver will do all DFS-related actions by itself,
|
||||
* informing user-space about CAC progress, radar detection event,
|
||||
* channel change triggered by radar detection event.
|
||||
* No need to start CAC from user-space, no need to react to
|
||||
* "radar detected" event.
|
||||
* @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
|
||||
* receiving control port frames over nl80211 instead of the netdevice.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
@ -5029,6 +5068,8 @@ enum nl80211_ext_feature_index {
|
||||
NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
|
||||
NL80211_EXT_FEATURE_LOW_POWER_SCAN,
|
||||
NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
|
||||
NL80211_EXT_FEATURE_DFS_OFFLOAD,
|
||||
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
@ -5204,6 +5245,8 @@ enum nl80211_smps_mode {
|
||||
* non-operating channel is expired and no longer valid. New CAC must
|
||||
* be done on this channel before starting the operation. This is not
|
||||
* applicable for ETSI dfs domain where pre-CAC is valid for ever.
|
||||
* @NL80211_RADAR_CAC_STARTED: Channel Availability Check has been started,
|
||||
* should be generated by HW if NL80211_EXT_FEATURE_DFS_OFFLOAD is enabled.
|
||||
*/
|
||||
enum nl80211_radar_event {
|
||||
NL80211_RADAR_DETECTED,
|
||||
@ -5211,6 +5254,7 @@ enum nl80211_radar_event {
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
NL80211_RADAR_NOP_FINISHED,
|
||||
NL80211_RADAR_PRE_CAC_EXPIRED,
|
||||
NL80211_RADAR_CAC_STARTED,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
@ -925,6 +926,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
*/
|
||||
sdata->control_port_protocol = params->crypto.control_port_ethertype;
|
||||
sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
|
||||
sdata->control_port_over_nl80211 =
|
||||
params->crypto.control_port_over_nl80211;
|
||||
sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
|
||||
¶ms->crypto,
|
||||
sdata->vif.type);
|
||||
@ -934,6 +937,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
params->crypto.control_port_ethertype;
|
||||
vlan->control_port_no_encrypt =
|
||||
params->crypto.control_port_no_encrypt;
|
||||
vlan->control_port_over_nl80211 =
|
||||
params->crypto.control_port_over_nl80211;
|
||||
vlan->encrypt_headroom =
|
||||
ieee80211_cs_headroom(sdata->local,
|
||||
¶ms->crypto,
|
||||
@ -2019,6 +2024,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sdata->control_port_over_nl80211 = setup->control_port_over_nl80211;
|
||||
|
||||
/* can mesh use other SMPS modes? */
|
||||
sdata->smps_mode = IEEE80211_SMPS_OFF;
|
||||
sdata->needed_rx_chains = sdata->local->rx_chains;
|
||||
@ -2156,6 +2163,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
||||
*/
|
||||
p.uapsd = false;
|
||||
|
||||
ieee80211_regulatory_limit_wmm_params(sdata, &p, params->ac);
|
||||
|
||||
sdata->tx_conf[params->ac] = p;
|
||||
if (drv_conf_tx(local, sdata, params->ac, &p)) {
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
@ -2313,6 +2322,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
|
||||
memcpy(sdata->vif.bss_conf.mcast_rate, rate,
|
||||
sizeof(int) * NUM_NL80211_BANDS);
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MCAST_RATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3786,4 +3797,5 @@ const struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_nan_func = ieee80211_add_nan_func,
|
||||
.del_nan_func = ieee80211_del_nan_func,
|
||||
.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
|
||||
.tx_control_port = ieee80211_tx_control_port,
|
||||
};
|
||||
|
@ -466,6 +466,21 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||
__ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_PEER_REQUEST);
|
||||
}
|
||||
|
||||
enum nl80211_smps_mode
|
||||
ieee80211_smps_mode_to_smps_mode(enum ieee80211_smps_mode smps)
|
||||
{
|
||||
switch (smps) {
|
||||
case IEEE80211_SMPS_OFF:
|
||||
return NL80211_SMPS_OFF;
|
||||
case IEEE80211_SMPS_STATIC:
|
||||
return NL80211_SMPS_STATIC;
|
||||
case IEEE80211_SMPS_DYNAMIC:
|
||||
return NL80211_SMPS_DYNAMIC;
|
||||
default:
|
||||
return NL80211_SMPS_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps, const u8 *da,
|
||||
const u8 *bssid)
|
||||
|
@ -1839,11 +1839,12 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED
|
||||
| IEEE80211_HT_PARAM_RIFS_MODE;
|
||||
|
||||
changed |= BSS_CHANGED_HT;
|
||||
changed |= BSS_CHANGED_HT | BSS_CHANGED_MCAST_RATE;
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
|
||||
sdata->smps_mode = IEEE80211_SMPS_OFF;
|
||||
sdata->needed_rx_chains = local->rx_chains;
|
||||
sdata->control_port_over_nl80211 = params->control_port_over_nl80211;
|
||||
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -899,6 +900,7 @@ struct ieee80211_sub_if_data {
|
||||
u16 sequence_number;
|
||||
__be16 control_port_protocol;
|
||||
bool control_port_no_encrypt;
|
||||
bool control_port_over_nl80211;
|
||||
int encrypt_headroom;
|
||||
|
||||
atomic_t num_tx_queued;
|
||||
@ -1734,6 +1736,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta);
|
||||
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
|
||||
void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_clear_fast_xmit(struct sta_info *sta);
|
||||
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *buf, size_t len,
|
||||
const u8 *dest, __be16 proto, bool unencrypted);
|
||||
|
||||
/* HT */
|
||||
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
@ -1788,6 +1793,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
|
||||
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
|
||||
|
||||
u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs);
|
||||
enum nl80211_smps_mode
|
||||
ieee80211_smps_mode_to_smps_mode(enum ieee80211_smps_mode smps);
|
||||
|
||||
/* VHT */
|
||||
void
|
||||
@ -1814,6 +1821,8 @@ void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_vht_cap *vht_cap);
|
||||
void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
|
||||
u16 vht_mask[NL80211_VHT_NSS_MAX]);
|
||||
enum nl80211_chan_width
|
||||
ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta);
|
||||
|
||||
/* Spectrum management */
|
||||
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
|
||||
@ -1865,6 +1874,9 @@ extern const void *const mac80211_wiphy_privid; /* for wiphy privid */
|
||||
int ieee80211_frame_duration(enum nl80211_band band, size_t len,
|
||||
int rate, int erp, int short_preamble,
|
||||
int shift);
|
||||
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_tx_queue_params *qparam,
|
||||
int ac);
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
bool bss_notify, bool enable_qos);
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -519,6 +519,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
master->control_port_protocol;
|
||||
sdata->control_port_no_encrypt =
|
||||
master->control_port_no_encrypt;
|
||||
sdata->control_port_over_nl80211 =
|
||||
master->control_port_over_nl80211;
|
||||
sdata->vif.cab_queue = master->vif.cab_queue;
|
||||
memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
|
||||
sizeof(sdata->vif.hw_queue));
|
||||
|
@ -126,7 +126,7 @@ static void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_sub_if_data *sdata = key->sdata;
|
||||
struct sta_info *sta;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
@ -162,7 +162,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
if (sta && !sta->uploaded)
|
||||
goto out_unsupported;
|
||||
|
||||
sdata = key->sdata;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||
/*
|
||||
* The driver doesn't know anything about VLAN interfaces.
|
||||
@ -214,8 +213,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
/* all of these we can do in software - if driver can */
|
||||
if (ret == 1)
|
||||
return 0;
|
||||
if (ieee80211_hw_check(&key->local->hw, SW_CRYPTO_CONTROL))
|
||||
if (ieee80211_hw_check(&key->local->hw, SW_CRYPTO_CONTROL)) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -554,6 +554,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
||||
NL80211_FEATURE_USERSPACE_MPM |
|
||||
NL80211_FEATURE_FULL_AP_CLIENT_STATE;
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA);
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211);
|
||||
|
||||
if (!ops->hw_scan)
|
||||
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
|
||||
@ -930,8 +932,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
IEEE80211_HT_CAP_SM_PS_SHIFT;
|
||||
}
|
||||
|
||||
/* if low-level driver supports AP, we also support VLAN */
|
||||
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
|
||||
/* if low-level driver supports AP, we also support VLAN.
|
||||
* drivers advertising SW_CRYPTO_CONTROL should enable AP_VLAN
|
||||
* based on their support to transmit SW encrypted packets.
|
||||
*/
|
||||
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP) &&
|
||||
!ieee80211_hw_check(&local->hw, SW_CRYPTO_CONTROL)) {
|
||||
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
||||
hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
||||
}
|
||||
|
@ -880,7 +880,8 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
BSS_CHANGED_BEACON_ENABLED |
|
||||
BSS_CHANGED_HT |
|
||||
BSS_CHANGED_BASIC_RATES |
|
||||
BSS_CHANGED_BEACON_INT;
|
||||
BSS_CHANGED_BEACON_INT |
|
||||
BSS_CHANGED_MCAST_RATE;
|
||||
|
||||
local->fif_other_bss++;
|
||||
/* mesh ifaces must set allmulti to forward mcast traffic */
|
||||
|
@ -1787,12 +1787,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
params[ac].acm = acm;
|
||||
params[ac].uapsd = uapsd;
|
||||
|
||||
if (params[ac].cw_min > params[ac].cw_max) {
|
||||
if (params->cw_min == 0 ||
|
||||
params[ac].cw_min > params[ac].cw_max) {
|
||||
sdata_info(sdata,
|
||||
"AP has invalid WMM params (CWmin/max=%d/%d for ACI %d), using defaults\n",
|
||||
params[ac].cw_min, params[ac].cw_max, aci);
|
||||
return false;
|
||||
}
|
||||
ieee80211_regulatory_limit_wmm_params(sdata, ¶ms[ac], ac);
|
||||
}
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
@ -2011,8 +2013,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
/* deauthenticate/disassociate now */
|
||||
if (tx || frame_buf) {
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
/*
|
||||
* In multi channel scenarios guarantee that the virtual
|
||||
* interface is granted immediate airtime to transmit the
|
||||
@ -3307,82 +3307,14 @@ static const u64 care_about_ies =
|
||||
(1ULL << WLAN_EID_HT_OPERATION) |
|
||||
(1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);
|
||||
|
||||
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_if_managed *ifmgd,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *chan;
|
||||
struct sta_info *sta;
|
||||
u32 changed = 0;
|
||||
bool erp_valid;
|
||||
u8 erp_value = 0;
|
||||
u32 ncrc;
|
||||
u8 *bssid;
|
||||
u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
/* Process beacon from the current BSS */
|
||||
baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
|
||||
if (baselen > len)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
chan = chanctx_conf->def.chan;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
|
||||
ieee802_11_parse_elems(mgmt->u.beacon.variable,
|
||||
len - baselen, false, &elems);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
if (elems.tim && !elems.parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems.tim;
|
||||
ifmgd->dtim_period = tim_ie->dtim_period;
|
||||
}
|
||||
ifmgd->have_beacon = true;
|
||||
ifmgd->assoc_data->need_beacon = false;
|
||||
if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
|
||||
sdata->vif.bss_conf.sync_tsf =
|
||||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
}
|
||||
/* continue assoc process */
|
||||
ifmgd->assoc_data->timeout = jiffies;
|
||||
ifmgd->assoc_data->timeout_started = true;
|
||||
run_again(sdata, ifmgd->assoc_data->timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ifmgd->associated ||
|
||||
!ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
|
||||
return;
|
||||
bssid = ifmgd->associated->bssid;
|
||||
|
||||
/* Track average RSSI from the Beacon frames of the current AP */
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
|
||||
ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
|
||||
ewma_beacon_signal_init(&ifmgd->ave_beacon_signal);
|
||||
@ -3469,6 +3401,86 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
sig, GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt, size_t len,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
|
||||
size_t baselen;
|
||||
struct ieee802_11_elems elems;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_channel *chan;
|
||||
struct sta_info *sta;
|
||||
u32 changed = 0;
|
||||
bool erp_valid;
|
||||
u8 erp_value = 0;
|
||||
u32 ncrc;
|
||||
u8 *bssid;
|
||||
u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
/* Process beacon from the current BSS */
|
||||
baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
|
||||
if (baselen > len)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
chan = chanctx_conf->def.chan;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
|
||||
ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
|
||||
ieee802_11_parse_elems(mgmt->u.beacon.variable,
|
||||
len - baselen, false, &elems);
|
||||
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
|
||||
if (elems.tim && !elems.parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems.tim;
|
||||
ifmgd->dtim_period = tim_ie->dtim_period;
|
||||
}
|
||||
ifmgd->have_beacon = true;
|
||||
ifmgd->assoc_data->need_beacon = false;
|
||||
if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
|
||||
sdata->vif.bss_conf.sync_tsf =
|
||||
le64_to_cpu(mgmt->u.beacon.timestamp);
|
||||
sdata->vif.bss_conf.sync_device_ts =
|
||||
rx_status->device_timestamp;
|
||||
if (elems.tim)
|
||||
sdata->vif.bss_conf.sync_dtim_count =
|
||||
elems.tim->dtim_count;
|
||||
else
|
||||
sdata->vif.bss_conf.sync_dtim_count = 0;
|
||||
}
|
||||
/* continue assoc process */
|
||||
ifmgd->assoc_data->timeout = jiffies;
|
||||
ifmgd->assoc_data->timeout_started = true;
|
||||
run_again(sdata, ifmgd->assoc_data->timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ifmgd->associated ||
|
||||
!ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
|
||||
return;
|
||||
bssid = ifmgd->associated->bssid;
|
||||
|
||||
if (!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL))
|
||||
ieee80211_handle_beacon_sig(sdata, ifmgd, bss_conf,
|
||||
local, rx_status);
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
|
||||
mlme_dbg_ratelimited(sdata,
|
||||
@ -4845,6 +4857,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
sdata->control_port_protocol = req->crypto.control_port_ethertype;
|
||||
sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
|
||||
sdata->control_port_over_nl80211 =
|
||||
req->crypto.control_port_over_nl80211;
|
||||
sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
|
||||
sdata->vif.type);
|
||||
|
||||
|
@ -2245,6 +2245,32 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
|
||||
struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct net_device *dev = sdata->dev;
|
||||
|
||||
if (unlikely((skb->protocol == sdata->control_port_protocol ||
|
||||
skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) &&
|
||||
sdata->control_port_over_nl80211)) {
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
bool noencrypt = status->flag & RX_FLAG_DECRYPTED;
|
||||
struct ethhdr *ehdr = eth_hdr(skb);
|
||||
|
||||
cfg80211_rx_control_port(dev, skb->data, skb->len,
|
||||
ehdr->h_source,
|
||||
be16_to_cpu(skb->protocol), noencrypt);
|
||||
dev_kfree_skb(skb);
|
||||
} else {
|
||||
/* deliver to local stack */
|
||||
if (rx->napi)
|
||||
napi_gro_receive(rx->napi, skb);
|
||||
else
|
||||
netif_receive_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* requires that rx->skb is a frame with ethernet header
|
||||
*/
|
||||
@ -2329,13 +2355,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
|
||||
#endif
|
||||
|
||||
if (skb) {
|
||||
/* deliver to local stack */
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
memset(skb->cb, 0, sizeof(skb->cb));
|
||||
if (rx->napi)
|
||||
napi_gro_receive(rx->napi, skb);
|
||||
else
|
||||
netif_receive_skb(skb);
|
||||
|
||||
ieee80211_deliver_skb_to_local_stack(skb, rx);
|
||||
}
|
||||
|
||||
if (xmit_skb) {
|
||||
@ -2804,7 +2827,8 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
|
||||
!(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
|
||||
int sig = 0;
|
||||
|
||||
if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM))
|
||||
if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
|
||||
!(status->flag & RX_FLAG_NO_SIGNAL_VAL))
|
||||
sig = status->signal;
|
||||
|
||||
cfg80211_report_obss_beacon(rx->local->hw.wiphy,
|
||||
@ -2882,7 +2906,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
if (rx->sta->sta.smps_mode == smps_mode)
|
||||
goto handled;
|
||||
rx->sta->sta.smps_mode = smps_mode;
|
||||
sta_opmode.smps_mode = smps_mode;
|
||||
sta_opmode.smps_mode =
|
||||
ieee80211_smps_mode_to_smps_mode(smps_mode);
|
||||
sta_opmode.changed = STA_OPMODE_SMPS_MODE_CHANGED;
|
||||
|
||||
sband = rx->local->hw.wiphy->bands[status->band];
|
||||
@ -2920,7 +2945,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
|
||||
rx->sta->sta.bandwidth = new_bw;
|
||||
sband = rx->local->hw.wiphy->bands[status->band];
|
||||
sta_opmode.bw = new_bw;
|
||||
sta_opmode.bw =
|
||||
ieee80211_sta_rx_bw_to_chan_width(rx->sta);
|
||||
sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED;
|
||||
|
||||
rate_control_rate_update(local, sband, rx->sta,
|
||||
@ -3145,7 +3171,8 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
|
||||
* it transmitted were processed or returned.
|
||||
*/
|
||||
|
||||
if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM))
|
||||
if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
|
||||
!(status->flag & RX_FLAG_NO_SIGNAL_VAL))
|
||||
sig = status->signal;
|
||||
|
||||
if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
|
||||
|
@ -73,7 +73,9 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
bool signal_valid;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
|
||||
if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)
|
||||
bss_meta.signal = 0; /* invalid signal indication */
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
|
||||
bss_meta.signal = rx_status->signal * 100;
|
||||
else if (ieee80211_hw_check(&local->hw, SIGNAL_UNSPEC))
|
||||
bss_meta.signal = (rx_status->signal * 100) / local->hw.max_signal;
|
||||
|
@ -4757,3 +4757,49 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_xmit(sdata, NULL, skb);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *buf, size_t len,
|
||||
const u8 *dest, __be16 proto, bool unencrypted)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ethhdr *ehdr;
|
||||
u32 flags;
|
||||
|
||||
/* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE
|
||||
* or Pre-Authentication
|
||||
*/
|
||||
if (proto != sdata->control_port_protocol &&
|
||||
proto != cpu_to_be16(ETH_P_PREAUTH))
|
||||
return -EINVAL;
|
||||
|
||||
if (unencrypted)
|
||||
flags = IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
else
|
||||
flags = 0;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
|
||||
sizeof(struct ethhdr) + len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom + sizeof(struct ethhdr));
|
||||
|
||||
skb_put_data(skb, buf, len);
|
||||
|
||||
ehdr = skb_push(skb, sizeof(struct ethhdr));
|
||||
memcpy(ehdr->h_dest, dest, ETH_ALEN);
|
||||
memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
|
||||
ehdr->h_proto = proto;
|
||||
|
||||
skb->dev = dev;
|
||||
skb->protocol = htons(ETH_P_802_3);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
__ieee80211_subif_start_xmit(skb, skb->dev, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -1113,6 +1114,48 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
return crc;
|
||||
}
|
||||
|
||||
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_tx_queue_params
|
||||
*qparam, int ac)
|
||||
{
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
const struct ieee80211_reg_rule *rrule;
|
||||
struct ieee80211_wmm_ac *wmm_ac;
|
||||
u16 center_freq = 0;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP &&
|
||||
sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (chanctx_conf)
|
||||
center_freq = chanctx_conf->def.chan->center_freq;
|
||||
|
||||
if (!center_freq) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
rrule = freq_reg_info(sdata->wdev.wiphy, MHZ_TO_KHZ(center_freq));
|
||||
|
||||
if (IS_ERR_OR_NULL(rrule) || !rrule->wmm_rule) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
wmm_ac = &rrule->wmm_rule->ap[ac];
|
||||
else
|
||||
wmm_ac = &rrule->wmm_rule->client[ac];
|
||||
qparam->cw_min = max_t(u16, qparam->cw_min, wmm_ac->cw_min);
|
||||
qparam->cw_max = max_t(u16, qparam->cw_max, wmm_ac->cw_max);
|
||||
qparam->aifs = max_t(u8, qparam->aifs, wmm_ac->aifsn);
|
||||
qparam->txop = !qparam->txop ? wmm_ac->cot / 32 :
|
||||
min_t(u16, qparam->txop, wmm_ac->cot / 32);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
bool bss_notify, bool enable_qos)
|
||||
{
|
||||
@ -1206,6 +1249,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
break;
|
||||
}
|
||||
}
|
||||
ieee80211_regulatory_limit_wmm_params(sdata, &qparam, ac);
|
||||
|
||||
qparam.uapsd = false;
|
||||
|
||||
@ -1968,7 +2012,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
BSS_CHANGED_CQM |
|
||||
BSS_CHANGED_QOS |
|
||||
BSS_CHANGED_IDLE |
|
||||
BSS_CHANGED_TXPOWER;
|
||||
BSS_CHANGED_TXPOWER |
|
||||
BSS_CHANGED_MCAST_RATE;
|
||||
|
||||
if (sdata->vif.mu_mimo_owner)
|
||||
changed |= BSS_CHANGED_MU_GROUPS;
|
||||
|
@ -358,6 +358,36 @@ enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta)
|
||||
return NL80211_CHAN_WIDTH_80;
|
||||
}
|
||||
|
||||
enum nl80211_chan_width
|
||||
ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta)
|
||||
{
|
||||
enum ieee80211_sta_rx_bandwidth cur_bw = sta->sta.bandwidth;
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
|
||||
u32 cap_width;
|
||||
|
||||
switch (cur_bw) {
|
||||
case IEEE80211_STA_RX_BW_20:
|
||||
if (!sta->sta.ht_cap.ht_supported)
|
||||
return NL80211_CHAN_WIDTH_20_NOHT;
|
||||
else
|
||||
return NL80211_CHAN_WIDTH_20;
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
return NL80211_CHAN_WIDTH_40;
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
return NL80211_CHAN_WIDTH_80;
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
cap_width =
|
||||
vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||
|
||||
if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)
|
||||
return NL80211_CHAN_WIDTH_160;
|
||||
|
||||
return NL80211_CHAN_WIDTH_80P80;
|
||||
default:
|
||||
return NL80211_CHAN_WIDTH_20;
|
||||
}
|
||||
}
|
||||
|
||||
enum ieee80211_sta_rx_bandwidth
|
||||
ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
|
||||
{
|
||||
@ -484,7 +514,7 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
|
||||
new_bw = ieee80211_sta_cur_vht_bw(sta);
|
||||
if (new_bw != sta->sta.bandwidth) {
|
||||
sta->sta.bandwidth = new_bw;
|
||||
sta_opmode.bw = new_bw;
|
||||
sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta);
|
||||
changed |= IEEE80211_RC_BW_CHANGED;
|
||||
sta_opmode.changed |= STA_OPMODE_MAX_BW_CHANGED;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
|
||||
err = rdev_stop_ap(rdev, dev);
|
||||
if (!err) {
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
wdev->beacon_interval = 0;
|
||||
memset(&wdev->chandef, 0, sizeof(wdev->chandef));
|
||||
wdev->ssid_len = 0;
|
||||
|
@ -579,6 +579,10 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
|
||||
{
|
||||
struct ieee80211_channel *c;
|
||||
u32 freq, start_freq, end_freq;
|
||||
bool dfs_offload;
|
||||
|
||||
dfs_offload = wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_DFS_OFFLOAD);
|
||||
|
||||
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
|
||||
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
|
||||
@ -596,8 +600,9 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
|
||||
if (c->flags & IEEE80211_CHAN_DISABLED)
|
||||
return false;
|
||||
|
||||
if ((c->flags & IEEE80211_CHAN_RADAR) &&
|
||||
(c->dfs_state != NL80211_DFS_AVAILABLE))
|
||||
if ((c->flags & IEEE80211_CHAN_RADAR) &&
|
||||
(c->dfs_state != NL80211_DFS_AVAILABLE) &&
|
||||
!(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -282,10 +282,10 @@ void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
|
||||
unsigned long age_secs);
|
||||
|
||||
/* IBSS */
|
||||
int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_ibss_params *params,
|
||||
struct cfg80211_cached_keys *connkeys);
|
||||
int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_ibss_params *params,
|
||||
struct cfg80211_cached_keys *connkeys);
|
||||
void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
|
||||
int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, bool nowext);
|
||||
@ -303,10 +303,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct mesh_setup *setup,
|
||||
const struct mesh_config *conf);
|
||||
int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct mesh_setup *setup,
|
||||
const struct mesh_config *conf);
|
||||
int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev);
|
||||
int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
||||
|
@ -84,14 +84,15 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_ibss_joined);
|
||||
|
||||
static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_ibss_params *params,
|
||||
struct cfg80211_cached_keys *connkeys)
|
||||
int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_ibss_params *params,
|
||||
struct cfg80211_cached_keys *connkeys)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
ASSERT_RTNL();
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->ssid_len)
|
||||
@ -146,23 +147,6 @@ static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_ibss_params *params,
|
||||
struct cfg80211_cached_keys *connkeys)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
@ -224,6 +208,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
__cfg80211_clear_ibss(dev, nowext);
|
||||
|
||||
return 0;
|
||||
|
@ -217,21 +217,6 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
return err;
|
||||
}
|
||||
|
||||
int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct mesh_setup *setup,
|
||||
const struct mesh_config *conf)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_join_mesh(rdev, dev, setup, conf);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
@ -286,6 +271,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
||||
|
||||
err = rdev_leave_mesh(rdev, dev);
|
||||
if (!err) {
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
wdev->mesh_id_len = 0;
|
||||
wdev->beacon_interval = 0;
|
||||
memset(&wdev->chandef, 0, sizeof(wdev->chandef));
|
||||
|
@ -872,7 +872,7 @@ void cfg80211_cac_event(struct net_device *netdev,
|
||||
|
||||
trace_cfg80211_cac_event(netdev, event);
|
||||
|
||||
if (WARN_ON(!wdev->cac_started))
|
||||
if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!wdev->chandef.chan))
|
||||
@ -888,14 +888,17 @@ void cfg80211_cac_event(struct net_device *netdev,
|
||||
sizeof(struct cfg80211_chan_def));
|
||||
queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
break;
|
||||
/* fall through */
|
||||
case NL80211_RADAR_CAC_ABORTED:
|
||||
wdev->cac_started = false;
|
||||
break;
|
||||
case NL80211_RADAR_CAC_STARTED:
|
||||
wdev->cac_started = true;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
wdev->cac_started = false;
|
||||
|
||||
nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
|
||||
}
|
||||
|
@ -287,6 +287,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
|
||||
@ -4134,6 +4135,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
||||
wdev->chandef = params.chandef;
|
||||
wdev->ssid_len = params.ssid_len;
|
||||
memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
|
||||
wdev->conn_owner_nlportid = info->snd_portid;
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
@ -7551,12 +7555,13 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_chan_def chandef;
|
||||
enum nl80211_dfs_regions dfs_region;
|
||||
unsigned int cac_time_ms;
|
||||
int err;
|
||||
|
||||
dfs_region = reg_get_dfs_region(wdev->wiphy);
|
||||
dfs_region = reg_get_dfs_region(wiphy);
|
||||
if (dfs_region == NL80211_DFS_UNSET)
|
||||
return -EINVAL;
|
||||
|
||||
@ -7570,17 +7575,20 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
|
||||
if (wdev->cac_started)
|
||||
return -EBUSY;
|
||||
|
||||
err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
|
||||
wdev->iftype);
|
||||
err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (err == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
|
||||
if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
|
||||
return -EINVAL;
|
||||
|
||||
/* CAC start is offloaded to HW and can't be started manually */
|
||||
if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!rdev->ops->start_radar_detection)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@ -8204,6 +8212,22 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int validate_pae_over_nl80211(struct cfg80211_registered_device *rdev,
|
||||
struct genl_info *info)
|
||||
{
|
||||
if (!info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
|
||||
GENL_SET_ERR_MSG(info, "SOCKET_OWNER not set");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!rdev->ops->tx_control_port ||
|
||||
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
|
||||
struct genl_info *info,
|
||||
struct cfg80211_crypto_settings *settings,
|
||||
@ -8227,6 +8251,15 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
|
||||
} else
|
||||
settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
|
||||
int r = validate_pae_over_nl80211(rdev, info);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
settings->control_port_over_nl80211 = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
|
||||
void *data;
|
||||
int len, i;
|
||||
@ -8672,12 +8705,26 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
||||
ibss.control_port =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
|
||||
int r = validate_pae_over_nl80211(rdev, info);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ibss.control_port_over_nl80211 = true;
|
||||
}
|
||||
|
||||
ibss.userspace_handles_dfs =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
|
||||
|
||||
err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
err = __cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
|
||||
if (err)
|
||||
kzfree(connkeys);
|
||||
else if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
|
||||
dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -10083,7 +10130,7 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
/* cfg80211_join_mesh() will sort it out */
|
||||
/* __cfg80211_join_mesh() will sort it out */
|
||||
setup.chandef.chan = NULL;
|
||||
}
|
||||
|
||||
@ -10121,7 +10168,22 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
|
||||
setup.userspace_handles_dfs =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
|
||||
|
||||
return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
|
||||
if (info->attrs[NL80211_ATTR_CONTROL_PORT_OVER_NL80211]) {
|
||||
int r = validate_pae_over_nl80211(rdev, info);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
setup.control_port_over_nl80211 = true;
|
||||
}
|
||||
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
err = __cfg80211_join_mesh(rdev, dev, &setup, &cfg);
|
||||
if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER])
|
||||
dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
|
||||
@ -12517,6 +12579,68 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info)
|
||||
return rdev_external_auth(rdev, dev, ¶ms);
|
||||
}
|
||||
|
||||
static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
const u8 *buf;
|
||||
size_t len;
|
||||
u8 *dest;
|
||||
u16 proto;
|
||||
bool noencrypt;
|
||||
int err;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!rdev->ops->tx_control_port)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_FRAME] ||
|
||||
!info->attrs[NL80211_ATTR_MAC] ||
|
||||
!info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
|
||||
GENL_SET_ERR_MSG(info, "Frame, MAC or ethertype missing");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wdev_lock(wdev);
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (wdev->current_bss)
|
||||
break;
|
||||
err = -ENOTCONN;
|
||||
goto out;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wdev_unlock(wdev);
|
||||
|
||||
buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
|
||||
len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
|
||||
dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
proto = nla_get_u16(info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
|
||||
noencrypt =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
|
||||
|
||||
return rdev_tx_control_port(rdev, dev, buf, len,
|
||||
dest, cpu_to_be16(proto), noencrypt);
|
||||
|
||||
out:
|
||||
wdev_unlock(wdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
#define NL80211_FLAG_NEED_WIPHY 0x01
|
||||
#define NL80211_FLAG_NEED_NETDEV 0x02
|
||||
#define NL80211_FLAG_NEED_RTNL 0x04
|
||||
@ -13420,7 +13544,14 @@ static const struct genl_ops nl80211_ops[] = {
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
|
||||
{
|
||||
.cmd = NL80211_CMD_CONTROL_PORT_FRAME,
|
||||
.doit = nl80211_tx_control_port,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family nl80211_fam __ro_after_init = {
|
||||
@ -14535,6 +14666,64 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
|
||||
|
||||
static int __nl80211_rx_control_port(struct net_device *dev,
|
||||
const u8 *buf, size_t len,
|
||||
const u8 *addr, u16 proto,
|
||||
bool unencrypted, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
u32 nlportid = READ_ONCE(wdev->conn_owner_nlportid);
|
||||
|
||||
if (!nlportid)
|
||||
return -ENOENT;
|
||||
|
||||
msg = nlmsg_new(100 + len, gfp);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONTROL_PORT_FRAME);
|
||||
if (!hdr) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
|
||||
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
|
||||
NL80211_ATTR_PAD) ||
|
||||
nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
|
||||
nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
|
||||
(unencrypted && nla_put_flag(msg,
|
||||
NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
|
||||
|
||||
nla_put_failure:
|
||||
nlmsg_free(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
bool cfg80211_rx_control_port(struct net_device *dev,
|
||||
const u8 *buf, size_t len,
|
||||
const u8 *addr, u16 proto, bool unencrypted)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_cfg80211_rx_control_port(dev, buf, len, addr, proto, unencrypted);
|
||||
ret = __nl80211_rx_control_port(dev, buf, len, addr, proto,
|
||||
unencrypted, GFP_ATOMIC);
|
||||
trace_cfg80211_return_bool(ret == 0);
|
||||
return ret == 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_control_port);
|
||||
|
||||
static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
|
||||
const char *mac, gfp_t gfp)
|
||||
{
|
||||
|
@ -714,6 +714,21 @@ static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
const void *buf, size_t len,
|
||||
const u8 *dest, __be16 proto,
|
||||
const bool noencrypt)
|
||||
{
|
||||
int ret;
|
||||
trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len,
|
||||
dest, proto, noencrypt);
|
||||
ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len,
|
||||
dest, proto, noencrypt);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_mgmt_tx_cancel_wait(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, u64 cookie)
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -134,12 +135,12 @@ static void restore_regulatory_settings(bool reset_user);
|
||||
|
||||
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
|
||||
{
|
||||
return rtnl_dereference(cfg80211_regdomain);
|
||||
return rcu_dereference_rtnl(cfg80211_regdomain);
|
||||
}
|
||||
|
||||
const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
|
||||
{
|
||||
return rtnl_dereference(wiphy->regd);
|
||||
return rcu_dereference_rtnl(wiphy->regd);
|
||||
}
|
||||
|
||||
static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region)
|
||||
@ -424,23 +425,36 @@ static const struct ieee80211_regdomain *
|
||||
reg_copy_regd(const struct ieee80211_regdomain *src_regd)
|
||||
{
|
||||
struct ieee80211_regdomain *regd;
|
||||
int size_of_regd;
|
||||
int size_of_regd, size_of_wmms;
|
||||
unsigned int i;
|
||||
struct ieee80211_wmm_rule *d_wmm, *s_wmm;
|
||||
|
||||
size_of_regd =
|
||||
sizeof(struct ieee80211_regdomain) +
|
||||
src_regd->n_reg_rules * sizeof(struct ieee80211_reg_rule);
|
||||
size_of_wmms = src_regd->n_wmm_rules *
|
||||
sizeof(struct ieee80211_wmm_rule);
|
||||
|
||||
regd = kzalloc(size_of_regd, GFP_KERNEL);
|
||||
regd = kzalloc(size_of_regd + size_of_wmms, GFP_KERNEL);
|
||||
if (!regd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
|
||||
|
||||
for (i = 0; i < src_regd->n_reg_rules; i++)
|
||||
d_wmm = (struct ieee80211_wmm_rule *)((u8 *)regd + size_of_regd);
|
||||
s_wmm = (struct ieee80211_wmm_rule *)((u8 *)src_regd + size_of_regd);
|
||||
memcpy(d_wmm, s_wmm, size_of_wmms);
|
||||
|
||||
for (i = 0; i < src_regd->n_reg_rules; i++) {
|
||||
memcpy(®d->reg_rules[i], &src_regd->reg_rules[i],
|
||||
sizeof(struct ieee80211_reg_rule));
|
||||
if (!src_regd->reg_rules[i].wmm_rule)
|
||||
continue;
|
||||
|
||||
regd->reg_rules[i].wmm_rule = d_wmm +
|
||||
(src_regd->reg_rules[i].wmm_rule - s_wmm) /
|
||||
sizeof(struct ieee80211_wmm_rule);
|
||||
}
|
||||
return regd;
|
||||
}
|
||||
|
||||
@ -595,6 +609,17 @@ enum fwdb_flags {
|
||||
FWDB_FLAG_AUTO_BW = BIT(4),
|
||||
};
|
||||
|
||||
struct fwdb_wmm_ac {
|
||||
u8 ecw;
|
||||
u8 aifsn;
|
||||
__be16 cot;
|
||||
} __packed;
|
||||
|
||||
struct fwdb_wmm_rule {
|
||||
struct fwdb_wmm_ac client[IEEE80211_NUM_ACS];
|
||||
struct fwdb_wmm_ac ap[IEEE80211_NUM_ACS];
|
||||
} __packed;
|
||||
|
||||
struct fwdb_rule {
|
||||
u8 len;
|
||||
u8 flags;
|
||||
@ -602,6 +627,7 @@ struct fwdb_rule {
|
||||
__be32 start, end, max_bw;
|
||||
/* start of optional data */
|
||||
__be16 cac_timeout;
|
||||
__be16 wmm_ptr;
|
||||
} __packed __aligned(4);
|
||||
|
||||
#define FWDB_MAGIC 0x52474442
|
||||
@ -613,6 +639,31 @@ struct fwdb_header {
|
||||
struct fwdb_country country[];
|
||||
} __packed __aligned(4);
|
||||
|
||||
static int ecw2cw(int ecw)
|
||||
{
|
||||
return (1 << ecw) - 1;
|
||||
}
|
||||
|
||||
static bool valid_wmm(struct fwdb_wmm_rule *rule)
|
||||
{
|
||||
struct fwdb_wmm_ac *ac = (struct fwdb_wmm_ac *)rule;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS * 2; i++) {
|
||||
u16 cw_min = ecw2cw((ac[i].ecw & 0xf0) >> 4);
|
||||
u16 cw_max = ecw2cw(ac[i].ecw & 0x0f);
|
||||
u8 aifsn = ac[i].aifsn;
|
||||
|
||||
if (cw_min >= cw_max)
|
||||
return false;
|
||||
|
||||
if (aifsn < 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool valid_rule(const u8 *data, unsigned int size, u16 rule_ptr)
|
||||
{
|
||||
struct fwdb_rule *rule = (void *)(data + (rule_ptr << 2));
|
||||
@ -623,7 +674,18 @@ static bool valid_rule(const u8 *data, unsigned int size, u16 rule_ptr)
|
||||
/* mandatory fields */
|
||||
if (rule->len < offsetofend(struct fwdb_rule, max_bw))
|
||||
return false;
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) {
|
||||
u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
|
||||
struct fwdb_wmm_rule *wmm;
|
||||
|
||||
if (wmm_ptr + sizeof(struct fwdb_wmm_rule) > size)
|
||||
return false;
|
||||
|
||||
wmm = (void *)(data + wmm_ptr);
|
||||
|
||||
if (!valid_wmm(wmm))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -798,23 +860,118 @@ static bool valid_regdb(const u8 *data, unsigned int size)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_wmm_rule(struct ieee80211_wmm_rule *rule,
|
||||
struct fwdb_wmm_rule *wmm)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
rule->client[i].cw_min =
|
||||
ecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
|
||||
rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
|
||||
rule->client[i].aifsn = wmm->client[i].aifsn;
|
||||
rule->client[i].cot = 1000 * be16_to_cpu(wmm->client[i].cot);
|
||||
rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
|
||||
rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
|
||||
rule->ap[i].aifsn = wmm->ap[i].aifsn;
|
||||
rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
|
||||
}
|
||||
}
|
||||
|
||||
static int __regdb_query_wmm(const struct fwdb_header *db,
|
||||
const struct fwdb_country *country, int freq,
|
||||
u32 *dbptr, struct ieee80211_wmm_rule *rule)
|
||||
{
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < coll->n_rules; i++) {
|
||||
__be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
|
||||
struct fwdb_rule *rrule = (void *)((u8 *)db + rule_ptr);
|
||||
struct fwdb_wmm_rule *wmm;
|
||||
unsigned int wmm_ptr;
|
||||
|
||||
if (rrule->len < offsetofend(struct fwdb_rule, wmm_ptr))
|
||||
continue;
|
||||
|
||||
if (freq >= KHZ_TO_MHZ(be32_to_cpu(rrule->start)) &&
|
||||
freq <= KHZ_TO_MHZ(be32_to_cpu(rrule->end))) {
|
||||
wmm_ptr = be16_to_cpu(rrule->wmm_ptr) << 2;
|
||||
wmm = (void *)((u8 *)db + wmm_ptr);
|
||||
set_wmm_rule(rule, wmm);
|
||||
if (dbptr)
|
||||
*dbptr = wmm_ptr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
int reg_query_regdb_wmm(char *alpha2, int freq, u32 *dbptr,
|
||||
struct ieee80211_wmm_rule *rule)
|
||||
{
|
||||
const struct fwdb_header *hdr = regdb;
|
||||
const struct fwdb_country *country;
|
||||
|
||||
if (IS_ERR(regdb))
|
||||
return PTR_ERR(regdb);
|
||||
|
||||
country = &hdr->country[0];
|
||||
while (country->coll_ptr) {
|
||||
if (alpha2_equal(alpha2, country->alpha2))
|
||||
return __regdb_query_wmm(regdb, country, freq, dbptr,
|
||||
rule);
|
||||
|
||||
country++;
|
||||
}
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
EXPORT_SYMBOL(reg_query_regdb_wmm);
|
||||
|
||||
struct wmm_ptrs {
|
||||
struct ieee80211_wmm_rule *rule;
|
||||
u32 ptr;
|
||||
};
|
||||
|
||||
static struct ieee80211_wmm_rule *find_wmm_ptr(struct wmm_ptrs *wmm_ptrs,
|
||||
u32 wmm_ptr, int n_wmms)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_wmms; i++) {
|
||||
if (wmm_ptrs[i].ptr == wmm_ptr)
|
||||
return wmm_ptrs[i].rule;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int regdb_query_country(const struct fwdb_header *db,
|
||||
const struct fwdb_country *country)
|
||||
{
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
|
||||
struct ieee80211_regdomain *regdom;
|
||||
unsigned int size_of_regd;
|
||||
unsigned int i;
|
||||
struct ieee80211_regdomain *tmp_rd;
|
||||
unsigned int size_of_regd, i, n_wmms = 0;
|
||||
struct wmm_ptrs *wmm_ptrs;
|
||||
|
||||
size_of_regd =
|
||||
sizeof(struct ieee80211_regdomain) +
|
||||
size_of_regd = sizeof(struct ieee80211_regdomain) +
|
||||
coll->n_rules * sizeof(struct ieee80211_reg_rule);
|
||||
|
||||
regdom = kzalloc(size_of_regd, GFP_KERNEL);
|
||||
if (!regdom)
|
||||
return -ENOMEM;
|
||||
|
||||
wmm_ptrs = kcalloc(coll->n_rules, sizeof(*wmm_ptrs), GFP_KERNEL);
|
||||
if (!wmm_ptrs) {
|
||||
kfree(regdom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
regdom->n_reg_rules = coll->n_rules;
|
||||
regdom->alpha2[0] = country->alpha2[0];
|
||||
regdom->alpha2[1] = country->alpha2[1];
|
||||
@ -851,7 +1008,38 @@ static int regdb_query_country(const struct fwdb_header *db,
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
|
||||
rrule->dfs_cac_ms =
|
||||
1000 * be16_to_cpu(rule->cac_timeout);
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) {
|
||||
u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
|
||||
struct ieee80211_wmm_rule *wmm_pos =
|
||||
find_wmm_ptr(wmm_ptrs, wmm_ptr, n_wmms);
|
||||
struct fwdb_wmm_rule *wmm;
|
||||
struct ieee80211_wmm_rule *wmm_rule;
|
||||
|
||||
if (wmm_pos) {
|
||||
rrule->wmm_rule = wmm_pos;
|
||||
continue;
|
||||
}
|
||||
wmm = (void *)((u8 *)db + wmm_ptr);
|
||||
tmp_rd = krealloc(regdom, size_of_regd + (n_wmms + 1) *
|
||||
sizeof(struct ieee80211_wmm_rule),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!tmp_rd) {
|
||||
kfree(regdom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
regdom = tmp_rd;
|
||||
|
||||
wmm_rule = (struct ieee80211_wmm_rule *)
|
||||
((u8 *)regdom + size_of_regd + n_wmms *
|
||||
sizeof(struct ieee80211_wmm_rule));
|
||||
|
||||
set_wmm_rule(wmm_rule, wmm);
|
||||
wmm_ptrs[n_wmms].ptr = wmm_ptr;
|
||||
wmm_ptrs[n_wmms++].rule = wmm_rule;
|
||||
}
|
||||
}
|
||||
kfree(wmm_ptrs);
|
||||
|
||||
return reg_schedule_apply(regdom);
|
||||
}
|
||||
|
@ -1239,17 +1239,38 @@ void cfg80211_autodisconnect_wk(struct work_struct *work)
|
||||
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);
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
cfg80211_leave_ibss(rdev, wdev->netdev, false);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
cfg80211_stop_ap(rdev, wdev->netdev, false);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
cfg80211_leave_mesh(rdev, wdev->netdev);
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
/*
|
||||
* 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);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wdev_unlock(wdev);
|
||||
|
@ -1882,6 +1882,32 @@ TRACE_EVENT(rdev_mgmt_tx,
|
||||
BOOL_TO_STR(__entry->dont_wait_for_ack))
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_tx_control_port,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
const u8 *buf, size_t len, const u8 *dest, __be16 proto,
|
||||
bool unencrypted),
|
||||
TP_ARGS(wiphy, netdev, buf, len, dest, proto, unencrypted),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
MAC_ENTRY(dest)
|
||||
__field(__be16, proto)
|
||||
__field(bool, unencrypted)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
MAC_ASSIGN(dest, dest);
|
||||
__entry->proto = proto;
|
||||
__entry->unencrypted = unencrypted;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ","
|
||||
" proto: 0x%x, unencrypted: %s",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest),
|
||||
be16_to_cpu(__entry->proto),
|
||||
BOOL_TO_STR(__entry->unencrypted))
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_noack_map,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
u16 noack_map),
|
||||
@ -2600,6 +2626,27 @@ TRACE_EVENT(cfg80211_mgmt_tx_status,
|
||||
WDEV_PR_ARG, __entry->cookie, BOOL_TO_STR(__entry->ack))
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_rx_control_port,
|
||||
TP_PROTO(struct net_device *netdev, const u8 *buf, size_t len,
|
||||
const u8 *addr, u16 proto, bool unencrypted),
|
||||
TP_ARGS(netdev, buf, len, addr, proto, unencrypted),
|
||||
TP_STRUCT__entry(
|
||||
NETDEV_ENTRY
|
||||
MAC_ENTRY(addr)
|
||||
__field(u16, proto)
|
||||
__field(bool, unencrypted)
|
||||
),
|
||||
TP_fast_assign(
|
||||
NETDEV_ASSIGN;
|
||||
MAC_ASSIGN(addr, addr);
|
||||
__entry->proto = proto;
|
||||
__entry->unencrypted = unencrypted;
|
||||
),
|
||||
TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT " proto: 0x%x, unencrypted: %s",
|
||||
NETDEV_PR_ARG, MAC_PR_ARG(addr),
|
||||
__entry->proto, BOOL_TO_STR(__entry->unencrypted))
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_cqm_rssi_notify,
|
||||
TP_PROTO(struct net_device *netdev,
|
||||
enum nl80211_cqm_rssi_threshold_event rssi_event,
|
||||
|
Loading…
Reference in New Issue
Block a user