Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
3cd17638fd
|
@ -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) {
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)) {
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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().
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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---
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(®->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);
|
||||
|
|
|
@ -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, ¶ms);
|
||||
wdev = rdev_add_virtual_intf(rdev,
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
|
||||
type, err ? NULL : &flags, ¶ms);
|
||||
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, ¶ms);
|
||||
err = rdev_start_ap(rdev, dev, ¶ms);
|
||||
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, ¶ms);
|
||||
return rdev_change_beacon(rdev, dev, ¶ms);
|
||||
}
|
||||
|
||||
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, ¶ms);
|
||||
err = rdev_change_station(rdev, dev, mac_addr, ¶ms);
|
||||
|
||||
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, ¶ms);
|
||||
err = rdev_add_station(rdev, dev, mac_addr, ¶ms);
|
||||
|
||||
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, ¶ms);
|
||||
return rdev_change_bss(rdev, dev, ¶ms);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include <linux/module.h>
|
||||
|
||||
#ifndef __CHECKER__
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue