Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

This commit is contained in:
John W. Linville 2012-10-19 15:36:53 -04:00
commit 3cd17638fd
60 changed files with 5363 additions and 992 deletions

View File

@ -452,7 +452,7 @@ static size_t gelic_wl_synthesize_ie(u8 *buf,
if (rsn)
*buf++ = WLAN_EID_RSN;
else
*buf++ = WLAN_EID_GENERIC;
*buf++ = WLAN_EID_VENDOR_SPECIFIC;
/* length filed; set later */
buf++;
@ -540,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
break;
switch (item_id) {
case WLAN_EID_GENERIC:
case WLAN_EID_VENDOR_SPECIFIC:
if ((OUI_LEN + 1 <= item_len) &&
!memcmp(pos, wpa_oui, OUI_LEN) &&
pos[OUI_LEN] == 0x01) {

View File

@ -7433,7 +7433,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
num_null_ies++;
break;
case WLAN_EID_GENERIC:
case WLAN_EID_VENDOR_SPECIFIC:
if (ie[1] >= 4 &&
ie[2] == 0x00 &&
ie[3] == 0x50 &&

View File

@ -301,7 +301,7 @@ static bool ath6kl_cfg80211_ready(struct ath6kl_vif *vif)
static bool ath6kl_is_wpa_ie(const u8 *pos)
{
return pos[0] == WLAN_EID_WPA && pos[1] >= 4 &&
return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
pos[2] == 0x00 && pos[3] == 0x50 &&
pos[4] == 0xf2 && pos[5] == 0x01;
}
@ -3651,7 +3651,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
ar->fw_capabilities))
ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER;
ar->wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
ar->wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |

View File

@ -2679,7 +2679,7 @@ brcmf_find_wpaie(u8 *parse, u32 len)
{
struct brcmf_tlv *ie;
while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_WPA))) {
while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
return (struct brcmf_vs_tlv *)ie;

View File

@ -415,7 +415,7 @@ static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb,
ssid = pos + 2;
ssid_len = pos[1];
break;
case WLAN_EID_GENERIC:
case WLAN_EID_VENDOR_SPECIFIC:
if (pos[1] >= 4 &&
pos[2] == 0x00 && pos[3] == 0x50 &&
pos[4] == 0xf2 && pos[5] == 1) {

View File

@ -1108,7 +1108,7 @@ static const char *get_info_element_string(u16 id)
MFIE_STRING(ERP_INFO);
MFIE_STRING(RSN);
MFIE_STRING(EXT_SUPP_RATES);
MFIE_STRING(GENERIC);
MFIE_STRING(VENDOR_SPECIFIC);
MFIE_STRING(QOS_PARAMETER);
default:
return "UNKNOWN";
@ -1248,8 +1248,8 @@ static int libipw_parse_info_param(struct libipw_info_element
LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
break;
case WLAN_EID_GENERIC:
LIBIPW_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n",
case WLAN_EID_VENDOR_SPECIFIC:
LIBIPW_DEBUG_MGMT("WLAN_EID_VENDOR_SPECIFIC: %d bytes\n",
info_element->len);
if (!libipw_parse_qos_info_param_IE(info_element,
network))

View File

@ -101,7 +101,7 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
switch (action) {
case CMD_ACT_MESH_CONFIG_START:
ie->id = WLAN_EID_GENERIC;
ie->id = WLAN_EID_VENDOR_SPECIFIC;
ie->val.oui[0] = 0x00;
ie->val.oui[1] = 0x50;
ie->val.oui[2] = 0x43;

View File

@ -2250,8 +2250,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;
wiphy->features = NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_INACTIVITY_TIMER;
wiphy->features |= NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_INACTIVITY_TIMER;
/* Reserve space for mwifiex specific private data for BSS */
wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);

View File

@ -153,7 +153,7 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
if (((bss_desc->bcn_wpa_ie) &&
((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id ==
WLAN_EID_WPA))) {
WLAN_EID_VENDOR_SPECIFIC))) {
iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
oui = &mwifiex_wpa_oui[cipher][0];
ret = mwifiex_search_oui_in_ie(iebody, oui);
@ -202,7 +202,7 @@ mwifiex_is_bss_no_sec(struct mwifiex_private *priv,
if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
!priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
WLAN_EID_WPA)) &&
WLAN_EID_VENDOR_SPECIFIC)) &&
((!bss_desc->bcn_rsn_ie) ||
((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
WLAN_EID_RSN)) &&
@ -237,7 +237,8 @@ mwifiex_is_bss_wpa(struct mwifiex_private *priv,
{
if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled &&
!priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) &&
((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == WLAN_EID_WPA))
((*(bss_desc->bcn_wpa_ie)).
vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC))
/*
* Privacy bit may NOT be set in some APs like
* LinkSys WRT54G && bss_desc->privacy
@ -309,7 +310,8 @@ mwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv,
if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
!priv->sec_info.wpa2_enabled &&
((!bss_desc->bcn_wpa_ie) ||
((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) &&
((*(bss_desc->bcn_wpa_ie)).
vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) &&
((!bss_desc->bcn_rsn_ie) ||
((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
!priv->sec_info.encryption_mode && bss_desc->privacy) {
@ -329,7 +331,8 @@ mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv,
if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
!priv->sec_info.wpa2_enabled &&
((!bss_desc->bcn_wpa_ie) ||
((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != WLAN_EID_WPA)) &&
((*(bss_desc->bcn_wpa_ie)).
vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) &&
((!bss_desc->bcn_rsn_ie) ||
((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
priv->sec_info.encryption_mode && bss_desc->privacy) {

View File

@ -713,7 +713,7 @@ static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
priv->wpa_ie_len, priv->wpa_ie[0]);
if (priv->wpa_ie[0] == WLAN_EID_WPA) {
if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {
priv->sec_info.wpa_enabled = true;
} else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
priv->sec_info.wpa2_enabled = true;
@ -1253,7 +1253,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
}
pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
/* Test to see if it is a WPA IE, if not, then it is a gen IE */
if (((pvendor_ie->element_id == WLAN_EID_WPA) &&
if (((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) &&
(!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) ||
(pvendor_ie->element_id == WLAN_EID_RSN)) {

View File

@ -39,7 +39,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
{
u8 *p = data;
while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
if ((p[0] == WLAN_EID_GENERIC) &&
if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) &&
(memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
return p;
p += p[1] + 2;

View File

@ -1107,20 +1107,6 @@ struct ieee80211_ht_operation {
#define WLAN_HT_SMPS_CONTROL_STATIC 1
#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3
#define VHT_MCS_SUPPORTED_SET_SIZE 8
struct ieee80211_vht_capabilities {
__le32 vht_capabilities_info;
u8 vht_supported_mcs_set[VHT_MCS_SUPPORTED_SET_SIZE];
} __packed;
struct ieee80211_vht_operation {
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg1_idx;
u8 vht_op_info_chan_center_freq_seg2_idx;
__le16 vht_basic_mcs_set;
} __packed;
/**
* struct ieee80211_vht_mcs_info - VHT MCS information
* @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams
@ -1141,6 +1127,37 @@ struct ieee80211_vht_mcs_info {
__le16 tx_highest;
} __packed;
/**
* struct ieee80211_vht_cap - VHT capabilities
*
* This structure is the "VHT capabilities element" as
* described in 802.11ac D3.0 8.4.2.160
* @vht_cap_info: VHT capability info
* @supp_mcs: VHT MCS supported rates
*/
struct ieee80211_vht_cap {
__le32 vht_cap_info;
struct ieee80211_vht_mcs_info supp_mcs;
} __packed;
/**
* struct ieee80211_vht_operation - VHT operation IE
*
* This structure is the "VHT operation element" as
* described in 802.11ac D3.0 8.4.2.161
* @chan_width: Operating channel width
* @center_freq_seg1_idx: center freq segment 1 index
* @center_freq_seg2_idx: center freq segment 2 index
* @basic_mcs_set: VHT Basic MCS rate set
*/
struct ieee80211_vht_operation {
u8 chan_width;
u8 center_freq_seg1_idx;
u8 center_freq_seg2_idx;
__le16 basic_mcs_set;
} __packed;
#define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0
#define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1
#define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2
@ -1440,8 +1457,6 @@ enum ieee80211_eid {
WLAN_EID_RSN = 48,
WLAN_EID_MMIE = 76,
WLAN_EID_WPA = 221,
WLAN_EID_GENERIC = 221,
WLAN_EID_VENDOR_SPECIFIC = 221,
WLAN_EID_QOS_PARAMETER = 222,

View File

@ -498,6 +498,7 @@ enum station_parameters_apply_mask {
* @plink_action: plink action to take
* @plink_state: set the peer link state for a station
* @ht_capa: HT capabilities of station
* @vht_capa: VHT capabilities of station
* @uapsd_queues: bitmap of queues configured for uapsd. same format
* as the AC bitmap in the QoS info field
* @max_sp: max Service Period. same format as the MAX_SP in the
@ -517,6 +518,7 @@ struct station_parameters {
u8 plink_action;
u8 plink_state;
struct ieee80211_ht_cap *ht_capa;
struct ieee80211_vht_cap *vht_capa;
u8 uapsd_queues;
u8 max_sp;
};
@ -1000,8 +1002,10 @@ struct cfg80211_ssid {
* @n_channels: total number of channels to scan
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
* @flags: bit field of flags controlling operation
* @rates: bitmap of rates to advertise for each band
* @wiphy: the wiphy this was for
* @scan_start: time (in jiffies) when the scan started
* @wdev: the wireless device to scan for
* @aborted: (internal) scan request was notified as aborted
* @no_cck: used to send probe requests at non CCK rate in 2GHz band
@ -1012,6 +1016,7 @@ struct cfg80211_scan_request {
u32 n_channels;
const u8 *ie;
size_t ie_len;
u32 flags;
u32 rates[IEEE80211_NUM_BANDS];
@ -1019,6 +1024,7 @@ struct cfg80211_scan_request {
/* internal */
struct wiphy *wiphy;
unsigned long scan_start;
bool aborted;
bool no_cck;
@ -1044,6 +1050,7 @@ struct cfg80211_match_set {
* @interval: interval between each scheduled scan cycle
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
* @flags: bit field of flags controlling operation
* @match_sets: sets of parameters to be matched for a scan result
* entry to be considered valid and to be passed to the host
* (others are filtered out).
@ -1061,6 +1068,7 @@ struct cfg80211_sched_scan_request {
u32 interval;
const u8 *ie;
size_t ie_len;
u32 flags;
struct cfg80211_match_set *match_sets;
int n_match_sets;
s32 rssi_thold;
@ -1068,6 +1076,7 @@ struct cfg80211_sched_scan_request {
/* internal */
struct wiphy *wiphy;
struct net_device *dev;
unsigned long scan_start;
/* keep last */
struct ieee80211_channel *channels[0];
@ -1152,6 +1161,9 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication
* @sae_data: Non-IE data to use with SAE or %NULL. This starts with
* Authentication transaction sequence number field.
* @sae_data_len: Length of sae_data buffer in octets
*/
struct cfg80211_auth_request {
struct cfg80211_bss *bss;
@ -1160,6 +1172,8 @@ struct cfg80211_auth_request {
enum nl80211_auth_type auth_type;
const u8 *key;
u8 key_len, key_idx;
const u8 *sae_data;
size_t sae_data_len;
};
/**

View File

@ -143,6 +143,41 @@ struct ieee80211_low_level_stats {
unsigned int dot11RTSSuccessCount;
};
/**
* enum ieee80211_chanctx_change - change flag for channel context
* @IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE: The channel type was changed
* @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed
*/
enum ieee80211_chanctx_change {
IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE = BIT(0),
IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1),
};
/**
* struct ieee80211_chanctx_conf - channel context that vifs may be tuned to
*
* This is the driver-visible part. The ieee80211_chanctx
* that contains it is visible in mac80211 only.
*
* @channel: the channel to tune to
* @channel_type: the channel (HT) type
* @rx_chains_static: The number of RX chains that must always be
* active on the channel to receive MIMO transmissions
* @rx_chains_dynamic: The number of RX chains that must be enabled
* after RTS/CTS handshake to receive SMPS MIMO transmissions;
* this will always be >= @rx_chains_always.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information.
*/
struct ieee80211_chanctx_conf {
struct ieee80211_channel *channel;
enum nl80211_channel_type channel_type;
u8 rx_chains_static, rx_chains_dynamic;
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
/**
* enum ieee80211_bss_change - BSS change notification flags
*
@ -223,6 +258,7 @@ enum ieee80211_rssi_event {
* @assoc: association status
* @ibss_joined: indicates whether this station is part of an IBSS
* or not
* @ibss_creator: indicates if a new IBSS network is being created
* @aid: association ID number, valid only when @assoc is true
* @use_cts_prot: use CTS protection
* @use_short_preamble: use 802.11b short preamble;
@ -278,6 +314,7 @@ struct ieee80211_bss_conf {
const u8 *bssid;
/* association related data */
bool assoc, ibss_joined;
bool ibss_creator;
u16 aid;
/* erp related data */
bool use_cts_prot;
@ -794,6 +831,8 @@ enum ieee80211_conf_flags {
* @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
* @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
* @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
* Note that this is only valid if channel contexts are not used,
* otherwise each channel context has the number of chains listed.
*/
enum ieee80211_conf_changed {
IEEE80211_CONF_CHANGE_SMPS = BIT(1),
@ -859,7 +898,9 @@ enum ieee80211_smps_mode {
*
* @smps_mode: spatial multiplexing powersave mode; note that
* %IEEE80211_SMPS_STATIC is used when the device is not
* configured for an HT channel
* configured for an HT channel.
* Note that this is only valid if channel contexts are not used,
* otherwise each channel context has the number of chains listed.
*/
struct ieee80211_conf {
u32 flags;
@ -931,6 +972,11 @@ enum ieee80211_vif_flags {
* at runtime, mac80211 will never touch this field
* @hw_queue: hardware queue for each AC
* @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
* @chanctx_conf: The channel context this interface is assigned to, or %NULL
* when it is not assigned. This pointer is RCU-protected due to the TX
* path needing to access it; even though the netdev carrier will always
* be off when it is %NULL there can still be races and packets could be
* processed after it switches back to %NULL.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
*/
@ -943,6 +989,8 @@ struct ieee80211_vif {
u8 cab_queue;
u8 hw_queue[IEEE80211_NUM_ACS];
struct ieee80211_chanctx_conf __rcu *chanctx_conf;
u32 driver_flags;
/* must be last */
@ -1076,6 +1124,8 @@ enum ieee80211_sta_state {
* @aid: AID we assigned to the station if we're an AP
* @supp_rates: Bitmap of supported rates (per band)
* @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
* @vht_cap: VHT capabilities of this STA; Not restricting any capabilities
* of remote STA. Taking as is.
* @wme: indicates whether the STA supports WME. Only valid during AP-mode.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information.
@ -1088,6 +1138,7 @@ struct ieee80211_sta {
u8 addr[ETH_ALEN];
u16 aid;
struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap;
bool wme;
u8 uapsd_queues;
u8 max_sp;
@ -1325,6 +1376,8 @@ enum ieee80211_hw_flags {
* within &struct ieee80211_vif.
* @sta_data_size: size (in bytes) of the drv_priv data area
* within &struct ieee80211_sta.
* @chanctx_data_size: size (in bytes) of the drv_priv data area
* within &struct ieee80211_chanctx_conf.
*
* @max_rates: maximum number of alternate rate retry stages the hw
* can handle.
@ -1369,6 +1422,7 @@ struct ieee80211_hw {
int channel_change_time;
int vif_data_size;
int sta_data_size;
int chanctx_data_size;
int napi_weight;
u16 queues;
u16 max_listen_interval;
@ -2317,6 +2371,16 @@ enum ieee80211_rate_control_changed {
* The callback will be called before each transmission and upon return
* mac80211 will transmit the frame right away.
* The callback is optional and can (should!) sleep.
*
* @add_chanctx: Notifies device driver about new channel context creation.
* @remove_chanctx: Notifies device driver about channel context destruction.
* @change_chanctx: Notifies device driver about channel context changes that
* may happen when combining different virtual interfaces on the same
* channel context with different settings
* @assign_vif_chanctx: Notifies device driver about channel context being bound
* to vif. Possible use is for hw queue remapping.
* @unassign_vif_chanctx: Notifies device driver about channel context being
* unbound from vif.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@ -2461,6 +2525,20 @@ struct ieee80211_ops {
void (*mgd_prepare_tx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int (*add_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void (*remove_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void (*change_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
u32 changed);
int (*assign_vif_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf *ctx);
void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf *ctx);
};
/**
@ -3523,6 +3601,27 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
void *data),
void *iter_data);
/**
* ieee80211_iter_chan_contexts_atomic - iterate channel contexts
* @hw: pointre obtained from ieee80211_alloc_hw().
* @iter: iterator function
* @iter_data: data passed to iterator function
*
* Iterate all active channel contexts. This function is atomic and
* doesn't acquire any locks internally that might be held in other
* places while calling into the driver.
*
* The iterator will not find a context that's being added (during
* the driver callback to add it) but will find it while it's being
* removed.
*/
void ieee80211_iter_chan_contexts_atomic(
struct ieee80211_hw *hw,
void (*iter)(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *chanctx_conf,
void *data),
void *iter_data);
/**
* ieee80211_ap_probereq_get - retrieve a Probe Request template
* @hw: pointer obtained from ieee80211_alloc_hw().

View File

@ -1273,6 +1273,14 @@ enum nl80211_commands {
* the connection request from a station. nl80211_connect_failed_reason
* enum has different reasons of connection failure.
*
* @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
* with the Authentication transaction sequence number field.
*
* @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
* association request when used with NL80211_CMD_NEW_STATION)
*
* @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32)
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@ -1530,6 +1538,12 @@ enum nl80211_attrs {
NL80211_ATTR_CONN_FAILED_REASON,
NL80211_ATTR_SAE_DATA,
NL80211_ATTR_VHT_CAPABILITY,
NL80211_ATTR_SCAN_FLAGS,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -1573,6 +1587,7 @@ enum nl80211_attrs {
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
#define NL80211_VHT_CAPABILITY_LEN 12
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@ -2489,6 +2504,7 @@ enum nl80211_bss_status {
* @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
* @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
* @__NL80211_AUTHTYPE_NUM: internal
* @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
* @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@ -2500,6 +2516,7 @@ enum nl80211_auth_type {
NL80211_AUTHTYPE_SHARED_KEY,
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
NL80211_AUTHTYPE_SAE,
/* keep last */
__NL80211_AUTHTYPE_NUM,
@ -3028,6 +3045,12 @@ enum nl80211_ap_sme_features {
* in the interface combinations, even when it's only used for scan
* and remain-on-channel. This could be due to, for example, the
* remain-on-channel implementation requiring a channel context.
* @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
* equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
* mode
* @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
* @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
* @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@ -3035,6 +3058,10 @@ enum nl80211_feature_flags {
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4,
NL80211_FEATURE_SAE = 1 << 5,
NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6,
NL80211_FEATURE_SCAN_FLUSH = 1 << 7,
NL80211_FEATURE_AP_SCAN = 1 << 8,
};
/**
@ -3069,4 +3096,25 @@ enum nl80211_connect_failed_reason {
NL80211_CONN_FAIL_BLOCKED_CLIENT,
};
/**
* enum nl80211_scan_flags - scan request control flags
*
* Scan request control flags are used to control the handling
* of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
* requests.
*
* @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
* @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
* @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
* as AP and the beaconing has already been configured. This attribute is
* dangerous because will destroy stations performance as a lot of frames
* will be lost while scanning off-channel, therefore it must be used only
* when really needed
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
NL80211_SCAN_FLAG_FLUSH = 1<<1,
NL80211_SCAN_FLAG_AP = 1<<2,
};
#endif /* __LINUX_NL80211_H */

View File

@ -248,7 +248,7 @@ config MAC80211_MHWMP_DEBUG
Do not select this option.
config MAC80211_MESH_SYNC_DEBUG
bool "Verbose mesh mesh synchronization debugging"
bool "Verbose mesh synchronization debugging"
depends on MAC80211_DEBUG_MENU
depends on MAC80211_MESH
---help---

View File

@ -8,6 +8,7 @@ mac80211-y := \
wpa.o \
scan.o offchannel.o \
ht.o agg-tx.o agg-rx.o \
vht.o \
ibss.o \
iface.o \
rate.o \

View File

@ -372,10 +372,11 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
{
enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);
if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
struct ieee80211_supported_band *sband;
sband = sta->local->hw.wiphy->bands[
sta->local->oper_channel->band];
sband = sta->local->hw.wiphy->bands[band];
rate->legacy = sband->bitrates[idx].bitrate;
} else
rate->mcs = idx;
@ -532,6 +533,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
u64 *data)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel;
struct sta_info *sta;
struct ieee80211_local *local = sdata->local;
struct station_info sinfo;
@ -607,19 +610,26 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
do_survey:
i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
/* Get survey stats for current channel */
q = 0;
while (true) {
survey.filled = 0;
if (drv_get_survey(local, q, &survey) != 0) {
survey.filled = 0;
break;
}
survey.filled = 0;
if (survey.channel &&
(local->oper_channel->center_freq ==
survey.channel->center_freq))
break;
q++;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf)
channel = chanctx_conf->channel;
else
channel = NULL;
rcu_read_unlock();
if (channel) {
q = 0;
do {
survey.filled = 0;
if (drv_get_survey(local, q, &survey) != 0) {
survey.filled = 0;
break;
}
q++;
} while (channel != survey.channel);
}
if (survey.filled)
@ -724,47 +734,42 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
static int ieee80211_set_channel(struct wiphy *wiphy,
struct net_device *netdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = NULL;
if (netdev)
sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
switch (ieee80211_get_channel_mode(local, NULL)) {
case CHAN_MODE_HOPPING:
return -EBUSY;
case CHAN_MODE_FIXED:
if (local->oper_channel != chan ||
(!sdata && local->_oper_channel_type != channel_type))
return -EBUSY;
if (!sdata && local->_oper_channel_type == channel_type)
return 0;
break;
case CHAN_MODE_UNDEFINED:
break;
}
if (!ieee80211_set_channel_type(local, sdata, channel_type))
return -EBUSY;
local->oper_channel = chan;
/* auto-detects changes */
ieee80211_hw_config(local, 0);
return 0;
}
static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata;
int ret = 0;
if (local->monitor_channel == chan &&
local->monitor_channel_type == channel_type)
return 0;
mutex_lock(&local->iflist_mtx);
if (local->use_chanctx) {
sdata = rcu_dereference_protected(
local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
if (sdata) {
ieee80211_vif_release_channel(sdata);
ret = ieee80211_vif_use_channel(
sdata, chan, channel_type,
IEEE80211_CHANCTX_EXCLUSIVE);
}
} else if (local->open_count == local->monitors) {
local->_oper_channel = chan;
local->_oper_channel_type = channel_type;
ieee80211_hw_config(local, 0);
}
if (ret == 0) {
local->monitor_channel = chan;
local->monitor_channel_type = channel_type;
}
mutex_unlock(&local->iflist_mtx);
return ret;
}
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
@ -879,8 +884,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (old)
return -EALREADY;
err = ieee80211_set_channel(wiphy, dev, params->channel,
params->channel_type);
/* TODO: make hostapd tell us what it wants */
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;
err = ieee80211_vif_use_channel(sdata, params->channel,
params->channel_type,
IEEE80211_CHANCTX_SHARED);
if (err)
return err;
@ -963,6 +973,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
sta_info_flush(sdata->local, sdata);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
ieee80211_vif_release_channel(sdata);
return 0;
}
@ -1019,9 +1031,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
int i, j;
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
u32 mask, set;
sband = local->hw.wiphy->bands[local->oper_channel->band];
sband = local->hw.wiphy->bands[band];
mask = params->sta_flags_mask;
set = params->sta_flags_set;
@ -1136,7 +1149,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
rates |= BIT(j);
}
}
sta->sta.supp_rates[local->oper_channel->band] = rates;
sta->sta.supp_rates[band] = rates;
}
if (params->ht_capa)
@ -1144,6 +1157,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
params->ht_capa,
&sta->sta.ht_cap);
if (params->vht_capa)
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
params->vht_capa,
&sta->sta.vht_cap);
if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
@ -1664,8 +1682,13 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
if (err)
return err;
err = ieee80211_set_channel(wiphy, dev, setup->channel,
setup->channel_type);
/* can mesh use other SMPS modes? */
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;
err = ieee80211_vif_use_channel(sdata, setup->channel,
setup->channel_type,
IEEE80211_CHANCTX_SHARED);
if (err)
return err;
@ -1679,6 +1702,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_stop_mesh(sdata);
ieee80211_vif_release_channel(sdata);
return 0;
}
@ -1688,10 +1712,14 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
struct net_device *dev,
struct bss_parameters *params)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
enum ieee80211_band band;
u32 changed = 0;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (!rtnl_dereference(sdata->u.ap.beacon))
return -ENOENT;
band = ieee80211_get_sdata_band(sdata);
if (params->use_cts_prot >= 0) {
sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
@ -1704,7 +1732,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
}
if (!sdata->vif.bss_conf.use_short_slot &&
sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) {
band == IEEE80211_BAND_5GHZ) {
sdata->vif.bss_conf.use_short_slot = true;
changed |= BSS_CHANGED_ERP_SLOT;
}
@ -1718,9 +1746,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
if (params->basic_rates) {
int i, j;
u32 rates = 0;
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_supported_band *sband =
wiphy->bands[local->oper_channel->band];
struct ieee80211_supported_band *sband = wiphy->bands[band];
for (i = 0; i < params->basic_rates_len; i++) {
int rate = (params->basic_rates[i] & 0x7f) * 5;
@ -1829,7 +1855,16 @@ static int ieee80211_scan(struct wiphy *wiphy,
* beaconing hasn't been configured yet
*/
case NL80211_IFTYPE_AP:
if (sdata->u.ap.beacon)
/*
* If the scan has been forced (and the driver supports
* forcing), don't care about being beaconing already.
* This will create problems to the attached stations (e.g. all
* the frames sent while scanning on other channel will be
* lost)
*/
if (sdata->u.ap.beacon &&
(!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
!(req->flags & NL80211_SCAN_FLAG_AP)))
return -EOPNOTSUPP;
break;
default:
@ -1872,20 +1907,6 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_assoc_request *req)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (ieee80211_get_channel_mode(local, sdata)) {
case CHAN_MODE_HOPPING:
return -EBUSY;
case CHAN_MODE_FIXED:
if (local->oper_channel == req->bss->channel)
break;
return -EBUSY;
case CHAN_MODE_UNDEFINED:
break;
}
return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
}
@ -1904,30 +1925,12 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (ieee80211_get_channel_mode(local, sdata)) {
case CHAN_MODE_HOPPING:
return -EBUSY;
case CHAN_MODE_FIXED:
if (!params->channel_fixed)
return -EBUSY;
if (local->oper_channel == params->channel)
break;
return -EBUSY;
case CHAN_MODE_UNDEFINED:
break;
}
return ieee80211_ibss_join(sdata, params);
return ieee80211_ibss_join(IEEE80211_DEV_TO_SUB_IF(dev), params);
}
static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
return ieee80211_ibss_leave(sdata);
return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
}
static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
@ -1971,9 +1974,13 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type, int mbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_channel *chan = local->oper_channel;
struct ieee80211_channel *chan = local->_oper_channel;
u32 changes = 0;
/* FIXME */
if (local->use_chanctx)
return -EOPNOTSUPP;
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
local->user_power_level = -1;
@ -2067,13 +2074,12 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
/*
* If not associated, or current association is not an HT
* association, there's no need to send an action frame.
* association, there's no need to do anything, just store
* the new value until we associate.
*/
if (!sdata->u.mgd.associated ||
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
ieee80211_recalc_smps(sdata->local);
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
return 0;
}
ap = sdata->u.mgd.associated->bssid;
@ -2189,6 +2195,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
lockdep_assert_held(&local->mtx);
if (local->use_chanctx && !local->ops->remain_on_channel)
return -EOPNOTSUPP;
roc = kzalloc(sizeof(*roc), GFP_KERNEL);
if (!roc)
return -ENOMEM;
@ -2515,10 +2524,20 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
/* Check if the operating channel is the requested channel */
if (!need_offchan) {
need_offchan = chan != local->oper_channel;
if (channel_type_valid &&
channel_type != local->_oper_channel_type)
struct ieee80211_chanctx_conf *chanctx_conf;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
need_offchan = chan != chanctx_conf->channel;
if (channel_type_valid &&
channel_type != chanctx_conf->channel_type)
need_offchan = true;
} else {
need_offchan = true;
}
rcu_read_unlock();
}
if (need_offchan && !offchan) {
@ -2667,7 +2686,7 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
u16 capab;
capab = 0;
if (local->oper_channel->band != IEEE80211_BAND_2GHZ)
if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
return capab;
if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
@ -2699,7 +2718,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_tdls_data *tf;
tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
@ -2719,10 +2738,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
tf->u.setup_req.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
ieee80211_add_srates_ie(sdata, skb, false,
local->oper_channel->band);
ieee80211_add_ext_srates_ie(sdata, skb, false,
local->oper_channel->band);
ieee80211_add_srates_ie(sdata, skb, false, band);
ieee80211_add_ext_srates_ie(sdata, skb, false, band);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_RESPONSE:
@ -2735,10 +2752,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
tf->u.setup_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
ieee80211_add_srates_ie(sdata, skb, false,
local->oper_channel->band);
ieee80211_add_ext_srates_ie(sdata, skb, false,
local->oper_channel->band);
ieee80211_add_srates_ie(sdata, skb, false, band);
ieee80211_add_ext_srates_ie(sdata, skb, false, band);
ieee80211_tdls_add_ext_capab(skb);
break;
case WLAN_TDLS_SETUP_CONFIRM:
@ -2776,7 +2791,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_mgmt *mgmt;
mgmt = (void *)skb_put(skb, 24);
@ -2799,10 +2814,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
ieee80211_add_srates_ie(sdata, skb, false,
local->oper_channel->band);
ieee80211_add_ext_srates_ie(sdata, skb, false,
local->oper_channel->band);
ieee80211_add_srates_ie(sdata, skb, false, band);
ieee80211_add_ext_srates_ie(sdata, skb, false, band);
ieee80211_tdls_add_ext_capab(skb);
break;
default:
@ -2819,7 +2832,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info;
struct sk_buff *skb = NULL;
bool send_direct;
int ret;
@ -2845,7 +2857,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
if (!skb)
return -ENOMEM;
info = IEEE80211_SKB_CB(skb);
skb_reserve(skb, local->hw.extra_tx_headroom);
switch (action_code) {
@ -2982,12 +2993,19 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
bool qos;
struct ieee80211_tx_info *info;
struct sta_info *sta;
struct ieee80211_chanctx_conf *chanctx_conf;
enum ieee80211_band band;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return -EINVAL;
}
band = chanctx_conf->channel->band;
sta = sta_info_get(sdata, peer);
if (sta) {
qos = test_sta_flag(sta, WLAN_STA_WME);
rcu_read_unlock();
} else {
rcu_read_unlock();
return -ENOLINK;
@ -3005,8 +3023,10 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
}
skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
if (!skb)
if (!skb) {
rcu_read_unlock();
return -ENOMEM;
}
skb->dev = dev;
@ -3031,8 +3051,9 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
nullfunc->qos_ctrl = cpu_to_le16(7);
local_bh_disable();
ieee80211_xmit(sdata, skb);
ieee80211_xmit(sdata, skb, band);
local_bh_enable();
rcu_read_unlock();
*cookie = (unsigned long) skb;
return 0;
@ -3042,10 +3063,19 @@ static struct ieee80211_channel *
ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
enum nl80211_channel_type *type)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan = NULL;
*type = local->_oper_channel_type;
return local->oper_channel;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
*type = chanctx_conf->channel_type;
chan = chanctx_conf->channel;
}
rcu_read_unlock();
return chan;
}
#ifdef CONFIG_PM

View File

@ -3,108 +3,10 @@
*/
#include <linux/nl80211.h>
#include <linux/export.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
static enum ieee80211_chan_mode
__ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore)
{
struct ieee80211_sub_if_data *sdata;
lockdep_assert_held(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata == ignore)
continue;
if (!ieee80211_sdata_running(sdata))
continue;
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
continue;
case NL80211_IFTYPE_STATION:
if (!sdata->u.mgd.associated)
continue;
break;
case NL80211_IFTYPE_ADHOC:
if (!sdata->u.ibss.ssid_len)
continue;
if (!sdata->u.ibss.fixed_channel)
return CHAN_MODE_HOPPING;
break;
case NL80211_IFTYPE_AP_VLAN:
/* will also have _AP interface */
continue;
case NL80211_IFTYPE_AP:
if (!sdata->u.ap.beacon)
continue;
break;
case NL80211_IFTYPE_MESH_POINT:
if (!sdata->wdev.mesh_id_len)
continue;
break;
default:
break;
}
return CHAN_MODE_FIXED;
}
return CHAN_MODE_UNDEFINED;
}
enum ieee80211_chan_mode
ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore)
{
enum ieee80211_chan_mode mode;
mutex_lock(&local->iflist_mtx);
mode = __ieee80211_get_channel_mode(local, ignore);
mutex_unlock(&local->iflist_mtx);
return mode;
}
static enum nl80211_channel_type
ieee80211_get_superchan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
struct ieee80211_sub_if_data *tmp;
mutex_lock(&local->iflist_mtx);
list_for_each_entry(tmp, &local->interfaces, list) {
if (tmp == sdata)
continue;
if (!ieee80211_sdata_running(tmp))
continue;
switch (tmp->vif.bss_conf.channel_type) {
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
if (superchan > tmp->vif.bss_conf.channel_type)
break;
superchan = tmp->vif.bss_conf.channel_type;
break;
case NL80211_CHAN_HT40PLUS:
WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
superchan = NL80211_CHAN_HT40PLUS;
break;
case NL80211_CHAN_HT40MINUS:
WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
superchan = NL80211_CHAN_HT40MINUS;
break;
}
}
mutex_unlock(&local->iflist_mtx);
return superchan;
}
#include "driver-ops.h"
static bool
ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
@ -148,23 +50,350 @@ ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
return true;
}
bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype)
static void ieee80211_change_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
enum nl80211_channel_type chantype)
{
enum nl80211_channel_type superchan;
enum nl80211_channel_type compatchan;
if (chantype == ctx->conf.channel_type)
return;
superchan = ieee80211_get_superchan(local, sdata);
if (!ieee80211_channel_types_are_compatible(superchan, chantype,
&compatchan))
return false;
local->_oper_channel_type = compatchan;
if (sdata)
sdata->vif.bss_conf.channel_type = chantype;
return true;
ctx->conf.channel_type = chantype;
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE);
if (!local->use_chanctx) {
local->_oper_channel_type = chantype;
ieee80211_hw_config(local, 0);
}
}
static struct ieee80211_chanctx *
ieee80211_find_chanctx(struct ieee80211_local *local,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
enum nl80211_channel_type compat_type;
lockdep_assert_held(&local->chanctx_mtx);
if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
return NULL;
if (WARN_ON(!channel))
return NULL;
list_for_each_entry(ctx, &local->chanctx_list, list) {
compat_type = ctx->conf.channel_type;
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
continue;
if (ctx->conf.channel != channel)
continue;
if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type,
channel_type,
&compat_type))
continue;
ieee80211_change_chantype(local, ctx, compat_type);
return ctx;
}
return NULL;
}
static struct ieee80211_chanctx *
ieee80211_new_chanctx(struct ieee80211_local *local,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
int err;
lockdep_assert_held(&local->chanctx_mtx);
ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
ctx->conf.channel = channel;
ctx->conf.channel_type = channel_type;
ctx->conf.rx_chains_static = 1;
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
if (!local->use_chanctx) {
local->_oper_channel_type = channel_type;
local->_oper_channel = channel;
ieee80211_hw_config(local, 0);
} else {
err = drv_add_chanctx(local, ctx);
if (err) {
kfree(ctx);
return ERR_PTR(err);
}
}
list_add_rcu(&ctx->list, &local->chanctx_list);
return ctx;
}
static void ieee80211_free_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
lockdep_assert_held(&local->chanctx_mtx);
WARN_ON_ONCE(ctx->refcount != 0);
if (!local->use_chanctx) {
local->_oper_channel_type = NL80211_CHAN_NO_HT;
ieee80211_hw_config(local, 0);
} else {
drv_remove_chanctx(local, ctx);
}
list_del_rcu(&ctx->list);
kfree_rcu(ctx, rcu_head);
}
static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_local *local = sdata->local;
int ret;
lockdep_assert_held(&local->chanctx_mtx);
ret = drv_assign_vif_chanctx(local, sdata, ctx);
if (ret)
return ret;
rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
ctx->refcount++;
return 0;
}
static enum nl80211_channel_type
ieee80211_calc_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_chanctx_conf *conf = &ctx->conf;
struct ieee80211_sub_if_data *sdata;
enum nl80211_channel_type result = NL80211_CHAN_NO_HT;
lockdep_assert_held(&local->chanctx_mtx);
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
continue;
WARN_ON_ONCE(!ieee80211_channel_types_are_compatible(
sdata->vif.bss_conf.channel_type,
result, &result));
}
rcu_read_unlock();
return result;
}
static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
enum nl80211_channel_type chantype;
lockdep_assert_held(&local->chanctx_mtx);
chantype = ieee80211_calc_chantype(local, ctx);
ieee80211_change_chantype(local, ctx, chantype);
}
static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
{
struct ieee80211_local *local = sdata->local;
lockdep_assert_held(&local->chanctx_mtx);
ctx->refcount--;
rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
drv_unassign_vif_chanctx(local, sdata, ctx);
if (ctx->refcount > 0) {
ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
}
}
static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
lockdep_assert_held(&local->chanctx_mtx);
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (!conf)
return;
ctx = container_of(conf, struct ieee80211_chanctx, conf);
ieee80211_unassign_vif_chanctx(sdata, ctx);
if (ctx->refcount == 0)
ieee80211_free_chanctx(local, ctx);
}
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx)
{
struct ieee80211_sub_if_data *sdata;
u8 rx_chains_static, rx_chains_dynamic;
lockdep_assert_held(&local->chanctx_mtx);
rx_chains_static = 1;
rx_chains_dynamic = 1;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
u8 needed_static, needed_dynamic;
if (!ieee80211_sdata_running(sdata))
continue;
if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
&chanctx->conf)
continue;
switch (sdata->vif.type) {
case NL80211_IFTYPE_P2P_DEVICE:
continue;
case NL80211_IFTYPE_STATION:
if (!sdata->u.mgd.associated)
continue;
break;
case NL80211_IFTYPE_AP_VLAN:
continue;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
break;
default:
WARN_ON_ONCE(1);
}
switch (sdata->smps_mode) {
default:
WARN_ONCE(1, "Invalid SMPS mode %d\n",
sdata->smps_mode);
/* fall through */
case IEEE80211_SMPS_OFF:
needed_static = sdata->needed_rx_chains;
needed_dynamic = sdata->needed_rx_chains;
break;
case IEEE80211_SMPS_DYNAMIC:
needed_static = 1;
needed_dynamic = sdata->needed_rx_chains;
break;
case IEEE80211_SMPS_STATIC:
needed_static = 1;
needed_dynamic = 1;
break;
}
rx_chains_static = max(rx_chains_static, needed_static);
rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
}
rcu_read_unlock();
if (!local->use_chanctx) {
if (rx_chains_static > 1)
local->smps_mode = IEEE80211_SMPS_OFF;
else if (rx_chains_dynamic > 1)
local->smps_mode = IEEE80211_SMPS_DYNAMIC;
else
local->smps_mode = IEEE80211_SMPS_STATIC;
ieee80211_hw_config(local, 0);
}
if (rx_chains_static == chanctx->conf.rx_chains_static &&
rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
return;
chanctx->conf.rx_chains_static = rx_chains_static;
chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
}
int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
int ret;
WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
mutex_lock(&local->chanctx_mtx);
__ieee80211_vif_release_channel(sdata);
ctx = ieee80211_find_chanctx(local, channel, channel_type, mode);
if (!ctx)
ctx = ieee80211_new_chanctx(local, channel, channel_type, mode);
if (IS_ERR(ctx)) {
ret = PTR_ERR(ctx);
goto out;
}
sdata->vif.bss_conf.channel_type = channel_type;
ret = ieee80211_assign_vif_chanctx(sdata, ctx);
if (ret) {
/* if assign fails refcount stays the same */
if (ctx->refcount == 0)
ieee80211_free_chanctx(local, ctx);
goto out;
}
ieee80211_recalc_smps_chanctx(local, ctx);
out:
mutex_unlock(&local->chanctx_mtx);
return ret;
}
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
{
WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
mutex_lock(&sdata->local->chanctx_mtx);
__ieee80211_vif_release_channel(sdata);
mutex_unlock(&sdata->local->chanctx_mtx);
}
void ieee80211_iter_chan_contexts_atomic(
struct ieee80211_hw *hw,
void (*iter)(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *chanctx_conf,
void *data),
void *iter_data)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_chanctx *ctx;
rcu_read_lock();
list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
iter(hw, &ctx->conf, iter_data);
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);

View File

@ -2,9 +2,9 @@
#define __MAC80211_DEBUGFS_H
#ifdef CONFIG_MAC80211_DEBUGFS
extern void debugfs_hw_add(struct ieee80211_local *local);
extern int mac80211_format_buffer(char __user *userbuf, size_t count,
loff_t *ppos, char *fmt, ...);
void debugfs_hw_add(struct ieee80211_local *local);
int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count,
loff_t *ppos, char *fmt, ...);
#else
static inline void debugfs_hw_add(struct ieee80211_local *local)
{

View File

@ -217,7 +217,7 @@ static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
return snprintf(buf, buflen, "request: %s\nused: %s\n",
smps_modes[sdata->u.mgd.req_smps],
smps_modes[sdata->u.mgd.ap_smps]);
smps_modes[sdata->smps_mode]);
}
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
@ -395,14 +395,14 @@ __IEEE80211_IF_FILE_W(uapsd_max_sp_len);
/* AP attributes */
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
return scnprintf(buf, buflen, "%u\n",
skb_queue_len(&sdata->u.ap.ps_bc_buf));
skb_queue_len(&sdata->u.ap.ps.bc_buf));
}
__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
@ -471,7 +471,7 @@ IEEE80211_IF_FILE(dropped_frames_congestion,
u.mesh.mshstats.dropped_frames_congestion, DEC);
IEEE80211_IF_FILE(dropped_frames_no_route,
u.mesh.mshstats.dropped_frames_no_route, DEC);
IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC);
IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
/* Mesh parameters */
IEEE80211_IF_FILE(dot11MeshMaxRetries,

View File

@ -871,4 +871,69 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
local->ops->mgd_prepare_tx(&local->hw, &sdata->vif);
trace_drv_return_void(local);
}
static inline int drv_add_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
int ret = -EOPNOTSUPP;
trace_drv_add_chanctx(local, ctx);
if (local->ops->add_chanctx)
ret = local->ops->add_chanctx(&local->hw, &ctx->conf);
trace_drv_return_int(local, ret);
return ret;
}
static inline void drv_remove_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
trace_drv_remove_chanctx(local, ctx);
if (local->ops->remove_chanctx)
local->ops->remove_chanctx(&local->hw, &ctx->conf);
trace_drv_return_void(local);
}
static inline void drv_change_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
u32 changed)
{
trace_drv_change_chanctx(local, ctx, changed);
if (local->ops->change_chanctx)
local->ops->change_chanctx(&local->hw, &ctx->conf, changed);
trace_drv_return_void(local);
}
static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
{
int ret = 0;
check_sdata_in_driver(sdata);
trace_drv_assign_vif_chanctx(local, sdata, ctx);
if (local->ops->assign_vif_chanctx)
ret = local->ops->assign_vif_chanctx(&local->hw,
&sdata->vif,
&ctx->conf);
trace_drv_return_int(local, ret);
return ret;
}
static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx)
{
check_sdata_in_driver(sdata);
trace_drv_unassign_vif_chanctx(local, sdata, ctx);
if (local->ops->unassign_vif_chanctx)
local->ops->unassign_vif_chanctx(&local->hw,
&sdata->vif,
&ctx->conf);
trace_drv_return_void(local);
}
#endif /* __MAC80211_DRIVER_OPS */

View File

@ -26,7 +26,6 @@
#include "rate.h"
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
@ -39,7 +38,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
const u8 *bssid, const int beacon_int,
struct ieee80211_channel *chan,
const u32 basic_rates,
const u16 capability, u64 tsf)
const u16 capability, u64 tsf,
bool creator)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
@ -72,25 +72,27 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
/* if merging, indicate to driver that we leave the old IBSS */
if (sdata->vif.bss_conf.ibss_joined) {
sdata->vif.bss_conf.ibss_joined = false;
sdata->vif.bss_conf.ibss_creator = false;
netif_carrier_off(sdata->dev);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
}
memcpy(ifibss->bssid, bssid, ETH_ALEN);
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
local->oper_channel = chan;
channel_type = ifibss->channel_type;
if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
channel_type = NL80211_CHAN_HT20;
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
/* can only fail due to HT40+/- mismatch */
channel_type = NL80211_CHAN_HT20;
WARN_ON(!ieee80211_set_channel_type(local, sdata,
NL80211_CHAN_HT20));
ieee80211_vif_release_channel(sdata);
if (ieee80211_vif_use_channel(sdata, chan, channel_type,
ifibss->fixed_channel ?
IEEE80211_CHANCTX_SHARED :
IEEE80211_CHANCTX_EXCLUSIVE)) {
sdata_info(sdata, "Failed to join IBSS, no channel context\n");
return;
}
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
memcpy(ifibss->bssid, bssid, ETH_ALEN);
sband = local->hw.wiphy->bands[chan->band];
@ -197,6 +199,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
bss_change |= BSS_CHANGED_HT;
bss_change |= BSS_CHANGED_IBSS;
sdata->vif.bss_conf.ibss_joined = true;
sdata->vif.bss_conf.ibss_creator = creator;
ieee80211_bss_info_change_notify(sdata, bss_change);
ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
@ -249,7 +252,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
cbss->channel,
basic_rates,
cbss->capability,
cbss->tsf);
cbss->tsf,
false);
}
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
@ -279,7 +283,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
ibss_dbg(sdata,
"TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
sdata->vif.addr, addr, sdata->u.ibss.bssid);
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0,
addr, sdata->u.ibss.bssid, NULL, 0, 0);
}
return sta;
@ -294,7 +298,8 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
int band = local->oper_channel->band;
struct ieee80211_chanctx_conf *chanctx_conf;
int band;
/*
* XXX: Consider removing the least recently used entry and
@ -317,6 +322,13 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
return NULL;
}
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON_ONCE(!chanctx_conf))
return NULL;
band = chanctx_conf->channel->band;
rcu_read_unlock();
sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
if (!sta) {
rcu_read_lock();
@ -389,7 +401,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
* However, try to reply to authentication attempts if someone
* has actually implemented this.
*/
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0,
mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0);
}
@ -517,7 +529,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
goto put_bss;
/* different channel */
if (cbss->channel != local->oper_channel)
if (sdata->u.ibss.fixed_channel &&
sdata->u.ibss.channel != cbss->channel)
goto put_bss;
/* different SSID */
@ -592,7 +605,8 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
int band = local->oper_channel->band;
struct ieee80211_chanctx_conf *chanctx_conf;
int band;
/*
* XXX: Consider removing the least recently used entry and
@ -610,6 +624,15 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
if (!ether_addr_equal(bssid, sdata->u.ibss.bssid))
return;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON_ONCE(!chanctx_conf)) {
rcu_read_unlock();
return;
}
band = chanctx_conf->channel->band;
rcu_read_unlock();
sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
if (!sta)
return;
@ -715,7 +738,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
ifibss->channel, ifibss->basic_rates,
capability, 0);
capability, 0, true);
}
/*
@ -784,18 +807,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
int interval = IEEE80211_SCAN_INTERVAL;
if (time_after(jiffies, ifibss->ibss_join_req +
IEEE80211_IBSS_JOIN_TIMEOUT)) {
if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) {
ieee80211_sta_create_ibss(sdata);
return;
}
sdata_info(sdata, "IBSS not allowed on %d MHz\n",
local->oper_channel->center_freq);
/* No IBSS found - decrease scan interval and continue
* scanning. */
interval = IEEE80211_SCAN_INTERVAL_SLOW;
}
IEEE80211_IBSS_JOIN_TIMEOUT))
ieee80211_sta_create_ibss(sdata);
mod_timer(&ifibss->timer,
round_jiffies(jiffies + interval));
@ -1086,17 +1099,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.channel_type = params->channel_type;
sdata->u.ibss.fixed_channel = params->channel_fixed;
/* fix ourselves to that channel now already */
if (params->channel_fixed) {
sdata->local->oper_channel = params->channel;
if (!ieee80211_set_channel_type(sdata->local, sdata,
params->channel_type)) {
mutex_unlock(&sdata->u.ibss.mtx);
kfree_skb(skb);
return -EINVAL;
}
}
if (params->ie) {
sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len,
GFP_KERNEL);
@ -1134,6 +1136,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
return 0;
@ -1197,6 +1202,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
lockdep_is_held(&sdata->u.ibss.mtx));
RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
sdata->vif.bss_conf.ibss_joined = false;
sdata->vif.bss_conf.ibss_creator = false;
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_IBSS);
synchronize_rcu();

View File

@ -280,21 +280,25 @@ struct probe_resp {
u8 data[0];
};
struct ps_data {
/* yes, this looks ugly, but guarantees that we can later use
* bitmap_empty :)
* NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
struct sk_buff_head bc_buf;
atomic_t num_sta_ps; /* number of stations in PS mode */
int dtim_count;
bool dtim_bc_mc;
};
struct ieee80211_if_ap {
struct beacon_data __rcu *beacon;
struct probe_resp __rcu *probe_resp;
struct list_head vlans;
/* yes, this looks ugly, but guarantees that we can later use
* bitmap_empty :)
* NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
struct sk_buff_head ps_bc_buf;
atomic_t num_sta_ps; /* number of stations in PS mode */
struct ps_data ps;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
int dtim_count;
bool dtim_bc_mc;
};
struct ieee80211_if_wds {
@ -316,7 +320,6 @@ struct mesh_stats {
__u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/
__u32 dropped_frames_no_route; /* Not transmitted, no route found */
__u32 dropped_frames_congestion;/* Not forwarded due to congestion */
atomic_t estab_plinks;
};
#define PREQ_Q_F_START 0x1
@ -378,8 +381,9 @@ struct ieee80211_mgd_auth_data {
u8 key_len, key_idx;
bool done;
size_t ie_len;
u8 ie[];
u16 sae_trans, sae_status;
size_t data_len;
u8 data[];
};
struct ieee80211_mgd_assoc_data {
@ -433,7 +437,6 @@ struct ieee80211_if_managed {
bool powersave; /* powersave requested for this iface */
bool broken_ap; /* AP is broken -- turn off powersave */
enum ieee80211_smps_mode req_smps, /* requested smps mode */
ap_smps, /* smps mode AP thinks we're in */
driver_smps_mode; /* smps mode request */
struct work_struct request_smps_work;
@ -599,6 +602,7 @@ struct ieee80211_if_mesh {
int preq_queue_len;
struct mesh_stats mshstats;
struct mesh_config mshcfg;
atomic_t estab_plinks;
u32 mesh_seqnum;
bool accepting_plinks;
int num_gates;
@ -610,7 +614,7 @@ struct ieee80211_if_mesh {
IEEE80211_MESH_SEC_SECURED = 0x2,
} security;
/* Extensible Synchronization Framework */
struct ieee80211_mesh_sync_ops *sync_ops;
const struct ieee80211_mesh_sync_ops *sync_ops;
s64 sync_offset_clockdrift_max;
spinlock_t sync_offset_lock;
bool adjusting_tbtt;
@ -658,6 +662,30 @@ enum ieee80211_sdata_state_bits {
SDATA_STATE_OFFCHANNEL,
};
/**
* enum ieee80211_chanctx_mode - channel context configuration mode
*
* @IEEE80211_CHANCTX_SHARED: channel context may be used by
* multiple interfaces
* @IEEE80211_CHANCTX_EXCLUSIVE: channel context can be used
* only by a single interface. This can be used for example for
* non-fixed channel IBSS.
*/
enum ieee80211_chanctx_mode {
IEEE80211_CHANCTX_SHARED,
IEEE80211_CHANCTX_EXCLUSIVE
};
struct ieee80211_chanctx {
struct list_head list;
struct rcu_head rcu_head;
enum ieee80211_chanctx_mode mode;
int refcount;
struct ieee80211_chanctx_conf conf;
};
struct ieee80211_sub_if_data {
struct list_head list;
@ -704,11 +732,17 @@ struct ieee80211_sub_if_data {
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
/* used to reconfigure hardware SM PS */
struct work_struct recalc_smps;
struct work_struct work;
struct sk_buff_head skb_queue;
bool arp_filter_state;
u8 needed_rx_chains;
enum ieee80211_smps_mode smps_mode;
/*
* AP this belongs to: self in AP mode and
* corresponding AP in VLAN mode, NULL for
@ -749,6 +783,21 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
return container_of(p, struct ieee80211_sub_if_data, vif);
}
static inline enum ieee80211_band
ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata)
{
enum ieee80211_band band = IEEE80211_BAND_2GHZ;
struct ieee80211_chanctx_conf *chanctx_conf;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!WARN_ON(!chanctx_conf))
band = chanctx_conf->channel->band;
rcu_read_unlock();
return band;
}
enum sdata_queue_type {
IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0,
IEEE80211_SDATA_QUEUE_AGG_START = 1,
@ -821,6 +870,7 @@ enum {
* @SCAN_SUSPEND: Suspend the scan and go back to operating channel to
* send out data
* @SCAN_RESUME: Resume the scan and scan the next channel
* @SCAN_ABORT: Abort the scan and go back to operating channel
*/
enum mac80211_scan_state {
SCAN_DECISION,
@ -828,6 +878,7 @@ enum mac80211_scan_state {
SCAN_SEND_PROBE,
SCAN_SUSPEND,
SCAN_RESUME,
SCAN_ABORT,
};
struct ieee80211_local {
@ -858,15 +909,14 @@ struct ieee80211_local {
bool wiphy_ciphers_allocated;
bool use_chanctx;
/* protects the aggregated multicast list and filter calls */
spinlock_t filter_lock;
/* used for uploading changed mc list */
struct work_struct reconfig_filter;
/* used to reconfigure hardware SM PS */
struct work_struct recalc_smps;
/* aggregated multicast list */
struct netdev_hw_addr_list mc_list;
@ -903,6 +953,9 @@ struct ieee80211_local {
/* wowlan is enabled -- don't reconfig on resume */
bool wowlan;
/* number of RX chains the hardware has */
u8 rx_chains;
int tx_headroom; /* required headroom for hardware/radiotap */
/* Tasklet and skb queue to process calls from IRQ mode. All frames
@ -980,13 +1033,19 @@ struct ieee80211_local {
enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
struct ieee80211_sub_if_data __rcu *scan_sdata;
struct ieee80211_channel *csa_channel;
/* For backward compatibility only -- do not use */
struct ieee80211_channel *_oper_channel;
enum nl80211_channel_type _oper_channel_type;
struct ieee80211_channel *oper_channel, *csa_channel;
/* Temporary remain-on-channel for off-channel operations */
struct ieee80211_channel *tmp_channel;
enum nl80211_channel_type tmp_channel_type;
/* channel contexts */
struct list_head chanctx_list;
struct mutex chanctx_mtx;
/* SNMP counters */
/* dot11CountersTable */
u32 dot11TransmittedFragmentCount;
@ -1091,6 +1150,8 @@ struct ieee80211_local {
/* virtual monitor interface */
struct ieee80211_sub_if_data __rcu *monitor_sdata;
struct ieee80211_channel *monitor_channel;
enum nl80211_channel_type monitor_channel_type;
};
static inline struct ieee80211_sub_if_data *
@ -1133,6 +1194,8 @@ struct ieee802_11_elems {
u8 *wmm_param;
struct ieee80211_ht_cap *ht_cap_elem;
struct ieee80211_ht_operation *ht_operation;
struct ieee80211_vht_cap *vht_cap_elem;
struct ieee80211_vht_operation *vht_operation;
struct ieee80211_meshconf_ie *mesh_config;
u8 *mesh_id;
u8 *peering;
@ -1359,6 +1422,13 @@ void ieee80211_ba_session_work(struct work_struct *work);
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs);
/* VHT */
void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
struct ieee80211_vht_cap *vht_cap_ie,
struct ieee80211_sta_vht_cap *vht_cap);
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
@ -1393,11 +1463,42 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
gfp_t gfp);
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
bool bss_notify);
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
enum ieee80211_band band);
void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid);
static void inline ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid,
enum ieee80211_band band);
static inline void
ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid,
enum ieee80211_band band)
{
rcu_read_lock();
__ieee80211_tx_skb_tid_band(sdata, skb, tid, band);
rcu_read_unlock();
}
static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid)
{
struct ieee80211_chanctx_conf *chanctx_conf;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
kfree_skb(skb);
return;
}
__ieee80211_tx_skb_tid_band(sdata, skb, tid,
chanctx_conf->channel->band);
rcu_read_unlock();
}
static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
/* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
@ -1444,7 +1545,7 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
}
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
u16 transaction, u16 auth_alg, u16 status,
u8 *extra, size_t extra_len, const u8 *bssid,
const u8 *da, const u8 *key, u8 key_len, u8 key_idx);
void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
@ -1464,7 +1565,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
u32 ratemask, bool directed, bool no_cck,
struct ieee80211_channel *channel);
struct ieee80211_channel *channel, bool scan);
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len,
@ -1474,7 +1575,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
enum ieee80211_band band, u32 *basic_rates);
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_local *local);
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, size_t offset);
@ -1495,21 +1596,19 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
enum ieee80211_band band);
/* channel management */
enum ieee80211_chan_mode {
CHAN_MODE_UNDEFINED,
CHAN_MODE_HOPPING,
CHAN_MODE_FIXED,
};
enum ieee80211_chan_mode
ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore);
bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype);
enum nl80211_channel_type
ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);
int __must_check
ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
enum nl80211_channel_type channel_type,
enum ieee80211_chanctx_mode mode);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
#else

View File

@ -380,6 +380,15 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
goto out_unlock;
}
ret = ieee80211_vif_use_channel(sdata, local->monitor_channel,
local->monitor_channel_type,
IEEE80211_CHANCTX_EXCLUSIVE);
if (ret) {
drv_remove_interface(local, sdata);
kfree(sdata);
goto out_unlock;
}
rcu_assign_pointer(local->monitor_sdata, sdata);
out_unlock:
mutex_unlock(&local->iflist_mtx);
@ -403,6 +412,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
rcu_assign_pointer(local->monitor_sdata, NULL);
synchronize_net();
ieee80211_vif_release_channel(sdata);
drv_remove_interface(local, sdata);
kfree(sdata);
@ -665,7 +676,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
int i;
enum nl80211_channel_type orig_ct;
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
@ -729,6 +739,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
cancel_work_sync(&sdata->recalc_smps);
/* APs need special treatment */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
@ -755,8 +767,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
WARN_ON(!list_empty(&sdata->u.ap.vlans));
/* free all potentially still buffered bcast frames */
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf);
skb_queue_purge(&sdata->u.ap.ps_bc_buf);
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
skb_queue_purge(&sdata->u.ap.ps.bc_buf);
} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
ieee80211_mgd_stop(sdata);
}
@ -837,14 +849,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
hw_reconf_flags = 0;
}
/* Re-calculate channel-type, in case there are multiple vifs
* on different channel types.
*/
orig_ct = local->_oper_channel_type;
ieee80211_set_channel_type(local, NULL, NL80211_CHAN_NO_HT);
/* do after stop to avoid reconfiguring when we stop anyway */
if (hw_reconf_flags || (orig_ct != local->_oper_channel_type))
if (hw_reconf_flags)
ieee80211_hw_config(local, hw_reconf_flags);
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
@ -1121,6 +1127,13 @@ static void ieee80211_iface_work(struct work_struct *work)
}
}
static void ieee80211_recalc_smps_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data, recalc_smps);
ieee80211_recalc_smps(sdata);
}
/*
* Helper function to initialise an interface to a specific type.
@ -1149,6 +1162,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
skb_queue_head_init(&sdata->skb_queue);
INIT_WORK(&sdata->work, ieee80211_iface_work);
INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
switch (type) {
case NL80211_IFTYPE_P2P_GO:
@ -1157,7 +1171,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->vif.p2p = true;
/* fall through */
case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
case NL80211_IFTYPE_P2P_CLIENT:
@ -1282,11 +1296,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
if (type == ieee80211_vif_type_p2p(&sdata->vif))
return 0;
/* Setting ad-hoc mode on non-IBSS channel is not supported. */
if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS &&
type == NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
if (ieee80211_sdata_running(sdata)) {
ret = ieee80211_runtime_change_iftype(sdata, type);
if (ret)
@ -1298,9 +1307,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
}
/* reset some values that shouldn't be kept across type changes */
sdata->vif.bss_conf.basic_rates =
ieee80211_mandatory_rates(sdata->local,
sdata->local->oper_channel->band);
sdata->drop_unencrypted = 0;
if (type == NL80211_IFTYPE_STATION)
sdata->u.mgd.use_4addr = false;

View File

@ -93,23 +93,21 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
ieee80211_configure_filter(local);
}
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
{
struct ieee80211_channel *chan;
int ret = 0;
u32 changed = 0;
int power;
enum nl80211_channel_type channel_type;
u32 offchannel_flag;
might_sleep();
offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
if (local->scan_channel) {
chan = local->scan_channel;
/* If scanning on oper channel, use whatever channel-type
* is currently in use.
*/
if (chan == local->oper_channel)
if (chan == local->_oper_channel)
channel_type = local->_oper_channel_type;
else
channel_type = NL80211_CHAN_NO_HT;
@ -117,11 +115,11 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
chan = local->tmp_channel;
channel_type = local->tmp_channel_type;
} else {
chan = local->oper_channel;
chan = local->_oper_channel;
channel_type = local->_oper_channel_type;
}
if (chan != local->oper_channel ||
if (chan != local->_oper_channel ||
channel_type != local->_oper_channel_type)
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
else
@ -164,6 +162,21 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
local->hw.conf.power_level = power;
}
return changed;
}
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
int ret = 0;
might_sleep();
if (!local->use_chanctx)
changed |= ieee80211_hw_conf_chan(local);
else
changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL |
IEEE80211_CONF_CHANGE_POWER);
if (changed && local->open_count) {
ret = drv_config(local, changed);
/*
@ -359,14 +372,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(ieee80211_restart_hw);
static void ieee80211_recalc_smps_work(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, recalc_smps);
ieee80211_recalc_smps(local);
}
#ifdef CONFIG_INET
static int ieee80211_ifa_changed(struct notifier_block *nb,
unsigned long data, void *arg)
@ -540,6 +545,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
struct ieee80211_local *local;
int priv_size, i;
struct wiphy *wiphy;
bool use_chanctx;
if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
!ops->add_interface || !ops->remove_interface ||
@ -549,6 +555,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
return NULL;
/* check all or no channel context operations exist */
i = !!ops->add_chanctx + !!ops->remove_chanctx +
!!ops->change_chanctx + !!ops->assign_vif_chanctx +
!!ops->unassign_vif_chanctx;
if (WARN_ON(i != 0 && i != 5))
return NULL;
use_chanctx = i == 5;
/* Ensure 32-byte alignment of our private data and hw private data.
* We use the wiphy priv data for both our ieee80211_local and for
* the driver's private data
@ -584,8 +598,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
if (ops->remain_on_channel)
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
wiphy->features = NL80211_FEATURE_SK_TX_STATUS |
NL80211_FEATURE_HT_IBSS;
wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
NL80211_FEATURE_SAE |
NL80211_FEATURE_HT_IBSS;
if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
NL80211_FEATURE_AP_SCAN;
if (!ops->set_key)
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@ -599,6 +619,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
local->ops = ops;
local->use_chanctx = use_chanctx;
/* set up some defaults */
local->hw.queues = 1;
@ -626,6 +647,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);
INIT_LIST_HEAD(&local->chanctx_list);
mutex_init(&local->chanctx_mtx);
/*
* The rx_skb_queue is only accessed from tasklets,
* but other SKB queues are used from within IRQ
@ -641,7 +665,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
INIT_WORK(&local->restart_work, ieee80211_restart_work);
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work);
local->smps_mode = IEEE80211_SMPS_OFF;
INIT_WORK(&local->dynamic_ps_enable_work,
@ -719,6 +742,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
return -EINVAL;
if (!local->use_chanctx) {
for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
const struct ieee80211_iface_combination *comb;
comb = &local->hw.wiphy->iface_combinations[i];
if (comb->num_different_channels > 1)
return -EINVAL;
}
/*
* WDS is currently prohibited when channel contexts are used
* because there's no clear definition of which channel WDS
* type interfaces use
*/
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
return -EINVAL;
}
/* Only HW csum features are currently compatible with mac80211 */
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_CSUM;
@ -728,6 +770,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (hw->max_report_rates == 0)
hw->max_report_rates = hw->max_rates;
local->rx_chains = 1;
/*
* generic code guarantees at least one band,
* set this very early because much code assumes
@ -743,18 +787,29 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
sband = local->hw.wiphy->bands[band];
if (!sband)
continue;
if (!local->oper_channel) {
if (!local->use_chanctx && !local->_oper_channel) {
/* init channel we're on */
local->hw.conf.channel =
local->oper_channel = &sband->channels[0];
local->_oper_channel = &sband->channels[0];
local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
}
if (!local->monitor_channel) {
local->monitor_channel = &sband->channels[0];
local->monitor_channel_type = NL80211_CHAN_NO_HT;
}
channels += sband->n_channels;
if (max_bitrates < sband->n_bitrates)
max_bitrates = sband->n_bitrates;
supp_ht = supp_ht || sband->ht_cap.ht_supported;
supp_vht = supp_vht || sband->vht_cap.vht_supported;
if (sband->ht_cap.ht_supported)
local->rx_chains =
max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
local->rx_chains);
/* TODO: consider VHT for RX chains, hopefully it's the same */
}
local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
@ -778,19 +833,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
/*
* mac80211 doesn't support more than 1 channel, and also not more
* than one IBSS interface
*/
/* mac80211 doesn't support more than one IBSS interface right now */
for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
const struct ieee80211_iface_combination *c;
int j;
c = &hw->wiphy->iface_combinations[i];
if (c->num_different_channels > 1)
return -EINVAL;
for (j = 0; j < c->n_limits; j++)
if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
c->limits[j].max > 1)
@ -832,7 +881,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (supp_vht)
local->scan_ies_len +=
2 + sizeof(struct ieee80211_vht_capabilities);
2 + sizeof(struct ieee80211_vht_cap);
if (!local->ops->hw_scan) {
/* For hw_scan, driver needs to set these up. */

View File

@ -97,7 +97,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
goto mismatch;
ieee80211_sta_get_rates(local, ie, local->oper_channel->band,
ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata),
&basic_rates);
if (sdata->vif.bss_conf.basic_rates != basic_rates)
@ -264,7 +264,7 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
/* Authentication Protocol identifier */
*pos++ = ifmsh->mesh_auth_id;
/* Mesh Formation Info - number of neighbors */
neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
neighbors = atomic_read(&ifmsh->estab_plinks);
/* Number of neighbor mesh STAs or 15 whichever is smaller */
neighbors = (neighbors > 15) ? 15 : neighbors;
*pos++ = neighbors << 1;
@ -355,12 +355,22 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan = local->oper_channel;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
u8 *pos;
if (skb_tailroom(skb) < 3)
return -ENOMEM;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return -EINVAL;
}
chan = chanctx_conf->channel;
rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band];
if (sband->band == IEEE80211_BAND_2GHZ) {
pos = skb_put(skb, 2 + 1);
@ -376,10 +386,11 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband;
u8 *pos;
sband = local->hw.wiphy->bands[local->oper_channel->band];
sband = local->hw.wiphy->bands[band];
if (!sband->ht_cap.ht_supported ||
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
return 0;
@ -397,14 +408,26 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_channel *channel = local->oper_channel;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel;
enum nl80211_channel_type channel_type =
sdata->vif.bss_conf.channel_type;
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[channel->band];
struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
sdata->vif.bss_conf.channel_type;
struct ieee80211_supported_band *sband;
struct ieee80211_sta_ht_cap *ht_cap;
u8 *pos;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return -EINVAL;
}
channel = chanctx_conf->channel;
rcu_read_unlock();
sband = local->hw.wiphy->bands[channel->band];
ht_cap = &sband->ht_cap;
if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
return 0;
@ -610,7 +633,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
sdata->vif.bss_conf.basic_rates =
ieee80211_mandatory_rates(sdata->local,
sdata->local->oper_channel->band);
ieee80211_get_sdata_band(sdata));
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_HT |

View File

@ -256,7 +256,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
/* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb,
@ -324,7 +324,7 @@ extern int mesh_allocated;
static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
{
return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks -
atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
atomic_read(&sdata->u.mesh.estab_plinks);
}
static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)

View File

@ -50,14 +50,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
static inline
u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
atomic_inc(&sdata->u.mesh.estab_plinks);
return mesh_accept_plinks_update(sdata);
}
static inline
u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
atomic_dec(&sdata->u.mesh.estab_plinks);
return mesh_accept_plinks_update(sdata);
}
@ -252,6 +252,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
mgmt->u.action.u.self_prot.action_code = action;
if (action != WLAN_SP_MESH_PEERING_CLOSE) {
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
/* capability info */
pos = skb_put(skb, 2);
memset(pos, 0, 2);
@ -260,10 +262,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, 2);
memcpy(pos + 2, &plid, 2);
}
if (ieee80211_add_srates_ie(sdata, skb, true,
local->oper_channel->band) ||
ieee80211_add_ext_srates_ie(sdata, skb, true,
local->oper_channel->band) ||
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata))
@ -343,7 +343,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems)
{
struct ieee80211_local *local = sdata->local;
enum ieee80211_band band = local->oper_channel->band;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband;
u32 rates, basic_rates = 0;
struct sta_info *sta;

View File

@ -234,49 +234,7 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
spin_unlock_bh(&ifmsh->sync_offset_lock);
}
static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 offset;
if (!ifmsh->ie || !ifmsh->ie_len)
return NULL;
offset = ieee80211_ie_split_vendor(ifmsh->ie,
ifmsh->ie_len, 0);
if (!offset)
return NULL;
return ifmsh->ie + offset + 2;
}
static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
u16 stype,
struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
struct ieee80211_rx_status *rx_status)
{
const u8 *oui;
WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n");
oui = mesh_get_vendor_oui(sdata);
/* here you would implement the vendor offset tracking for this oui */
}
static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
{
const u8 *oui;
WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n");
oui = mesh_get_vendor_oui(sdata);
/* here you would implement the vendor tsf adjustment for this oui */
}
/* global variable */
static struct sync_method sync_methods[] = {
static const struct sync_method sync_methods[] = {
{
.method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
.ops = {
@ -284,18 +242,11 @@ static struct sync_method sync_methods[] = {
.adjust_tbtt = &mesh_sync_offset_adjust_tbtt,
}
},
{
.method = IEEE80211_SYNC_METHOD_VENDOR,
.ops = {
.rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp,
.adjust_tbtt = &mesh_sync_vendor_adjust_tbtt,
}
},
};
struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
{
struct ieee80211_mesh_sync_ops *ops = NULL;
const struct ieee80211_mesh_sync_ops *ops = NULL;
u8 i;
for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) {

View File

@ -178,20 +178,30 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
struct sta_info *sta;
u32 changed = 0;
u16 ht_opmode;
bool disable_40 = false;
sband = local->hw.wiphy->bands[local->oper_channel->band];
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return 0;
}
chan = chanctx_conf->channel;
rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band];
switch (sdata->vif.bss_conf.channel_type) {
case NL80211_CHAN_HT40PLUS:
if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
disable_40 = true;
break;
case NL80211_CHAN_HT40MINUS:
if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
disable_40 = true;
break;
default:
@ -343,7 +353,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
cap = vht_cap.cap;
/* reserve and fill IE */
pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2);
pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
}
@ -359,11 +369,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
int i, count, rates_len, supp_rates_len;
u16 capab;
struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
u32 rates = 0;
lockdep_assert_held(&ifmgd->mtx);
sband = local->hw.wiphy->bands[local->oper_channel->band];
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return;
}
chan = chanctx_conf->channel;
rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band];
if (assoc_data->supp_rates_len) {
/*
@ -392,7 +412,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
4 + /* power capability */
2 + 2 * sband->n_channels + /* supported channels */
2 + sizeof(struct ieee80211_ht_cap) + /* HT */
2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */
2 + sizeof(struct ieee80211_vht_cap) + /* VHT */
assoc_data->ie_len + /* extra IEs */
9, /* WMM */
GFP_KERNEL);
@ -485,7 +505,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
*pos++ = WLAN_EID_PWR_CAPABILITY;
*pos++ = 2;
*pos++ = 0; /* min tx power */
*pos++ = local->oper_channel->max_power; /* max tx power */
*pos++ = chan->max_power; /* max tx power */
/* 2. supported channels */
/* TODO: get this in reg domain format */
@ -523,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
sband, local->oper_channel, ifmgd->ap_smps);
sband, chan, sdata->smps_mode);
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
ieee80211_add_vht_ie(sdata, skb, sband);
@ -657,18 +677,18 @@ static void ieee80211_chswitch_work(struct work_struct *work)
if (!ifmgd->associated)
goto out;
sdata->local->oper_channel = sdata->local->csa_channel;
sdata->local->_oper_channel = sdata->local->csa_channel;
if (!sdata->local->ops->channel_switch) {
/* call "hw_config" only if doing sw channel switch */
ieee80211_hw_config(sdata->local,
IEEE80211_CONF_CHANGE_CHANNEL);
} else {
/* update the device channel directly */
sdata->local->hw.conf.channel = sdata->local->oper_channel;
sdata->local->hw.conf.channel = sdata->local->_oper_channel;
}
/* XXX: shouldn't really modify cfg80211-owned data! */
ifmgd->associated->channel = sdata->local->oper_channel;
ifmgd->associated->channel = sdata->local->_oper_channel;
/* XXX: wait for a beacon first? */
ieee80211_wake_queues_by_reason(&sdata->local->hw,
@ -680,11 +700,8 @@ static void ieee80211_chswitch_work(struct work_struct *work)
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_managed *ifmgd;
sdata = vif_to_sdata(vif);
ifmgd = &sdata->u.mgd;
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
trace_api_chswitch_done(sdata, success);
if (!success) {
@ -723,6 +740,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num,
cbss->channel->band);
struct ieee80211_chanctx *chanctx;
ASSERT_MGD_MTX(ifmgd);
@ -748,10 +766,34 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return;
}
sdata->local->csa_channel = new_ch;
ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
if (sdata->local->use_chanctx) {
sdata_info(sdata,
"not handling channel switch with channel contexts\n");
ieee80211_queue_work(&sdata->local->hw,
&ifmgd->csa_connection_drop_work);
}
mutex_lock(&sdata->local->chanctx_mtx);
if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
mutex_unlock(&sdata->local->chanctx_mtx);
return;
}
chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
struct ieee80211_chanctx, conf);
if (chanctx->refcount > 1) {
sdata_info(sdata,
"channel switch with multiple interfaces on the same channel, disconnecting\n");
ieee80211_queue_work(&sdata->local->hw,
&ifmgd->csa_connection_drop_work);
mutex_unlock(&sdata->local->chanctx_mtx);
return;
}
mutex_unlock(&sdata->local->chanctx_mtx);
sdata->local->csa_channel = new_ch;
if (sw_elem->mode)
ieee80211_stop_queues_by_reason(&sdata->local->hw,
IEEE80211_QUEUE_STOP_REASON_CSA);
@ -1280,7 +1322,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
}
use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ)
if (ieee80211_get_sdata_band(sdata) == IEEE80211_BAND_5GHZ)
use_short_slot = true;
if (use_protection != bss_conf->use_cts_prot) {
@ -1350,7 +1392,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx);
ieee80211_recalc_smps(local);
ieee80211_recalc_smps(sdata);
ieee80211_recalc_ps_vif(sdata);
netif_tx_start_all_queues(sdata->dev);
@ -1465,9 +1507,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);
/* channel(_type) changes are handled by ieee80211_hw_config */
WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
ieee80211_hw_config(local, 0);
ieee80211_vif_release_channel(sdata);
/* disassociated - set to defaults now */
ieee80211_set_wmm_default(sdata, false);
@ -1589,7 +1629,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
0, (u32) -1, true, false,
ifmgd->associated->channel);
ifmgd->associated->channel, false);
}
ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
@ -1692,8 +1732,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
ssid_len = ssid[1];
skb = ieee80211_build_probe_req(sdata, cbss->bssid,
(u32) -1,
sdata->local->oper_channel,
(u32) -1, cbss->channel,
ssid + 2, ssid_len,
NULL, 0, true);
@ -1804,6 +1843,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
ieee80211_vif_release_channel(sdata);
}
cfg80211_put_bss(auth_data->bss);
@ -1824,7 +1864,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
return;
auth_data->expected_transaction = 4;
drv_mgd_prepare_tx(sdata->local, sdata);
ieee80211_send_auth(sdata, 3, auth_data->algorithm,
ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
elems.challenge - 2, elems.challenge_len + 2,
auth_data->bss->bssid, auth_data->bss->bssid,
auth_data->key, auth_data->key_len,
@ -1858,8 +1898,13 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
status_code = le16_to_cpu(mgmt->u.auth.status_code);
if (auth_alg != ifmgd->auth_data->algorithm ||
auth_transaction != ifmgd->auth_data->expected_transaction)
auth_transaction != ifmgd->auth_data->expected_transaction) {
sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n",
mgmt->sa, auth_alg, ifmgd->auth_data->algorithm,
auth_transaction,
ifmgd->auth_data->expected_transaction);
return RX_MGMT_NONE;
}
if (status_code != WLAN_STATUS_SUCCESS) {
sdata_info(sdata, "%pM denied authentication (status %d)\n",
@ -1872,6 +1917,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
case WLAN_AUTH_OPEN:
case WLAN_AUTH_LEAP:
case WLAN_AUTH_FT:
case WLAN_AUTH_SAE:
break;
case WLAN_AUTH_SHARED_KEY:
if (ifmgd->auth_data->expected_transaction != 4) {
@ -1891,6 +1937,15 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
run_again(ifmgd, ifmgd->auth_data->timeout);
if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
ifmgd->auth_data->expected_transaction != 2) {
/*
* Report auth frame to user space for processing since another
* round of Authentication frames is still needed.
*/
return RX_MGMT_CFG80211_RX_AUTH;
}
/* move station state to auth */
mutex_lock(&sdata->local->sta_mtx);
sta = sta_info_get(sdata, bssid);
@ -2030,6 +2085,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
ieee80211_vif_release_channel(sdata);
}
kfree(assoc_data);
@ -2091,7 +2147,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
return false;
}
sband = local->hw.wiphy->bands[local->oper_channel->band];
sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
@ -2100,6 +2156,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
sta->supports_40mhz =
sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
elems.vht_cap_elem,
&sta->sta.vht_cap);
rate_control_rate_init(sta);
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
@ -2369,6 +2430,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
size_t baselen;
struct ieee802_11_elems elems;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
u32 changed = 0;
bool erp_valid, directed_tim = false;
u8 erp_value = 0;
@ -2382,8 +2445,19 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (baselen > len)
return;
if (rx_status->freq != local->oper_channel->center_freq)
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return;
}
if (rx_status->freq != chanctx_conf->channel->center_freq) {
rcu_read_unlock();
return;
}
chan = chanctx_conf->channel;
rcu_read_unlock();
if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
@ -2543,19 +2617,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) {
struct ieee80211_supported_band *sband;
sband = local->hw.wiphy->bands[local->oper_channel->band];
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
bssid, true);
}
if (elems.country_elem && elems.pwr_constr_elem &&
mgmt->u.probe_resp.capab_info &
cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
ieee80211_handle_pwr_constr(sdata, local->oper_channel,
ieee80211_handle_pwr_constr(sdata, chan,
elems.country_elem,
elems.country_elem_len,
elems.pwr_constr_elem);
@ -2703,13 +2772,23 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
drv_mgd_prepare_tx(local, sdata);
if (auth_data->bss->proberesp_ies) {
u16 trans = 1;
u16 status = 0;
sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
auth_data->bss->bssid, auth_data->tries,
IEEE80211_AUTH_MAX_TRIES);
auth_data->expected_transaction = 2;
ieee80211_send_auth(sdata, 1, auth_data->algorithm,
auth_data->ie, auth_data->ie_len,
if (auth_data->algorithm == WLAN_AUTH_SAE) {
trans = auth_data->sae_trans;
status = auth_data->sae_status;
auth_data->expected_transaction = trans;
}
ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
auth_data->data, auth_data->data_len,
auth_data->bss->bssid,
auth_data->bss->bssid, NULL, 0, 0);
} else {
@ -2728,7 +2807,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
*/
ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
NULL, 0, (u32) -1, true, false,
auth_data->bss->channel);
auth_data->bss->channel, false);
}
auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@ -3103,6 +3182,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
}
if (ht_oper) {
const u8 *ht_cap_ie;
const struct ieee80211_ht_cap *ht_cap;
u8 chains = 1;
channel_type = NL80211_CHAN_HT20;
if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
@ -3116,22 +3199,25 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
break;
}
}
ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY,
cbss->information_elements,
cbss->len_information_elements);
if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) {
ht_cap = (void *)(ht_cap_ie + 2);
chains = ieee80211_mcs_to_chains(&ht_cap->mcs);
}
sdata->needed_rx_chains = min(chains, local->rx_chains);
} else {
sdata->needed_rx_chains = 1;
}
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
/* can only fail due to HT40+/- mismatch */
channel_type = NL80211_CHAN_HT20;
sdata_info(sdata,
"disabling 40 MHz due to multi-vif mismatch\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
WARN_ON(!ieee80211_set_channel_type(local, sdata,
channel_type));
}
/* will change later if needed */
sdata->smps_mode = IEEE80211_SMPS_OFF;
local->oper_channel = cbss->channel;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
return 0;
ieee80211_vif_release_channel(sdata);
return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type,
IEEE80211_CHANCTX_SHARED);
}
static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
@ -3201,7 +3287,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.basic_rates = basic_rates;
/* cf. IEEE 802.11 9.2.12 */
if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
if (cbss->channel->band == IEEE80211_BAND_2GHZ &&
have_higher_than_11mbit)
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
else
@ -3263,19 +3349,33 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
case NL80211_AUTHTYPE_NETWORK_EAP:
auth_alg = WLAN_AUTH_LEAP;
break;
case NL80211_AUTHTYPE_SAE:
auth_alg = WLAN_AUTH_SAE;
break;
default:
return -EOPNOTSUPP;
}
auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL);
auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len +
req->ie_len, GFP_KERNEL);
if (!auth_data)
return -ENOMEM;
auth_data->bss = req->bss;
if (req->sae_data_len >= 4) {
__le16 *pos = (__le16 *) req->sae_data;
auth_data->sae_trans = le16_to_cpu(pos[0]);
auth_data->sae_status = le16_to_cpu(pos[1]);
memcpy(auth_data->data, req->sae_data + 4,
req->sae_data_len - 4);
auth_data->data_len += req->sae_data_len - 4;
}
if (req->ie && req->ie_len) {
memcpy(auth_data->ie, req->ie, req->ie_len);
auth_data->ie_len = req->ie_len;
memcpy(&auth_data->data[auth_data->data_len],
req->ie, req->ie_len);
auth_data->data_len += req->ie_len;
}
if (req->key && req->key_len) {
@ -3442,11 +3542,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
if (ifmgd->powersave)
ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
else
ifmgd->ap_smps = IEEE80211_SMPS_OFF;
sdata->smps_mode = IEEE80211_SMPS_OFF;
} else
ifmgd->ap_smps = ifmgd->req_smps;
sdata->smps_mode = ifmgd->req_smps;
assoc_data->capability = req->bss->capability;
assoc_data->wmm = bss->wmm_used &&

View File

@ -107,6 +107,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
{
struct ieee80211_sub_if_data *sdata;
if (WARN_ON(local->use_chanctx))
return;
/*
* notify the AP about us leaving the channel and stop all
* STA interfaces.
@ -145,6 +148,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
{
struct ieee80211_sub_if_data *sdata;
if (WARN_ON(local->use_chanctx))
return;
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
@ -193,7 +199,8 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
if (roc->mgmt_tx_cookie) {
if (!WARN_ON(!roc->frame)) {
ieee80211_tx_skb(roc->sdata, roc->frame);
ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7,
roc->chan->band);
roc->frame = NULL;
}
} else {

View File

@ -135,6 +135,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);
/* the interface is leaving the channel and is removed */
ieee80211_vif_release_channel(sdata);
drv_remove_interface(local, sdata);
}

View File

@ -52,11 +52,21 @@ static inline void rate_control_rate_init(struct sta_info *sta)
struct ieee80211_sta *ista = &sta->sta;
void *priv_sta = sta->rate_ctrl_priv;
struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf;
if (!ref)
return;
sband = local->hw.wiphy->bands[local->oper_channel->band];
rcu_read_lock();
chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
return;
}
sband = local->hw.wiphy->bands[chanctx_conf->channel->band];
rcu_read_unlock();
ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
set_sta_flag(sta, WLAN_STA_RATE_CONTROL);

View File

@ -1141,12 +1141,19 @@ ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}
static void ap_sta_ps_start(struct sta_info *sta)
static void sta_ps_start(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct ps_data *ps;
atomic_inc(&sdata->bss->num_sta_ps);
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
else
return;
atomic_inc(&ps->num_sta_ps);
set_sta_flag(sta, WLAN_STA_PS_STA);
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
@ -1154,7 +1161,7 @@ static void ap_sta_ps_start(struct sta_info *sta)
sta->sta.addr, sta->sta.aid);
}
static void ap_sta_ps_end(struct sta_info *sta)
static void sta_ps_end(struct sta_info *sta)
{
ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
sta->sta.addr, sta->sta.aid);
@ -1181,9 +1188,9 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
return -EINVAL;
if (start)
ap_sta_ps_start(sta_inf);
sta_ps_start(sta_inf);
else
ap_sta_ps_end(sta_inf);
sta_ps_end(sta_inf);
return 0;
}
@ -1335,10 +1342,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
*/
if (ieee80211_is_data(hdr->frame_control) &&
!ieee80211_has_pm(hdr->frame_control))
ap_sta_ps_end(sta);
sta_ps_end(sta);
} else {
if (ieee80211_has_pm(hdr->frame_control))
ap_sta_ps_start(sta);
sta_ps_start(sta);
}
}
@ -1384,9 +1391,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
struct sk_buff **skb)
{
struct ieee80211_fragment_entry *entry;
int idx;
idx = sdata->fragment_next;
entry = &sdata->fragments[sdata->fragment_next++];
if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
sdata->fragment_next = 0;
@ -3010,8 +3015,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
WARN_ON_ONCE(softirq_count() == 0);
if (WARN_ON(status->band < 0 ||
status->band >= IEEE80211_NUM_BANDS))
if (WARN_ON(status->band >= IEEE80211_NUM_BANDS))
goto drop;
sband = local->hw.wiphy->bands[status->band];
@ -3056,8 +3060,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
* hardware error. The driver should catch hardware
* errors.
*/
if (WARN((status->rate_idx < 0 ||
status->rate_idx > 76),
if (WARN(status->rate_idx > 76,
"Rate marked as an HT rate but passed "
"status->rate_idx is not "
"an MCS index [0-76]: %d (0x%02x)\n",
@ -3065,8 +3068,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
status->rate_idx))
goto drop;
} else {
if (WARN_ON(status->rate_idx < 0 ||
status->rate_idx >= sband->n_bitrates))
if (WARN_ON(status->rate_idx >= sband->n_bitrates))
goto drop;
rate = &sband->bitrates[status->rate_idx];
}

View File

@ -336,6 +336,10 @@ EXPORT_SYMBOL(ieee80211_scan_completed);
static int ieee80211_start_sw_scan(struct ieee80211_local *local)
{
/* Software scan is not supported in multi-channel cases */
if (local->use_chanctx)
return -EOPNOTSUPP;
/*
* Hardware/driver doesn't support hw_scan, so use software
* scanning instead. First send a nullfunc frame with power save
@ -417,7 +421,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
local->scan_req->ie, local->scan_req->ie_len,
local->scan_req->rates[band], false,
local->scan_req->no_cck,
local->hw.conf.channel);
local->hw.conf.channel, true);
/*
* After sending probe requests, wait for probe responses
@ -462,6 +466,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
sizeof(*local->hw_scan_req) +
req->n_channels * sizeof(req->channels[0]);
local->hw_scan_req->ie = ies;
local->hw_scan_req->flags = req->flags;
local->hw_scan_band = 0;
@ -480,7 +485,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (local->ops->hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning);
} else if ((req->n_channels == 1) &&
(req->channels[0] == local->oper_channel)) {
(req->channels[0] == local->_oper_channel)) {
/*
* If we are scanning only on the operating channel
* then we do not need to stop normal activities
@ -562,6 +567,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
unsigned long min_beacon_int = 0;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_channel *next_chan;
enum mac80211_scan_state next_scan_state;
/*
* check if at least one STA interface is associated,
@ -620,10 +626,18 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
usecs_to_jiffies(min_beacon_int * 1024) *
local->hw.conf.listen_interval);
if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
local->next_scan_state = SCAN_SUSPEND;
else
local->next_scan_state = SCAN_SET_CHANNEL;
if (associated && !tx_empty) {
if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
next_scan_state = SCAN_ABORT;
else
next_scan_state = SCAN_SUSPEND;
} else if (associated && (bad_latency || listen_int_exceeded)) {
next_scan_state = SCAN_SUSPEND;
} else {
next_scan_state = SCAN_SET_CHANNEL;
}
local->next_scan_state = next_scan_state;
*next_delay = 0;
}
@ -794,6 +808,9 @@ void ieee80211_scan_work(struct work_struct *work)
case SCAN_RESUME:
ieee80211_scan_state_resume(local, &next_delay);
break;
case SCAN_ABORT:
aborted = true;
goto out_complete;
}
} while (next_delay == 0);

View File

@ -98,6 +98,7 @@ static void free_sta_work(struct work_struct *wk)
struct tid_ampdu_tx *tid_tx;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct ps_data *ps;
/*
* At this point, when being called as call_rcu callback,
@ -107,11 +108,15 @@ static void free_sta_work(struct work_struct *wk)
*/
if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
BUG_ON(!sdata->bss);
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
else
return;
clear_sta_flag(sta, WLAN_STA_PS_STA);
atomic_dec(&sdata->bss->num_sta_ps);
atomic_dec(&ps->num_sta_ps);
sta_info_recalc_tim(sta);
}
@ -502,22 +507,22 @@ int sta_info_insert(struct sta_info *sta)
return err;
}
static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
static inline void __bss_tim_set(u8 *tim, u16 id)
{
/*
* This format has been mandated by the IEEE specifications,
* so this line may not be changed to use the __set_bit() format.
*/
bss->tim[aid / 8] |= (1 << (aid % 8));
tim[id / 8] |= (1 << (id % 8));
}
static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
static inline void __bss_tim_clear(u8 *tim, u16 id)
{
/*
* This format has been mandated by the IEEE specifications,
* so this line may not be changed to use the __clear_bit() format.
*/
bss->tim[aid / 8] &= ~(1 << (aid % 8));
tim[id / 8] &= ~(1 << (id % 8));
}
static unsigned long ieee80211_tids_for_ac(int ac)
@ -541,14 +546,23 @@ static unsigned long ieee80211_tids_for_ac(int ac)
void sta_info_recalc_tim(struct sta_info *sta)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_if_ap *bss = sta->sdata->bss;
struct ps_data *ps;
unsigned long flags;
bool indicate_tim = false;
u8 ignore_for_tim = sta->sta.uapsd_queues;
int ac;
u16 id;
if (WARN_ON_ONCE(!sta->sdata->bss))
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
if (WARN_ON_ONCE(!sta->sdata->bss))
return;
ps = &sta->sdata->bss->ps;
id = sta->sta.aid;
} else {
return;
}
/* No need to do anything if the driver does all */
if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
@ -587,9 +601,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
spin_lock_irqsave(&local->tim_lock, flags);
if (indicate_tim)
__bss_tim_set(bss, sta->sta.aid);
__bss_tim_set(ps->tim, id);
else
__bss_tim_clear(bss, sta->sta.aid);
__bss_tim_clear(ps->tim, id);
if (local->ops->set_tim) {
local->tim_in_locked_section = true;
@ -893,8 +907,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
continue;
if (time_after(jiffies, sta->last_rx + exp_time)) {
ibss_dbg(sdata, "expiring inactive STA %pM\n",
sta->sta.addr);
sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
sta->sta.addr);
WARN_ON(__sta_info_destroy(sta));
}
}
@ -948,10 +962,17 @@ static void clear_sta_ps_flags(void *_sta)
{
struct sta_info *sta = _sta;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ps_data *ps;
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
else
return;
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
atomic_dec(&sdata->bss->num_sta_ps);
atomic_dec(&ps->num_sta_ps);
}
/* powersave support code */
@ -1008,6 +1029,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
__le16 fc;
bool qos = test_sta_flag(sta, WLAN_STA_WME);
struct ieee80211_tx_info *info;
struct ieee80211_chanctx_conf *chanctx_conf;
if (qos) {
fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
@ -1057,7 +1079,16 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
ieee80211_xmit(sdata, skb);
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock();
kfree_skb(skb);
return;
}
ieee80211_xmit(sdata, skb, chanctx_conf->channel->band);
rcu_read_unlock();
}
static void

View File

@ -189,30 +189,31 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
}
if (ieee80211_is_action(mgmt->frame_control) &&
sdata->vif.type == NL80211_IFTYPE_STATION &&
mgmt->u.action.category == WLAN_CATEGORY_HT &&
mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) {
mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS &&
sdata->vif.type == NL80211_IFTYPE_STATION &&
ieee80211_sdata_running(sdata)) {
/*
* This update looks racy, but isn't -- if we come
* here we've definitely got a station that we're
* talking to, and on a managed interface that can
* only be the AP. And the only other place updating
* this variable is before we're associated.
* this variable in managed mode is before association.
*/
switch (mgmt->u.action.u.ht_smps.smps_control) {
case WLAN_HT_SMPS_CONTROL_DYNAMIC:
sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC;
sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
break;
case WLAN_HT_SMPS_CONTROL_STATIC:
sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC;
sdata->smps_mode = IEEE80211_SMPS_STATIC;
break;
case WLAN_HT_SMPS_CONTROL_DISABLED:
default: /* shouldn't happen since we don't send that */
sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF;
sdata->smps_mode = IEEE80211_SMPS_OFF;
break;
}
ieee80211_queue_work(&local->hw, &local->recalc_smps);
ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
}
}

View File

@ -28,6 +28,20 @@
#define VIF_PR_FMT " vif:%s(%d%s)"
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
#define CHANCTX_ENTRY __field(int, freq) \
__field(int, chantype) \
__field(u8, rx_chains_static) \
__field(u8, rx_chains_dynamic)
#define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq; \
__entry->chantype = ctx->conf.channel_type; \
__entry->rx_chains_static = ctx->conf.rx_chains_static; \
__entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d chains:%d/%d"
#define CHANCTX_PR_ARG __entry->freq, __entry->chantype, \
__entry->rx_chains_static, __entry->rx_chains_dynamic
/*
* Tracing for driver callbacks.
*/
@ -1256,6 +1270,104 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx,
TP_ARGS(local, sdata)
);
DECLARE_EVENT_CLASS(local_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx),
TP_ARGS(local, ctx),
TP_STRUCT__entry(
LOCAL_ENTRY
CHANCTX_ENTRY
),
TP_fast_assign(
LOCAL_ASSIGN;
CHANCTX_ASSIGN;
),
TP_printk(
LOCAL_PR_FMT CHANCTX_PR_FMT,
LOCAL_PR_ARG, CHANCTX_PR_ARG
)
);
DEFINE_EVENT(local_chanctx, drv_add_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx),
TP_ARGS(local, ctx)
);
DEFINE_EVENT(local_chanctx, drv_remove_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx),
TP_ARGS(local, ctx)
);
TRACE_EVENT(drv_change_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
u32 changed),
TP_ARGS(local, ctx, changed),
TP_STRUCT__entry(
LOCAL_ENTRY
CHANCTX_ENTRY
__field(u32, changed)
),
TP_fast_assign(
LOCAL_ASSIGN;
CHANCTX_ASSIGN;
__entry->changed = changed;
),
TP_printk(
LOCAL_PR_FMT CHANCTX_PR_FMT " changed:%#x",
LOCAL_PR_ARG, CHANCTX_PR_ARG, __entry->changed
)
);
DECLARE_EVENT_CLASS(local_sdata_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx),
TP_ARGS(local, sdata, ctx),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
CHANCTX_ENTRY
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
CHANCTX_ASSIGN;
),
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT CHANCTX_PR_FMT,
LOCAL_PR_ARG, VIF_PR_ARG, CHANCTX_PR_ARG
)
);
DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx),
TP_ARGS(local, sdata, ctx)
);
DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx *ctx),
TP_ARGS(local, sdata, ctx)
);
/*
* Tracing for API calls that drivers call.
*/

View File

@ -324,22 +324,20 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
/*
* virtual interfaces are protected by RCU
*/
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
struct ieee80211_if_ap *ap;
if (sdata->vif.type != NL80211_IFTYPE_AP)
struct ps_data *ps;
if (sdata->vif.type == NL80211_IFTYPE_AP)
ps = &sdata->u.ap.ps;
else
continue;
ap = &sdata->u.ap;
skb = skb_dequeue(&ap->ps_bc_buf);
skb = skb_dequeue(&ps->bc_buf);
if (skb) {
purged++;
dev_kfree_skb(skb);
}
total += skb_queue_len(&ap->ps_bc_buf);
total += skb_queue_len(&ps->bc_buf);
}
/*
@ -360,8 +358,6 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
}
}
rcu_read_unlock();
local->total_ps_buffered = total;
ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);
}
@ -371,6 +367,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
struct ps_data *ps;
/*
* broadcast/multicast frame
@ -380,16 +377,24 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
* This is done either by the hardware or us.
*/
/* powersaving STAs only in AP/VLAN mode */
if (!tx->sdata->bss)
/* powersaving STAs currently only in AP/VLAN mode */
if (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
if (!tx->sdata->bss)
return TX_CONTINUE;
ps = &tx->sdata->bss->ps;
} else {
return TX_CONTINUE;
}
/* no buffering for ordered frames */
if (ieee80211_has_order(hdr->frame_control))
return TX_CONTINUE;
/* no stations in PS mode */
if (!atomic_read(&tx->sdata->bss->num_sta_ps))
if (!atomic_read(&ps->num_sta_ps))
return TX_CONTINUE;
info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
@ -404,14 +409,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local);
if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) {
if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) {
ps_dbg(tx->sdata,
"BC TX buffer full - dropping the oldest frame\n");
dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
dev_kfree_skb(skb_dequeue(&ps->bc_buf));
} else
tx->local->total_ps_buffered++;
skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
skb_queue_tail(&ps->bc_buf, tx->skb);
return TX_QUEUED;
}
@ -951,7 +956,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
fragnum = 0;
skb_queue_walk(&tx->skbs, skb) {
int next_len;
const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
hdr = (void *)skb->data;
@ -970,7 +974,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
hdr->frame_control &= ~morefrags;
next_len = 0;
}
hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
fragnum++;
@ -1372,7 +1375,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
* Returns false if the frame couldn't be transmitted but was queued instead.
*/
static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool txpending)
struct sk_buff *skb, bool txpending,
enum ieee80211_band band)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_data tx;
@ -1386,20 +1390,18 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
return true;
}
rcu_read_lock();
/* initialises tx */
led_len = skb->len;
res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
if (unlikely(res_prepare == TX_DROP)) {
ieee80211_free_txskb(&local->hw, skb);
goto out;
return true;
} else if (unlikely(res_prepare == TX_QUEUED)) {
goto out;
return true;
}
info->band = local->hw.conf.channel->band;
info->band = band;
/* set up hw_queue value early */
if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
@ -1410,8 +1412,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
if (!invoke_tx_handlers(&tx))
result = __ieee80211_tx(local, &tx.skbs, led_len,
tx.sta, txpending);
out:
rcu_read_unlock();
return result;
}
@ -1446,7 +1447,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
return 0;
}
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
enum ieee80211_band band)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@ -1454,8 +1456,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
int headroom;
bool may_encrypt;
rcu_read_lock();
may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
headroom = local->tx_headroom;
@ -1466,7 +1466,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
ieee80211_free_txskb(&local->hw, skb);
rcu_read_unlock();
return;
}
@ -1478,13 +1477,11 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
!is_multicast_ether_addr(hdr->addr1) &&
mesh_nexthop_resolve(skb, sdata)) {
/* skb queued: don't free */
rcu_read_unlock();
return;
}
ieee80211_set_qos_hdr(sdata, skb);
ieee80211_tx(sdata, skb, false);
rcu_read_unlock();
ieee80211_tx(sdata, skb, false, band);
}
static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
@ -1574,7 +1571,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_channel *chan = local->hw.conf.channel;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
struct ieee80211_radiotap_header *prthdr =
(struct ieee80211_radiotap_header *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@ -1583,26 +1581,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
u16 len_rthdr;
int hdrlen;
/*
* Frame injection is not allowed if beaconing is not allowed
* or if we need radar detection. Beaconing is usually not allowed when
* the mode or operation (Adhoc, AP, Mesh) does not support DFS.
* Passive scan is also used in world regulatory domains where
* your country is not known and as such it should be treated as
* NO TX unless the channel is explicitly allowed in which case
* your current regulatory domain would not have the passive scan
* flag.
*
* Since AP mode uses monitor interfaces to inject/TX management
* frames we can make AP mode the exception to this rule once it
* supports radar detection as its implementation can deal with
* radar detection by itself. We can do that later by adding a
* monitor flag interfaces used for AP support.
*/
if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_PASSIVE_SCAN)))
goto fail;
/* check for not even having the fixed radiotap header part */
if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
goto fail; /* too short to be possibly valid */
@ -1688,11 +1666,45 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
}
}
ieee80211_xmit(sdata, skb);
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
tmp_sdata = rcu_dereference(local->monitor_sdata);
if (tmp_sdata)
chanctx_conf =
rcu_dereference(tmp_sdata->vif.chanctx_conf);
}
if (!chanctx_conf)
goto fail_rcu;
chan = chanctx_conf->channel;
/*
* Frame injection is not allowed if beaconing is not allowed
* or if we need radar detection. Beaconing is usually not allowed when
* the mode or operation (Adhoc, AP, Mesh) does not support DFS.
* Passive scan is also used in world regulatory domains where
* your country is not known and as such it should be treated as
* NO TX unless the channel is explicitly allowed in which case
* your current regulatory domain would not have the passive scan
* flag.
*
* Since AP mode uses monitor interfaces to inject/TX management
* frames we can make AP mode the exception to this rule once it
* supports radar detection as its implementation can deal with
* radar detection by itself. We can do that later by adding a
* monitor flag interfaces used for AP support.
*/
if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_PASSIVE_SCAN)))
goto fail_rcu;
ieee80211_xmit(sdata, skb, chan->band);
rcu_read_unlock();
return NETDEV_TX_OK;
fail_rcu:
rcu_read_unlock();
fail:
dev_kfree_skb(skb);
return NETDEV_TX_OK; /* meaning, we dealt with the skb */
@ -1734,6 +1746,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
bool multicast;
u32 info_flags = 0;
u16 info_id = 0;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_sub_if_data *ap_sdata;
enum ieee80211_band band;
if (unlikely(skb->len < ETH_HLEN))
goto fail;
@ -1743,9 +1758,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
ethertype = (skb->data[12] << 8) | skb->data[13];
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
rcu_read_lock();
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
rcu_read_lock();
sta = rcu_dereference(sdata->u.vlan.sta);
if (sta) {
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@ -1758,7 +1774,12 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
wme_sta = test_sta_flag(sta, WLAN_STA_WME);
}
rcu_read_unlock();
ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
u.ap);
chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
band = chanctx_conf->channel->band;
if (sta)
break;
/* fall through */
@ -1769,6 +1790,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 24;
if (sdata->vif.type == NL80211_IFTYPE_AP)
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
band = chanctx_conf->channel->band;
break;
case NL80211_IFTYPE_WDS:
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@ -1778,15 +1804,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr3, skb->data, ETH_ALEN);
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 30;
/*
* This is the exception! WDS style interfaces are prohibited
* when channel contexts are in used so this must be valid
*/
band = local->hw.conf.channel->band;
break;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
/* Do not send frames with mesh_ttl == 0 */
sdata->u.mesh.mshstats.dropped_frames_ttl++;
goto fail;
goto fail_rcu;
}
rcu_read_lock();
if (!is_multicast_ether_addr(skb->data)) {
mpath = mesh_path_lookup(skb->data, sdata);
if (!mpath)
@ -1803,7 +1834,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
!(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
skb->data, skb->data + ETH_ALEN);
rcu_read_unlock();
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
sdata, NULL, NULL);
} else {
@ -1819,7 +1849,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
mesh_da = mppath->mpp;
else if (mpath)
mesh_da = mpath->dst;
rcu_read_unlock();
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
mesh_da, sdata->vif.addr);
@ -1839,13 +1868,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
skb->data + ETH_ALEN);
}
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
band = chanctx_conf->channel->band;
break;
#endif
case NL80211_IFTYPE_STATION:
if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
bool tdls_peer = false;
rcu_read_lock();
sta = sta_info_get(sdata, skb->data);
if (sta) {
authorized = test_sta_flag(sta,
@ -1856,7 +1888,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
tdls_auth = test_sta_flag(sta,
WLAN_STA_TDLS_PEER_AUTH);
}
rcu_read_unlock();
/*
* If the TDLS link is enabled, send everything
@ -1871,7 +1902,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (tdls_direct) {
/* link during setup - throw out frames to peer */
if (!tdls_auth)
goto fail;
goto fail_rcu;
/* DA SA BSSID */
memcpy(hdr.addr1, skb->data, ETH_ALEN);
@ -1896,6 +1927,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr3, skb->data, ETH_ALEN);
hdrlen = 24;
}
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
band = chanctx_conf->channel->band;
break;
case NL80211_IFTYPE_ADHOC:
/* DA SA BSSID */
@ -1903,9 +1938,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
hdrlen = 24;
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf)
goto fail_rcu;
band = chanctx_conf->channel->band;
break;
default:
goto fail;
goto fail_rcu;
}
/*
@ -1915,13 +1954,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
*/
multicast = is_multicast_ether_addr(hdr.addr1);
if (!multicast) {
rcu_read_lock();
sta = sta_info_get(sdata, hdr.addr1);
if (sta) {
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
wme_sta = test_sta_flag(sta, WLAN_STA_WME);
}
rcu_read_unlock();
}
/* For mesh, the use of the QoS header is mandatory */
@ -1949,7 +1986,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
goto fail;
goto fail_rcu;
}
if (unlikely(!multicast && skb->sk &&
@ -2004,7 +2041,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
kfree_skb(tmp_skb);
if (!skb)
goto fail;
goto fail_rcu;
}
hdr.frame_control = fc;
@ -2052,7 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
head_need = max_t(int, 0, head_need);
if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
ieee80211_free_txskb(&local->hw, skb);
return NETDEV_TX_OK;
goto fail_rcu;
}
}
@ -2104,10 +2141,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
info->flags = info_flags;
info->ack_frame_id = info_id;
ieee80211_xmit(sdata, skb);
ieee80211_xmit(sdata, skb, band);
rcu_read_unlock();
return NETDEV_TX_OK;
fail_rcu:
rcu_read_unlock();
fail:
dev_kfree_skb(skb);
return NETDEV_TX_OK;
@ -2139,11 +2179,18 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
struct sta_info *sta;
struct ieee80211_hdr *hdr;
bool result;
struct ieee80211_chanctx_conf *chanctx_conf;
sdata = vif_to_sdata(info->control.vif);
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
result = ieee80211_tx(sdata, skb, true);
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (unlikely(!chanctx_conf)) {
dev_kfree_skb(skb);
return true;
}
result = ieee80211_tx(sdata, skb, true,
chanctx_conf->channel->band);
} else {
struct sk_buff_head skbs;
@ -2211,9 +2258,8 @@ void ieee80211_tx_pending(unsigned long data)
/* functions for drivers to get certain frames */
static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ap *bss,
struct sk_buff *skb,
struct beacon_data *beacon)
struct ps_data *ps,
struct sk_buff *skb)
{
u8 *pos, *tim;
int aid0 = 0;
@ -2221,27 +2267,27 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
/* Generate bitmap for TIM only if there are any STAs in power save
* mode. */
if (atomic_read(&bss->num_sta_ps) > 0)
if (atomic_read(&ps->num_sta_ps) > 0)
/* in the hope that this is faster than
* checking byte-for-byte */
have_bits = !bitmap_empty((unsigned long*)bss->tim,
have_bits = !bitmap_empty((unsigned long*)ps->tim,
IEEE80211_MAX_AID+1);
if (bss->dtim_count == 0)
bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
if (ps->dtim_count == 0)
ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
else
bss->dtim_count--;
ps->dtim_count--;
tim = pos = (u8 *) skb_put(skb, 6);
*pos++ = WLAN_EID_TIM;
*pos++ = 4;
*pos++ = bss->dtim_count;
*pos++ = ps->dtim_count;
*pos++ = sdata->vif.bss_conf.dtim_period;
if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf))
aid0 = 1;
bss->dtim_bc_mc = aid0 == 1;
ps->dtim_bc_mc = aid0 == 1;
if (have_bits) {
/* Find largest even number N1 so that bits numbered 1 through
@ -2249,14 +2295,14 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
* (N2 + 1) x 8 through 2007 are 0. */
n1 = 0;
for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
if (bss->tim[i]) {
if (ps->tim[i]) {
n1 = i & 0xfe;
break;
}
}
n2 = n1;
for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
if (bss->tim[i]) {
if (ps->tim[i]) {
n2 = i;
break;
}
@ -2266,7 +2312,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
*pos++ = n1 | aid0;
/* Part Virt Bitmap */
skb_put(skb, n2 - n1);
memcpy(pos, bss->tim + n1, n2 - n1 + 1);
memcpy(pos, ps->tim + n1, n2 - n1 + 1);
tim[1] = n2 - n1 + 4;
} else {
@ -2283,16 +2329,16 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info;
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
struct beacon_data *beacon;
enum ieee80211_band band = local->oper_channel->band;
enum ieee80211_band band;
struct ieee80211_tx_rate_control txrc;
struct ieee80211_chanctx_conf *chanctx_conf;
rcu_read_lock();
sdata = vif_to_sdata(vif);
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!ieee80211_sdata_running(sdata))
if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
goto out;
if (tim_offset)
@ -2301,8 +2347,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
*tim_length = 0;
if (sdata->vif.type == NL80211_IFTYPE_AP) {
ap = &sdata->u.ap;
beacon = rcu_dereference(ap->beacon);
struct ieee80211_if_ap *ap = &sdata->u.ap;
struct beacon_data *beacon = rcu_dereference(ap->beacon);
if (beacon) {
/*
* headroom, head length,
@ -2326,14 +2373,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
* of the tim bitmap in mac80211 and the driver.
*/
if (local->tim_in_locked_section) {
ieee80211_beacon_add_tim(sdata, ap, skb,
beacon);
ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
} else {
unsigned long flags;
spin_lock_irqsave(&local->tim_lock, flags);
ieee80211_beacon_add_tim(sdata, ap, skb,
beacon);
ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
spin_unlock_irqrestore(&local->tim_lock, flags);
}
@ -2409,6 +2454,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;
band = chanctx_conf->channel->band;
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(skb, sdata) ||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@ -2426,6 +2473,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
goto out;
}
band = chanctx_conf->channel->band;
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@ -2653,29 +2702,40 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
struct sk_buff *skb = NULL;
struct ieee80211_tx_data tx;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
struct beacon_data *beacon;
struct ps_data *ps;
struct ieee80211_tx_info *info;
struct ieee80211_chanctx_conf *chanctx_conf;
sdata = vif_to_sdata(vif);
bss = &sdata->u.ap;
rcu_read_lock();
beacon = rcu_dereference(bss->beacon);
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head)
if (!chanctx_conf)
goto out;
if (bss->dtim_count != 0 || !bss->dtim_bc_mc)
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct beacon_data *beacon =
rcu_dereference(sdata->u.ap.beacon);
if (!beacon || !beacon->head)
goto out;
ps = &sdata->u.ap.ps;
} else {
goto out;
}
if (ps->dtim_count != 0 || !ps->dtim_bc_mc)
goto out; /* send buffered bc/mc only after DTIM beacon */
while (1) {
skb = skb_dequeue(&bss->ps_bc_buf);
skb = skb_dequeue(&ps->bc_buf);
if (!skb)
goto out;
local->total_ps_buffered--;
if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
if (!skb_queue_empty(&ps->bc_buf) && skb->len >= 2) {
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *) skb->data;
/* more buffered multicast/broadcast frames ==> set
@ -2693,7 +2753,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);
tx.flags |= IEEE80211_TX_PS_BUFFERED;
info->band = local->oper_channel->band;
info->band = chanctx_conf->channel->band;
if (invoke_tx_handlers(&tx))
skb = NULL;
@ -2704,8 +2764,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_get_buffered_bc);
void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid)
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid,
enum ieee80211_band band)
{
int ac = ieee802_1d_to_ac[tid & 7];
@ -2722,6 +2783,6 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
* requirements are that we do not come into tx with bhs on.
*/
local_bh_disable();
ieee80211_xmit(sdata, skb);
ieee80211_xmit(sdata, skb, band);
local_bh_enable();
}

View File

@ -741,6 +741,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
else
elem_parse_failed = true;
break;
case WLAN_EID_VHT_CAPABILITY:
if (elen >= sizeof(struct ieee80211_vht_cap))
elems->vht_cap_elem = (void *)pos;
else
elem_parse_failed = true;
break;
case WLAN_EID_VHT_OPERATION:
if (elen >= sizeof(struct ieee80211_vht_operation))
elems->vht_operation = (void *)pos;
else
elem_parse_failed = true;
break;
case WLAN_EID_MESH_ID:
elems->mesh_id = pos;
elems->mesh_id_len = elen;
@ -832,6 +844,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
struct ieee80211_chanctx_conf *chanctx_conf;
int ac;
bool use_11b, enable_qos;
int aCWmin, aCWmax;
@ -844,8 +857,12 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
memset(&qparam, 0, sizeof(qparam));
use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) &&
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
use_11b = (chanctx_conf &&
chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
rcu_read_unlock();
/*
* By default disable QoS in STA mode for old access points, which do
@ -924,7 +941,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
const size_t supp_rates_len,
const u8 *supp_rates)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
int i, have_higher_than_11mbit = 0;
/* cf. IEEE 802.11 9.2.12 */
@ -932,11 +949,16 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
if ((supp_rates[i] & 0x7f) * 5 > 110)
have_higher_than_11mbit = 1;
if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf &&
chanctx_conf->channel->band == IEEE80211_BAND_2GHZ &&
have_higher_than_11mbit)
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
rcu_read_unlock();
ieee80211_set_wmm_default(sdata, true);
}
@ -968,7 +990,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
}
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
u16 transaction, u16 auth_alg, u16 status,
u8 *extra, size_t extra_len, const u8 *da,
const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx)
{
@ -993,7 +1015,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
memcpy(mgmt->bssid, bssid, ETH_ALEN);
mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
mgmt->u.auth.status_code = cpu_to_le16(0);
mgmt->u.auth.status_code = cpu_to_le16(status);
if (extra)
memcpy(skb_put(skb, extra_len), extra, extra_len);
@ -1206,7 +1228,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len,
u32 ratemask, bool directed, bool no_cck,
struct ieee80211_channel *channel)
struct ieee80211_channel *channel, bool scan)
{
struct sk_buff *skb;
@ -1217,7 +1239,10 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
if (no_cck)
IEEE80211_SKB_CB(skb)->flags |=
IEEE80211_TX_CTL_NO_CCK_RATE;
ieee80211_tx_skb(sdata, skb);
if (scan)
ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);
else
ieee80211_tx_skb(sdata, skb);
}
}
@ -1280,6 +1305,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
{
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_chanctx *ctx;
struct sta_info *sta;
int res, i;
@ -1352,6 +1378,12 @@ int ieee80211_reconfig(struct ieee80211_local *local)
res = drv_add_interface(local, sdata);
}
/* add channel contexts */
mutex_lock(&local->chanctx_mtx);
list_for_each_entry(ctx, &local->chanctx_list, list)
WARN_ON(drv_add_chanctx(local, ctx));
mutex_unlock(&local->chanctx_mtx);
/* add STAs back */
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
@ -1392,11 +1424,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
struct ieee80211_chanctx_conf *ctx_conf;
u32 changed;
if (!ieee80211_sdata_running(sdata))
continue;
mutex_lock(&local->chanctx_mtx);
ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (ctx_conf) {
ctx = container_of(ctx_conf, struct ieee80211_chanctx,
conf);
drv_assign_vif_chanctx(local, sdata, ctx);
}
mutex_unlock(&local->chanctx_mtx);
/* common change flags for all interface types */
changed = BSS_CHANGED_ERP_CTS_PROT |
BSS_CHANGED_ERP_PREAMBLE |
@ -1587,68 +1630,24 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
}
EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
enum ieee80211_smps_mode *smps_mode)
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
{
if (ifmgd->associated) {
*smps_mode = ifmgd->ap_smps;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
if (ifmgd->powersave)
*smps_mode = IEEE80211_SMPS_DYNAMIC;
else
*smps_mode = IEEE80211_SMPS_OFF;
}
mutex_lock(&local->chanctx_mtx);
return 1;
}
chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
return 0;
}
void ieee80211_recalc_smps(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
int count = 0;
mutex_lock(&local->iflist_mtx);
/*
* This function could be improved to handle multiple
* interfaces better, but right now it makes any
* non-station interfaces force SM PS to be turned
* off. If there are multiple station interfaces it
* could also use the best possible mode, e.g. if
* one is in static and the other in dynamic then
* dynamic is ok.
*/
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
continue;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
goto set;
count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
if (count > 1) {
smps_mode = IEEE80211_SMPS_OFF;
break;
}
}
if (smps_mode == local->smps_mode)
if (WARN_ON_ONCE(!chanctx_conf))
goto unlock;
set:
local->smps_mode = smps_mode;
/* changed flag is auto-detected for this */
ieee80211_hw_config(local, 0);
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
ieee80211_recalc_smps_chanctx(local, chanctx);
unlock:
mutex_unlock(&local->iflist_mtx);
mutex_unlock(&local->chanctx_mtx);
}
static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
@ -1788,8 +1787,8 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
__le32 tmp;
*pos++ = WLAN_EID_VHT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_vht_capabilities);
memset(pos, 0, sizeof(struct ieee80211_vht_capabilities));
*pos++ = sizeof(struct ieee80211_vht_cap);
memset(pos, 0, sizeof(struct ieee80211_vht_cap));
/* capability flags */
tmp = cpu_to_le32(cap);
@ -1947,3 +1946,19 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif)
return ifmgd->ave_beacon_signal;
}
EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs)
{
if (!mcs)
return 1;
/* TODO: consider rx_highest */
if (mcs->rx_mask[3])
return 4;
if (mcs->rx_mask[2])
return 3;
if (mcs->rx_mask[1])
return 2;
return 1;
}

35
net/mac80211/vht.c Normal file
View File

@ -0,0 +1,35 @@
/*
* VHT handling
*
* 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
* published by the Free Software Foundation.
*/
#include <linux/ieee80211.h>
#include <linux/export.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
struct ieee80211_vht_cap *vht_cap_ie,
struct ieee80211_sta_vht_cap *vht_cap)
{
if (WARN_ON_ONCE(!vht_cap))
return;
memset(vht_cap, 0, sizeof(*vht_cap));
if (!vht_cap_ie || !sband->vht_cap.vht_supported)
return;
vht_cap->vht_supported = true;
vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
/* Copy peer MCS info, the driver might need them. */
memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
sizeof(struct ieee80211_vht_mcs_info));
}

View File

@ -10,11 +10,13 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
CFLAGS_trace.o := -I$(src)
ccflags-y += -D__CHECK_ENDIAN__
$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk

View File

@ -3,6 +3,7 @@
#include <net/cfg80211.h>
#include "nl80211.h"
#include "core.h"
#include "rdev-ops.h"
static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
@ -23,7 +24,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
if (!wdev->beacon_interval)
return -ENOENT;
err = rdev->ops->stop_ap(&rdev->wiphy, dev);
err = rdev_stop_ap(rdev, dev);
if (!err) {
wdev->beacon_interval = 0;
wdev->channel = NULL;

View File

@ -9,6 +9,7 @@
#include <linux/export.h>
#include <net/cfg80211.h>
#include "core.h"
#include "rdev-ops.h"
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
@ -52,6 +53,8 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
struct ieee80211_channel *sec_chan;
int diff;
trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type);
switch (channel_type) {
case NL80211_CHAN_HT40PLUS:
diff = 20;
@ -60,20 +63,25 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
diff = -20;
break;
default:
trace_cfg80211_return_bool(true);
return true;
}
sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
if (!sec_chan)
if (!sec_chan) {
trace_cfg80211_return_bool(false);
return false;
}
/* we'll need a DFS capability later */
if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_PASSIVE_SCAN |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_RADAR))
IEEE80211_CHAN_RADAR)) {
trace_cfg80211_return_bool(false);
return false;
}
trace_cfg80211_return_bool(true);
return true;
}
EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
@ -92,7 +100,7 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
if (!chan)
return -EINVAL;
return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
return rdev_set_monitor_channel(rdev, chan, chantype);
}
void

View File

@ -26,6 +26,7 @@
#include "debugfs.h"
#include "wext-compat.h"
#include "ethtool.h"
#include "rdev-ops.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@ -216,7 +217,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
{
struct cfg80211_registered_device *rdev = data;
rdev->ops->rfkill_poll(&rdev->wiphy);
rdev_rfkill_poll(rdev);
}
static int cfg80211_rfkill_set_block(void *data, bool blocked)
@ -370,6 +371,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
rdev->wiphy.rts_threshold = (u32) -1;
rdev->wiphy.coverage_class = 0;
rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
return &rdev->wiphy;
}
EXPORT_SYMBOL(wiphy_new);
@ -688,7 +691,7 @@ void wiphy_unregister(struct wiphy *wiphy)
flush_work(&rdev->event_work);
if (rdev->wowlan && rdev->ops->set_wakeup)
rdev->ops->set_wakeup(&rdev->wiphy, false);
rdev_set_wakeup(rdev, false);
cfg80211_rdev_free_wowlan(rdev);
}
EXPORT_SYMBOL(wiphy_unregister);
@ -962,9 +965,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
rdev->ops->set_power_mgmt)
if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
wdev->ps,
wdev->ps_timeout)) {
if (rdev_set_power_mgmt(rdev, dev, wdev->ps,
wdev->ps_timeout)) {
/* assume this means it's off */
wdev->ps = false;
}

View File

@ -320,13 +320,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx);
const u8 *key, int key_len, int key_idx,
const u8 *sae_data, int sae_data_len);
int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct ieee80211_channel *chan,
enum nl80211_auth_type auth_type, const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx);
const u8 *key, int key_len, int key_idx,
const u8 *sae_data, int sae_data_len);
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,

View File

@ -2,6 +2,7 @@
#include <net/cfg80211.h>
#include "core.h"
#include "ethtool.h"
#include "rdev-ops.h"
static void cfg80211_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
@ -47,9 +48,8 @@ static void cfg80211_get_ringparam(struct net_device *dev,
memset(rp, 0, sizeof(*rp));
if (rdev->ops->get_ringparam)
rdev->ops->get_ringparam(wdev->wiphy,
&rp->tx_pending, &rp->tx_max_pending,
&rp->rx_pending, &rp->rx_max_pending);
rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending,
&rp->rx_pending, &rp->rx_max_pending);
}
static int cfg80211_set_ringparam(struct net_device *dev,
@ -62,8 +62,7 @@ static int cfg80211_set_ringparam(struct net_device *dev,
return -EINVAL;
if (rdev->ops->set_ringparam)
return rdev->ops->set_ringparam(wdev->wiphy,
rp->tx_pending, rp->rx_pending);
return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending);
return -ENOTSUPP;
}
@ -73,7 +72,7 @@ static int cfg80211_get_sset_count(struct net_device *dev, int sset)
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
if (rdev->ops->get_et_sset_count)
return rdev->ops->get_et_sset_count(wdev->wiphy, dev, sset);
return rdev_get_et_sset_count(rdev, dev, sset);
return -EOPNOTSUPP;
}
@ -83,7 +82,7 @@ static void cfg80211_get_stats(struct net_device *dev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
if (rdev->ops->get_et_stats)
rdev->ops->get_et_stats(wdev->wiphy, dev, stats, data);
rdev_get_et_stats(rdev, dev, stats, data);
}
static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
@ -91,7 +90,7 @@ static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
if (rdev->ops->get_et_strings)
rdev->ops->get_et_strings(wdev->wiphy, dev, sset, data);
rdev_get_et_strings(rdev, dev, sset, data);
}
const struct ethtool_ops cfg80211_ethtool_ops = {

View File

@ -11,6 +11,7 @@
#include <net/cfg80211.h>
#include "wext-compat.h"
#include "nl80211.h"
#include "rdev-ops.h"
void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
@ -61,6 +62,8 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
struct cfg80211_event *ev;
unsigned long flags;
trace_cfg80211_ibss_joined(dev, bssid);
CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
ev = kzalloc(sizeof(*ev), gfp);
@ -128,7 +131,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
return err;
}
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
err = rdev_join_ibss(rdev, dev, params);
if (err) {
wdev->connect_keys = NULL;
wdev->sme_state = CFG80211_SME_IDLE;
@ -175,7 +178,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
*/
if (rdev->ops->del_key)
for (i = 0; i < 6; i++)
rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
rdev_del_key(rdev, dev, i, false, NULL);
if (wdev->current_bss) {
cfg80211_unhold_bss(wdev->current_bss);
@ -211,7 +214,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
if (!wdev->ssid_len)
return -ENOLINK;
err = rdev->ops->leave_ibss(&rdev->wiphy, dev);
err = rdev_leave_ibss(rdev, dev);
if (err)
return err;

View File

@ -3,6 +3,7 @@
#include <net/cfg80211.h>
#include "nl80211.h"
#include "core.h"
#include "rdev-ops.h"
/* Default values, timeouts in ms */
#define MESH_TTL 31
@ -160,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (err)
return err;
err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
err = rdev_join_mesh(rdev, dev, conf, setup);
if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
wdev->mesh_id_len = setup->mesh_id_len;
@ -220,9 +221,8 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
if (err)
return err;
err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
wdev->netdev,
channel);
err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
channel);
if (!err)
wdev->channel = channel;
@ -242,6 +242,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
trace_cfg80211_notify_new_peer_candidate(dev, macaddr);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
return;
@ -267,7 +268,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
if (!wdev->mesh_id_len)
return -ENOTCONN;
err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
err = rdev_leave_mesh(rdev, dev);
if (!err) {
wdev->mesh_id_len = 0;
wdev->channel = NULL;

View File

@ -15,6 +15,8 @@
#include <net/iw_handler.h>
#include "core.h"
#include "nl80211.h"
#include "rdev-ops.h"
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
{
@ -22,6 +24,7 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_send_rx_auth(dev);
wdev_lock(wdev);
nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
@ -42,6 +45,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
u8 *ie = mgmt->u.assoc_resp.variable;
int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
trace_cfg80211_send_rx_assoc(dev, bss);
wdev_lock(wdev);
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
@ -98,6 +102,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
const u8 *bssid = mgmt->bssid;
bool was_current = false;
trace___cfg80211_send_deauth(dev);
ASSERT_WDEV_LOCK(wdev);
if (wdev->current_bss &&
@ -147,6 +152,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
u16 reason_code;
bool from_ap;
trace___cfg80211_send_disassoc(dev);
ASSERT_WDEV_LOCK(wdev);
nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
@ -188,6 +194,7 @@ void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_send_unprot_deauth(dev);
nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC);
}
EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
@ -199,6 +206,7 @@ void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_send_unprot_disassoc(dev);
nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC);
}
EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
@ -209,6 +217,7 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_send_auth_timeout(dev, addr);
wdev_lock(wdev);
nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
@ -227,6 +236,7 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_send_assoc_timeout(dev, addr);
wdev_lock(wdev);
nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
@ -261,6 +271,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
}
#endif
trace_cfg80211_michael_mic_failure(dev, addr, key_type, key_id, tsc);
nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
}
EXPORT_SYMBOL(cfg80211_michael_mic_failure);
@ -273,7 +284,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx)
const u8 *key, int key_len, int key_idx,
const u8 *sae_data, int sae_data_len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_auth_request req;
@ -293,6 +305,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
req.ie = ie;
req.ie_len = ie_len;
req.sae_data = sae_data;
req.sae_data_len = sae_data_len;
req.auth_type = auth_type;
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@ -307,7 +321,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
if (err)
goto out;
err = rdev->ops->auth(&rdev->wiphy, dev, &req);
err = rdev_auth(rdev, dev, &req);
out:
cfg80211_put_bss(req.bss);
@ -319,7 +333,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
enum nl80211_auth_type auth_type, const u8 *bssid,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx)
const u8 *key, int key_len, int key_idx,
const u8 *sae_data, int sae_data_len)
{
int err;
@ -327,7 +342,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
wdev_lock(dev->ieee80211_ptr);
err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
key, key_len, key_idx);
key, key_len, key_idx,
sae_data, sae_data_len);
wdev_unlock(dev->ieee80211_ptr);
mutex_unlock(&rdev->devlist_mtx);
@ -410,7 +426,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
if (err)
goto out;
err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
err = rdev_assoc(rdev, dev, &req);
out:
if (err) {
@ -472,7 +488,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
return 0;
}
return rdev->ops->deauth(&rdev->wiphy, dev, &req);
return rdev_deauth(rdev, dev, &req);
}
int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
@ -517,7 +533,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
else
return -ENOTCONN;
return rdev->ops->disassoc(&rdev->wiphy, dev, &req);
return rdev_disassoc(rdev, dev, &req);
}
int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
@ -558,7 +574,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
req.bssid = bssid;
rdev->ops->deauth(&rdev->wiphy, dev, &req);
rdev_deauth(rdev, dev, &req);
if (wdev->current_bss) {
cfg80211_unhold_bss(wdev->current_bss);
@ -575,6 +591,8 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type,
duration);
nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type,
duration, gfp);
}
@ -588,6 +606,8 @@ void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan,
channel_type);
nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan,
channel_type, gfp);
}
@ -599,6 +619,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_new_sta(dev, mac_addr, sinfo);
nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
}
EXPORT_SYMBOL(cfg80211_new_sta);
@ -608,6 +629,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_del_sta(dev, mac_addr);
nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp);
}
EXPORT_SYMBOL(cfg80211_del_sta);
@ -688,7 +710,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
list_add(&nreg->list, &wdev->mgmt_registrations);
if (rdev->ops->mgmt_frame_register)
rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true);
rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
out:
spin_unlock_bh(&wdev->mgmt_registrations_lock);
@ -711,8 +733,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
if (rdev->ops->mgmt_frame_register) {
u16 frame_type = le16_to_cpu(reg->frame_type);
rdev->ops->mgmt_frame_register(wiphy, wdev,
frame_type, false);
rdev_mgmt_frame_register(rdev, wdev,
frame_type, false);
}
list_del(&reg->list);
@ -838,10 +860,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return -EINVAL;
/* Transmit the Action frame as requested by user space */
return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
channel_type, channel_type_valid,
wait, buf, len, no_cck, dont_wait_for_ack,
cookie);
return rdev_mgmt_tx(rdev, wdev, chan, offchan,
channel_type, channel_type_valid,
wait, buf, len, no_cck, dont_wait_for_ack,
cookie);
}
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
@ -860,10 +882,13 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
u16 stype;
trace_cfg80211_rx_mgmt(wdev, freq, sig_mbm);
stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
if (!(stypes->rx & BIT(stype)))
if (!(stypes->rx & BIT(stype))) {
trace_cfg80211_return_bool(false);
return false;
}
data = buf + ieee80211_hdrlen(mgmt->frame_control);
data_len = len - ieee80211_hdrlen(mgmt->frame_control);
@ -894,6 +919,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
spin_unlock_bh(&wdev->mgmt_registrations_lock);
trace_cfg80211_return_bool(result);
return result;
}
EXPORT_SYMBOL(cfg80211_rx_mgmt);
@ -904,6 +930,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
/* Indicate TX status of the Action frame to user space */
nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp);
}
@ -917,6 +945,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
/* Indicate roaming trigger event to user space */
nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
}
@ -929,6 +959,8 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
/* Indicate roaming trigger event to user space */
nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
}
@ -954,6 +986,7 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_gtk_rekey_notify(dev, bssid);
nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
}
EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
@ -965,6 +998,7 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
}
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
@ -977,6 +1011,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct ieee80211_channel *chan;
trace_cfg80211_ch_switch_notify(dev, freq, type);
wdev_lock(wdev);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
@ -999,12 +1035,18 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
bool ret;
trace_cfg80211_rx_spurious_frame(dev, addr);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO))
wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
trace_cfg80211_return_bool(false);
return false;
return nl80211_unexpected_frame(dev, addr, gfp);
}
ret = nl80211_unexpected_frame(dev, addr, gfp);
trace_cfg80211_return_bool(ret);
return ret;
}
EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
@ -1012,12 +1054,18 @@ bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
bool ret;
trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO &&
wdev->iftype != NL80211_IFTYPE_AP_VLAN))
wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
trace_cfg80211_return_bool(false);
return false;
return nl80211_unexpected_4addr_frame(dev, addr, gfp);
}
ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
trace_cfg80211_return_bool(ret);
return ret;
}
EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);

View File

@ -22,8 +22,8 @@
#include "core.h"
#include "nl80211.h"
#include "reg.h"
#include "rdev-ops.h"
static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type);
static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
struct genl_info *info,
struct cfg80211_crypto_settings *settings,
@ -355,6 +355,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@ -690,7 +693,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
static struct cfg80211_cached_keys *
nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
struct nlattr *keys)
struct nlattr *keys, bool *no_ht)
{
struct key_parse parse;
struct nlattr *key;
@ -733,6 +736,12 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
result->params[parse.idx].key_len = parse.p.key_len;
result->params[parse.idx].key = result->data[parse.idx];
memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
if (parse.p.cipher == WLAN_CIPHER_SUITE_WEP40 ||
parse.p.cipher == WLAN_CIPHER_SUITE_WEP104) {
if (no_ht)
*no_ht = true;
}
}
return result;
@ -943,7 +952,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag
dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
u32 tx_ant = 0, rx_ant = 0;
int res;
res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant);
res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
if (!res) {
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX,
tx_ant) ||
@ -1457,7 +1466,7 @@ static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP;
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid);
return rdev_set_wds_peer(rdev, dev, bssid);
}
@ -1562,9 +1571,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
if (result)
goto bad_res;
result = rdev->ops->set_txq_params(&rdev->wiphy,
netdev,
&txq_params);
result = rdev_set_txq_params(rdev, netdev,
&txq_params);
if (result)
goto bad_res;
}
@ -1599,7 +1607,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
mbm = nla_get_u32(info->attrs[idx]);
}
result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
result = rdev_set_tx_power(rdev, type, mbm);
if (result)
goto bad_res;
}
@ -1628,7 +1636,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant);
result = rdev_set_antenna(rdev, tx_ant, rx_ant);
if (result)
goto bad_res;
}
@ -1713,7 +1721,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
if (changed & WIPHY_PARAM_COVERAGE_CLASS)
rdev->wiphy.coverage_class = coverage_class;
result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed);
result = rdev_set_wiphy_params(rdev, changed);
if (result) {
rdev->wiphy.retry_short = old_retry_short;
rdev->wiphy.retry_long = old_retry_long;
@ -1765,8 +1773,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type;
chan = rdev->ops->get_channel(&rdev->wiphy, wdev,
&channel_type);
chan = rdev_get_channel(rdev, wdev, &channel_type);
if (chan &&
(nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chan->center_freq) ||
@ -2014,9 +2021,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
wdev = rdev->ops->add_virtual_intf(&rdev->wiphy,
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params);
wdev = rdev_add_virtual_intf(rdev,
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params);
if (IS_ERR(wdev)) {
nlmsg_free(msg);
return PTR_ERR(wdev);
@ -2083,7 +2090,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
if (!wdev->netdev)
info->user_ptr[1] = NULL;
return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev);
return rdev_del_virtual_intf(rdev, wdev);
}
static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
@ -2100,7 +2107,7 @@ static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
return rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map);
return rdev_set_noack_map(rdev, dev, noack_map);
}
struct get_key_cookie {
@ -2210,8 +2217,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
!(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
return -ENOENT;
err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise,
mac_addr, &cookie, get_key_callback);
err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
get_key_callback);
if (err)
goto free_msg;
@ -2259,7 +2266,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out;
err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx,
err = rdev_set_default_key(rdev, dev, key.idx,
key.def_uni, key.def_multi);
if (err)
@ -2283,8 +2290,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out;
err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
dev, key.idx);
err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
if (err)
goto out;
@ -2340,9 +2346,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr);
if (!err)
err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE,
mac_addr, &key.p);
err = rdev_add_key(rdev, dev, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE,
mac_addr, &key.p);
wdev_unlock(dev->ieee80211_ptr);
return err;
@ -2386,9 +2392,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
err = -ENOENT;
if (!err)
err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE,
mac_addr);
err = rdev_del_key(rdev, dev, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE,
mac_addr);
#ifdef CONFIG_CFG80211_WEXT
if (!err) {
@ -2490,6 +2496,30 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
return ret;
}
static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
enum nl80211_auth_type auth_type,
enum nl80211_commands cmd)
{
if (auth_type > NL80211_AUTHTYPE_MAX)
return false;
switch (cmd) {
case NL80211_CMD_AUTHENTICATE:
if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
auth_type == NL80211_AUTHTYPE_SAE)
return false;
return true;
case NL80211_CMD_CONNECT:
case NL80211_CMD_START_AP:
/* SAE not supported yet */
if (auth_type == NL80211_AUTHTYPE_SAE)
return false;
return true;
default:
return false;
}
}
static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@ -2559,7 +2589,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
params.auth_type = nla_get_u32(
info->attrs[NL80211_ATTR_AUTH_TYPE]);
if (!nl80211_valid_auth_type(params.auth_type))
if (!nl80211_valid_auth_type(rdev, params.auth_type,
NL80211_CMD_START_AP))
return -EINVAL;
} else
params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@ -2607,7 +2638,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
err = rdev_start_ap(rdev, dev, &params);
if (!err) {
wdev->preset_chan = params.channel;
wdev->preset_chantype = params.channel_type;
@ -2639,7 +2670,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
return rdev_change_beacon(rdev, dev, &params);
}
static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
@ -2923,8 +2954,8 @@ static int nl80211_dump_station(struct sk_buff *skb,
while (1) {
memset(&sinfo, 0, sizeof(sinfo));
err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
mac_addr, &sinfo);
err = rdev_dump_station(dev, netdev, sta_idx,
mac_addr, &sinfo);
if (err == -ENOENT)
break;
if (err)
@ -2969,7 +3000,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->get_station)
return -EOPNOTSUPP;
err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
if (err)
return err;
@ -3146,7 +3177,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
/* be aware of params.vlan when changing code here */
err = rdev->ops->change_station(&rdev->wiphy, dev, mac_addr, &params);
err = rdev_change_station(rdev, dev, mac_addr, &params);
if (params.vlan)
dev_put(params.vlan);
@ -3198,6 +3229,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
params.vht_capa =
nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
params.plink_action =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
@ -3275,7 +3310,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
/* be aware of params.vlan when changing code here */
err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
err = rdev_add_station(rdev, dev, mac_addr, &params);
if (params.vlan)
dev_put(params.vlan);
@ -3300,7 +3335,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->del_station)
return -EOPNOTSUPP;
return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
return rdev_del_station(rdev, dev, mac_addr);
}
static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
@ -3382,8 +3417,8 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
}
while (1) {
err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
dst, next_hop, &pinfo);
err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop,
&pinfo);
if (err == -ENOENT)
break;
if (err)
@ -3430,7 +3465,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
err = rdev_get_mpath(rdev, dev, dst, next_hop, &pinfo);
if (err)
return err;
@ -3469,7 +3504,7 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
return rdev_change_mpath(rdev, dev, dst, next_hop);
}
static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
@ -3494,7 +3529,7 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
return rdev_add_mpath(rdev, dev, dst, next_hop);
}
static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
@ -3509,7 +3544,7 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->del_mpath)
return -EOPNOTSUPP;
return rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
return rdev_del_mpath(rdev, dev, dst);
}
static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
@ -3554,7 +3589,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
return rdev->ops->change_bss(&rdev->wiphy, dev, &params);
return rdev_change_bss(rdev, dev, &params);
}
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@ -3668,8 +3703,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
if (!wdev->mesh_id_len)
memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
else
err = rdev->ops->get_mesh_config(&rdev->wiphy, dev,
&cur_params);
err = rdev_get_mesh_config(rdev, dev, &cur_params);
wdev_unlock(wdev);
if (err)
@ -3971,8 +4005,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb,
err = -ENOLINK;
if (!err)
err = rdev->ops->update_mesh_config(&rdev->wiphy, dev,
mask, &cfg);
err = rdev_update_mesh_config(rdev, dev, mask, &cfg);
wdev_unlock(wdev);
@ -4337,14 +4370,27 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
}
if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
request->flags = nla_get_u32(
info->attrs[NL80211_ATTR_SCAN_FLAGS]);
if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
!(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
err = -EOPNOTSUPP;
goto out_free;
}
}
request->no_cck =
nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
request->scan_start = jiffies;
rdev->scan_req = request;
err = rdev->ops->scan(&rdev->wiphy, request);
err = rdev_scan(rdev, request);
if (!err) {
nl80211_send_scan_start(rdev, wdev);
@ -4568,11 +4614,24 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
request->ie_len);
}
if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
request->flags = nla_get_u32(
info->attrs[NL80211_ATTR_SCAN_FLAGS]);
if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
!(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
err = -EOPNOTSUPP;
goto out_free;
}
}
request->dev = dev;
request->wiphy = &rdev->wiphy;
request->interval = interval;
request->scan_start = jiffies;
err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
err = rdev_sched_scan_start(rdev, dev, request);
if (!err) {
rdev->sched_scan_req = request;
nl80211_send_sched_scan(rdev, dev,
@ -4815,8 +4874,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
while (1) {
struct ieee80211_channel *chan;
res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
&survey);
res = rdev_dump_survey(dev, netdev, survey_idx, &survey);
if (res == -ENOENT)
break;
if (res)
@ -4852,11 +4910,6 @@ static int nl80211_dump_survey(struct sk_buff *skb,
return res;
}
static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
{
return auth_type <= NL80211_AUTHTYPE_MAX;
}
static bool nl80211_valid_wpa_versions(u32 wpa_versions)
{
return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
@ -4868,8 +4921,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL;
int err, ssid_len, ie_len = 0;
const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
int err, ssid_len, ie_len = 0, sae_data_len = 0;
enum nl80211_auth_type auth_type;
struct key_parse key;
bool local_state_change;
@ -4945,9 +4998,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
}
auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
if (!nl80211_valid_auth_type(auth_type))
if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
return -EINVAL;
if (auth_type == NL80211_AUTHTYPE_SAE &&
!info->attrs[NL80211_ATTR_SAE_DATA])
return -EINVAL;
if (info->attrs[NL80211_ATTR_SAE_DATA]) {
if (auth_type != NL80211_AUTHTYPE_SAE)
return -EINVAL;
sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
/* need to include at least Auth Transaction and Status Code */
if (sae_data_len < 4)
return -EINVAL;
}
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
/*
@ -4959,7 +5026,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
key.p.key, key.p.key_len, key.idx);
key.p.key, key.p.key_len, key.idx,
sae_data, sae_data_len);
}
static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
@ -5339,10 +5407,18 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
bool no_ht = false;
connkeys = nl80211_parse_connkeys(rdev,
info->attrs[NL80211_ATTR_KEYS]);
info->attrs[NL80211_ATTR_KEYS],
&no_ht);
if (IS_ERR(connkeys))
return PTR_ERR(connkeys);
if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) {
kfree(connkeys);
return -EINVAL;
}
}
ibss.control_port =
@ -5384,7 +5460,7 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
err = -EOPNOTSUPP;
if (rdev->ops->testmode_cmd) {
rdev->testmode_info = info;
err = rdev->ops->testmode_cmd(&rdev->wiphy,
err = rdev_testmode_cmd(rdev,
nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
rdev->testmode_info = NULL;
@ -5466,8 +5542,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
genlmsg_cancel(skb, hdr);
break;
}
err = rdev->ops->testmode_dump(&rdev->wiphy, skb, cb,
data, data_len);
err = rdev_testmode_dump(rdev, skb, cb, data, data_len);
nla_nest_end(skb, tmdata);
if (err == -ENOBUFS || err == -ENOENT) {
@ -5596,7 +5671,8 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
connect.auth_type =
nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
if (!nl80211_valid_auth_type(connect.auth_type))
if (!nl80211_valid_auth_type(rdev, connect.auth_type,
NL80211_CMD_CONNECT))
return -EINVAL;
} else
connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@ -5642,7 +5718,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
connkeys = nl80211_parse_connkeys(rdev,
info->attrs[NL80211_ATTR_KEYS]);
info->attrs[NL80211_ATTR_KEYS], NULL);
if (IS_ERR(connkeys))
return PTR_ERR(connkeys);
}
@ -5771,7 +5847,7 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->flush_pmksa)
return -EOPNOTSUPP;
return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
return rdev_flush_pmksa(rdev, dev);
}
static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
@ -5798,10 +5874,10 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info)
status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]);
return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
dialog_token, status_code,
nla_data(info->attrs[NL80211_ATTR_IE]),
nla_len(info->attrs[NL80211_ATTR_IE]));
return rdev_tdls_mgmt(rdev, dev, peer, action_code,
dialog_token, status_code,
nla_data(info->attrs[NL80211_ATTR_IE]),
nla_len(info->attrs[NL80211_ATTR_IE]));
}
static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
@ -5822,7 +5898,7 @@ static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info)
operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]);
peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation);
return rdev_tdls_oper(rdev, dev, peer, operation);
}
static int nl80211_remain_on_channel(struct sk_buff *skb,
@ -5877,8 +5953,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
goto free_msg;
}
err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
channel_type, duration, &cookie);
err = rdev_remain_on_channel(rdev, wdev, chan, channel_type, duration,
&cookie);
if (err)
goto free_msg;
@ -5912,7 +5988,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
return rdev_cancel_remain_on_channel(rdev, wdev, cookie);
}
static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
@ -6055,7 +6131,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
}
}
return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
}
static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
@ -6230,7 +6306,7 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
return rdev_mgmt_tx_cancel_wait(rdev, wdev, cookie);
}
static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
@ -6260,8 +6336,7 @@ static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
if (state == wdev->ps)
return 0;
err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state,
wdev->ps_timeout);
err = rdev_set_power_mgmt(rdev, dev, state, wdev->ps_timeout);
if (!err)
wdev->ps = state;
return err;
@ -6341,8 +6416,7 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
return -EOPNOTSUPP;
return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev,
rate, pkts, intvl);
return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
}
static int nl80211_set_cqm_rssi(struct genl_info *info,
@ -6364,8 +6438,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
return -EOPNOTSUPP;
return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
threshold, hysteresis);
return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
}
static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@ -6690,7 +6763,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
set_wakeup:
if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
rdev_set_wakeup(rdev, rdev->wowlan);
return 0;
error:
@ -6746,7 +6819,7 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
goto out;
}
err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data);
err = rdev_set_rekey_data(rdev, dev, &rekey_data);
out:
wdev_unlock(wdev);
return err;
@ -6805,7 +6878,7 @@ static int nl80211_probe_client(struct sk_buff *skb,
addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
err = rdev_probe_client(rdev, dev, addr, &cookie);
if (err)
goto free_msg;
@ -7622,6 +7695,9 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
goto nla_put_failure;
if (req->flags)
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags);
return 0;
nla_put_failure:
return -ENOBUFS;
@ -8800,7 +8876,10 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
void *hdr;
int err;
trace_cfg80211_probe_status(dev, addr, cookie, acked);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@ -8842,6 +8921,8 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
void *hdr;
u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid);
trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
if (!nlportid)
return;

861
net/wireless/rdev-ops.h Normal file
View File

@ -0,0 +1,861 @@
#ifndef __CFG80211_RDEV_OPS
#define __CFG80211_RDEV_OPS
#include <linux/rtnetlink.h>
#include <net/cfg80211.h>
#include "core.h"
#include "trace.h"
static inline int rdev_suspend(struct cfg80211_registered_device *rdev)
{
int ret;
trace_rdev_suspend(&rdev->wiphy, rdev->wowlan);
ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_resume(struct cfg80211_registered_device *rdev)
{
int ret;
trace_rdev_resume(&rdev->wiphy);
ret = rdev->ops->resume(&rdev->wiphy);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev,
bool enabled)
{
trace_rdev_set_wakeup(&rdev->wiphy, enabled);
rdev->ops->set_wakeup(&rdev->wiphy, enabled);
trace_rdev_return_void(&rdev->wiphy);
}
static inline struct wireless_dev
*rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
struct wireless_dev *ret;
trace_rdev_add_virtual_intf(&rdev->wiphy, name, type);
ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags,
params);
trace_rdev_return_wdev(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_del_virtual_intf(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
int ret;
trace_rdev_del_virtual_intf(&rdev->wiphy, wdev);
ret = rdev->ops->del_virtual_intf(&rdev->wiphy, wdev);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_change_virtual_intf(struct cfg80211_registered_device *rdev,
struct net_device *dev, enum nl80211_iftype type,
u32 *flags, struct vif_params *params)
{
int ret;
trace_rdev_change_virtual_intf(&rdev->wiphy, dev, type);
ret = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, flags,
params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
int ret;
trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise,
mac_addr, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_get_key(struct cfg80211_registered_device *rdev, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*))
{
int ret;
trace_rdev_get_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
ret = rdev->ops->get_key(&rdev->wiphy, netdev, key_index, pairwise,
mac_addr, cookie, callback);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_del_key(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr)
{
int ret;
trace_rdev_del_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
ret = rdev->ops->del_key(&rdev->wiphy, netdev, key_index, pairwise,
mac_addr);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_set_default_key(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u8 key_index, bool unicast,
bool multicast)
{
int ret;
trace_rdev_set_default_key(&rdev->wiphy, netdev, key_index,
unicast, multicast);
ret = rdev->ops->set_default_key(&rdev->wiphy, netdev, key_index,
unicast, multicast);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_set_default_mgmt_key(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u8 key_index)
{
int ret;
trace_rdev_set_default_mgmt_key(&rdev->wiphy, netdev, key_index);
ret = rdev->ops->set_default_mgmt_key(&rdev->wiphy, netdev,
key_index);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_start_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_ap_settings *settings)
{
int ret;
trace_rdev_start_ap(&rdev->wiphy, dev, settings);
ret = rdev->ops->start_ap(&rdev->wiphy, dev, settings);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_change_beacon(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_beacon_data *info)
{
int ret;
trace_rdev_change_beacon(&rdev->wiphy, dev, info);
ret = rdev->ops->change_beacon(&rdev->wiphy, dev, info);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
int ret;
trace_rdev_stop_ap(&rdev->wiphy, dev);
ret = rdev->ops->stop_ap(&rdev->wiphy, dev);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_add_station(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *mac,
struct station_parameters *params)
{
int ret;
trace_rdev_add_station(&rdev->wiphy, dev, mac, params);
ret = rdev->ops->add_station(&rdev->wiphy, dev, mac, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_del_station(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *mac)
{
int ret;
trace_rdev_del_station(&rdev->wiphy, dev, mac);
ret = rdev->ops->del_station(&rdev->wiphy, dev, mac);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_change_station(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *mac,
struct station_parameters *params)
{
int ret;
trace_rdev_change_station(&rdev->wiphy, dev, mac, params);
ret = rdev->ops->change_station(&rdev->wiphy, dev, mac, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_get_station(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *mac,
struct station_info *sinfo)
{
int ret;
trace_rdev_get_station(&rdev->wiphy, dev, mac);
ret = rdev->ops->get_station(&rdev->wiphy, dev, mac, sinfo);
trace_rdev_return_int_station_info(&rdev->wiphy, ret, sinfo);
return ret;
}
static inline int rdev_dump_station(struct cfg80211_registered_device *rdev,
struct net_device *dev, int idx, u8 *mac,
struct station_info *sinfo)
{
int ret;
trace_rdev_dump_station(&rdev->wiphy, dev, idx, mac);
ret = rdev->ops->dump_station(&rdev->wiphy, dev, idx, mac, sinfo);
trace_rdev_return_int_station_info(&rdev->wiphy, ret, sinfo);
return ret;
}
static inline int rdev_add_mpath(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *dst, u8 *next_hop)
{
int ret;
trace_rdev_add_mpath(&rdev->wiphy, dev, dst, next_hop);
ret = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_del_mpath(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *dst)
{
int ret;
trace_rdev_del_mpath(&rdev->wiphy, dev, dst);
ret = rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_change_mpath(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *dst,
u8 *next_hop)
{
int ret;
trace_rdev_change_mpath(&rdev->wiphy, dev, dst, next_hop);
ret = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *dst, u8 *next_hop,
struct mpath_info *pinfo)
{
int ret;
trace_rdev_get_mpath(&rdev->wiphy, dev, dst, next_hop);
ret = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, pinfo);
trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
return ret;
}
static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
struct net_device *dev, int idx, u8 *dst,
u8 *next_hop, struct mpath_info *pinfo)
{
int ret;
trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
pinfo);
trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
return ret;
}
static inline int
rdev_get_mesh_config(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct mesh_config *conf)
{
int ret;
trace_rdev_get_mesh_config(&rdev->wiphy, dev);
ret = rdev->ops->get_mesh_config(&rdev->wiphy, dev, conf);
trace_rdev_return_int_mesh_config(&rdev->wiphy, ret, conf);
return ret;
}
static inline int
rdev_update_mesh_config(struct cfg80211_registered_device *rdev,
struct net_device *dev, u32 mask,
const struct mesh_config *nconf)
{
int ret;
trace_rdev_update_mesh_config(&rdev->wiphy, dev, mask, nconf);
ret = rdev->ops->update_mesh_config(&rdev->wiphy, dev, mask, nconf);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
const struct mesh_config *conf,
const struct mesh_setup *setup)
{
int ret;
trace_rdev_join_mesh(&rdev->wiphy, dev, conf, setup);
ret = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
int ret;
trace_rdev_leave_mesh(&rdev->wiphy, dev);
ret = rdev->ops->leave_mesh(&rdev->wiphy, dev);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_change_bss(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct bss_parameters *params)
{
int ret;
trace_rdev_change_bss(&rdev->wiphy, dev, params);
ret = rdev->ops->change_bss(&rdev->wiphy, dev, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_set_txq_params(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_txq_params *params)
{
int ret;
trace_rdev_set_txq_params(&rdev->wiphy, dev, params);
ret = rdev->ops->set_txq_params(&rdev->wiphy, dev, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan)
{
int ret;
trace_rdev_libertas_set_mesh_channel(&rdev->wiphy, dev, chan);
ret = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, dev, chan);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
int ret;
trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type);
ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_scan(struct cfg80211_registered_device *rdev,
struct cfg80211_scan_request *request)
{
int ret;
trace_rdev_scan(&rdev->wiphy, request);
ret = rdev->ops->scan(&rdev->wiphy, request);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_auth(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_auth_request *req)
{
int ret;
trace_rdev_auth(&rdev->wiphy, dev, req);
ret = rdev->ops->auth(&rdev->wiphy, dev, req);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_assoc_request *req)
{
int ret;
trace_rdev_assoc(&rdev->wiphy, dev, req);
ret = rdev->ops->assoc(&rdev->wiphy, dev, req);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_deauth(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_deauth_request *req)
{
int ret;
trace_rdev_deauth(&rdev->wiphy, dev, req);
ret = rdev->ops->deauth(&rdev->wiphy, dev, req);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_disassoc_request *req)
{
int ret;
trace_rdev_disassoc(&rdev->wiphy, dev, req);
ret = rdev->ops->disassoc(&rdev->wiphy, dev, req);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_connect(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_connect_params *sme)
{
int ret;
trace_rdev_connect(&rdev->wiphy, dev, sme);
ret = rdev->ops->connect(&rdev->wiphy, dev, sme);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_disconnect(struct cfg80211_registered_device *rdev,
struct net_device *dev, u16 reason_code)
{
int ret;
trace_rdev_disconnect(&rdev->wiphy, dev, reason_code);
ret = rdev->ops->disconnect(&rdev->wiphy, dev, reason_code);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_join_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_ibss_params *params)
{
int ret;
trace_rdev_join_ibss(&rdev->wiphy, dev, params);
ret = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
int ret;
trace_rdev_leave_ibss(&rdev->wiphy, dev);
ret = rdev->ops->leave_ibss(&rdev->wiphy, dev);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed)
{
int ret;
trace_rdev_set_wiphy_params(&rdev->wiphy, changed);
ret = rdev->ops->set_wiphy_params(&rdev->wiphy, changed);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev,
enum nl80211_tx_power_setting type, int mbm)
{
int ret;
trace_rdev_set_tx_power(&rdev->wiphy, type, mbm);
ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev,
int *dbm)
{
int ret;
trace_rdev_get_tx_power(&rdev->wiphy);
ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm);
trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);
return ret;
}
static inline int rdev_set_wds_peer(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *addr)
{
int ret;
trace_rdev_set_wds_peer(&rdev->wiphy, dev, addr);
ret = rdev->ops->set_wds_peer(&rdev->wiphy, dev, addr);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
{
trace_rdev_rfkill_poll(&rdev->wiphy);
rdev->ops->rfkill_poll(&rdev->wiphy);
trace_rdev_return_void(&rdev->wiphy);
}
#ifdef CONFIG_NL80211_TESTMODE
static inline int rdev_testmode_cmd(struct cfg80211_registered_device *rdev,
void *data, int len)
{
int ret;
trace_rdev_testmode_cmd(&rdev->wiphy);
ret = rdev->ops->testmode_cmd(&rdev->wiphy, data, len);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev,
struct sk_buff *skb,
struct netlink_callback *cb, void *data,
int len)
{
int ret;
trace_rdev_testmode_dump(&rdev->wiphy);
ret = rdev->ops->testmode_dump(&rdev->wiphy, skb, cb, data, len);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
#endif
static inline int
rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *peer,
const struct cfg80211_bitrate_mask *mask)
{
int ret;
trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, peer, mask);
ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_dump_survey(struct cfg80211_registered_device *rdev,
struct net_device *netdev, int idx,
struct survey_info *info)
{
int ret;
trace_rdev_dump_survey(&rdev->wiphy, netdev, idx);
ret = rdev->ops->dump_survey(&rdev->wiphy, netdev, idx, info);
if (ret < 0)
trace_rdev_return_int(&rdev->wiphy, ret);
else
trace_rdev_return_int_survey_info(&rdev->wiphy, ret, info);
return ret;
}
static inline int rdev_set_pmksa(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
struct cfg80211_pmksa *pmksa)
{
int ret;
trace_rdev_set_pmksa(&rdev->wiphy, netdev, pmksa);
ret = rdev->ops->set_pmksa(&rdev->wiphy, netdev, pmksa);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_del_pmksa(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
struct cfg80211_pmksa *pmksa)
{
int ret;
trace_rdev_del_pmksa(&rdev->wiphy, netdev, pmksa);
ret = rdev->ops->del_pmksa(&rdev->wiphy, netdev, pmksa);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_flush_pmksa(struct cfg80211_registered_device *rdev,
struct net_device *netdev)
{
int ret;
trace_rdev_flush_pmksa(&rdev->wiphy, netdev);
ret = rdev->ops->flush_pmksa(&rdev->wiphy, netdev);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_remain_on_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, u64 *cookie)
{
int ret;
trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, channel_type,
duration);
ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
channel_type, duration, cookie);
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
return ret;
}
static inline int
rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u64 cookie)
{
int ret;
trace_rdev_cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
ret = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
{
int ret;
trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type,
channel_type_valid, wait, no_cck, dont_wait_for_ack);
ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
channel_type, channel_type_valid, wait, buf,
len, no_cck, dont_wait_for_ack, cookie);
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
return ret;
}
static inline int
rdev_mgmt_tx_cancel_wait(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u64 cookie)
{
int ret;
trace_rdev_mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
ret = rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_set_power_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool enabled,
int timeout)
{
int ret;
trace_rdev_set_power_mgmt(&rdev->wiphy, dev, enabled, timeout);
ret = rdev->ops->set_power_mgmt(&rdev->wiphy, dev, enabled, timeout);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev,
struct net_device *dev, s32 rssi_thold, u32 rssi_hyst)
{
int ret;
trace_rdev_set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold,
rssi_hyst);
ret = rdev->ops->set_cqm_rssi_config(&rdev->wiphy, dev, rssi_thold,
rssi_hyst);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
struct net_device *dev, u32 rate, u32 pkts, u32 intvl)
{
int ret;
trace_rdev_set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts, intvl);
ret = rdev->ops->set_cqm_txe_config(&rdev->wiphy, dev, rate, pkts,
intvl);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline void
rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u16 frame_type, bool reg)
{
trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
trace_rdev_return_void(&rdev->wiphy);
}
static inline int rdev_set_antenna(struct cfg80211_registered_device *rdev,
u32 tx_ant, u32 rx_ant)
{
int ret;
trace_rdev_set_antenna(&rdev->wiphy, tx_ant, rx_ant);
ret = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_get_antenna(struct cfg80211_registered_device *rdev,
u32 *tx_ant, u32 *rx_ant)
{
int ret;
trace_rdev_get_antenna(&rdev->wiphy);
ret = rdev->ops->get_antenna(&rdev->wiphy, tx_ant, rx_ant);
if (ret)
trace_rdev_return_int(&rdev->wiphy, ret);
else
trace_rdev_return_int_tx_rx(&rdev->wiphy, ret, *tx_ant,
*rx_ant);
return ret;
}
static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev,
u32 tx, u32 rx)
{
int ret;
trace_rdev_set_ringparam(&rdev->wiphy, tx, rx);
ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev,
u32 *tx, u32 *tx_max, u32 *rx,
u32 *rx_max)
{
trace_rdev_get_ringparam(&rdev->wiphy);
rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max);
trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max);
}
static inline int
rdev_sched_scan_start(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_sched_scan_request *request)
{
int ret;
trace_rdev_sched_scan_start(&rdev->wiphy, dev, request);
ret = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_sched_scan_stop(struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
int ret;
trace_rdev_sched_scan_stop(&rdev->wiphy, dev);
ret = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_gtk_rekey_data *data)
{
int ret;
trace_rdev_set_rekey_data(&rdev->wiphy, dev);
ret = rdev->ops->set_rekey_data(&rdev->wiphy, dev, data);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *peer,
u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, size_t len)
{
int ret;
trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
dialog_token, status_code, buf, len);
ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code,
dialog_token, status_code, buf, len);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_tdls_oper(struct cfg80211_registered_device *rdev,
struct net_device *dev, u8 *peer,
enum nl80211_tdls_operation oper)
{
int ret;
trace_rdev_tdls_oper(&rdev->wiphy, dev, peer, oper);
ret = rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, oper);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_probe_client(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *peer,
u64 *cookie)
{
int ret;
trace_rdev_probe_client(&rdev->wiphy, dev, peer);
ret = rdev->ops->probe_client(&rdev->wiphy, dev, peer, cookie);
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
return ret;
}
static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev,
struct net_device *dev, u16 noack_map)
{
int ret;
trace_rdev_set_noack_map(&rdev->wiphy, dev, noack_map);
ret = rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_get_et_sset_count(struct cfg80211_registered_device *rdev,
struct net_device *dev, int sset)
{
int ret;
trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset);
ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
trace_rdev_get_et_stats(&rdev->wiphy, dev);
rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data);
trace_rdev_return_void(&rdev->wiphy);
}
static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev,
struct net_device *dev, u32 sset,
u8 *data)
{
trace_rdev_get_et_strings(&rdev->wiphy, dev, sset);
rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data);
trace_rdev_return_void(&rdev->wiphy);
}
static inline struct ieee80211_channel
*rdev_get_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, enum nl80211_channel_type *type)
{
struct ieee80211_channel *ret;
trace_rdev_get_channel(&rdev->wiphy, wdev);
ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type);
trace_rdev_return_channel(&rdev->wiphy, ret, *type);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */

View File

@ -17,9 +17,58 @@
#include "core.h"
#include "nl80211.h"
#include "wext-compat.h"
#include "rdev-ops.h"
#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
static void bss_release(struct kref *ref)
{
struct cfg80211_internal_bss *bss;
bss = container_of(ref, struct cfg80211_internal_bss, ref);
if (bss->pub.free_priv)
bss->pub.free_priv(&bss->pub);
if (bss->beacon_ies_allocated)
kfree(bss->pub.beacon_ies);
if (bss->proberesp_ies_allocated)
kfree(bss->pub.proberesp_ies);
BUG_ON(atomic_read(&bss->hold));
kfree(bss);
}
/* must hold dev->bss_lock! */
static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
struct cfg80211_internal_bss *bss)
{
list_del_init(&bss->list);
rb_erase(&bss->rbn, &dev->bss_tree);
kref_put(&bss->ref, bss_release);
}
/* must hold dev->bss_lock! */
static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
unsigned long expire_time)
{
struct cfg80211_internal_bss *bss, *tmp;
bool expired = false;
list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
if (atomic_read(&bss->hold))
continue;
if (!time_after(expire_time, bss->ts))
continue;
__cfg80211_unlink_bss(dev, bss);
expired = true;
}
if (expired)
dev->bss_generation++;
}
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
struct cfg80211_scan_request *request;
@ -45,10 +94,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
if (wdev->netdev)
cfg80211_sme_scan_done(wdev->netdev);
if (request->aborted)
if (request->aborted) {
nl80211_send_scan_aborted(rdev, wdev);
else
} else {
if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start);
spin_unlock_bh(&rdev->bss_lock);
}
nl80211_send_scan_done(rdev, wdev);
}
#ifdef CONFIG_CFG80211_WEXT
if (wdev->netdev && !request->aborted) {
@ -89,6 +145,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
{
trace_cfg80211_scan_done(request, aborted);
WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
request->aborted = aborted;
@ -99,22 +156,34 @@ EXPORT_SYMBOL(cfg80211_scan_done);
void __cfg80211_sched_scan_results(struct work_struct *wk)
{
struct cfg80211_registered_device *rdev;
struct cfg80211_sched_scan_request *request;
rdev = container_of(wk, struct cfg80211_registered_device,
sched_scan_results_wk);
request = rdev->sched_scan_req;
mutex_lock(&rdev->sched_scan_mtx);
/* we don't have sched_scan_req anymore if the scan is stopping */
if (rdev->sched_scan_req)
nl80211_send_sched_scan_results(rdev,
rdev->sched_scan_req->dev);
if (request) {
if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start);
spin_unlock_bh(&rdev->bss_lock);
request->scan_start =
jiffies + msecs_to_jiffies(request->interval);
}
nl80211_send_sched_scan_results(rdev, request->dev);
}
mutex_unlock(&rdev->sched_scan_mtx);
}
void cfg80211_sched_scan_results(struct wiphy *wiphy)
{
trace_cfg80211_sched_scan_results(wiphy);
/* ignore if we're not scanning */
if (wiphy_to_dev(wiphy)->sched_scan_req)
queue_work(cfg80211_wq,
@ -126,6 +195,8 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_sched_scan_stopped(wiphy);
mutex_lock(&rdev->sched_scan_mtx);
__cfg80211_stop_sched_scan(rdev, true);
mutex_unlock(&rdev->sched_scan_mtx);
@ -145,7 +216,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
dev = rdev->sched_scan_req->dev;
if (!driver_initiated) {
int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
int err = rdev_sched_scan_stop(rdev, dev);
if (err)
return err;
}
@ -158,24 +229,6 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
return 0;
}
static void bss_release(struct kref *ref)
{
struct cfg80211_internal_bss *bss;
bss = container_of(ref, struct cfg80211_internal_bss, ref);
if (bss->pub.free_priv)
bss->pub.free_priv(&bss->pub);
if (bss->beacon_ies_allocated)
kfree(bss->pub.beacon_ies);
if (bss->proberesp_ies_allocated)
kfree(bss->pub.proberesp_ies);
BUG_ON(atomic_read(&bss->hold));
kfree(bss);
}
/* must hold dev->bss_lock! */
void cfg80211_bss_age(struct cfg80211_registered_device *dev,
unsigned long age_secs)
@ -188,32 +241,9 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
}
}
/* must hold dev->bss_lock! */
static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
struct cfg80211_internal_bss *bss)
{
list_del_init(&bss->list);
rb_erase(&bss->rbn, &dev->bss_tree);
kref_put(&bss->ref, bss_release);
}
/* must hold dev->bss_lock! */
void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
{
struct cfg80211_internal_bss *bss, *tmp;
bool expired = false;
list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
if (atomic_read(&bss->hold))
continue;
if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
continue;
__cfg80211_unlink_bss(dev, bss);
expired = true;
}
if (expired)
dev->bss_generation++;
__cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
}
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
@ -459,6 +489,9 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
struct cfg80211_internal_bss *bss, *res = NULL;
unsigned long now = jiffies;
trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
capa_val);
spin_lock_bh(&dev->bss_lock);
list_for_each_entry(bss, &dev->bss_list, list) {
@ -480,6 +513,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
spin_unlock_bh(&dev->bss_lock);
if (!res)
return NULL;
trace_cfg80211_return_bss(&res->pub);
return &res->pub;
}
EXPORT_SYMBOL(cfg80211_get_bss);
@ -792,6 +826,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
if (res->pub.capability & WLAN_CAPABILITY_ESS)
regulatory_hint_found_beacon(wiphy, channel, gfp);
trace_cfg80211_return_bss(&res->pub);
/* cfg80211_bss_update gives us a referenced result */
return &res->pub;
}
@ -804,10 +839,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
s32 signal, gfp_t gfp)
{
struct cfg80211_internal_bss *res;
size_t ielen = len - offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
size_t privsz;
trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal);
if (WARN_ON(!mgmt))
return NULL;
@ -861,6 +899,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
if (res->pub.capability & WLAN_CAPABILITY_ESS)
regulatory_hint_found_beacon(wiphy, channel, gfp);
trace_cfg80211_return_bss(&res->pub);
/* cfg80211_bss_update gives us a referenced result */
return &res->pub;
}
@ -962,6 +1001,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
creq->ssids = (void *)&creq->channels[n_channels];
creq->n_channels = n_channels;
creq->n_ssids = 1;
creq->scan_start = jiffies;
/* translate "Scan on frequencies" request */
i = 0;
@ -1026,7 +1066,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
rdev->scan_req = creq;
err = rdev->ops->scan(wiphy, creq);
err = rdev_scan(rdev, creq);
if (err) {
rdev->scan_req = NULL;
/* creq will be freed below */

View File

@ -16,6 +16,7 @@
#include <net/rtnetlink.h>
#include "nl80211.h"
#include "reg.h"
#include "rdev-ops.h"
struct cfg80211_conn {
struct cfg80211_connect_params params;
@ -138,10 +139,11 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
request->scan_start = jiffies;
rdev->scan_req = request;
err = rdev->ops->scan(wdev->wiphy, request);
err = rdev_scan(rdev, request);
if (!err) {
wdev->conn->state = CFG80211_CONN_SCANNING;
nl80211_send_scan_start(rdev, wdev);
@ -179,7 +181,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
params->ssid, params->ssid_len,
NULL, 0,
params->key, params->key_len,
params->key_idx);
params->key_idx, NULL, 0);
case CFG80211_CONN_ASSOCIATE_NEXT:
BUG_ON(!rdev->ops->assoc);
wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@ -716,7 +718,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
*/
if (rdev->ops->del_key)
for (i = 0; i < 6; i++)
rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
rdev_del_key(rdev, dev, i, false, NULL);
#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
@ -892,7 +894,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
} else {
wdev->sme_state = CFG80211_SME_CONNECTING;
wdev->connect_keys = connkeys;
err = rdev->ops->connect(&rdev->wiphy, dev, connect);
err = rdev_connect(rdev, dev, connect);
if (err) {
wdev->connect_keys = NULL;
wdev->sme_state = CFG80211_SME_IDLE;
@ -964,7 +966,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
if (err)
return err;
} else {
err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
err = rdev_disconnect(rdev, dev, reason);
if (err)
return err;
}

View File

@ -16,6 +16,7 @@
#include <net/cfg80211.h>
#include "sysfs.h"
#include "core.h"
#include "rdev-ops.h"
static inline struct cfg80211_registered_device *dev_to_rdev(
struct device *dev)
@ -94,7 +95,7 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
if (rdev->ops->suspend) {
rtnl_lock();
if (rdev->wiphy.registered)
ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
ret = rdev_suspend(rdev);
rtnl_unlock();
}
@ -114,7 +115,7 @@ static int wiphy_resume(struct device *dev)
if (rdev->ops->resume) {
rtnl_lock();
if (rdev->wiphy.registered)
ret = rdev->ops->resume(&rdev->wiphy);
ret = rdev_resume(rdev);
rtnl_unlock();
}

7
net/wireless/trace.c Normal file
View File

@ -0,0 +1,7 @@
#include <linux/module.h>
#ifndef __CHECKER__
#define CREATE_TRACE_POINTS
#include "trace.h"
#endif

2286
net/wireless/trace.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,8 @@
#include <net/ip.h>
#include <net/dsfield.h>
#include "core.h"
#include "rdev-ops.h"
struct ieee80211_rate *
ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
@ -703,19 +705,18 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
for (i = 0; i < 6; i++) {
if (!wdev->connect_keys->params[i].cipher)
continue;
if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL,
&wdev->connect_keys->params[i])) {
if (rdev_add_key(rdev, dev, i, false, NULL,
&wdev->connect_keys->params[i])) {
netdev_err(dev, "failed to set key %d\n", i);
continue;
}
if (wdev->connect_keys->def == i)
if (rdev->ops->set_default_key(wdev->wiphy, dev,
i, true, true)) {
if (rdev_set_default_key(rdev, dev, i, true, true)) {
netdev_err(dev, "failed to set defkey %d\n", i);
continue;
}
if (wdev->connect_keys->defmgmt == i)
if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
if (rdev_set_default_mgmt_key(rdev, dev, i))
netdev_err(dev, "failed to set mgtdef %d\n", i);
}
@ -848,8 +849,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
cfg80211_process_rdev_events(rdev);
}
err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
ntype, flags, params);
err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params);
WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);

View File

@ -19,6 +19,7 @@
#include <net/cfg80211-wext.h>
#include "wext-compat.h"
#include "core.h"
#include "rdev-ops.h"
int cfg80211_wext_giwname(struct net_device *dev,
struct iw_request_info *info,
@ -301,8 +302,7 @@ int cfg80211_wext_siwrts(struct net_device *dev,
else
wdev->wiphy->rts_threshold = rts->value;
err = rdev->ops->set_wiphy_params(wdev->wiphy,
WIPHY_PARAM_RTS_THRESHOLD);
err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_RTS_THRESHOLD);
if (err)
wdev->wiphy->rts_threshold = orts;
@ -342,8 +342,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev,
wdev->wiphy->frag_threshold = frag->value & ~0x1;
}
err = rdev->ops->set_wiphy_params(wdev->wiphy,
WIPHY_PARAM_FRAG_THRESHOLD);
err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_FRAG_THRESHOLD);
if (err)
wdev->wiphy->frag_threshold = ofrag;
@ -396,7 +395,7 @@ static int cfg80211_wext_siwretry(struct net_device *dev,
if (!changed)
return 0;
err = rdev->ops->set_wiphy_params(wdev->wiphy, changed);
err = rdev_set_wiphy_params(rdev, changed);
if (err) {
wdev->wiphy->retry_short = oshort;
wdev->wiphy->retry_long = olong;
@ -490,8 +489,8 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
!(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
err = -ENOENT;
else
err = rdev->ops->del_key(&rdev->wiphy, dev, idx,
pairwise, addr);
err = rdev_del_key(rdev, dev, idx, pairwise,
addr);
}
wdev->wext.connect.privacy = false;
/*
@ -525,8 +524,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
err = 0;
if (wdev->current_bss)
err = rdev->ops->add_key(&rdev->wiphy, dev, idx,
pairwise, addr, params);
err = rdev_add_key(rdev, dev, idx, pairwise, addr, params);
if (err)
return err;
@ -552,8 +550,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
__cfg80211_leave_ibss(rdev, wdev->netdev, true);
rejoin = true;
}
err = rdev->ops->set_default_key(&rdev->wiphy, dev,
idx, true, true);
err = rdev_set_default_key(rdev, dev, idx, true, true);
}
if (!err) {
wdev->wext.default_key = idx;
@ -566,8 +563,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
(tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
if (wdev->current_bss)
err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
dev, idx);
err = rdev_set_default_mgmt_key(rdev, dev, idx);
if (!err)
wdev->wext.default_mgmt_key = idx;
return err;
@ -631,8 +627,8 @@ static int cfg80211_wext_siwencode(struct net_device *dev,
err = 0;
wdev_lock(wdev);
if (wdev->current_bss)
err = rdev->ops->set_default_key(&rdev->wiphy, dev,
idx, true, true);
err = rdev_set_default_key(rdev, dev, idx, true,
true);
if (!err)
wdev->wext.default_key = idx;
wdev_unlock(wdev);
@ -839,7 +835,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
if (!rdev->ops->get_channel)
return -EINVAL;
chan = rdev->ops->get_channel(wdev->wiphy, wdev, &channel_type);
chan = rdev_get_channel(rdev, wdev, &channel_type);
if (!chan)
return -EINVAL;
freq->m = chan->center_freq;
@ -899,7 +895,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,
return 0;
}
return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm));
return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm));
}
static int cfg80211_wext_giwtxpower(struct net_device *dev,
@ -918,7 +914,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
if (!rdev->ops->get_tx_power)
return -EOPNOTSUPP;
err = rdev->ops->get_tx_power(wdev->wiphy, &val);
err = rdev_get_tx_power(rdev, &val);
if (err)
return err;
@ -1158,7 +1154,7 @@ static int cfg80211_wext_siwpower(struct net_device *dev,
timeout = wrq->value / 1000;
}
err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, ps, timeout);
err = rdev_set_power_mgmt(rdev, dev, ps, timeout);
if (err)
return err;
@ -1200,7 +1196,7 @@ static int cfg80211_wds_wext_siwap(struct net_device *dev,
if (!rdev->ops->set_wds_peer)
return -EOPNOTSUPP;
err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data);
err = rdev_set_wds_peer(rdev, dev, (u8 *)&addr->sa_data);
if (err)
return err;
@ -1272,7 +1268,7 @@ static int cfg80211_wext_siwrate(struct net_device *dev,
if (!match)
return -EINVAL;
return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
}
static int cfg80211_wext_giwrate(struct net_device *dev,
@ -1302,7 +1298,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
if (err)
return err;
err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
err = rdev_get_station(rdev, dev, addr, &sinfo);
if (err)
return err;
@ -1339,7 +1335,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
wdev_unlock(wdev);
if (rdev->ops->get_station(&rdev->wiphy, dev, bssid, &sinfo))
if (rdev_get_station(rdev, dev, bssid, &sinfo))
return NULL;
memset(&wstats, 0, sizeof(wstats));
@ -1474,19 +1470,19 @@ static int cfg80211_wext_siwpmksa(struct net_device *dev,
if (!rdev->ops->set_pmksa)
return -EOPNOTSUPP;
return rdev->ops->set_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
return rdev_set_pmksa(rdev, dev, &cfg_pmksa);
case IW_PMKSA_REMOVE:
if (!rdev->ops->del_pmksa)
return -EOPNOTSUPP;
return rdev->ops->del_pmksa(&rdev->wiphy, dev, &cfg_pmksa);
return rdev_del_pmksa(rdev, dev, &cfg_pmksa);
case IW_PMKSA_FLUSH:
if (!rdev->ops->flush_pmksa)
return -EOPNOTSUPP;
return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
return rdev_flush_pmksa(rdev, dev);
default:
return -EOPNOTSUPP;