This time around, we have
* Neighbor Awareness Networking (NAN) APIs * a fix for a previous patch that caused memory corruption in wireless extensions key settings * beacon rate configuration for AP and mesh * memory limits for mac80211's internal TXQs * a (fairly involved) fix for the TXQ vs. crypto problems * direct cfg80211 driver API for WEP keys This also pulls in net-next to fix the merge conflicts, see the merge commit for more details. -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJX816EAAoJEGt7eEactAAdIPcP/1tbKUNQWPDrJAhBOBeUAs63 mjjzN8S+LZSQqD6efdHrIyP5JPSaLRvRkfn2nbhRa8bs/h2H/AczEd7Mrb5/fHvG FLXYGM/5VaCedts0td1iPV0CquSyLh/kwMzM9IPoFdqPnxs0lU0Mym7TrCDRaZjg pFjLxTypKhwdDj7qykaZpO0IQ91KpTW7ys5CAk6FpQJrgenjMiFQI0uzx4CdZZxl fQvbjHkZxPcxgL/78OJVsVasVR7rBydjog8BBV+j/7pFOjTjghxB25DmqIyHDMbU Z8q/uOGrZx08cVyXFASHNdj7wNsefD0d4nYh7qmbzUoaEnlpO8vX45avvxHr2AHV nMQd7lGYuGJ+fbZfvFTibHCE4mSTiiQ20VzCSXGROFmvlZa8vhgXXPUfkouCFfw/ /U498kFKC7Yg9qz7hioSi9FHUJOaZl/WkMqQ7qxB5F+mgvWYwwPXsMbAq1+BTmMm 6FGv0ehCaxEaNPgIcQHTGxiL2pP53sZipaqoR0lCxgbic736+l3o4vtnJQwmmFak f4eJ7fzYi9fppmOzDjVGEtGV4jRasmcXmucDlHKlvwXeG4FOIOY32U2qOUtqS+nM CUx7dPGArUeNWAPpkljLDg5GptXTk40HBLFDsyNbmOuj5Ax6OqcaFZNNeGgogCiU awbgk5xnCTOlU8LU88Do =qTne -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2016-10-04' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== This time around, we have * Neighbor Awareness Networking (NAN) APIs * a fix for a previous patch that caused memory corruption in wireless extensions key settings * beacon rate configuration for AP and mesh * memory limits for mac80211's internal TXQs * a (fairly involved) fix for the TXQ vs. crypto problems * direct cfg80211 driver API for WEP keys This also pulls in net-next to fix the merge conflicts, see the merge commit for more details. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
1ebf8b42b1
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
* Copyright 2015-2016 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
|
@ -593,6 +593,8 @@ struct survey_info {
|
|||
s8 noise;
|
||||
};
|
||||
|
||||
#define CFG80211_MAX_WEP_KEYS 4
|
||||
|
||||
/**
|
||||
* struct cfg80211_crypto_settings - Crypto settings
|
||||
* @wpa_versions: indicates which, if any, WPA versions are enabled
|
||||
|
@ -610,6 +612,9 @@ struct survey_info {
|
|||
* allowed through even on unauthorized ports
|
||||
* @control_port_no_encrypt: TRUE to prevent encryption of control port
|
||||
* protocol frames.
|
||||
* @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
|
||||
*/
|
||||
struct cfg80211_crypto_settings {
|
||||
u32 wpa_versions;
|
||||
|
@ -621,6 +626,8 @@ struct cfg80211_crypto_settings {
|
|||
bool control_port;
|
||||
__be16 control_port_ethertype;
|
||||
bool control_port_no_encrypt;
|
||||
struct key_params *wep_keys;
|
||||
int wep_tx_key;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -676,6 +683,18 @@ struct cfg80211_acl_data {
|
|||
struct mac_address mac_addrs[];
|
||||
};
|
||||
|
||||
/*
|
||||
* cfg80211_bitrate_mask - masks for bitrate control
|
||||
*/
|
||||
struct cfg80211_bitrate_mask {
|
||||
struct {
|
||||
u32 legacy;
|
||||
u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
|
||||
u16 vht_mcs[NL80211_VHT_NSS_MAX];
|
||||
enum nl80211_txrate_gi gi;
|
||||
} control[NUM_NL80211_BANDS];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_ap_settings - AP configuration
|
||||
*
|
||||
|
@ -700,6 +719,7 @@ struct cfg80211_acl_data {
|
|||
* MAC address based access control
|
||||
* @pbss: If set, start as a PCP instead of AP. Relevant for DMG
|
||||
* networks.
|
||||
* @beacon_rate: bitrate to be used for beacons
|
||||
*/
|
||||
struct cfg80211_ap_settings {
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
@ -719,6 +739,7 @@ struct cfg80211_ap_settings {
|
|||
bool p2p_opp_ps;
|
||||
const struct cfg80211_acl_data *acl;
|
||||
bool pbss;
|
||||
struct cfg80211_bitrate_mask beacon_rate;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1351,6 +1372,7 @@ struct mesh_config {
|
|||
* @beacon_interval: beacon interval to use
|
||||
* @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
|
||||
* @basic_rates: basic rates to use when creating the mesh
|
||||
* @beacon_rate: bitrate to be used for beacons
|
||||
*
|
||||
* These parameters are fixed when the mesh is created.
|
||||
*/
|
||||
|
@ -1371,6 +1393,7 @@ struct mesh_setup {
|
|||
u16 beacon_interval;
|
||||
int mcast_rate[NUM_NL80211_BANDS];
|
||||
u32 basic_rates;
|
||||
struct cfg80211_bitrate_mask beacon_rate;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2010,17 +2033,6 @@ enum wiphy_params_flags {
|
|||
WIPHY_PARAM_DYN_ACK = 1 << 5,
|
||||
};
|
||||
|
||||
/*
|
||||
* cfg80211_bitrate_mask - masks for bitrate control
|
||||
*/
|
||||
struct cfg80211_bitrate_mask {
|
||||
struct {
|
||||
u32 legacy;
|
||||
u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
|
||||
u16 vht_mcs[NL80211_VHT_NSS_MAX];
|
||||
enum nl80211_txrate_gi gi;
|
||||
} control[NUM_NL80211_BANDS];
|
||||
};
|
||||
/**
|
||||
* struct cfg80211_pmksa - PMK Security Association
|
||||
*
|
||||
|
@ -2301,6 +2313,98 @@ struct cfg80211_qos_map {
|
|||
struct cfg80211_dscp_range up[8];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_nan_conf - NAN configuration
|
||||
*
|
||||
* This struct defines NAN configuration parameters
|
||||
*
|
||||
* @master_pref: master preference (1 - 255)
|
||||
* @dual: dual band operation mode, see &enum nl80211_nan_dual_band_conf
|
||||
*/
|
||||
struct cfg80211_nan_conf {
|
||||
u8 master_pref;
|
||||
u8 dual;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cfg80211_nan_conf_changes - indicates changed fields in NAN
|
||||
* configuration
|
||||
*
|
||||
* @CFG80211_NAN_CONF_CHANGED_PREF: master preference
|
||||
* @CFG80211_NAN_CONF_CHANGED_DUAL: dual band operation
|
||||
*/
|
||||
enum cfg80211_nan_conf_changes {
|
||||
CFG80211_NAN_CONF_CHANGED_PREF = BIT(0),
|
||||
CFG80211_NAN_CONF_CHANGED_DUAL = BIT(1),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_nan_func_filter - a NAN function Rx / Tx filter
|
||||
*
|
||||
* @filter: the content of the filter
|
||||
* @len: the length of the filter
|
||||
*/
|
||||
struct cfg80211_nan_func_filter {
|
||||
const u8 *filter;
|
||||
u8 len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_nan_func - a NAN function
|
||||
*
|
||||
* @type: &enum nl80211_nan_function_type
|
||||
* @service_id: the service ID of the function
|
||||
* @publish_type: &nl80211_nan_publish_type
|
||||
* @close_range: if true, the range should be limited. Threshold is
|
||||
* implementation specific.
|
||||
* @publish_bcast: if true, the solicited publish should be broadcasted
|
||||
* @subscribe_active: if true, the subscribe is active
|
||||
* @followup_id: the instance ID for follow up
|
||||
* @followup_reqid: the requestor instance ID for follow up
|
||||
* @followup_dest: MAC address of the recipient of the follow up
|
||||
* @ttl: time to live counter in DW.
|
||||
* @serv_spec_info: Service Specific Info
|
||||
* @serv_spec_info_len: Service Specific Info length
|
||||
* @srf_include: if true, SRF is inclusive
|
||||
* @srf_bf: Bloom Filter
|
||||
* @srf_bf_len: Bloom Filter length
|
||||
* @srf_bf_idx: Bloom Filter index
|
||||
* @srf_macs: SRF MAC addresses
|
||||
* @srf_num_macs: number of MAC addresses in SRF
|
||||
* @rx_filters: rx filters that are matched with corresponding peer's tx_filter
|
||||
* @tx_filters: filters that should be transmitted in the SDF.
|
||||
* @num_rx_filters: length of &rx_filters.
|
||||
* @num_tx_filters: length of &tx_filters.
|
||||
* @instance_id: driver allocated id of the function.
|
||||
* @cookie: unique NAN function identifier.
|
||||
*/
|
||||
struct cfg80211_nan_func {
|
||||
enum nl80211_nan_function_type type;
|
||||
u8 service_id[NL80211_NAN_FUNC_SERVICE_ID_LEN];
|
||||
u8 publish_type;
|
||||
bool close_range;
|
||||
bool publish_bcast;
|
||||
bool subscribe_active;
|
||||
u8 followup_id;
|
||||
u8 followup_reqid;
|
||||
struct mac_address followup_dest;
|
||||
u32 ttl;
|
||||
const u8 *serv_spec_info;
|
||||
u8 serv_spec_info_len;
|
||||
bool srf_include;
|
||||
const u8 *srf_bf;
|
||||
u8 srf_bf_len;
|
||||
u8 srf_bf_idx;
|
||||
struct mac_address *srf_macs;
|
||||
int srf_num_macs;
|
||||
struct cfg80211_nan_func_filter *rx_filters;
|
||||
struct cfg80211_nan_func_filter *tx_filters;
|
||||
u8 num_tx_filters;
|
||||
u8 num_rx_filters;
|
||||
u8 instance_id;
|
||||
u64 cookie;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_ops - backend description for wireless configuration
|
||||
*
|
||||
|
@ -2589,6 +2693,19 @@ struct cfg80211_qos_map {
|
|||
* and returning to the base channel for communication with the AP.
|
||||
* @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both
|
||||
* peers must be on the base channel when the call completes.
|
||||
* @start_nan: Start the NAN interface.
|
||||
* @stop_nan: Stop the NAN interface.
|
||||
* @add_nan_func: Add a NAN function. Returns negative value on failure.
|
||||
* On success @nan_func ownership is transferred to the driver and
|
||||
* it may access it outside of the scope of this function. The driver
|
||||
* should free the @nan_func when no longer needed by calling
|
||||
* cfg80211_free_nan_func().
|
||||
* On success the driver should assign an instance_id in the
|
||||
* provided @nan_func.
|
||||
* @del_nan_func: Delete a NAN function.
|
||||
* @nan_change_conf: changes NAN configuration. The changed parameters must
|
||||
* be specified in @changes (using &enum cfg80211_nan_conf_changes);
|
||||
* All other parameters must be ignored.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||
|
@ -2854,6 +2971,17 @@ struct cfg80211_ops {
|
|||
void (*tdls_cancel_channel_switch)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
const u8 *addr);
|
||||
int (*start_nan)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf);
|
||||
void (*stop_nan)(struct wiphy *wiphy, struct wireless_dev *wdev);
|
||||
int (*add_nan_func)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_func *nan_func);
|
||||
void (*del_nan_func)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
u64 cookie);
|
||||
int (*nan_change_conf)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf,
|
||||
u32 changes);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2900,6 +3028,8 @@ struct cfg80211_ops {
|
|||
* @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
|
||||
* @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
|
||||
* beaconing mode (AP, IBSS, Mesh, ...).
|
||||
* @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation
|
||||
* before connection.
|
||||
*/
|
||||
enum wiphy_flags {
|
||||
/* use hole at 0 */
|
||||
|
@ -2925,6 +3055,7 @@ enum wiphy_flags {
|
|||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21),
|
||||
WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
|
||||
WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23),
|
||||
WIPHY_FLAG_HAS_STATIC_WEP = BIT(24),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -3302,6 +3433,8 @@ struct wiphy_iftype_ext_capab {
|
|||
* @bss_select_support: bitmask indicating the BSS selection criteria supported
|
||||
* by the driver in the .connect() callback. The bit position maps to the
|
||||
* attribute indices defined in &enum nl80211_bss_select_attr.
|
||||
*
|
||||
* @cookie_counter: unique generic cookie counter, used to identify objects.
|
||||
*/
|
||||
struct wiphy {
|
||||
/* assign these fields before you register the wiphy */
|
||||
|
@ -3431,6 +3564,8 @@ struct wiphy {
|
|||
|
||||
u32 bss_select_support;
|
||||
|
||||
u64 cookie_counter;
|
||||
|
||||
char priv[0] __aligned(NETDEV_ALIGN);
|
||||
};
|
||||
|
||||
|
@ -3611,6 +3746,7 @@ struct cfg80211_cached_keys;
|
|||
* beacons, 0 when not valid
|
||||
* @address: The address for this device, valid only if @netdev is %NULL
|
||||
* @p2p_started: true if this is a P2P Device that has been started
|
||||
* @nan_started: true if this is a NAN interface that has been started
|
||||
* @cac_started: true if DFS channel availability check has been started
|
||||
* @cac_start_time: timestamp (jiffies) when the dfs state was entered.
|
||||
* @cac_time_ms: CAC time in ms
|
||||
|
@ -3642,7 +3778,7 @@ struct wireless_dev {
|
|||
|
||||
struct mutex mtx;
|
||||
|
||||
bool use_4addr, p2p_started;
|
||||
bool use_4addr, p2p_started, nan_started;
|
||||
|
||||
u8 address[ETH_ALEN] __aligned(sizeof(u16));
|
||||
|
||||
|
@ -5550,6 +5686,67 @@ wiphy_ext_feature_isset(struct wiphy *wiphy,
|
|||
return (ft_byte & BIT(ftidx % 8)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_free_nan_func - free NAN function
|
||||
* @f: NAN function that should be freed
|
||||
*
|
||||
* Frees all the NAN function and all it's allocated members.
|
||||
*/
|
||||
void cfg80211_free_nan_func(struct cfg80211_nan_func *f);
|
||||
|
||||
/**
|
||||
* struct cfg80211_nan_match_params - NAN match parameters
|
||||
* @type: the type of the function that triggered a match. If it is
|
||||
* %NL80211_NAN_FUNC_SUBSCRIBE it means that we replied to a subscriber.
|
||||
* If it is %NL80211_NAN_FUNC_PUBLISH, it means that we got a discovery
|
||||
* result.
|
||||
* If it is %NL80211_NAN_FUNC_FOLLOW_UP, we received a follow up.
|
||||
* @inst_id: the local instance id
|
||||
* @peer_inst_id: the instance id of the peer's function
|
||||
* @addr: the MAC address of the peer
|
||||
* @info_len: the length of the &info
|
||||
* @info: the Service Specific Info from the peer (if any)
|
||||
* @cookie: unique identifier of the corresponding function
|
||||
*/
|
||||
struct cfg80211_nan_match_params {
|
||||
enum nl80211_nan_function_type type;
|
||||
u8 inst_id;
|
||||
u8 peer_inst_id;
|
||||
const u8 *addr;
|
||||
u8 info_len;
|
||||
const u8 *info;
|
||||
u64 cookie;
|
||||
};
|
||||
|
||||
/**
|
||||
* cfg80211_nan_match - report a match for a NAN function.
|
||||
* @wdev: the wireless device reporting the match
|
||||
* @match: match notification parameters
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* This function reports that the a NAN function had a match. This
|
||||
* can be a subscribe that had a match or a solicited publish that
|
||||
* was sent. It can also be a follow up that was received.
|
||||
*/
|
||||
void cfg80211_nan_match(struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_match_params *match, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_nan_func_terminated - notify about NAN function termination.
|
||||
*
|
||||
* @wdev: the wireless device reporting the match
|
||||
* @inst_id: the local instance id
|
||||
* @reason: termination reason (one of the NL80211_NAN_FUNC_TERM_REASON_*)
|
||||
* @cookie: unique NAN function identifier
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* This function reports that the a NAN function is terminated.
|
||||
*/
|
||||
void cfg80211_nan_func_terminated(struct wireless_dev *wdev,
|
||||
u8 inst_id,
|
||||
enum nl80211_nan_func_term_reason reason,
|
||||
u64 cookie, gfp_t gfp);
|
||||
|
||||
/* ethtool helper */
|
||||
void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
|
||||
|
||||
|
|
|
@ -72,9 +72,12 @@ struct fq {
|
|||
u32 flows_cnt;
|
||||
u32 perturbation;
|
||||
u32 limit;
|
||||
u32 memory_limit;
|
||||
u32 memory_usage;
|
||||
u32 quantum;
|
||||
u32 backlog;
|
||||
u32 overlimit;
|
||||
u32 overmemory;
|
||||
u32 collisions;
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ static struct sk_buff *fq_flow_dequeue(struct fq *fq,
|
|||
tin->backlog_packets--;
|
||||
flow->backlog -= skb->len;
|
||||
fq->backlog--;
|
||||
fq->memory_usage -= skb->truesize;
|
||||
|
||||
if (flow->backlog == 0) {
|
||||
list_del_init(&flow->backlogchain);
|
||||
|
@ -154,6 +155,7 @@ static void fq_tin_enqueue(struct fq *fq,
|
|||
flow->backlog += skb->len;
|
||||
tin->backlog_bytes += skb->len;
|
||||
tin->backlog_packets++;
|
||||
fq->memory_usage += skb->truesize;
|
||||
fq->backlog++;
|
||||
|
||||
fq_recalc_backlog(fq, tin, flow);
|
||||
|
@ -166,7 +168,7 @@ static void fq_tin_enqueue(struct fq *fq,
|
|||
|
||||
__skb_queue_tail(&flow->queue, skb);
|
||||
|
||||
if (fq->backlog > fq->limit) {
|
||||
if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) {
|
||||
flow = list_first_entry_or_null(&fq->backlogs,
|
||||
struct fq_flow,
|
||||
backlogchain);
|
||||
|
@ -181,6 +183,8 @@ static void fq_tin_enqueue(struct fq *fq,
|
|||
|
||||
flow->tin->overlimit++;
|
||||
fq->overlimit++;
|
||||
if (fq->memory_usage > fq->memory_limit)
|
||||
fq->overmemory++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,6 +255,7 @@ static int fq_init(struct fq *fq, int flows_cnt)
|
|||
fq->perturbation = prandom_u32();
|
||||
fq->quantum = 300;
|
||||
fq->limit = 8192;
|
||||
fq->memory_limit = 16 << 20; /* 16 MBytes */
|
||||
|
||||
fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL);
|
||||
if (!fq->flows)
|
||||
|
|
|
@ -715,6 +715,7 @@ enum mac80211_tx_info_flags {
|
|||
* frame (PS-Poll or uAPSD).
|
||||
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
|
||||
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
|
||||
* @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path
|
||||
*
|
||||
* These flags are used in tx_info->control.flags.
|
||||
*/
|
||||
|
@ -723,6 +724,7 @@ enum mac80211_tx_control_flags {
|
|||
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
|
||||
IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
|
||||
IEEE80211_TX_CTRL_AMSDU = BIT(3),
|
||||
IEEE80211_TX_CTRL_FAST_XMIT = BIT(4),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2177,6 +2179,8 @@ enum ieee80211_hw_flags {
|
|||
* @n_cipher_schemes: a size of an array of cipher schemes definitions.
|
||||
* @cipher_schemes: a pointer to an array of cipher scheme definitions
|
||||
* supported by HW.
|
||||
* @max_nan_de_entries: maximum number of NAN DE functions supported by the
|
||||
* device.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
|
@ -2211,6 +2215,7 @@ struct ieee80211_hw {
|
|||
u8 uapsd_max_sp_len;
|
||||
u8 n_cipher_schemes;
|
||||
const struct ieee80211_cipher_scheme *cipher_schemes;
|
||||
u8 max_nan_de_entries;
|
||||
};
|
||||
|
||||
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
|
||||
|
@ -3166,6 +3171,12 @@ enum ieee80211_reconfig_type {
|
|||
* required function.
|
||||
* The callback can sleep.
|
||||
*
|
||||
* @offset_tsf: Offset the TSF timer by the specified value in the
|
||||
* firmware/hardware. Preferred to set_tsf as it avoids delay between
|
||||
* calling set_tsf() and hardware getting programmed, which will show up
|
||||
* as TSF delay. Is not a required function.
|
||||
* The callback can sleep.
|
||||
*
|
||||
* @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
|
||||
* with other STAs in the IBSS. This is only used in IBSS mode. This
|
||||
* function is optional if the firmware/hardware takes full care of
|
||||
|
@ -3420,6 +3431,21 @@ enum ieee80211_reconfig_type {
|
|||
* synchronization which is needed in case driver has in its RSS queues
|
||||
* pending frames that were received prior to the control path action
|
||||
* currently taken (e.g. disassociation) but are not processed yet.
|
||||
*
|
||||
* @start_nan: join an existing NAN cluster, or create a new one.
|
||||
* @stop_nan: leave the NAN cluster.
|
||||
* @nan_change_conf: change NAN configuration. The data in cfg80211_nan_conf
|
||||
* contains full new configuration and changes specify which parameters
|
||||
* are changed with respect to the last NAN config.
|
||||
* The driver gets both full configuration and the changed parameters since
|
||||
* some devices may need the full configuration while others need only the
|
||||
* changed parameters.
|
||||
* @add_nan_func: Add a NAN function. Returns 0 on success. The data in
|
||||
* cfg80211_nan_func must not be referenced outside the scope of
|
||||
* this call.
|
||||
* @del_nan_func: Remove a NAN function. The driver must call
|
||||
* ieee80211_nan_func_terminated() with
|
||||
* NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
|
@ -3531,6 +3557,8 @@ struct ieee80211_ops {
|
|||
u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u64 tsf);
|
||||
void (*offset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
s64 offset);
|
||||
void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
||||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||
|
@ -3655,6 +3683,21 @@ struct ieee80211_ops {
|
|||
void (*wake_tx_queue)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq);
|
||||
void (*sync_rx_queues)(struct ieee80211_hw *hw);
|
||||
|
||||
int (*start_nan)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_conf *conf);
|
||||
int (*stop_nan)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
int (*nan_change_conf)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_conf *conf, u32 changes);
|
||||
int (*add_nan_func)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
const struct cfg80211_nan_func *nan_func);
|
||||
void (*del_nan_func)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u8 instance_id);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5728,4 +5771,36 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
|||
void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
|
||||
unsigned long *frame_cnt,
|
||||
unsigned long *byte_cnt);
|
||||
|
||||
/**
|
||||
* ieee80211_nan_func_terminated - notify about NAN function termination.
|
||||
*
|
||||
* This function is used to notify mac80211 about NAN function termination.
|
||||
* Note that this function can't be called from hard irq.
|
||||
*
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
* @inst_id: the local instance id
|
||||
* @reason: termination reason (one of the NL80211_NAN_FUNC_TERM_REASON_*)
|
||||
* @gfp: allocation flags
|
||||
*/
|
||||
void ieee80211_nan_func_terminated(struct ieee80211_vif *vif,
|
||||
u8 inst_id,
|
||||
enum nl80211_nan_func_term_reason reason,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* ieee80211_nan_func_match - notify about NAN function match event.
|
||||
*
|
||||
* This function is used to notify mac80211 about NAN function match. The
|
||||
* cookie inside the match struct will be assigned by mac80211.
|
||||
* Note that this function can't be called from hard irq.
|
||||
*
|
||||
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
|
||||
* @match: match event information
|
||||
* @gfp: allocation flags
|
||||
*/
|
||||
void ieee80211_nan_func_match(struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_match_params *match,
|
||||
gfp_t gfp);
|
||||
|
||||
#endif /* MAC80211_H */
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define NL80211_MULTICAST_GROUP_REG "regulatory"
|
||||
#define NL80211_MULTICAST_GROUP_MLME "mlme"
|
||||
#define NL80211_MULTICAST_GROUP_VENDOR "vendor"
|
||||
#define NL80211_MULTICAST_GROUP_NAN "nan"
|
||||
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
|
||||
|
||||
/**
|
||||
|
@ -838,6 +839,41 @@
|
|||
* not running. The driver indicates the status of the scan through
|
||||
* cfg80211_scan_done().
|
||||
*
|
||||
* @NL80211_CMD_START_NAN: Start NAN operation, identified by its
|
||||
* %NL80211_ATTR_WDEV interface. This interface must have been previously
|
||||
* created with %NL80211_CMD_NEW_INTERFACE. After it has been started, the
|
||||
* NAN interface will create or join a cluster. This command must have a
|
||||
* valid %NL80211_ATTR_NAN_MASTER_PREF attribute and optional
|
||||
* %NL80211_ATTR_NAN_DUAL attributes.
|
||||
* After this command NAN functions can be added.
|
||||
* @NL80211_CMD_STOP_NAN: Stop the NAN operation, identified by
|
||||
* its %NL80211_ATTR_WDEV interface.
|
||||
* @NL80211_CMD_ADD_NAN_FUNCTION: Add a NAN function. The function is defined
|
||||
* with %NL80211_ATTR_NAN_FUNC nested attribute. When called, this
|
||||
* operation returns the strictly positive and unique instance id
|
||||
* (%NL80211_ATTR_NAN_FUNC_INST_ID) and a cookie (%NL80211_ATTR_COOKIE)
|
||||
* of the function upon success.
|
||||
* Since instance ID's can be re-used, this cookie is the right
|
||||
* way to identify the function. This will avoid races when a termination
|
||||
* event is handled by the user space after it has already added a new
|
||||
* function that got the same instance id from the kernel as the one
|
||||
* which just terminated.
|
||||
* This cookie may be used in NAN events even before the command
|
||||
* returns, so userspace shouldn't process NAN events until it processes
|
||||
* the response to this command.
|
||||
* Look at %NL80211_ATTR_SOCKET_OWNER as well.
|
||||
* @NL80211_CMD_DEL_NAN_FUNCTION: Delete a NAN function by cookie.
|
||||
* This command is also used as a notification sent when a NAN function is
|
||||
* terminated. This will contain a %NL80211_ATTR_NAN_FUNC_INST_ID
|
||||
* and %NL80211_ATTR_COOKIE attributes.
|
||||
* @NL80211_CMD_CHANGE_NAN_CONFIG: Change current NAN configuration. NAN
|
||||
* must be operational (%NL80211_CMD_START_NAN was executed).
|
||||
* It must contain at least one of the following attributes:
|
||||
* %NL80211_ATTR_NAN_MASTER_PREF, %NL80211_ATTR_NAN_DUAL.
|
||||
* @NL80211_CMD_NAN_FUNC_MATCH: Notification sent when a match is reported.
|
||||
* This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
|
||||
* %NL80211_ATTR_COOKIE.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -1026,6 +1062,13 @@ enum nl80211_commands {
|
|||
|
||||
NL80211_CMD_ABORT_SCAN,
|
||||
|
||||
NL80211_CMD_START_NAN,
|
||||
NL80211_CMD_STOP_NAN,
|
||||
NL80211_CMD_ADD_NAN_FUNCTION,
|
||||
NL80211_CMD_DEL_NAN_FUNCTION,
|
||||
NL80211_CMD_CHANGE_NAN_CONFIG,
|
||||
NL80211_CMD_NAN_MATCH,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
|
@ -1343,7 +1386,13 @@ enum nl80211_commands {
|
|||
* enum nl80211_band value is used as the index (nla_type() of the nested
|
||||
* data. If a band is not included, it will be configured to allow all
|
||||
* rates based on negotiated supported rates information. This attribute
|
||||
* is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
|
||||
* is used with %NL80211_CMD_SET_TX_BITRATE_MASK and with starting AP,
|
||||
* and joining mesh networks (not IBSS yet). In the later case, it must
|
||||
* specify just a single bitrate, which is to be used for the beacon.
|
||||
* The driver must also specify support for this with the extended
|
||||
* features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
|
||||
* NL80211_EXT_FEATURE_BEACON_RATE_HT and
|
||||
* NL80211_EXT_FEATURE_BEACON_RATE_VHT.
|
||||
*
|
||||
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
|
||||
* at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
|
||||
|
@ -1733,6 +1782,12 @@ enum nl80211_commands {
|
|||
* regulatory indoor configuration would be owned by the netlink socket
|
||||
* that configured the indoor setting, and the indoor operation would be
|
||||
* cleared when the socket is closed.
|
||||
* If set during NAN interface creation, the interface will be destroyed
|
||||
* if the socket is closed just like any other interface. Moreover, only
|
||||
* the netlink socket that created the interface will be allowed to add
|
||||
* 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.
|
||||
*
|
||||
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
|
||||
* the TDLS link initiator.
|
||||
|
@ -1867,6 +1922,21 @@ enum nl80211_commands {
|
|||
* @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
|
||||
* used to pull the stored data for mesh peer in power save state.
|
||||
*
|
||||
* @NL80211_ATTR_NAN_MASTER_PREF: the master preference to be used by
|
||||
* %NL80211_CMD_START_NAN and optionally with
|
||||
* %NL80211_CMD_CHANGE_NAN_CONFIG. Its type is u8 and it can't be 0.
|
||||
* Also, values 1 and 255 are reserved for certification purposes and
|
||||
* should not be used during a normal device operation.
|
||||
* @NL80211_ATTR_NAN_DUAL: NAN dual band operation config (see
|
||||
* &enum nl80211_nan_dual_band_conf). This attribute is used with
|
||||
* %NL80211_CMD_START_NAN and optionally with
|
||||
* %NL80211_CMD_CHANGE_NAN_CONFIG.
|
||||
* @NL80211_ATTR_NAN_FUNC: a function that can be added to NAN. See
|
||||
* &enum nl80211_nan_func_attributes for description of this nested
|
||||
* attribute.
|
||||
* @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
|
||||
* See &enum nl80211_nan_match_attributes.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -2261,6 +2331,11 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_MESH_PEER_AID,
|
||||
|
||||
NL80211_ATTR_NAN_MASTER_PREF,
|
||||
NL80211_ATTR_NAN_DUAL,
|
||||
NL80211_ATTR_NAN_FUNC,
|
||||
NL80211_ATTR_NAN_MATCH,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -2339,6 +2414,7 @@ enum nl80211_attrs {
|
|||
* commands to create and destroy one
|
||||
* @NL80211_IF_TYPE_OCB: Outside Context of a BSS
|
||||
* This mode corresponds to the MIB variable dot11OCBActivated=true
|
||||
* @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev)
|
||||
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
|
||||
* @NUM_NL80211_IFTYPES: number of defined interface types
|
||||
*
|
||||
|
@ -2359,6 +2435,7 @@ enum nl80211_iftype {
|
|||
NL80211_IFTYPE_P2P_GO,
|
||||
NL80211_IFTYPE_P2P_DEVICE,
|
||||
NL80211_IFTYPE_OCB,
|
||||
NL80211_IFTYPE_NAN,
|
||||
|
||||
/* keep last */
|
||||
NUM_NL80211_IFTYPES,
|
||||
|
@ -4551,6 +4628,12 @@ enum nl80211_feature_flags {
|
|||
* (if available).
|
||||
* @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of
|
||||
* channel dwell time.
|
||||
* @NL80211_EXT_FEATURE_BEACON_RATE_LEGACY: Driver supports beacon rate
|
||||
* configuration (AP/mesh), supporting a legacy (non HT/VHT) rate.
|
||||
* @NL80211_EXT_FEATURE_BEACON_RATE_HT: Driver supports beacon rate
|
||||
* configuration (AP/mesh) with HT rates.
|
||||
* @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate
|
||||
* configuration (AP/mesh) with VHT rates.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
|
@ -4562,6 +4645,9 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_SCAN_START_TIME,
|
||||
NL80211_EXT_FEATURE_BSS_PARENT_TSF,
|
||||
NL80211_EXT_FEATURE_SET_SCAN_DWELL,
|
||||
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
|
||||
NL80211_EXT_FEATURE_BEACON_RATE_HT,
|
||||
NL80211_EXT_FEATURE_BEACON_RATE_VHT,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
@ -4855,4 +4941,186 @@ enum nl80211_bss_select_attr {
|
|||
NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_nan_dual_band_conf - NAN dual band configuration
|
||||
*
|
||||
* Defines the NAN dual band mode of operation
|
||||
*
|
||||
* @NL80211_NAN_BAND_DEFAULT: device default mode
|
||||
* @NL80211_NAN_BAND_2GHZ: 2.4GHz mode
|
||||
* @NL80211_NAN_BAND_5GHZ: 5GHz mode
|
||||
*/
|
||||
enum nl80211_nan_dual_band_conf {
|
||||
NL80211_NAN_BAND_DEFAULT = 1 << 0,
|
||||
NL80211_NAN_BAND_2GHZ = 1 << 1,
|
||||
NL80211_NAN_BAND_5GHZ = 1 << 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_nan_function_type - NAN function type
|
||||
*
|
||||
* Defines the function type of a NAN function
|
||||
*
|
||||
* @NL80211_NAN_FUNC_PUBLISH: function is publish
|
||||
* @NL80211_NAN_FUNC_SUBSCRIBE: function is subscribe
|
||||
* @NL80211_NAN_FUNC_FOLLOW_UP: function is follow-up
|
||||
*/
|
||||
enum nl80211_nan_function_type {
|
||||
NL80211_NAN_FUNC_PUBLISH,
|
||||
NL80211_NAN_FUNC_SUBSCRIBE,
|
||||
NL80211_NAN_FUNC_FOLLOW_UP,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_NAN_FUNC_TYPE_AFTER_LAST,
|
||||
NL80211_NAN_FUNC_MAX_TYPE = __NL80211_NAN_FUNC_TYPE_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_nan_publish_type - NAN publish tx type
|
||||
*
|
||||
* Defines how to send publish Service Discovery Frames
|
||||
*
|
||||
* @NL80211_NAN_SOLICITED_PUBLISH: publish function is solicited
|
||||
* @NL80211_NAN_UNSOLICITED_PUBLISH: publish function is unsolicited
|
||||
*/
|
||||
enum nl80211_nan_publish_type {
|
||||
NL80211_NAN_SOLICITED_PUBLISH = 1 << 0,
|
||||
NL80211_NAN_UNSOLICITED_PUBLISH = 1 << 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_nan_func_term_reason - NAN functions termination reason
|
||||
*
|
||||
* Defines termination reasons of a NAN function
|
||||
*
|
||||
* @NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST: requested by user
|
||||
* @NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED: timeout
|
||||
* @NL80211_NAN_FUNC_TERM_REASON_ERROR: errored
|
||||
*/
|
||||
enum nl80211_nan_func_term_reason {
|
||||
NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST,
|
||||
NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED,
|
||||
NL80211_NAN_FUNC_TERM_REASON_ERROR,
|
||||
};
|
||||
|
||||
#define NL80211_NAN_FUNC_SERVICE_ID_LEN 6
|
||||
#define NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN 0xff
|
||||
#define NL80211_NAN_FUNC_SRF_MAX_LEN 0xff
|
||||
|
||||
/**
|
||||
* enum nl80211_nan_func_attributes - NAN function attributes
|
||||
* @__NL80211_NAN_FUNC_INVALID: invalid
|
||||
* @NL80211_NAN_FUNC_TYPE: &enum nl80211_nan_function_type (u8).
|
||||
* @NL80211_NAN_FUNC_SERVICE_ID: 6 bytes of the service ID hash as
|
||||
* specified in NAN spec. This is a binary attribute.
|
||||
* @NL80211_NAN_FUNC_PUBLISH_TYPE: relevant if the function's type is
|
||||
* publish. Defines the transmission type for the publish Service Discovery
|
||||
* Frame, see &enum nl80211_nan_publish_type. Its type is u8.
|
||||
* @NL80211_NAN_FUNC_PUBLISH_BCAST: relevant if the function is a solicited
|
||||
* publish. Should the solicited publish Service Discovery Frame be sent to
|
||||
* the NAN Broadcast address. This is a flag.
|
||||
* @NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE: relevant if the function's type is
|
||||
* subscribe. Is the subscribe active. This is a flag.
|
||||
* @NL80211_NAN_FUNC_FOLLOW_UP_ID: relevant if the function's type is follow up.
|
||||
* The instance ID for the follow up Service Discovery Frame. This is u8.
|
||||
* @NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID: relevant if the function's type
|
||||
* is follow up. This is a u8.
|
||||
* The requestor instance ID for the follow up Service Discovery Frame.
|
||||
* @NL80211_NAN_FUNC_FOLLOW_UP_DEST: the MAC address of the recipient of the
|
||||
* follow up Service Discovery Frame. This is a binary attribute.
|
||||
* @NL80211_NAN_FUNC_CLOSE_RANGE: is this function limited for devices in a
|
||||
* close range. The range itself (RSSI) is defined by the device.
|
||||
* This is a flag.
|
||||
* @NL80211_NAN_FUNC_TTL: strictly positive number of DWs this function should
|
||||
* stay active. If not present infinite TTL is assumed. This is a u32.
|
||||
* @NL80211_NAN_FUNC_SERVICE_INFO: array of bytes describing the service
|
||||
* specific info. This is a binary attribute.
|
||||
* @NL80211_NAN_FUNC_SRF: Service Receive Filter. This is a nested attribute.
|
||||
* See &enum nl80211_nan_srf_attributes.
|
||||
* @NL80211_NAN_FUNC_RX_MATCH_FILTER: Receive Matching filter. This is a nested
|
||||
* attribute. It is a list of binary values.
|
||||
* @NL80211_NAN_FUNC_TX_MATCH_FILTER: Transmit Matching filter. This is a
|
||||
* nested attribute. It is a list of binary values.
|
||||
* @NL80211_NAN_FUNC_INSTANCE_ID: The instance ID of the function.
|
||||
* Its type is u8 and it cannot be 0.
|
||||
* @NL80211_NAN_FUNC_TERM_REASON: NAN function termination reason.
|
||||
* See &enum nl80211_nan_func_term_reason.
|
||||
*
|
||||
* @NUM_NL80211_NAN_FUNC_ATTR: internal
|
||||
* @NL80211_NAN_FUNC_ATTR_MAX: highest NAN function attribute
|
||||
*/
|
||||
enum nl80211_nan_func_attributes {
|
||||
__NL80211_NAN_FUNC_INVALID,
|
||||
NL80211_NAN_FUNC_TYPE,
|
||||
NL80211_NAN_FUNC_SERVICE_ID,
|
||||
NL80211_NAN_FUNC_PUBLISH_TYPE,
|
||||
NL80211_NAN_FUNC_PUBLISH_BCAST,
|
||||
NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE,
|
||||
NL80211_NAN_FUNC_FOLLOW_UP_ID,
|
||||
NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID,
|
||||
NL80211_NAN_FUNC_FOLLOW_UP_DEST,
|
||||
NL80211_NAN_FUNC_CLOSE_RANGE,
|
||||
NL80211_NAN_FUNC_TTL,
|
||||
NL80211_NAN_FUNC_SERVICE_INFO,
|
||||
NL80211_NAN_FUNC_SRF,
|
||||
NL80211_NAN_FUNC_RX_MATCH_FILTER,
|
||||
NL80211_NAN_FUNC_TX_MATCH_FILTER,
|
||||
NL80211_NAN_FUNC_INSTANCE_ID,
|
||||
NL80211_NAN_FUNC_TERM_REASON,
|
||||
|
||||
/* keep last */
|
||||
NUM_NL80211_NAN_FUNC_ATTR,
|
||||
NL80211_NAN_FUNC_ATTR_MAX = NUM_NL80211_NAN_FUNC_ATTR - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_nan_srf_attributes - NAN Service Response filter attributes
|
||||
* @__NL80211_NAN_SRF_INVALID: invalid
|
||||
* @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set.
|
||||
* This is a flag.
|
||||
* @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if
|
||||
* &NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
|
||||
* @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if
|
||||
* &NL80211_NAN_SRF_BF is present. This is a u8.
|
||||
* @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if
|
||||
* and only if &NL80211_NAN_SRF_BF isn't present. This is a nested
|
||||
* attribute. Each nested attribute is a MAC address.
|
||||
* @NUM_NL80211_NAN_SRF_ATTR: internal
|
||||
* @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute
|
||||
*/
|
||||
enum nl80211_nan_srf_attributes {
|
||||
__NL80211_NAN_SRF_INVALID,
|
||||
NL80211_NAN_SRF_INCLUDE,
|
||||
NL80211_NAN_SRF_BF,
|
||||
NL80211_NAN_SRF_BF_IDX,
|
||||
NL80211_NAN_SRF_MAC_ADDRS,
|
||||
|
||||
/* keep last */
|
||||
NUM_NL80211_NAN_SRF_ATTR,
|
||||
NL80211_NAN_SRF_ATTR_MAX = NUM_NL80211_NAN_SRF_ATTR - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_nan_match_attributes - NAN match attributes
|
||||
* @__NL80211_NAN_MATCH_INVALID: invalid
|
||||
* @NL80211_NAN_MATCH_FUNC_LOCAL: the local function that had the
|
||||
* match. This is a nested attribute.
|
||||
* See &enum nl80211_nan_func_attributes.
|
||||
* @NL80211_NAN_MATCH_FUNC_PEER: the peer function
|
||||
* that caused the match. This is a nested attribute.
|
||||
* See &enum nl80211_nan_func_attributes.
|
||||
*
|
||||
* @NUM_NL80211_NAN_MATCH_ATTR: internal
|
||||
* @NL80211_NAN_MATCH_ATTR_MAX: highest NAN match attribute
|
||||
*/
|
||||
enum nl80211_nan_match_attributes {
|
||||
__NL80211_NAN_MATCH_INVALID,
|
||||
NL80211_NAN_MATCH_FUNC_LOCAL,
|
||||
NL80211_NAN_MATCH_FUNC_PEER,
|
||||
|
||||
/* keep last */
|
||||
NUM_NL80211_NAN_MATCH_ATTR,
|
||||
NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
|
||||
};
|
||||
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
|
@ -152,6 +153,149 @@ static void ieee80211_stop_p2p_device(struct wiphy *wiphy,
|
|||
ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev));
|
||||
}
|
||||
|
||||
static int ieee80211_start_nan(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&sdata->local->chanctx_mtx);
|
||||
ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
|
||||
mutex_unlock(&sdata->local->chanctx_mtx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ieee80211_do_open(wdev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drv_start_nan(sdata->local, sdata, conf);
|
||||
if (ret)
|
||||
ieee80211_sdata_stop(sdata);
|
||||
|
||||
sdata->u.nan.conf = *conf;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ieee80211_stop_nan(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
|
||||
drv_stop_nan(sdata->local, sdata);
|
||||
ieee80211_sdata_stop(sdata);
|
||||
}
|
||||
|
||||
static int ieee80211_nan_change_conf(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf,
|
||||
u32 changes)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
struct cfg80211_nan_conf new_conf;
|
||||
int ret = 0;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_NAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
new_conf = sdata->u.nan.conf;
|
||||
|
||||
if (changes & CFG80211_NAN_CONF_CHANGED_PREF)
|
||||
new_conf.master_pref = conf->master_pref;
|
||||
|
||||
if (changes & CFG80211_NAN_CONF_CHANGED_DUAL)
|
||||
new_conf.dual = conf->dual;
|
||||
|
||||
ret = drv_nan_change_conf(sdata->local, sdata, &new_conf, changes);
|
||||
if (!ret)
|
||||
sdata->u.nan.conf = new_conf;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ieee80211_add_nan_func(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_func *nan_func)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
int ret;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_NAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
spin_lock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
ret = idr_alloc(&sdata->u.nan.function_inst_ids,
|
||||
nan_func, 1, sdata->local->hw.max_nan_de_entries + 1,
|
||||
GFP_ATOMIC);
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
nan_func->instance_id = ret;
|
||||
|
||||
WARN_ON(nan_func->instance_id == 0);
|
||||
|
||||
ret = drv_add_nan_func(sdata->local, sdata, nan_func);
|
||||
if (ret) {
|
||||
spin_lock_bh(&sdata->u.nan.func_lock);
|
||||
idr_remove(&sdata->u.nan.function_inst_ids,
|
||||
nan_func->instance_id);
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct cfg80211_nan_func *
|
||||
ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data *sdata,
|
||||
u64 cookie)
|
||||
{
|
||||
struct cfg80211_nan_func *func;
|
||||
int id;
|
||||
|
||||
lockdep_assert_held(&sdata->u.nan.func_lock);
|
||||
|
||||
idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) {
|
||||
if (func->cookie == cookie)
|
||||
return func;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ieee80211_del_nan_func(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev, u64 cookie)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
struct cfg80211_nan_func *func;
|
||||
u8 instance_id = 0;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_NAN ||
|
||||
!ieee80211_sdata_running(sdata))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
func = ieee80211_find_nan_func_by_cookie(sdata, cookie);
|
||||
if (func)
|
||||
instance_id = func->instance_id;
|
||||
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
if (instance_id)
|
||||
drv_del_nan_func(sdata->local, sdata, instance_id);
|
||||
}
|
||||
|
||||
static int ieee80211_set_noack_map(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u16 noack_map)
|
||||
|
@ -257,6 +401,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
|
@ -2036,6 +2181,7 @@ static int ieee80211_scan(struct wiphy *wiphy,
|
|||
!(req->flags & NL80211_SCAN_FLAG_AP)))
|
||||
return -EOPNOTSUPP;
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -3377,6 +3523,63 @@ static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
void ieee80211_nan_func_terminated(struct ieee80211_vif *vif,
|
||||
u8 inst_id,
|
||||
enum nl80211_nan_func_term_reason reason,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct cfg80211_nan_func *func;
|
||||
u64 cookie;
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
func = idr_find(&sdata->u.nan.function_inst_ids, inst_id);
|
||||
if (WARN_ON(!func)) {
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
cookie = func->cookie;
|
||||
idr_remove(&sdata->u.nan.function_inst_ids, inst_id);
|
||||
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
cfg80211_free_nan_func(func);
|
||||
|
||||
cfg80211_nan_func_terminated(ieee80211_vif_to_wdev(vif), inst_id,
|
||||
reason, cookie, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_nan_func_terminated);
|
||||
|
||||
void ieee80211_nan_func_match(struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_match_params *match,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct cfg80211_nan_func *func;
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
func = idr_find(&sdata->u.nan.function_inst_ids, match->inst_id);
|
||||
if (WARN_ON(!func)) {
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
return;
|
||||
}
|
||||
match->cookie = func->cookie;
|
||||
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
cfg80211_nan_match(ieee80211_vif_to_wdev(vif), match, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_nan_func_match);
|
||||
|
||||
const struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
|
@ -3462,4 +3665,9 @@ const struct cfg80211_ops mac80211_config_ops = {
|
|||
.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
|
||||
.add_tx_ts = ieee80211_add_tx_ts,
|
||||
.del_tx_ts = ieee80211_del_tx_ts,
|
||||
.start_nan = ieee80211_start_nan,
|
||||
.stop_nan = ieee80211_stop_nan,
|
||||
.nan_change_conf = ieee80211_nan_change_conf,
|
||||
.add_nan_func = ieee80211_add_nan_func,
|
||||
.del_nan_func = ieee80211_del_nan_func,
|
||||
};
|
||||
|
|
|
@ -274,6 +274,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
|
|||
ieee80211_get_max_required_bw(sdata));
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
continue;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
|
@ -646,6 +647,9 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_chanctx *curr_ctx = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
|
||||
return -ENOTSUPP;
|
||||
|
||||
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
|
||||
lockdep_is_held(&local->chanctx_mtx));
|
||||
|
||||
|
@ -718,6 +722,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
|
|||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
continue;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!sdata->u.mgd.associated)
|
||||
|
@ -980,6 +985,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
|
|||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
|
|
|
@ -89,13 +89,19 @@ static ssize_t aqm_read(struct file *file,
|
|||
"R fq_flows_cnt %u\n"
|
||||
"R fq_backlog %u\n"
|
||||
"R fq_overlimit %u\n"
|
||||
"R fq_overmemory %u\n"
|
||||
"R fq_collisions %u\n"
|
||||
"R fq_memory_usage %u\n"
|
||||
"RW fq_memory_limit %u\n"
|
||||
"RW fq_limit %u\n"
|
||||
"RW fq_quantum %u\n",
|
||||
fq->flows_cnt,
|
||||
fq->backlog,
|
||||
fq->overmemory,
|
||||
fq->overlimit,
|
||||
fq->collisions,
|
||||
fq->memory_usage,
|
||||
fq->memory_limit,
|
||||
fq->limit,
|
||||
fq->quantum);
|
||||
|
||||
|
@ -128,6 +134,8 @@ static ssize_t aqm_write(struct file *file,
|
|||
|
||||
if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1)
|
||||
return count;
|
||||
else if (sscanf(buf, "fq_memory_limit %u", &local->fq.memory_limit) == 1)
|
||||
return count;
|
||||
else if (sscanf(buf, "fq_quantum %u", &local->fq.quantum) == 1)
|
||||
return count;
|
||||
|
||||
|
|
|
@ -556,9 +556,15 @@ static ssize_t ieee80211_if_parse_tsf(
|
|||
ret = kstrtoull(buf, 10, &tsf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (tsf_is_delta && local->ops->offset_tsf) {
|
||||
drv_offset_tsf(local, sdata, tsf_is_delta * tsf);
|
||||
wiphy_info(local->hw.wiphy,
|
||||
"debugfs offset TSF by %018lld\n",
|
||||
tsf_is_delta * tsf);
|
||||
} else if (local->ops->set_tsf) {
|
||||
if (tsf_is_delta)
|
||||
tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;
|
||||
if (local->ops->set_tsf) {
|
||||
tsf = drv_get_tsf(local, sdata) +
|
||||
tsf_is_delta * tsf;
|
||||
drv_set_tsf(local, sdata, tsf);
|
||||
wiphy_info(local->hw.wiphy,
|
||||
"debugfs set TSF to %#018llx\n", tsf);
|
||||
|
|
|
@ -215,6 +215,21 @@ void drv_set_tsf(struct ieee80211_local *local,
|
|||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
void drv_offset_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
s64 offset)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
trace_drv_offset_tsf(local, sdata, offset);
|
||||
if (local->ops->offset_tsf)
|
||||
local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
void drv_reset_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
|
|
|
@ -162,6 +162,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
|
|||
return;
|
||||
|
||||
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
|
||||
sdata->vif.type == NL80211_IFTYPE_NAN ||
|
||||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
|
||||
!sdata->vif.mu_mimo_owner)))
|
||||
return;
|
||||
|
@ -568,6 +569,9 @@ u64 drv_get_tsf(struct ieee80211_local *local,
|
|||
void drv_set_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
u64 tsf);
|
||||
void drv_offset_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
s64 offset);
|
||||
void drv_reset_tsf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
|
@ -1165,4 +1169,83 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
|
|||
local->ops->wake_tx_queue(&local->hw, &txq->txq);
|
||||
}
|
||||
|
||||
static inline int drv_start_nan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_nan_conf *conf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
trace_drv_start_nan(local, sdata, conf);
|
||||
ret = local->ops->start_nan(&local->hw, &sdata->vif, conf);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_stop_nan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
trace_drv_stop_nan(local, sdata);
|
||||
local->ops->stop_nan(&local->hw, &sdata->vif);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline int drv_nan_change_conf(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_nan_conf *conf,
|
||||
u32 changes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
if (!local->ops->nan_change_conf)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
trace_drv_nan_change_conf(local, sdata, conf, changes);
|
||||
ret = local->ops->nan_change_conf(&local->hw, &sdata->vif, conf,
|
||||
changes);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int drv_add_nan_func(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_nan_func *nan_func)
|
||||
{
|
||||
int ret;
|
||||
|
||||
might_sleep();
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
if (!local->ops->add_nan_func)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
trace_drv_add_nan_func(local, sdata, nan_func);
|
||||
ret = local->ops->add_nan_func(&local->hw, &sdata->vif, nan_func);
|
||||
trace_drv_return_int(local, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_del_nan_func(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
u8 instance_id)
|
||||
{
|
||||
might_sleep();
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
trace_drv_del_nan_func(local, sdata, instance_id);
|
||||
if (local->ops->del_nan_func)
|
||||
local->ops->del_nan_func(&local->hw, &sdata->vif, instance_id);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
|
|
|
@ -86,6 +86,8 @@ struct ieee80211_local;
|
|||
|
||||
#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */)
|
||||
|
||||
#define IEEE80211_MAX_NAN_INSTANCE_ID 255
|
||||
|
||||
struct ieee80211_fragment_entry {
|
||||
struct sk_buff_head skb_list;
|
||||
unsigned long first_frag_time;
|
||||
|
@ -813,12 +815,14 @@ enum txq_info_flags {
|
|||
* @def_flow: used as a fallback flow when a packet destined to @tin hashes to
|
||||
* a fq_flow which is already owned by a different tin
|
||||
* @def_cvars: codel vars for @def_flow
|
||||
* @frags: used to keep fragments created after dequeue
|
||||
*/
|
||||
struct txq_info {
|
||||
struct fq_tin tin;
|
||||
struct fq_flow def_flow;
|
||||
struct codel_vars def_cvars;
|
||||
struct codel_stats cstats;
|
||||
struct sk_buff_head frags;
|
||||
unsigned long flags;
|
||||
|
||||
/* keep last! */
|
||||
|
@ -830,6 +834,20 @@ struct ieee80211_if_mntr {
|
|||
u8 mu_follow_addr[ETH_ALEN] __aligned(2);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_if_nan - NAN state
|
||||
*
|
||||
* @conf: current NAN configuration
|
||||
* @func_ids: a bitmap of available instance_id's
|
||||
*/
|
||||
struct ieee80211_if_nan {
|
||||
struct cfg80211_nan_conf conf;
|
||||
|
||||
/* protects function_inst_ids */
|
||||
spinlock_t func_lock;
|
||||
struct idr function_inst_ids;
|
||||
};
|
||||
|
||||
struct ieee80211_sub_if_data {
|
||||
struct list_head list;
|
||||
|
||||
|
@ -929,6 +947,7 @@ struct ieee80211_sub_if_data {
|
|||
struct ieee80211_if_mesh mesh;
|
||||
struct ieee80211_if_ocb ocb;
|
||||
struct ieee80211_if_mntr mntr;
|
||||
struct ieee80211_if_nan nan;
|
||||
} u;
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
|
@ -1481,6 +1500,13 @@ static inline struct txq_info *to_txq_info(struct ieee80211_txq *txq)
|
|||
return container_of(txq, struct txq_info, txq);
|
||||
}
|
||||
|
||||
static inline bool txq_has_queue(struct ieee80211_txq *txq)
|
||||
{
|
||||
struct txq_info *txqi = to_txq_info(txq);
|
||||
|
||||
return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets);
|
||||
}
|
||||
|
||||
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
|
||||
{
|
||||
return ether_addr_equal(raddr, addr) ||
|
||||
|
|
|
@ -327,6 +327,9 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
|
|||
int n_queues = sdata->local->hw.queues;
|
||||
int i;
|
||||
|
||||
if (iftype == NL80211_IFTYPE_NAN)
|
||||
return 0;
|
||||
|
||||
if (iftype != NL80211_IFTYPE_P2P_DEVICE) {
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
if (WARN_ON_ONCE(sdata->vif.hw_queue[i] ==
|
||||
|
@ -545,6 +548,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_OCB:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
/* no special treatment */
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
|
@ -646,7 +650,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
local->fif_probe_req++;
|
||||
}
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE)
|
||||
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
|
||||
sdata->vif.type != NL80211_IFTYPE_NAN)
|
||||
changed |= ieee80211_reset_erp_info(sdata);
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
|
||||
|
@ -660,6 +665,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
break;
|
||||
default:
|
||||
/* not reached */
|
||||
|
@ -792,6 +798,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
struct ps_data *ps;
|
||||
struct cfg80211_chan_def chandef;
|
||||
bool cancel_scan;
|
||||
struct cfg80211_nan_func *func;
|
||||
|
||||
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||
|
||||
|
@ -944,6 +951,18 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
/* clean all the functions */
|
||||
spin_lock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
|
||||
idr_remove(&sdata->u.nan.function_inst_ids, i);
|
||||
cfg80211_free_nan_func(func);
|
||||
}
|
||||
idr_destroy(&sdata->u.nan.function_inst_ids);
|
||||
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
/* relies on synchronize_rcu() below */
|
||||
RCU_INIT_POINTER(local->p2p_sdata, NULL);
|
||||
|
@ -1455,6 +1474,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
|||
case NL80211_IFTYPE_WDS:
|
||||
sdata->vif.bss_conf.bssid = NULL;
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
idr_init(&sdata->u.nan.function_inst_ids);
|
||||
spin_lock_init(&sdata->u.nan.func_lock);
|
||||
sdata->vif.bss_conf.bssid = sdata->vif.addr;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
sdata->vif.bss_conf.bssid = sdata->vif.addr;
|
||||
|
@ -1722,7 +1746,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
|||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (type == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
if (type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN) {
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size,
|
||||
|
|
|
@ -821,6 +821,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
!local->ops->tdls_recv_channel_switch))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (WARN_ON(local->hw.wiphy->interface_modes &
|
||||
BIT(NL80211_IFTYPE_NAN) &&
|
||||
(!local->ops->start_nan || !local->ops->stop_nan)))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume))
|
||||
return -EINVAL;
|
||||
|
@ -1058,6 +1063,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
|
||||
local->dynamic_ps_forced_timeout = -1;
|
||||
|
||||
if (!local->hw.max_nan_de_entries)
|
||||
local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID;
|
||||
|
||||
result = ieee80211_wep_init(local);
|
||||
if (result < 0)
|
||||
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* could be, for instance, in case a neighbor is restarted and its TSF counter
|
||||
* reset.
|
||||
*/
|
||||
#define TOFFSET_MAXIMUM_ADJUSTMENT 30000 /* 30 ms */
|
||||
#define TOFFSET_MAXIMUM_ADJUSTMENT 800 /* 0.8 ms */
|
||||
|
||||
struct sync_method {
|
||||
u8 method;
|
||||
|
@ -70,9 +70,13 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
spin_unlock_bh(&ifmsh->sync_offset_lock);
|
||||
|
||||
if (local->ops->offset_tsf) {
|
||||
drv_offset_tsf(local, sdata, tsfdelta);
|
||||
} else {
|
||||
tsf = drv_get_tsf(local, sdata);
|
||||
if (tsf != -1ULL)
|
||||
drv_set_tsf(local, sdata, tsf + tsfdelta);
|
||||
}
|
||||
}
|
||||
|
||||
static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -128,7 +128,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
|
|||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
|
||||
sdata->vif.type == NL80211_IFTYPE_NAN)
|
||||
continue;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
|
@ -838,6 +839,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
need_offchan = true;
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
@ -1323,9 +1323,7 @@ static void sta_ps_start(struct sta_info *sta)
|
|||
return;
|
||||
|
||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
||||
|
||||
if (txqi->tin.backlog_packets)
|
||||
if (txq_has_queue(sta->sta.txq[tid]))
|
||||
set_bit(tid, &sta->txq_buffered_tids);
|
||||
else
|
||||
clear_bit(tid, &sta->txq_buffered_tids);
|
||||
|
@ -3586,6 +3584,9 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
|||
ieee80211_is_probe_req(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control) ||
|
||||
ieee80211_is_beacon(hdr->frame_control);
|
||||
case NL80211_IFTYPE_NAN:
|
||||
/* Currently no frames on NAN interface are allowed */
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1202,12 +1202,10 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
|||
|
||||
if (sta->sta.txq[0]) {
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
|
||||
if (!txqi->tin.backlog_packets)
|
||||
if (!txq_has_queue(sta->sta.txq[i]))
|
||||
continue;
|
||||
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1638,10 +1636,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
|
|||
return;
|
||||
|
||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
||||
|
||||
if (!(driver_release_tids & BIT(tid)) ||
|
||||
txqi->tin.backlog_packets)
|
||||
txq_has_queue(sta->sta.txq[tid]))
|
||||
continue;
|
||||
|
||||
sta_info_recalc_tim(sta);
|
||||
|
|
|
@ -984,6 +984,32 @@ TRACE_EVENT(drv_set_tsf,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_offset_tsf,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
s64 offset),
|
||||
|
||||
TP_ARGS(local, sdata, offset),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(s64, tsf_offset)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->tsf_offset = offset;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT " tsf offset:%lld",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG,
|
||||
(unsigned long long)__entry->tsf_offset
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
|
@ -1700,6 +1726,139 @@ TRACE_EVENT(drv_get_expected_throughput,
|
|||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_start_nan,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_nan_conf *conf),
|
||||
|
||||
TP_ARGS(local, sdata, conf),
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(u8, master_pref)
|
||||
__field(u8, dual)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->master_pref = conf->master_pref;
|
||||
__entry->dual = conf->dual;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT
|
||||
", master preference: %u, dual: %d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->master_pref,
|
||||
__entry->dual
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_stop_nan,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
|
||||
TP_ARGS(local, sdata),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT,
|
||||
LOCAL_PR_ARG, VIF_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_nan_change_conf,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_nan_conf *conf,
|
||||
u32 changes),
|
||||
|
||||
TP_ARGS(local, sdata, conf, changes),
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(u8, master_pref)
|
||||
__field(u8, dual)
|
||||
__field(u32, changes)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->master_pref = conf->master_pref;
|
||||
__entry->dual = conf->dual;
|
||||
__entry->changes = changes;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT
|
||||
", master preference: %u, dual: %d, changes: 0x%x",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->master_pref,
|
||||
__entry->dual, __entry->changes
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_add_nan_func,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_nan_func *func),
|
||||
|
||||
TP_ARGS(local, sdata, func),
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(u8, type)
|
||||
__field(u8, inst_id)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->type = func->type;
|
||||
__entry->inst_id = func->instance_id;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT
|
||||
", type: %u, inst_id: %u",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->type, __entry->inst_id
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_del_nan_func,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
u8 instance_id),
|
||||
|
||||
TP_ARGS(local, sdata, instance_id),
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(u8, instance_id)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->instance_id = instance_id;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT
|
||||
", instance_id: %u",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->instance_id
|
||||
)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracing for API calls that drivers call.
|
||||
*/
|
||||
|
|
|
@ -796,36 +796,6 @@ static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *pubsta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_txq *txq = NULL;
|
||||
|
||||
if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
|
||||
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
|
||||
return NULL;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
return NULL;
|
||||
|
||||
if (pubsta) {
|
||||
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
txq = pubsta->txq[tid];
|
||||
} else if (vif) {
|
||||
txq = vif->txq;
|
||||
}
|
||||
|
||||
if (!txq)
|
||||
return NULL;
|
||||
|
||||
return to_txq_info(txq);
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
@ -883,8 +853,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
|||
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
||||
tx->sta->tx_stats.msdu[tid]++;
|
||||
|
||||
if (!ieee80211_get_txq(tx->local, info->control.vif, &tx->sta->sta,
|
||||
tx->skb))
|
||||
hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);
|
||||
|
||||
return TX_CONTINUE;
|
||||
|
@ -1274,6 +1242,36 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
|||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *pubsta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_txq *txq = NULL;
|
||||
|
||||
if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
|
||||
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
|
||||
return NULL;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
return NULL;
|
||||
|
||||
if (pubsta) {
|
||||
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
txq = pubsta->txq[tid];
|
||||
} else if (vif) {
|
||||
txq = vif->txq;
|
||||
}
|
||||
|
||||
if (!txq)
|
||||
return NULL;
|
||||
|
||||
return to_txq_info(txq);
|
||||
}
|
||||
|
||||
static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
|
||||
{
|
||||
IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
|
||||
|
@ -1405,6 +1403,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
|
|||
fq_flow_init(&txqi->def_flow);
|
||||
codel_vars_init(&txqi->def_cvars);
|
||||
codel_stats_init(&txqi->cstats);
|
||||
__skb_queue_head_init(&txqi->frags);
|
||||
|
||||
txqi->txq.vif = &sdata->vif;
|
||||
|
||||
|
@ -1427,6 +1426,7 @@ void ieee80211_txq_purge(struct ieee80211_local *local,
|
|||
struct fq_tin *tin = &txqi->tin;
|
||||
|
||||
fq_tin_reset(fq, tin, fq_skb_free_func);
|
||||
ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
|
||||
}
|
||||
|
||||
int ieee80211_txq_setup_flows(struct ieee80211_local *local)
|
||||
|
@ -1434,6 +1434,8 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local)
|
|||
struct fq *fq = &local->fq;
|
||||
int ret;
|
||||
int i;
|
||||
bool supp_vht = false;
|
||||
enum nl80211_band band;
|
||||
|
||||
if (!local->ops->wake_tx_queue)
|
||||
return 0;
|
||||
|
@ -1442,6 +1444,23 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If the hardware doesn't support VHT, it is safe to limit the maximum
|
||||
* queue size. 4 Mbytes is 64 max-size aggregates in 802.11n.
|
||||
*/
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (!sband)
|
||||
continue;
|
||||
|
||||
supp_vht = supp_vht || sband->vht_cap.vht_supported;
|
||||
}
|
||||
|
||||
if (!supp_vht)
|
||||
fq->memory_limit = 4 << 20; /* 4 Mbytes */
|
||||
|
||||
codel_params_init(&local->cparams);
|
||||
local->cparams.interval = MS2TIME(100);
|
||||
local->cparams.target = MS2TIME(20);
|
||||
|
@ -1477,54 +1496,46 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
|
|||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
|
||||
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
static bool ieee80211_queue_skb(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct txq_info *txqi = container_of(txq, struct txq_info, txq);
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
struct ieee80211_vif *vif;
|
||||
struct txq_info *txqi;
|
||||
struct ieee80211_sta *pubsta;
|
||||
|
||||
if (!local->ops->wake_tx_queue ||
|
||||
sdata->vif.type == NL80211_IFTYPE_MONITOR)
|
||||
return false;
|
||||
|
||||
if (sta && sta->uploaded)
|
||||
pubsta = &sta->sta;
|
||||
else
|
||||
pubsta = NULL;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap);
|
||||
|
||||
vif = &sdata->vif;
|
||||
txqi = ieee80211_get_txq(local, vif, pubsta, skb);
|
||||
|
||||
if (!txqi)
|
||||
return false;
|
||||
|
||||
info->control.vif = vif;
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
|
||||
goto out;
|
||||
|
||||
skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
ieee80211_set_skb_vif(skb, txqi);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
struct sta_info *sta = container_of(txq->sta, struct sta_info,
|
||||
sta);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid);
|
||||
if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
|
||||
info->flags |= IEEE80211_TX_CTL_AMPDU;
|
||||
else
|
||||
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||
}
|
||||
|
||||
out:
|
||||
ieee80211_txq_enqueue(local, txqi, skb);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
if (skb && skb_has_frag_list(skb) &&
|
||||
!ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) {
|
||||
if (skb_linearize(skb)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
|
||||
return skb;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
||||
|
||||
static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
|
@ -1533,9 +1544,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
|||
bool txpending)
|
||||
{
|
||||
struct ieee80211_tx_control control = {};
|
||||
struct fq *fq = &local->fq;
|
||||
struct sk_buff *skb, *tmp;
|
||||
struct txq_info *txqi;
|
||||
unsigned long flags;
|
||||
|
||||
skb_queue_walk_safe(skbs, skb, tmp) {
|
||||
|
@ -1550,21 +1559,6 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
|||
}
|
||||
#endif
|
||||
|
||||
txqi = ieee80211_get_txq(local, vif, sta, skb);
|
||||
if (txqi) {
|
||||
info->control.vif = vif;
|
||||
|
||||
__skb_unlink(skb, skbs);
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_enqueue(local, txqi, skb);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
if (local->queue_stop_reasons[q] ||
|
||||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
|
||||
|
@ -1685,10 +1679,13 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
|
|||
/*
|
||||
* Invoke TX handlers, return 0 on success and non-zero if the
|
||||
* frame was dropped or queued.
|
||||
*
|
||||
* The handlers are split into an early and late part. The latter is everything
|
||||
* that can be sensitive to reordering, and will be deferred to after packets
|
||||
* are dequeued from the intermediate queues (when they are enabled).
|
||||
*/
|
||||
static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
||||
static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
ieee80211_tx_result res = TX_DROP;
|
||||
|
||||
#define CALL_TXH(txh) \
|
||||
|
@ -1706,6 +1703,31 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
|||
if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
|
||||
CALL_TXH(ieee80211_tx_h_rate_ctrl);
|
||||
|
||||
txh_done:
|
||||
if (unlikely(res == TX_DROP)) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop);
|
||||
if (tx->skb)
|
||||
ieee80211_free_txskb(&tx->local->hw, tx->skb);
|
||||
else
|
||||
ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
|
||||
return -1;
|
||||
} else if (unlikely(res == TX_QUEUED)) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_queued);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Late handlers can be called while the sta lock is held. Handlers that can
|
||||
* cause packets to be generated will cause deadlock!
|
||||
*/
|
||||
static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
ieee80211_tx_result res = TX_CONTINUE;
|
||||
|
||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
|
||||
__skb_queue_tail(&tx->skbs, tx->skb);
|
||||
tx->skb = NULL;
|
||||
|
@ -1738,6 +1760,15 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
int r = invoke_tx_handlers_early(tx);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
return invoke_tx_handlers_late(tx);
|
||||
}
|
||||
|
||||
bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, struct sk_buff *skb,
|
||||
int band, struct ieee80211_sta **sta)
|
||||
|
@ -1812,7 +1843,13 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
|||
info->hw_queue =
|
||||
sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
|
||||
|
||||
if (!invoke_tx_handlers(&tx))
|
||||
if (invoke_tx_handlers_early(&tx))
|
||||
return false;
|
||||
|
||||
if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
|
||||
return true;
|
||||
|
||||
if (!invoke_tx_handlers_late(&tx))
|
||||
result = __ieee80211_tx(local, &tx.skbs, led_len,
|
||||
tx.sta, txpending);
|
||||
|
||||
|
@ -3156,8 +3193,71 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can be called while the sta lock is held. Anything that can cause packets to
|
||||
* be generated will cause deadlock!
|
||||
*/
|
||||
static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, u8 pn_offs,
|
||||
struct ieee80211_key *key,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
u8 tid = IEEE80211_NUM_TIDS;
|
||||
|
||||
if (key)
|
||||
info->control.hw_key = &key->conf;
|
||||
|
||||
ieee80211_tx_stats(skb->dev, skb->len);
|
||||
|
||||
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
*ieee80211_get_qos_ctl(hdr) = tid;
|
||||
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
||||
} else {
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
|
||||
sdata->sequence_number += 0x10;
|
||||
}
|
||||
|
||||
if (skb_shinfo(skb)->gso_size)
|
||||
sta->tx_stats.msdu[tid] +=
|
||||
DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
|
||||
else
|
||||
sta->tx_stats.msdu[tid]++;
|
||||
|
||||
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
|
||||
|
||||
/* statistics normally done by ieee80211_tx_h_stats (but that
|
||||
* has to consider fragmentation, so is more complex)
|
||||
*/
|
||||
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
|
||||
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
|
||||
|
||||
if (pn_offs) {
|
||||
u64 pn;
|
||||
u8 *crypto_hdr = skb->data + pn_offs;
|
||||
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
pn = atomic64_inc_return(&key->conf.tx_pn);
|
||||
crypto_hdr[0] = pn;
|
||||
crypto_hdr[1] = pn >> 8;
|
||||
crypto_hdr[4] = pn >> 16;
|
||||
crypto_hdr[5] = pn >> 24;
|
||||
crypto_hdr[6] = pn >> 32;
|
||||
crypto_hdr[7] = pn >> 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
||||
struct net_device *dev, struct sta_info *sta,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_fast_tx *fast_tx,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -3208,8 +3308,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
return true;
|
||||
}
|
||||
|
||||
ieee80211_tx_stats(dev, skb->len + extra_head);
|
||||
|
||||
if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
|
||||
ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
|
||||
return true;
|
||||
|
@ -3238,24 +3336,7 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
|
||||
IEEE80211_TX_CTL_DONTFRAG |
|
||||
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
|
||||
|
||||
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||
*ieee80211_get_qos_ctl(hdr) = tid;
|
||||
if (!ieee80211_get_txq(local, &sdata->vif, &sta->sta, skb))
|
||||
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
||||
} else {
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
|
||||
sdata->sequence_number += 0x10;
|
||||
}
|
||||
|
||||
if (skb_shinfo(skb)->gso_size)
|
||||
sta->tx_stats.msdu[tid] +=
|
||||
DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
|
||||
else
|
||||
sta->tx_stats.msdu[tid]++;
|
||||
|
||||
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
|
||||
info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
|
||||
|
||||
__skb_queue_head_init(&tx.skbs);
|
||||
|
||||
|
@ -3265,9 +3346,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
tx.sta = sta;
|
||||
tx.key = fast_tx->key;
|
||||
|
||||
if (fast_tx->key)
|
||||
info->control.hw_key = &fast_tx->key->conf;
|
||||
|
||||
if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
|
||||
tx.skb = skb;
|
||||
r = ieee80211_tx_h_rate_ctrl(&tx);
|
||||
|
@ -3281,31 +3359,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
/* statistics normally done by ieee80211_tx_h_stats (but that
|
||||
* has to consider fragmentation, so is more complex)
|
||||
*/
|
||||
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
|
||||
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
|
||||
if (ieee80211_queue_skb(local, sdata, sta, skb))
|
||||
return true;
|
||||
|
||||
if (fast_tx->pn_offs) {
|
||||
u64 pn;
|
||||
u8 *crypto_hdr = skb->data + fast_tx->pn_offs;
|
||||
|
||||
switch (fast_tx->key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
pn = atomic64_inc_return(&fast_tx->key->conf.tx_pn);
|
||||
crypto_hdr[0] = pn;
|
||||
crypto_hdr[1] = pn >> 8;
|
||||
crypto_hdr[4] = pn >> 16;
|
||||
crypto_hdr[5] = pn >> 24;
|
||||
crypto_hdr[6] = pn >> 32;
|
||||
crypto_hdr[7] = pn >> 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
|
||||
fast_tx->key, skb);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
|
@ -3316,6 +3374,94 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
return true;
|
||||
}
|
||||
|
||||
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct txq_info *txqi = container_of(txq, struct txq_info, txq);
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_tx_data tx;
|
||||
ieee80211_tx_result r;
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
|
||||
goto out;
|
||||
|
||||
/* Make sure fragments stay together. */
|
||||
skb = __skb_dequeue(&txqi->frags);
|
||||
if (skb)
|
||||
goto out;
|
||||
|
||||
begin:
|
||||
skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
ieee80211_set_skb_vif(skb, txqi);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
memset(&tx, 0, sizeof(tx));
|
||||
__skb_queue_head_init(&tx.skbs);
|
||||
tx.local = local;
|
||||
tx.skb = skb;
|
||||
tx.sdata = vif_to_sdata(info->control.vif);
|
||||
|
||||
if (txq->sta)
|
||||
tx.sta = container_of(txq->sta, struct sta_info, sta);
|
||||
|
||||
/*
|
||||
* The key can be removed while the packet was queued, so need to call
|
||||
* this here to get the current key.
|
||||
*/
|
||||
r = ieee80211_tx_h_select_key(&tx);
|
||||
if (r != TX_CONTINUE) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
goto begin;
|
||||
}
|
||||
|
||||
if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
|
||||
struct sta_info *sta = container_of(txq->sta, struct sta_info,
|
||||
sta);
|
||||
u8 pn_offs = 0;
|
||||
|
||||
if (tx.key &&
|
||||
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
|
||||
pn_offs = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
|
||||
tx.key, skb);
|
||||
} else {
|
||||
if (invoke_tx_handlers_late(&tx))
|
||||
goto begin;
|
||||
|
||||
skb = __skb_dequeue(&tx.skbs);
|
||||
|
||||
if (!skb_queue_empty(&tx.skbs))
|
||||
skb_queue_splice_tail(&tx.skbs, &txqi->frags);
|
||||
}
|
||||
|
||||
if (skb && skb_has_frag_list(skb) &&
|
||||
!ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) {
|
||||
if (skb_linearize(skb)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
goto begin;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
||||
|
||||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags)
|
||||
|
@ -3340,7 +3486,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
fast_tx = rcu_dereference(sta->fast_tx);
|
||||
|
||||
if (fast_tx &&
|
||||
ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb))
|
||||
ieee80211_xmit_fast(sdata, sta, fast_tx, skb))
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -1209,7 +1209,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
|
||||
sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) {
|
||||
sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
|
||||
sdata->vif.type != NL80211_IFTYPE_NAN) {
|
||||
sdata->vif.bss_conf.qos = enable_qos;
|
||||
if (bss_notify)
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
|
@ -1748,6 +1749,46 @@ static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata)
|
|||
mutex_unlock(&local->sta_mtx);
|
||||
}
|
||||
|
||||
static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct cfg80211_nan_func *func, **funcs;
|
||||
int res, id, i = 0;
|
||||
|
||||
res = drv_start_nan(sdata->local, sdata,
|
||||
&sdata->u.nan.conf);
|
||||
if (WARN_ON(res))
|
||||
return res;
|
||||
|
||||
funcs = kzalloc((sdata->local->hw.max_nan_de_entries + 1) *
|
||||
sizeof(*funcs), GFP_KERNEL);
|
||||
if (!funcs)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Add all the functions:
|
||||
* This is a little bit ugly. We need to call a potentially sleeping
|
||||
* callback for each NAN function, so we can't hold the spinlock.
|
||||
*/
|
||||
spin_lock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id)
|
||||
funcs[i++] = func;
|
||||
|
||||
spin_unlock_bh(&sdata->u.nan.func_lock);
|
||||
|
||||
for (i = 0; funcs[i]; i++) {
|
||||
res = drv_add_nan_func(sdata->local, sdata, funcs[i]);
|
||||
if (WARN_ON(res))
|
||||
ieee80211_nan_func_terminated(&sdata->vif,
|
||||
funcs[i]->instance_id,
|
||||
NL80211_NAN_FUNC_TERM_REASON_ERROR,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
kfree(funcs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_hw *hw = &local->hw;
|
||||
|
@ -1971,6 +2012,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
res = ieee80211_reconfig_nan(sdata);
|
||||
if (res < 0) {
|
||||
ieee80211_handle_reconfig_failure(local);
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
|
@ -3393,11 +3441,18 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
|
|||
unsigned long *byte_cnt)
|
||||
{
|
||||
struct txq_info *txqi = to_txq_info(txq);
|
||||
u32 frag_cnt = 0, frag_bytes = 0;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb_queue_walk(&txqi->frags, skb) {
|
||||
frag_cnt++;
|
||||
frag_bytes += skb->len;
|
||||
}
|
||||
|
||||
if (frame_cnt)
|
||||
*frame_cnt = txqi->tin.backlog_packets;
|
||||
*frame_cnt = txqi->tin.backlog_packets + frag_cnt;
|
||||
|
||||
if (byte_cnt)
|
||||
*byte_cnt = txqi->tin.backlog_bytes;
|
||||
*byte_cnt = txqi->tin.backlog_bytes + frag_bytes;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_txq_get_depth);
|
||||
|
|
|
@ -372,6 +372,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
|
|||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
|
@ -946,6 +947,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
|
|||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
/* these interface types don't really have a channel */
|
||||
return;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
|
|
|
@ -225,6 +225,23 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
}
|
||||
|
||||
void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
|
||||
return;
|
||||
|
||||
if (!wdev->nan_started)
|
||||
return;
|
||||
|
||||
rdev_stop_nan(rdev, wdev);
|
||||
wdev->nan_started = false;
|
||||
|
||||
rdev->opencount--;
|
||||
}
|
||||
|
||||
void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
|
@ -242,6 +259,9 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
|
|||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
cfg80211_stop_p2p_device(rdev, wdev);
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
cfg80211_stop_nan(rdev, wdev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -537,6 +557,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
|
|||
c->limits[j].max > 1))
|
||||
return -EINVAL;
|
||||
|
||||
/* Only a single NAN can be allowed */
|
||||
if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
|
||||
c->limits[j].max > 1))
|
||||
return -EINVAL;
|
||||
|
||||
cnt += c->limits[j].max;
|
||||
/*
|
||||
* Don't advertise an unsupported type
|
||||
|
@ -579,6 +604,11 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
!rdev->ops->tdls_cancel_channel_switch)))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN)) &&
|
||||
(!rdev->ops->start_nan || !rdev->ops->stop_nan ||
|
||||
!rdev->ops->add_nan_func || !rdev->ops->del_nan_func)))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* if a wiphy has unsupported modes for regulatory channel enforcement,
|
||||
* opt-out of enforcement checking
|
||||
|
@ -589,6 +619,7 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_P2P_DEVICE) |
|
||||
BIT(NL80211_IFTYPE_NAN) |
|
||||
BIT(NL80211_IFTYPE_AP_VLAN) |
|
||||
BIT(NL80211_IFTYPE_MONITOR)))
|
||||
wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
|
||||
|
@ -916,6 +947,9 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
|
|||
cfg80211_mlme_purge_registrations(wdev);
|
||||
cfg80211_stop_p2p_device(rdev, wdev);
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
cfg80211_stop_nan(rdev, wdev);
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
|
@ -979,6 +1013,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
|
|||
/* must be handled by mac80211/driver, has no APIs */
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
/* cannot happen, has no netdev */
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
|
|
|
@ -249,8 +249,8 @@ struct cfg80211_event {
|
|||
};
|
||||
|
||||
struct cfg80211_cached_keys {
|
||||
struct key_params params[4];
|
||||
u8 data[4][WLAN_KEY_LEN_WEP104];
|
||||
struct key_params params[CFG80211_MAX_WEP_KEYS];
|
||||
u8 data[CFG80211_MAX_WEP_KEYS][WLAN_KEY_LEN_WEP104];
|
||||
int def;
|
||||
};
|
||||
|
||||
|
@ -488,6 +488,9 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
|
|||
void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
|
||||
void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
|
||||
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
|
||||
|
|
|
@ -43,6 +43,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
|
|||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
wdev->current_bss = bss_from_pub(bss);
|
||||
|
||||
if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
|
||||
cfg80211_upload_connect_keys(wdev);
|
||||
|
||||
nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid,
|
||||
|
@ -296,7 +297,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
|
|||
ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
|
||||
if (!ck)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < 4; i++)
|
||||
for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
|
||||
ck->params[i].key = ck->data[i];
|
||||
}
|
||||
err = __cfg80211_join_ibss(rdev, wdev->netdev,
|
||||
|
|
|
@ -634,6 +634,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
|||
* fall through, P2P device only supports
|
||||
* public action frames
|
||||
*/
|
||||
case NL80211_IFTYPE_NAN:
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -887,6 +887,64 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev,
|
|||
trace_rdev_return_void(&rdev->wiphy);
|
||||
}
|
||||
|
||||
static inline int rdev_start_nan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_rdev_start_nan(&rdev->wiphy, wdev, conf);
|
||||
ret = rdev->ops->start_nan(&rdev->wiphy, wdev, conf);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void rdev_stop_nan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
trace_rdev_stop_nan(&rdev->wiphy, wdev);
|
||||
rdev->ops->stop_nan(&rdev->wiphy, wdev);
|
||||
trace_rdev_return_void(&rdev->wiphy);
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_add_nan_func(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_func *nan_func)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_rdev_add_nan_func(&rdev->wiphy, wdev, nan_func);
|
||||
ret = rdev->ops->add_nan_func(&rdev->wiphy, wdev, nan_func);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void rdev_del_nan_func(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, u64 cookie)
|
||||
{
|
||||
trace_rdev_del_nan_func(&rdev->wiphy, wdev, cookie);
|
||||
rdev->ops->del_nan_func(&rdev->wiphy, wdev, cookie);
|
||||
trace_rdev_return_void(&rdev->wiphy);
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_nan_change_conf(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf, u32 changes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_rdev_nan_change_conf(&rdev->wiphy, wdev, conf, changes);
|
||||
if (rdev->ops->nan_change_conf)
|
||||
ret = rdev->ops->nan_change_conf(&rdev->wiphy, wdev, conf,
|
||||
changes);
|
||||
else
|
||||
ret = -ENOTSUPP;
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_acl_data *params)
|
||||
|
|
|
@ -726,6 +726,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
|
||||
wdev->current_bss = bss_from_pub(bss);
|
||||
|
||||
if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
|
||||
cfg80211_upload_connect_keys(wdev);
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -1043,6 +1044,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
|||
connect->crypto.ciphers_pairwise[0] = cipher;
|
||||
}
|
||||
}
|
||||
|
||||
connect->crypto.wep_keys = connkeys->params;
|
||||
connect->crypto.wep_tx_key = connkeys->def;
|
||||
} else {
|
||||
if (WARN_ON(connkeys))
|
||||
return -EINVAL;
|
||||
|
|
|
@ -1889,6 +1889,96 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device,
|
|||
TP_ARGS(wiphy, wdev)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_start_nan,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf),
|
||||
TP_ARGS(wiphy, wdev, conf),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u8, master_pref)
|
||||
__field(u8, dual);
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->master_pref = conf->master_pref;
|
||||
__entry->dual = conf->dual;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT
|
||||
", master preference: %u, dual: %d",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->master_pref,
|
||||
__entry->dual)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_nan_change_conf,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_nan_conf *conf, u32 changes),
|
||||
TP_ARGS(wiphy, wdev, conf, changes),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u8, master_pref)
|
||||
__field(u8, dual);
|
||||
__field(u32, changes);
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->master_pref = conf->master_pref;
|
||||
__entry->dual = conf->dual;
|
||||
__entry->changes = changes;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT
|
||||
", master preference: %u, dual: %d, changes: %x",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->master_pref,
|
||||
__entry->dual, __entry->changes)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_nan,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
|
||||
TP_ARGS(wiphy, wdev)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_add_nan_func,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
const struct cfg80211_nan_func *func),
|
||||
TP_ARGS(wiphy, wdev, func),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u8, func_type)
|
||||
__field(u64, cookie)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->func_type = func->type;
|
||||
__entry->cookie = func->cookie
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type=%u, cookie=%llu",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->func_type,
|
||||
__entry->cookie)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_del_nan_func,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
u64 cookie),
|
||||
TP_ARGS(wiphy, wdev, cookie),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u64, cookie)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->cookie = cookie;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie=%llu",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_mac_acl,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_acl_data *params),
|
||||
|
|
|
@ -912,7 +912,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
|
|||
if (!wdev->connect_keys)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) {
|
||||
if (!wdev->connect_keys->params[i].cipher)
|
||||
continue;
|
||||
if (rdev_add_key(rdev, dev, i, false, NULL,
|
||||
|
@ -1008,8 +1008,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
if (otype == NL80211_IFTYPE_AP_VLAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* cannot change into P2P device type */
|
||||
if (ntype == NL80211_IFTYPE_P2P_DEVICE)
|
||||
/* cannot change into P2P device or NAN */
|
||||
if (ntype == NL80211_IFTYPE_P2P_DEVICE ||
|
||||
ntype == NL80211_IFTYPE_NAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!rdev->ops->change_virtual_intf ||
|
||||
|
@ -1088,6 +1089,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
/* not happening */
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
case NL80211_IFTYPE_NAN:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
@ -1760,6 +1762,28 @@ int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr,
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_get_station);
|
||||
|
||||
void cfg80211_free_nan_func(struct cfg80211_nan_func *f)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
kfree(f->serv_spec_info);
|
||||
kfree(f->srf_bf);
|
||||
kfree(f->srf_macs);
|
||||
for (i = 0; i < f->num_rx_filters; i++)
|
||||
kfree(f->rx_filters[i].filter);
|
||||
|
||||
for (i = 0; i < f->num_tx_filters; i++)
|
||||
kfree(f->tx_filters[i].filter);
|
||||
|
||||
kfree(f->rx_filters);
|
||||
kfree(f->tx_filters);
|
||||
kfree(f);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_free_nan_func);
|
||||
|
||||
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||
const unsigned char rfc1042_header[] __aligned(2) =
|
||||
|
|
|
@ -406,12 +406,16 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
|
|||
if (pairwise && !addr)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* In many cases we won't actually need this, but it's better
|
||||
* to do it first in case the allocation fails. Don't use wext.
|
||||
*/
|
||||
if (!wdev->wext.keys) {
|
||||
wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
|
||||
GFP_KERNEL);
|
||||
if (!wdev->wext.keys)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < 4; i++)
|
||||
for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
|
||||
wdev->wext.keys->params[i].key =
|
||||
wdev->wext.keys->data[i];
|
||||
}
|
||||
|
@ -493,7 +497,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (!addr) {
|
||||
/*
|
||||
* We only need to store WEP keys, since they're the only keys that
|
||||
* can be be set before a connection is established and persist after
|
||||
* disconnecting.
|
||||
*/
|
||||
if (!addr && (params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
||||
params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
|
||||
wdev->wext.keys->params[idx] = *params;
|
||||
memcpy(wdev->wext.keys->data[idx],
|
||||
params->key, params->key_len);
|
||||
|
|
|
@ -46,7 +46,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
|
|||
ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
|
||||
if (!ck)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < 4; i++)
|
||||
for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
|
||||
ck->params[i].key = ck->data[i];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue