mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-14 15:54:15 +08:00
Merge branch 'for-john' of git://git.sipsolutions.net/mac80211-next
This commit is contained in:
commit
0af5491c2f
@ -3627,6 +3627,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
wiphy->cipher_suites = cipher_suites;
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
|
||||
WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
|
||||
@ -3636,6 +3637,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
|
||||
wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
|
||||
wiphy->wowlan.pattern_min_len = 1;
|
||||
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
|
||||
#endif
|
||||
|
||||
wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
|
||||
|
||||
|
@ -277,11 +277,11 @@ static void carl9170_tx_release(struct kref *ref)
|
||||
return;
|
||||
|
||||
BUILD_BUG_ON(
|
||||
offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23);
|
||||
offsetof(struct ieee80211_tx_info, status.ack_signal) != 20);
|
||||
|
||||
memset(&txinfo->status.ampdu_ack_len, 0,
|
||||
memset(&txinfo->status.ack_signal, 0,
|
||||
sizeof(struct ieee80211_tx_info) -
|
||||
offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
|
||||
offsetof(struct ieee80211_tx_info, status.ack_signal));
|
||||
|
||||
if (atomic_read(&ar->tx_total_queued))
|
||||
ar->tx_schedule = true;
|
||||
|
@ -946,7 +946,7 @@ il3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
rs_sta->expected_tpt = il3945_expected_tpt_a;
|
||||
break;
|
||||
case IEEE80211_NUM_BANDS:
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ struct mac80211_hwsim_data {
|
||||
struct list_head list;
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
struct ieee80211_supported_band bands[2];
|
||||
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
|
||||
struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)];
|
||||
struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
|
||||
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
|
||||
@ -1082,6 +1082,8 @@ enum hwsim_testmode_attr {
|
||||
enum hwsim_testmode_cmd {
|
||||
HWSIM_TM_CMD_SET_PS = 0,
|
||||
HWSIM_TM_CMD_GET_PS = 1,
|
||||
HWSIM_TM_CMD_STOP_QUEUES = 2,
|
||||
HWSIM_TM_CMD_WAKE_QUEUES = 3,
|
||||
};
|
||||
|
||||
static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
|
||||
@ -1121,6 +1123,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
|
||||
if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps))
|
||||
goto nla_put_failure;
|
||||
return cfg80211_testmode_reply(skb);
|
||||
case HWSIM_TM_CMD_STOP_QUEUES:
|
||||
ieee80211_stop_queues(hw);
|
||||
return 0;
|
||||
case HWSIM_TM_CMD_WAKE_QUEUES:
|
||||
ieee80211_wake_queues(hw);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@ -1855,7 +1863,7 @@ static int __init init_mac80211_hwsim(void)
|
||||
sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
sband->ht_cap.ht_supported = true;
|
||||
|
@ -422,11 +422,11 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
|
||||
* Clear manually, ieee80211_tx_info_clear_status would
|
||||
* clear the counts too and we need them.
|
||||
*/
|
||||
memset(&info->status.ampdu_ack_len, 0,
|
||||
memset(&info->status.ack_signal, 0,
|
||||
sizeof(struct ieee80211_tx_info) -
|
||||
offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
|
||||
offsetof(struct ieee80211_tx_info, status.ack_signal));
|
||||
BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
|
||||
status.ampdu_ack_len) != 23);
|
||||
status.ack_signal) != 20);
|
||||
|
||||
if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
|
||||
pad = entry_data->align[0];
|
||||
|
@ -5504,6 +5504,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
goto out_free_hw;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
ret = enable_irq_wake(wl->irq);
|
||||
if (!ret) {
|
||||
wl->irq_wake_enabled = true;
|
||||
@ -5517,6 +5518,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
|
||||
WL1271_RX_FILTER_MAX_PATTERN_SIZE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
disable_irq(wl->irq);
|
||||
|
||||
ret = wl12xx_get_hw_info(wl);
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define IEEE80211_FCTL_MOREDATA 0x2000
|
||||
#define IEEE80211_FCTL_PROTECTED 0x4000
|
||||
#define IEEE80211_FCTL_ORDER 0x8000
|
||||
#define IEEE80211_FCTL_CTL_EXT 0x0f00
|
||||
|
||||
#define IEEE80211_SCTL_FRAG 0x000F
|
||||
#define IEEE80211_SCTL_SEQ 0xFFF0
|
||||
@ -54,6 +55,7 @@
|
||||
#define IEEE80211_FTYPE_MGMT 0x0000
|
||||
#define IEEE80211_FTYPE_CTL 0x0004
|
||||
#define IEEE80211_FTYPE_DATA 0x0008
|
||||
#define IEEE80211_FTYPE_EXT 0x000c
|
||||
|
||||
/* management */
|
||||
#define IEEE80211_STYPE_ASSOC_REQ 0x0000
|
||||
@ -70,6 +72,7 @@
|
||||
#define IEEE80211_STYPE_ACTION 0x00D0
|
||||
|
||||
/* control */
|
||||
#define IEEE80211_STYPE_CTL_EXT 0x0060
|
||||
#define IEEE80211_STYPE_BACK_REQ 0x0080
|
||||
#define IEEE80211_STYPE_BACK 0x0090
|
||||
#define IEEE80211_STYPE_PSPOLL 0x00A0
|
||||
@ -97,6 +100,18 @@
|
||||
#define IEEE80211_STYPE_QOS_CFPOLL 0x00E0
|
||||
#define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0
|
||||
|
||||
/* extension, added by 802.11ad */
|
||||
#define IEEE80211_STYPE_DMG_BEACON 0x0000
|
||||
|
||||
/* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */
|
||||
#define IEEE80211_CTL_EXT_POLL 0x2000
|
||||
#define IEEE80211_CTL_EXT_SPR 0x3000
|
||||
#define IEEE80211_CTL_EXT_GRANT 0x4000
|
||||
#define IEEE80211_CTL_EXT_DMG_CTS 0x5000
|
||||
#define IEEE80211_CTL_EXT_DMG_DTS 0x6000
|
||||
#define IEEE80211_CTL_EXT_SSW 0x8000
|
||||
#define IEEE80211_CTL_EXT_SSW_FBACK 0x9000
|
||||
#define IEEE80211_CTL_EXT_SSW_ACK 0xa000
|
||||
|
||||
/* miscellaneous IEEE 802.11 constants */
|
||||
#define IEEE80211_MAX_FRAG_THRESHOLD 2352
|
||||
@ -1092,6 +1107,73 @@ 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
|
||||
* @rx_highest: Indicates highest long GI VHT PPDU data rate
|
||||
* STA can receive. Rate expressed in units of 1 Mbps.
|
||||
* If this field is 0 this value should not be used to
|
||||
* consider the highest RX data rate supported.
|
||||
* @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams
|
||||
* @tx_highest: Indicates highest long GI VHT PPDU data rate
|
||||
* STA can transmit. Rate expressed in units of 1 Mbps.
|
||||
* If this field is 0 this value should not be used to
|
||||
* consider the highest TX data rate supported.
|
||||
*/
|
||||
struct ieee80211_vht_mcs_info {
|
||||
__le16 rx_mcs_map;
|
||||
__le16 rx_highest;
|
||||
__le16 tx_mcs_map;
|
||||
__le16 tx_highest;
|
||||
} __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
|
||||
#define IEEE80211_VHT_MCS_NOT_SUPPORTED 3
|
||||
|
||||
/* 802.11ac VHT Capabilities */
|
||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
|
||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
|
||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002
|
||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
|
||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
|
||||
#define IEEE80211_VHT_CAP_RXLDPC 0x00000010
|
||||
#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020
|
||||
#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040
|
||||
#define IEEE80211_VHT_CAP_TXSTBC 0x00000080
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
|
||||
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
|
||||
#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
|
||||
#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
|
||||
#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000
|
||||
#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000
|
||||
#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
|
||||
#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
|
||||
#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000
|
||||
#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000
|
||||
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT 0x00800000
|
||||
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000
|
||||
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000
|
||||
#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000
|
||||
#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000
|
||||
|
||||
/* Authentication algorithms */
|
||||
#define WLAN_AUTH_OPEN 0
|
||||
#define WLAN_AUTH_SHARED_KEY 1
|
||||
@ -1124,6 +1206,21 @@ struct ieee80211_ht_operation {
|
||||
#define WLAN_CAPABILITY_QOS (1<<9)
|
||||
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
|
||||
#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
|
||||
|
||||
/* DMG (60gHz) 802.11ad */
|
||||
/* type - bits 0..1 */
|
||||
#define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */
|
||||
#define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */
|
||||
#define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */
|
||||
|
||||
#define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2)
|
||||
#define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3)
|
||||
#define WLAN_CAPABILITY_DMG_PRIVACY (1<<4)
|
||||
#define WLAN_CAPABILITY_DMG_ECPAC (1<<5)
|
||||
|
||||
#define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
|
||||
#define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
|
||||
|
||||
/* measurement */
|
||||
#define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0)
|
||||
#define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1)
|
||||
@ -1133,7 +1230,6 @@ struct ieee80211_ht_operation {
|
||||
#define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1
|
||||
#define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2
|
||||
|
||||
|
||||
/* 802.11g ERP information element */
|
||||
#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
|
||||
#define WLAN_ERP_USE_PROTECTION (1<<1)
|
||||
@ -1145,6 +1241,16 @@ enum {
|
||||
WLAN_ERP_PREAMBLE_LONG = 1,
|
||||
};
|
||||
|
||||
/* Band ID, 802.11ad #8.4.1.45 */
|
||||
enum {
|
||||
IEEE80211_BANDID_TV_WS = 0, /* TV white spaces */
|
||||
IEEE80211_BANDID_SUB1 = 1, /* Sub-1 GHz (excluding TV white spaces) */
|
||||
IEEE80211_BANDID_2G = 2, /* 2.4 GHz */
|
||||
IEEE80211_BANDID_3G = 3, /* 3.6 GHz */
|
||||
IEEE80211_BANDID_5G = 4, /* 4.9 and 5 GHz */
|
||||
IEEE80211_BANDID_60G = 5, /* 60 GHz */
|
||||
};
|
||||
|
||||
/* Status codes */
|
||||
enum ieee80211_statuscode {
|
||||
WLAN_STATUS_SUCCESS = 0,
|
||||
@ -1196,6 +1302,17 @@ enum ieee80211_statuscode {
|
||||
WLAN_STATUS_ANTI_CLOG_REQUIRED = 76,
|
||||
WLAN_STATUS_FCG_NOT_SUPP = 78,
|
||||
WLAN_STATUS_STA_NO_TBTT = 78,
|
||||
/* 802.11ad */
|
||||
WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES = 39,
|
||||
WLAN_STATUS_REJECTED_FOR_DELAY_PERIOD = 47,
|
||||
WLAN_STATUS_REJECT_WITH_SCHEDULE = 83,
|
||||
WLAN_STATUS_PENDING_ADMITTING_FST_SESSION = 86,
|
||||
WLAN_STATUS_PERFORMING_FST_NOW = 87,
|
||||
WLAN_STATUS_PENDING_GAP_IN_BA_WINDOW = 88,
|
||||
WLAN_STATUS_REJECT_U_PID_SETTING = 89,
|
||||
WLAN_STATUS_REJECT_DSE_BAND = 96,
|
||||
WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
|
||||
WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
|
||||
};
|
||||
|
||||
|
||||
@ -1352,6 +1469,43 @@ enum ieee80211_eid {
|
||||
WLAN_EID_DSE_REGISTERED_LOCATION = 58,
|
||||
WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59,
|
||||
WLAN_EID_EXT_CHANSWITCH_ANN = 60,
|
||||
|
||||
WLAN_EID_VHT_CAPABILITY = 191,
|
||||
WLAN_EID_VHT_OPERATION = 192,
|
||||
|
||||
/* 802.11ad */
|
||||
WLAN_EID_NON_TX_BSSID_CAP = 83,
|
||||
WLAN_EID_WAKEUP_SCHEDULE = 143,
|
||||
WLAN_EID_EXT_SCHEDULE = 144,
|
||||
WLAN_EID_STA_AVAILABILITY = 145,
|
||||
WLAN_EID_DMG_TSPEC = 146,
|
||||
WLAN_EID_DMG_AT = 147,
|
||||
WLAN_EID_DMG_CAP = 148,
|
||||
WLAN_EID_DMG_OPERATION = 151,
|
||||
WLAN_EID_DMG_BSS_PARAM_CHANGE = 152,
|
||||
WLAN_EID_DMG_BEAM_REFINEMENT = 153,
|
||||
WLAN_EID_CHANNEL_MEASURE_FEEDBACK = 154,
|
||||
WLAN_EID_AWAKE_WINDOW = 157,
|
||||
WLAN_EID_MULTI_BAND = 158,
|
||||
WLAN_EID_ADDBA_EXT = 159,
|
||||
WLAN_EID_NEXT_PCP_LIST = 160,
|
||||
WLAN_EID_PCP_HANDOVER = 161,
|
||||
WLAN_EID_DMG_LINK_MARGIN = 162,
|
||||
WLAN_EID_SWITCHING_STREAM = 163,
|
||||
WLAN_EID_SESSION_TRANSITION = 164,
|
||||
WLAN_EID_DYN_TONE_PAIRING_REPORT = 165,
|
||||
WLAN_EID_CLUSTER_REPORT = 166,
|
||||
WLAN_EID_RELAY_CAP = 167,
|
||||
WLAN_EID_RELAY_XFER_PARAM_SET = 168,
|
||||
WLAN_EID_BEAM_LINK_MAINT = 169,
|
||||
WLAN_EID_MULTIPLE_MAC_ADDR = 170,
|
||||
WLAN_EID_U_PID = 171,
|
||||
WLAN_EID_DMG_LINK_ADAPT_ACK = 172,
|
||||
WLAN_EID_QUIET_PERIOD_REQ = 175,
|
||||
WLAN_EID_QUIET_PERIOD_RESP = 177,
|
||||
WLAN_EID_EPAC_POLICY = 182,
|
||||
WLAN_EID_CLISTER_TIME_OFF = 183,
|
||||
WLAN_EID_ANTENNA_SECTOR_ID_PATTERN = 190,
|
||||
};
|
||||
|
||||
/* Action category code */
|
||||
@ -1368,7 +1522,10 @@ enum ieee80211_category {
|
||||
WLAN_CATEGORY_MESH_ACTION = 13,
|
||||
WLAN_CATEGORY_MULTIHOP_ACTION = 14,
|
||||
WLAN_CATEGORY_SELF_PROTECTED = 15,
|
||||
WLAN_CATEGORY_DMG = 16,
|
||||
WLAN_CATEGORY_WMM = 17,
|
||||
WLAN_CATEGORY_FST = 18,
|
||||
WLAN_CATEGORY_UNPROT_DMG = 20,
|
||||
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
|
||||
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
|
||||
};
|
||||
@ -1616,6 +1773,7 @@ enum ieee80211_sa_query_action {
|
||||
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
|
||||
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
|
||||
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
|
||||
#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
|
||||
|
||||
#define WLAN_CIPHER_SUITE_SMS4 0x00147201
|
||||
|
||||
|
@ -1638,12 +1638,20 @@ struct nl80211_sta_flag_update {
|
||||
*
|
||||
* These attribute types are used with %NL80211_STA_INFO_TXRATE
|
||||
* when getting information about the bitrate of a station.
|
||||
* There are 2 attributes for bitrate, a legacy one that represents
|
||||
* a 16-bit value, and new one that represents a 32-bit value.
|
||||
* If the rate value fits into 16 bit, both attributes are reported
|
||||
* with the same value. If the rate is too high to fit into 16 bits
|
||||
* (>6.5535Gbps) only 32-bit attribute is included.
|
||||
* User space tools encouraged to use the 32-bit attribute and fall
|
||||
* back to the 16-bit one for compatibility with older kernels.
|
||||
*
|
||||
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
|
||||
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
|
||||
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
|
||||
* @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
|
||||
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
|
||||
* @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
|
||||
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
|
||||
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -1653,6 +1661,7 @@ enum nl80211_rate_info {
|
||||
NL80211_RATE_INFO_MCS,
|
||||
NL80211_RATE_INFO_40_MHZ_WIDTH,
|
||||
NL80211_RATE_INFO_SHORT_GI,
|
||||
NL80211_RATE_INFO_BITRATE32,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_RATE_INFO_AFTER_LAST,
|
||||
@ -1813,6 +1822,9 @@ enum nl80211_mpath_info {
|
||||
* @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
|
||||
* @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
|
||||
* @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
|
||||
* @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
|
||||
* defined in 802.11ac
|
||||
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
|
||||
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
|
||||
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -1826,6 +1838,9 @@ enum nl80211_band_attr {
|
||||
NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
|
||||
NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
|
||||
|
||||
NL80211_BAND_ATTR_VHT_MCS_SET,
|
||||
NL80211_BAND_ATTR_VHT_CAPA,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_BAND_ATTR_AFTER_LAST,
|
||||
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
|
||||
@ -2539,10 +2554,12 @@ enum nl80211_tx_rate_attributes {
|
||||
* enum nl80211_band - Frequency band
|
||||
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
|
||||
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
|
||||
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
|
||||
*/
|
||||
enum nl80211_band {
|
||||
NL80211_BAND_2GHZ,
|
||||
NL80211_BAND_5GHZ,
|
||||
NL80211_BAND_60GHZ,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -70,11 +70,13 @@
|
||||
*
|
||||
* @IEEE80211_BAND_2GHZ: 2.4GHz ISM band
|
||||
* @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
|
||||
* @IEEE80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
|
||||
* @IEEE80211_NUM_BANDS: number of defined bands
|
||||
*/
|
||||
enum ieee80211_band {
|
||||
IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ,
|
||||
IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ,
|
||||
IEEE80211_BAND_60GHZ = NL80211_BAND_60GHZ,
|
||||
|
||||
/* keep last */
|
||||
IEEE80211_NUM_BANDS
|
||||
@ -210,6 +212,22 @@ struct ieee80211_sta_ht_cap {
|
||||
struct ieee80211_mcs_info mcs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_sta_vht_cap - STA's VHT capabilities
|
||||
*
|
||||
* This structure describes most essential parameters needed
|
||||
* to describe 802.11ac VHT capabilities for an STA.
|
||||
*
|
||||
* @vht_supported: is VHT supported by the STA
|
||||
* @cap: VHT capabilities map as described in 802.11ac spec
|
||||
* @vht_mcs: Supported VHT MCS rates
|
||||
*/
|
||||
struct ieee80211_sta_vht_cap {
|
||||
bool vht_supported;
|
||||
u32 cap; /* use IEEE80211_VHT_CAP_ */
|
||||
struct ieee80211_vht_mcs_info vht_mcs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_supported_band - frequency band definition
|
||||
*
|
||||
@ -233,6 +251,7 @@ struct ieee80211_supported_band {
|
||||
int n_channels;
|
||||
int n_bitrates;
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
struct ieee80211_sta_vht_cap vht_cap;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -561,11 +580,13 @@ enum station_info_flags {
|
||||
* @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
|
||||
* @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
|
||||
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
|
||||
* @RATE_INFO_FLAGS_60G: 60gHz MCS
|
||||
*/
|
||||
enum rate_info_flags {
|
||||
RATE_INFO_FLAGS_MCS = 1<<0,
|
||||
RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1,
|
||||
RATE_INFO_FLAGS_SHORT_GI = 1<<2,
|
||||
RATE_INFO_FLAGS_60G = 1<<3,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1482,9 +1503,8 @@ struct cfg80211_gtk_rekey_data {
|
||||
* interfaces are active this callback should reject the configuration.
|
||||
* If no interfaces are active or the device is down, the channel should
|
||||
* be stored for when a monitor interface becomes active.
|
||||
* @get_channel: Get the current operating channel, should return %NULL if
|
||||
* there's no single defined operating channel if for example the
|
||||
* device implements channel hopping for multi-channel virtual interfaces.
|
||||
* @set_monitor_enabled: Notify driver that there are only monitor
|
||||
* interfaces running.
|
||||
*
|
||||
* @scan: Request to do a scan. If returning zero, the scan request is given
|
||||
* the driver, and will be valid until passed to cfg80211_scan_done().
|
||||
@ -1791,15 +1811,14 @@ struct cfg80211_ops {
|
||||
struct net_device *dev,
|
||||
u16 noack_map);
|
||||
|
||||
struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy,
|
||||
enum nl80211_channel_type *type);
|
||||
|
||||
int (*get_et_sset_count)(struct wiphy *wiphy,
|
||||
struct net_device *dev, int sset);
|
||||
void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct ethtool_stats *stats, u64 *data);
|
||||
void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
|
||||
u32 sset, u8 *data);
|
||||
|
||||
void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2153,7 +2172,9 @@ struct wiphy {
|
||||
char fw_version[ETHTOOL_BUSINFO_LEN];
|
||||
u32 hw_version;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct wiphy_wowlan_support wowlan;
|
||||
#endif
|
||||
|
||||
u16 max_remain_on_channel_duration;
|
||||
|
||||
@ -2389,6 +2410,11 @@ struct wireless_dev {
|
||||
struct ieee80211_channel *preset_chan;
|
||||
enum nl80211_channel_type preset_chantype;
|
||||
|
||||
/* for AP and mesh channel tracking */
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
bool ibss_fixed;
|
||||
|
||||
bool ps;
|
||||
int ps_timeout;
|
||||
|
||||
@ -3463,7 +3489,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
|
||||
*
|
||||
* return 0 if MCS index >= 32
|
||||
*/
|
||||
u16 cfg80211_calculate_bitrate(struct rate_info *rate);
|
||||
u32 cfg80211_calculate_bitrate(struct rate_info *rate);
|
||||
|
||||
/* Logging, debugging and troubleshooting/diagnostic helpers. */
|
||||
|
||||
|
@ -475,7 +475,7 @@ enum mac80211_rate_control_flags {
|
||||
#define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24
|
||||
|
||||
/* maximum number of rate stages */
|
||||
#define IEEE80211_TX_MAX_RATES 5
|
||||
#define IEEE80211_TX_MAX_RATES 4
|
||||
|
||||
/**
|
||||
* struct ieee80211_tx_rate - rate selection/status
|
||||
@ -563,11 +563,11 @@ struct ieee80211_tx_info {
|
||||
} control;
|
||||
struct {
|
||||
struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
|
||||
u8 ampdu_ack_len;
|
||||
int ack_signal;
|
||||
u8 ampdu_ack_len;
|
||||
u8 ampdu_len;
|
||||
u8 antenna;
|
||||
/* 14 bytes free */
|
||||
/* 21 bytes free */
|
||||
} status;
|
||||
struct {
|
||||
struct ieee80211_tx_rate driver_rates[
|
||||
@ -634,7 +634,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
||||
info->status.rates[i].count = 0;
|
||||
|
||||
BUILD_BUG_ON(
|
||||
offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23);
|
||||
offsetof(struct ieee80211_tx_info, status.ack_signal) != 20);
|
||||
memset(&info->status.ampdu_ack_len, 0,
|
||||
sizeof(struct ieee80211_tx_info) -
|
||||
offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
|
||||
@ -1896,19 +1896,6 @@ enum ieee80211_rate_control_changed {
|
||||
* The low-level driver should send the frame out based on
|
||||
* configuration in the TX control data. This handler should,
|
||||
* preferably, never fail and stop queues appropriately.
|
||||
* This must be implemented if @tx_frags is not.
|
||||
* Must be atomic.
|
||||
*
|
||||
* @tx_frags: Called to transmit multiple fragments of a single MSDU.
|
||||
* This handler must consume all fragments, sending out some of
|
||||
* them only is useless and it can't ask for some of them to be
|
||||
* queued again. If the frame is not fragmented the queue has a
|
||||
* single SKB only. To avoid issues with the networking stack
|
||||
* when TX status is reported the frames should be removed from
|
||||
* the skb queue.
|
||||
* If this is used, the tx_info @vif and @sta pointers will be
|
||||
* invalid -- you must not use them in that case.
|
||||
* This must be implemented if @tx isn't.
|
||||
* Must be atomic.
|
||||
*
|
||||
* @start: Called before the first netdevice attached to the hardware
|
||||
@ -2257,11 +2244,21 @@ enum ieee80211_rate_control_changed {
|
||||
* @get_rssi: Get current signal strength in dBm, the function is optional
|
||||
* and can sleep.
|
||||
*
|
||||
* @mgd_prepare_tx: Prepare for transmitting a management frame for association
|
||||
* before associated. In multi-channel scenarios, a virtual interface is
|
||||
* bound to a channel before it is associated, but as it isn't associated
|
||||
* yet it need not necessarily be given airtime, in particular since any
|
||||
* transmission to a P2P GO needs to be synchronized against the GO's
|
||||
* powersave state. mac80211 will call this function before transmitting a
|
||||
* management frame prior to having successfully associated to allow the
|
||||
* driver to give it channel time for the transmission, to get a response
|
||||
* and to be able to synchronize with the GO.
|
||||
* 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.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
void (*tx_frags)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct sk_buff_head *skbs);
|
||||
int (*start)(struct ieee80211_hw *hw);
|
||||
void (*stop)(struct ieee80211_hw *hw);
|
||||
#ifdef CONFIG_PM
|
||||
@ -2398,6 +2395,9 @@ struct ieee80211_ops {
|
||||
u32 sset, u8 *data);
|
||||
int (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, s8 *rssi_dbm);
|
||||
|
||||
void (*mgd_prepare_tx)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3832,12 +3832,6 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
|
||||
|
||||
void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
|
||||
|
||||
int ieee80211_add_srates_ie(struct ieee80211_vif *vif,
|
||||
struct sk_buff *skb, bool need_basic);
|
||||
|
||||
int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
|
||||
struct sk_buff *skb, bool need_basic);
|
||||
|
||||
/**
|
||||
* ieee80211_ave_rssi - report the average rssi for the specified interface
|
||||
*
|
||||
|
@ -2668,8 +2668,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->vif, skb, false);
|
||||
ieee80211_add_ext_srates_ie(&sdata->vif, skb, false);
|
||||
ieee80211_add_srates_ie(sdata, skb, false);
|
||||
ieee80211_add_ext_srates_ie(sdata, skb, false);
|
||||
ieee80211_tdls_add_ext_capab(skb);
|
||||
break;
|
||||
case WLAN_TDLS_SETUP_RESPONSE:
|
||||
@ -2682,8 +2682,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->vif, skb, false);
|
||||
ieee80211_add_ext_srates_ie(&sdata->vif, skb, false);
|
||||
ieee80211_add_srates_ie(sdata, skb, false);
|
||||
ieee80211_add_ext_srates_ie(sdata, skb, false);
|
||||
ieee80211_tdls_add_ext_capab(skb);
|
||||
break;
|
||||
case WLAN_TDLS_SETUP_CONFIRM:
|
||||
@ -2743,8 +2743,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->vif, skb, false);
|
||||
ieee80211_add_ext_srates_ie(&sdata->vif, skb, false);
|
||||
ieee80211_add_srates_ie(sdata, skb, false);
|
||||
ieee80211_add_ext_srates_ie(sdata, skb, false);
|
||||
ieee80211_tdls_add_ext_capab(skb);
|
||||
break;
|
||||
default:
|
||||
@ -2980,14 +2980,14 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ieee80211_channel *
|
||||
ieee80211_wiphy_get_channel(struct wiphy *wiphy,
|
||||
enum nl80211_channel_type *type)
|
||||
static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
|
||||
*type = local->_oper_channel_type;
|
||||
return local->oper_channel;
|
||||
if (enabled)
|
||||
WARN_ON(ieee80211_add_virtual_monitor(local));
|
||||
else
|
||||
ieee80211_del_virtual_monitor(local);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -3063,8 +3063,8 @@ struct cfg80211_ops mac80211_config_ops = {
|
||||
.tdls_oper = ieee80211_tdls_oper,
|
||||
.tdls_mgmt = ieee80211_tdls_mgmt,
|
||||
.probe_client = ieee80211_probe_client,
|
||||
.get_channel = ieee80211_wiphy_get_channel,
|
||||
.set_noack_map = ieee80211_set_noack_map,
|
||||
.set_monitor_enabled = ieee80211_set_monitor_enabled,
|
||||
#ifdef CONFIG_PM
|
||||
.set_wakeup = ieee80211_set_wakeup,
|
||||
#endif
|
||||
|
@ -283,6 +283,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
|
||||
|
||||
lockdep_assert_held(&sdata->local->key_mtx);
|
||||
|
||||
if (sdata->debugfs.default_unicast_key) {
|
||||
debugfs_remove(sdata->debugfs.default_unicast_key);
|
||||
sdata->debugfs.default_unicast_key = NULL;
|
||||
}
|
||||
|
||||
if (sdata->default_unicast_key) {
|
||||
key = key_mtx_dereference(sdata->local,
|
||||
sdata->default_unicast_key);
|
||||
@ -290,9 +295,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->debugfs.default_unicast_key =
|
||||
debugfs_create_symlink("default_unicast_key",
|
||||
sdata->debugfs.dir, buf);
|
||||
} else {
|
||||
debugfs_remove(sdata->debugfs.default_unicast_key);
|
||||
sdata->debugfs.default_unicast_key = NULL;
|
||||
}
|
||||
|
||||
if (sdata->debugfs.default_multicast_key) {
|
||||
debugfs_remove(sdata->debugfs.default_multicast_key);
|
||||
sdata->debugfs.default_multicast_key = NULL;
|
||||
}
|
||||
|
||||
if (sdata->default_multicast_key) {
|
||||
@ -302,9 +309,6 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->debugfs.default_multicast_key =
|
||||
debugfs_create_symlink("default_multicast_key",
|
||||
sdata->debugfs.dir, buf);
|
||||
} else {
|
||||
debugfs_remove(sdata->debugfs.default_multicast_key);
|
||||
sdata->debugfs.default_multicast_key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,14 +27,6 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
local->ops->tx(&local->hw, skb);
|
||||
}
|
||||
|
||||
static inline void drv_tx_frags(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct sk_buff_head *skbs)
|
||||
{
|
||||
local->ops->tx_frags(&local->hw, vif, sta, skbs);
|
||||
}
|
||||
|
||||
static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata,
|
||||
u32 sset, u8 *data)
|
||||
{
|
||||
@ -860,4 +852,18 @@ static inline int drv_get_rssi(struct ieee80211_local *local,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
check_sdata_in_driver(sdata);
|
||||
WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION);
|
||||
|
||||
trace_drv_mgd_prepare_tx(local, sdata);
|
||||
if (local->ops->mgd_prepare_tx)
|
||||
local->ops->mgd_prepare_tx(&local->hw, &sdata->vif);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
|
@ -1284,7 +1284,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type);
|
||||
void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_remove_interfaces(struct ieee80211_local *local);
|
||||
u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
|
||||
const int offset);
|
||||
@ -1481,6 +1480,16 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type channel_type,
|
||||
u16 prot_mode);
|
||||
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
u32 cap);
|
||||
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, bool need_basic);
|
||||
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, bool need_basic);
|
||||
|
||||
/* virtual monitor */
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
|
||||
void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
|
||||
|
||||
/* channel management */
|
||||
enum ieee80211_chan_mode {
|
||||
|
@ -43,6 +43,127 @@
|
||||
*/
|
||||
|
||||
|
||||
static u32 ieee80211_idle_off(struct ieee80211_local *local,
|
||||
const char *reason)
|
||||
{
|
||||
if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
|
||||
return 0;
|
||||
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
|
||||
return IEEE80211_CONF_CHANGE_IDLE;
|
||||
}
|
||||
|
||||
static u32 ieee80211_idle_on(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
|
||||
return 0;
|
||||
|
||||
drv_flush(local, false);
|
||||
|
||||
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
|
||||
return IEEE80211_CONF_CHANGE_IDLE;
|
||||
}
|
||||
|
||||
static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int count = 0;
|
||||
bool working = false, scanning = false;
|
||||
unsigned int led_trig_start = 0, led_trig_stop = 0;
|
||||
struct ieee80211_roc_work *roc;
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
|
||||
!lockdep_is_held(&local->iflist_mtx));
|
||||
#endif
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata)) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
sdata->old_idle = sdata->vif.bss_conf.idle;
|
||||
|
||||
/* do not count disabled managed interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!sdata->u.mgd.associated &&
|
||||
!sdata->u.mgd.auth_data &&
|
||||
!sdata->u.mgd.assoc_data) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
/* do not count unused IBSS interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
!sdata->u.ibss.ssid_len) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
/* count everything else */
|
||||
sdata->vif.bss_conf.idle = false;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!local->ops->remain_on_channel) {
|
||||
list_for_each_entry(roc, &local->roc_list, list) {
|
||||
working = true;
|
||||
roc->sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (local->scan_sdata &&
|
||||
!(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
|
||||
scanning = true;
|
||||
local->scan_sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
continue;
|
||||
if (sdata->old_idle == sdata->vif.bss_conf.idle)
|
||||
continue;
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
||||
}
|
||||
|
||||
if (working || scanning)
|
||||
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
else
|
||||
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
|
||||
if (count)
|
||||
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
|
||||
else
|
||||
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
|
||||
|
||||
ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
|
||||
|
||||
if (working)
|
||||
return ieee80211_idle_off(local, "working");
|
||||
if (scanning)
|
||||
return ieee80211_idle_off(local, "scanning");
|
||||
if (!count)
|
||||
return ieee80211_idle_on(local);
|
||||
else
|
||||
return ieee80211_idle_off(local, "in use");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
u32 chg;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
chg = __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
if (chg)
|
||||
ieee80211_hw_config(local, chg);
|
||||
}
|
||||
|
||||
static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
int meshhdrlen;
|
||||
@ -209,7 +330,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
|
||||
}
|
||||
|
||||
static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int ret;
|
||||
@ -250,7 +371,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
|
||||
void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
@ -366,12 +487,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
|
||||
break;
|
||||
}
|
||||
|
||||
if (local->monitors == 0 && local->open_count == 0) {
|
||||
res = ieee80211_add_virtual_monitor(local);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
/* must be before the call to ieee80211_configure_filter */
|
||||
local->monitors++;
|
||||
if (local->monitors == 1) {
|
||||
@ -386,8 +501,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
|
||||
break;
|
||||
default:
|
||||
if (coming_up) {
|
||||
ieee80211_del_virtual_monitor(local);
|
||||
|
||||
res = drv_add_interface(local, sdata);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
@ -622,7 +735,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
if (local->monitors == 0) {
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
|
||||
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
|
||||
ieee80211_del_virtual_monitor(local);
|
||||
}
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
@ -696,9 +808,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
if (local->monitors == local->open_count && local->monitors > 0)
|
||||
ieee80211_add_virtual_monitor(local);
|
||||
}
|
||||
|
||||
static int ieee80211_stop(struct net_device *dev)
|
||||
@ -1403,127 +1512,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
|
||||
list_del(&unreg_list);
|
||||
}
|
||||
|
||||
static u32 ieee80211_idle_off(struct ieee80211_local *local,
|
||||
const char *reason)
|
||||
{
|
||||
if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
|
||||
return 0;
|
||||
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
|
||||
return IEEE80211_CONF_CHANGE_IDLE;
|
||||
}
|
||||
|
||||
static u32 ieee80211_idle_on(struct ieee80211_local *local)
|
||||
{
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
|
||||
return 0;
|
||||
|
||||
drv_flush(local, false);
|
||||
|
||||
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
|
||||
return IEEE80211_CONF_CHANGE_IDLE;
|
||||
}
|
||||
|
||||
u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int count = 0;
|
||||
bool working = false, scanning = false;
|
||||
unsigned int led_trig_start = 0, led_trig_stop = 0;
|
||||
struct ieee80211_roc_work *roc;
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
|
||||
!lockdep_is_held(&local->iflist_mtx));
|
||||
#endif
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (!ieee80211_sdata_running(sdata)) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
sdata->old_idle = sdata->vif.bss_conf.idle;
|
||||
|
||||
/* do not count disabled managed interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!sdata->u.mgd.associated &&
|
||||
!sdata->u.mgd.auth_data &&
|
||||
!sdata->u.mgd.assoc_data) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
/* do not count unused IBSS interfaces */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
!sdata->u.ibss.ssid_len) {
|
||||
sdata->vif.bss_conf.idle = true;
|
||||
continue;
|
||||
}
|
||||
/* count everything else */
|
||||
sdata->vif.bss_conf.idle = false;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!local->ops->remain_on_channel) {
|
||||
list_for_each_entry(roc, &local->roc_list, list) {
|
||||
working = true;
|
||||
roc->sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (local->scan_sdata &&
|
||||
!(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
|
||||
scanning = true;
|
||||
local->scan_sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
continue;
|
||||
if (sdata->old_idle == sdata->vif.bss_conf.idle)
|
||||
continue;
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
|
||||
}
|
||||
|
||||
if (working || scanning)
|
||||
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
else
|
||||
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK;
|
||||
|
||||
if (count)
|
||||
led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
|
||||
else
|
||||
led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED;
|
||||
|
||||
ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
|
||||
|
||||
if (working)
|
||||
return ieee80211_idle_off(local, "working");
|
||||
if (scanning)
|
||||
return ieee80211_idle_off(local, "scanning");
|
||||
if (!count)
|
||||
return ieee80211_idle_on(local);
|
||||
else
|
||||
return ieee80211_idle_off(local, "in use");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
{
|
||||
u32 chg;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
chg = __ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
if (chg)
|
||||
ieee80211_hw_config(local, chg);
|
||||
}
|
||||
|
||||
static int netdev_notify(struct notifier_block *nb,
|
||||
unsigned long state,
|
||||
void *ndev)
|
||||
|
@ -587,7 +587,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
|
||||
local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
|
||||
|
||||
BUG_ON(!ops->tx && !ops->tx_frags);
|
||||
BUG_ON(!ops->tx);
|
||||
BUG_ON(!ops->start);
|
||||
BUG_ON(!ops->stop);
|
||||
BUG_ON(!ops->config);
|
||||
@ -688,7 +688,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
int result, i;
|
||||
enum ieee80211_band band;
|
||||
int channels, max_bitrates;
|
||||
bool supp_ht;
|
||||
bool supp_ht, supp_vht;
|
||||
netdev_features_t feature_whitelist;
|
||||
static const u32 cipher_suites[] = {
|
||||
/* keep WEP first, it may be removed below */
|
||||
@ -706,12 +706,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
local->hw.offchannel_tx_hw_queue >= local->hw.queues))
|
||||
return -EINVAL;
|
||||
|
||||
if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns)
|
||||
#ifdef CONFIG_PM
|
||||
&& (!local->ops->suspend || !local->ops->resume)
|
||||
#endif
|
||||
)
|
||||
if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) &&
|
||||
(!local->ops->suspend || !local->ops->resume))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
|
||||
return -EINVAL;
|
||||
@ -733,6 +732,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
channels = 0;
|
||||
max_bitrates = 0;
|
||||
supp_ht = false;
|
||||
supp_vht = false;
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
@ -750,6 +750,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
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;
|
||||
}
|
||||
|
||||
local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
|
||||
@ -825,6 +826,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
if (supp_ht)
|
||||
local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);
|
||||
|
||||
if (supp_vht)
|
||||
local->scan_ies_len +=
|
||||
2 + sizeof(struct ieee80211_vht_capabilities);
|
||||
|
||||
if (!local->ops->hw_scan) {
|
||||
/* For hw_scan, driver needs to set these up. */
|
||||
local->hw.wiphy->max_scan_ssids = 4;
|
||||
|
@ -258,8 +258,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->vif, skb, true) ||
|
||||
ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) ||
|
||||
if (ieee80211_add_srates_ie(sdata, skb, true) ||
|
||||
ieee80211_add_ext_srates_ie(sdata, skb, true) ||
|
||||
mesh_add_rsn_ie(skb, sdata) ||
|
||||
mesh_add_meshid_ie(skb, sdata) ||
|
||||
mesh_add_meshconf_ie(skb, sdata))
|
||||
|
@ -541,6 +541,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
||||
memcpy(pos, assoc_data->ie + offset, noffset - offset);
|
||||
}
|
||||
|
||||
drv_mgd_prepare_tx(local, sdata);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
@ -580,6 +582,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
|
||||
IEEE80211_SKB_CB(skb)->flags |=
|
||||
IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
|
||||
drv_mgd_prepare_tx(local, sdata);
|
||||
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
}
|
||||
@ -902,9 +907,6 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
|
||||
if (!mgd->associated)
|
||||
return false;
|
||||
|
||||
if (!mgd->associated->beacon_ies)
|
||||
return false;
|
||||
|
||||
if (mgd->flags & (IEEE80211_STA_BEACON_POLL |
|
||||
IEEE80211_STA_CONNECTION_POLL))
|
||||
return false;
|
||||
@ -1362,6 +1364,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
|
||||
if (tx)
|
||||
drv_flush(local, false);
|
||||
|
||||
/* deauthenticate/disassociate now */
|
||||
if (tx || frame_buf)
|
||||
ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
|
||||
@ -1610,6 +1616,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct cfg80211_bss *cbss;
|
||||
struct sk_buff *skb;
|
||||
const u8 *ssid;
|
||||
int ssid_len;
|
||||
@ -1619,16 +1626,22 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
|
||||
|
||||
ASSERT_MGD_MTX(ifmgd);
|
||||
|
||||
if (!ifmgd->associated)
|
||||
if (ifmgd->associated)
|
||||
cbss = ifmgd->associated;
|
||||
else if (ifmgd->auth_data)
|
||||
cbss = ifmgd->auth_data->bss;
|
||||
else if (ifmgd->assoc_data)
|
||||
cbss = ifmgd->assoc_data->bss;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
|
||||
ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID);
|
||||
if (WARN_ON_ONCE(ssid == NULL))
|
||||
ssid_len = 0;
|
||||
else
|
||||
ssid_len = ssid[1];
|
||||
|
||||
skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid,
|
||||
skb = ieee80211_build_probe_req(sdata, cbss->bssid,
|
||||
(u32) -1, ssid + 2, ssid_len,
|
||||
NULL, 0, true);
|
||||
|
||||
@ -1747,6 +1760,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
|
||||
if (!elems.challenge)
|
||||
return;
|
||||
auth_data->expected_transaction = 4;
|
||||
drv_mgd_prepare_tx(sdata->local, sdata);
|
||||
ieee80211_send_auth(sdata, 3, auth_data->algorithm,
|
||||
elems.challenge - 2, elems.challenge_len + 2,
|
||||
auth_data->bss->bssid, auth_data->bss->bssid,
|
||||
@ -2630,6 +2644,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
drv_mgd_prepare_tx(local, sdata);
|
||||
|
||||
if (auth_data->bss->proberesp_ies) {
|
||||
sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
|
||||
auth_data->bss->bssid, auth_data->tries,
|
||||
|
@ -1244,6 +1244,13 @@ TRACE_EVENT(drv_get_rssi,
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
|
||||
TP_ARGS(local, sdata)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracing for API calls that drivers call.
|
||||
*/
|
||||
|
@ -140,6 +140,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
||||
if (r->flags & IEEE80211_RATE_MANDATORY_A)
|
||||
mrate = r->bitrate;
|
||||
break;
|
||||
case IEEE80211_BAND_60GHZ:
|
||||
/* TODO, for now fall through */
|
||||
case IEEE80211_NUM_BANDS:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
@ -957,8 +959,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
||||
info->control.rates[1].idx = -1;
|
||||
info->control.rates[2].idx = -1;
|
||||
info->control.rates[3].idx = -1;
|
||||
info->control.rates[4].idx = -1;
|
||||
BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
|
||||
BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);
|
||||
info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
||||
} else {
|
||||
hdr->frame_control &= ~morefrags;
|
||||
@ -1293,11 +1294,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
|
||||
break;
|
||||
}
|
||||
|
||||
if (local->ops->tx_frags)
|
||||
drv_tx_frags(local, vif, pubsta, skbs);
|
||||
else
|
||||
result = ieee80211_tx_frags(local, vif, pubsta, skbs,
|
||||
txpending);
|
||||
result = ieee80211_tx_frags(local, vif, pubsta, skbs,
|
||||
txpending);
|
||||
|
||||
ieee80211_tpt_led_trig_tx(local, fc, led_len);
|
||||
ieee80211_led_tx(local, 1);
|
||||
@ -2420,9 +2418,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = 0x0;
|
||||
|
||||
if (ieee80211_add_srates_ie(&sdata->vif, skb, true) ||
|
||||
if (ieee80211_add_srates_ie(sdata, skb, true) ||
|
||||
mesh_add_ds_params_ie(skb, sdata) ||
|
||||
ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) ||
|
||||
ieee80211_add_ext_srates_ie(sdata, skb, true) ||
|
||||
mesh_add_rsn_ie(skb, sdata) ||
|
||||
mesh_add_ht_cap_ie(skb, sdata) ||
|
||||
mesh_add_ht_oper_ie(skb, sdata) ||
|
||||
|
@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration);
|
||||
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int n_acs = IEEE80211_NUM_ACS;
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
n_acs = 1;
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
int ac;
|
||||
@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
|
||||
local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
|
||||
continue;
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
for (ac = 0; ac < n_acs; ac++) {
|
||||
int ac_queue = sdata->vif.hw_queue[ac];
|
||||
|
||||
if (ac_queue == queue ||
|
||||
@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int n_acs = IEEE80211_NUM_ACS;
|
||||
|
||||
trace_stop_queue(local, queue, reason);
|
||||
|
||||
@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
|
||||
|
||||
__set_bit(reason, &local->queue_stop_reasons[queue]);
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
n_acs = 1;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
int ac;
|
||||
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
for (ac = 0; ac < n_acs; ac++) {
|
||||
if (sdata->vif.hw_queue[ac] == queue ||
|
||||
sdata->vif.cab_queue == queue)
|
||||
netif_stop_subqueue(sdata->dev, ac);
|
||||
@ -1072,6 +1080,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
pos += noffset - offset;
|
||||
}
|
||||
|
||||
if (sband->vht_cap.vht_supported)
|
||||
pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
|
||||
sband->vht_cap.cap);
|
||||
|
||||
return pos - buffer;
|
||||
}
|
||||
|
||||
@ -1411,10 +1423,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
if (ieee80211_sdata_running(sdata))
|
||||
ieee80211_enable_keys(sdata);
|
||||
|
||||
wake_up:
|
||||
local->in_reconfig = false;
|
||||
barrier();
|
||||
|
||||
wake_up:
|
||||
/*
|
||||
* Clear the WLAN_STA_BLOCK_BA flag so new aggregation
|
||||
* sessions can be established after a resume.
|
||||
@ -1699,6 +1711,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
return pos;
|
||||
}
|
||||
|
||||
u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
u32 cap)
|
||||
{
|
||||
__le32 tmp;
|
||||
|
||||
*pos++ = WLAN_EID_VHT_CAPABILITY;
|
||||
*pos++ = sizeof(struct ieee80211_vht_capabilities);
|
||||
memset(pos, 0, sizeof(struct ieee80211_vht_capabilities));
|
||||
|
||||
/* capability flags */
|
||||
tmp = cpu_to_le32(cap);
|
||||
memcpy(pos, &tmp, sizeof(u32));
|
||||
pos += sizeof(u32);
|
||||
|
||||
/* VHT MCS set */
|
||||
memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs));
|
||||
pos += sizeof(vht_cap->vht_mcs);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
struct ieee80211_channel *channel,
|
||||
enum nl80211_channel_type channel_type,
|
||||
@ -1764,15 +1797,14 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
|
||||
return channel_type;
|
||||
}
|
||||
|
||||
int ieee80211_add_srates_ie(struct ieee80211_vif *vif,
|
||||
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, bool need_basic)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
int rate;
|
||||
u8 i, rates, *pos;
|
||||
u32 basic_rates = vif->bss_conf.basic_rates;
|
||||
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
rates = sband->n_bitrates;
|
||||
@ -1796,15 +1828,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif,
|
||||
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, bool need_basic)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
int rate;
|
||||
u8 i, exrates, *pos;
|
||||
u32 basic_rates = vif->bss_conf.basic_rates;
|
||||
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
exrates = sband->n_bitrates;
|
||||
|
@ -10,7 +10,7 @@ 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
|
||||
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o
|
||||
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
|
||||
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
|
||||
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
|
||||
|
46
net/wireless/ap.c
Normal file
46
net/wireless/ap.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/export.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "nl80211.h"
|
||||
#include "core.h"
|
||||
|
||||
|
||||
static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!rdev->ops->stop_ap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!wdev->beacon_interval)
|
||||
return -ENOENT;
|
||||
|
||||
err = rdev->ops->stop_ap(&rdev->wiphy, dev);
|
||||
if (!err) {
|
||||
wdev->beacon_interval = 0;
|
||||
wdev->channel = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_stop_ap(rdev, dev);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
}
|
@ -82,13 +82,73 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
int freq, enum nl80211_channel_type chantype)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
int err;
|
||||
|
||||
if (!rdev->ops->set_monitor_channel)
|
||||
return -EOPNOTSUPP;
|
||||
if (!cfg80211_has_monitors_only(rdev))
|
||||
return -EBUSY;
|
||||
|
||||
chan = rdev_freq_to_chan(rdev, freq, chantype);
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
|
||||
return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
|
||||
err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
|
||||
if (!err) {
|
||||
rdev->monitor_channel = chan;
|
||||
rdev->monitor_channel_type = chantype;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel **chan,
|
||||
enum cfg80211_chan_mode *chanmode)
|
||||
{
|
||||
*chan = NULL;
|
||||
*chanmode = CHAN_MODE_UNDEFINED;
|
||||
|
||||
ASSERT_RDEV_LOCK(rdev);
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!netif_running(wdev->netdev))
|
||||
return;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (wdev->current_bss) {
|
||||
*chan = wdev->current_bss->pub.channel;
|
||||
*chanmode = wdev->ibss_fixed
|
||||
? CHAN_MODE_SHARED
|
||||
: CHAN_MODE_EXCLUSIVE;
|
||||
return;
|
||||
}
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (wdev->current_bss) {
|
||||
*chan = wdev->current_bss->pub.channel;
|
||||
*chanmode = CHAN_MODE_SHARED;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
*chan = wdev->channel;
|
||||
*chanmode = CHAN_MODE_SHARED;
|
||||
return;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
/* these interface types don't really have a channel */
|
||||
return;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
|
||||
if (WARN_ON(!c->num_different_channels))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Put a sane limit on maximum number of different
|
||||
* channels to simplify channel accounting code.
|
||||
*/
|
||||
if (WARN_ON(c->num_different_channels >
|
||||
CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(!c->n_limits))
|
||||
return -EINVAL;
|
||||
|
||||
@ -421,9 +429,11 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
int i;
|
||||
u16 ifmodes = wiphy->interface_modes;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
|
||||
!(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
if (WARN_ON(wiphy->ap_sme_capa &&
|
||||
!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
|
||||
@ -458,8 +468,14 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
continue;
|
||||
|
||||
sband->band = band;
|
||||
|
||||
if (WARN_ON(!sband->n_channels || !sband->n_bitrates))
|
||||
if (WARN_ON(!sband->n_channels))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* on 60gHz band, there are no legacy rates, so
|
||||
* n_bitrates is 0
|
||||
*/
|
||||
if (WARN_ON(band != IEEE80211_BAND_60GHZ &&
|
||||
!sband->n_bitrates))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
@ -500,12 +516,14 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (rdev->wiphy.wowlan.n_patterns) {
|
||||
if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
|
||||
rdev->wiphy.wowlan.pattern_min_len >
|
||||
rdev->wiphy.wowlan.pattern_max_len))
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check and set up bitrates */
|
||||
ieee80211_set_bitrate_flags(wiphy);
|
||||
@ -713,6 +731,61 @@ static struct device_type wiphy_type = {
|
||||
.name = "wlan",
|
||||
};
|
||||
|
||||
static struct ieee80211_channel *
|
||||
cfg80211_get_any_chan(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
|
||||
sband = rdev->wiphy.bands[i];
|
||||
if (sband && sband->n_channels > 0)
|
||||
return &sband->channels[0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
chan = cfg80211_get_any_chan(rdev);
|
||||
if (WARN_ON(!chan))
|
||||
return;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq,
|
||||
NL80211_CHAN_NO_HT));
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
}
|
||||
|
||||
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype iftype, int num)
|
||||
{
|
||||
bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
|
||||
bool has_monitors_only_new;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
rdev->num_running_ifaces += num;
|
||||
if (iftype == NL80211_IFTYPE_MONITOR)
|
||||
rdev->num_running_monitor_ifaces += num;
|
||||
|
||||
has_monitors_only_new = cfg80211_has_monitors_only(rdev);
|
||||
if (has_monitors_only_new != has_monitors_only_old) {
|
||||
rdev->ops->set_monitor_enabled(&rdev->wiphy,
|
||||
has_monitors_only_new);
|
||||
|
||||
if (!has_monitors_only_new) {
|
||||
rdev->monitor_channel = NULL;
|
||||
rdev->monitor_channel_type = NL80211_CHAN_NO_HT;
|
||||
} else {
|
||||
cfg80211_init_mon_chan(rdev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
unsigned long state,
|
||||
void *ndev)
|
||||
@ -806,12 +879,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
cfg80211_leave_mesh(rdev, dev);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
cfg80211_stop_ap(rdev, dev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
wdev->beacon_interval = 0;
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
|
||||
dev_hold(dev);
|
||||
queue_work(cfg80211_wq, &wdev->cleanup_work);
|
||||
break;
|
||||
@ -917,9 +994,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
return notifier_from_errno(-EOPNOTSUPP);
|
||||
if (rfkill_blocked(rdev->rfkill))
|
||||
return notifier_from_errno(-ERFKILL);
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
ret = cfg80211_can_add_interface(rdev, wdev->iftype);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
if (ret)
|
||||
return notifier_from_errno(ret);
|
||||
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "reg.h"
|
||||
@ -56,6 +57,13 @@ struct cfg80211_registered_device {
|
||||
|
||||
u32 ap_beacons_nlpid;
|
||||
|
||||
/* protected by RTNL only */
|
||||
int num_running_ifaces;
|
||||
int num_running_monitor_ifaces;
|
||||
|
||||
struct ieee80211_channel *monitor_channel;
|
||||
enum nl80211_channel_type monitor_channel_type;
|
||||
|
||||
/* BSSes/scanning */
|
||||
spinlock_t bss_lock;
|
||||
struct list_head bss_list;
|
||||
@ -197,6 +205,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
|
||||
#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx)
|
||||
#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx)
|
||||
|
||||
static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
|
||||
rdev->num_running_ifaces > 0;
|
||||
}
|
||||
|
||||
enum cfg80211_event_type {
|
||||
EVENT_CONNECT_RESULT,
|
||||
EVENT_ROAMED,
|
||||
@ -241,6 +257,12 @@ struct cfg80211_cached_keys {
|
||||
int def, defmgmt;
|
||||
};
|
||||
|
||||
enum cfg80211_chan_mode {
|
||||
CHAN_MODE_UNDEFINED,
|
||||
CHAN_MODE_SHARED,
|
||||
CHAN_MODE_EXCLUSIVE,
|
||||
};
|
||||
|
||||
|
||||
/* free object */
|
||||
extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
|
||||
@ -289,6 +311,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, int freq,
|
||||
enum nl80211_channel_type channel_type);
|
||||
|
||||
/* AP */
|
||||
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev);
|
||||
|
||||
/* MLME */
|
||||
int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
@ -404,9 +430,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
u32 *flags, struct vif_params *params);
|
||||
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
||||
|
||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype);
|
||||
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode);
|
||||
|
||||
static inline int
|
||||
cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
|
||||
CHAN_MODE_UNDEFINED);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
|
||||
@ -415,6 +452,22 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
|
||||
return cfg80211_can_change_interface(rdev, NULL, iftype);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode)
|
||||
{
|
||||
return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
|
||||
chan, chanmode);
|
||||
}
|
||||
|
||||
void
|
||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel **chan,
|
||||
enum cfg80211_chan_mode *chanmode);
|
||||
|
||||
struct ieee80211_channel *
|
||||
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
|
||||
int freq, enum nl80211_channel_type channel_type);
|
||||
@ -428,6 +481,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
|
||||
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
u32 beacon_int);
|
||||
|
||||
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype iftype, int num);
|
||||
|
||||
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
|
||||
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
|
||||
#else
|
||||
|
@ -113,10 +113,21 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = connkeys;
|
||||
|
||||
wdev->ibss_fixed = params->channel_fixed;
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
wdev->wext.ibss.channel = params->channel;
|
||||
#endif
|
||||
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, params->channel,
|
||||
params->channel_fixed
|
||||
? CHAN_MODE_SHARED
|
||||
: CHAN_MODE_EXCLUSIVE);
|
||||
if (err) {
|
||||
wdev->connect_keys = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
|
||||
if (err) {
|
||||
wdev->connect_keys = NULL;
|
||||
|
@ -155,10 +155,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
setup->channel_type))
|
||||
return -EINVAL;
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
|
||||
if (!err) {
|
||||
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
|
||||
wdev->mesh_id_len = setup->mesh_id_len;
|
||||
wdev->channel = setup->channel;
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -172,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_join_mesh(rdev, dev, setup, conf);
|
||||
wdev_unlock(wdev);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -184,6 +192,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ieee80211_channel *channel;
|
||||
int err;
|
||||
|
||||
channel = rdev_freq_to_chan(rdev, freq, channel_type);
|
||||
if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
|
||||
@ -205,9 +214,19 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
|
||||
|
||||
if (!netif_running(wdev->netdev))
|
||||
return -ENETDOWN;
|
||||
return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
|
||||
wdev->netdev,
|
||||
channel);
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
|
||||
wdev->netdev,
|
||||
channel);
|
||||
if (!err)
|
||||
wdev->channel = channel;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
if (wdev->mesh_id_len)
|
||||
@ -249,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
||||
return -ENOTCONN;
|
||||
|
||||
err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
|
||||
if (!err)
|
||||
if (!err) {
|
||||
wdev->mesh_id_len = 0;
|
||||
wdev->channel = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
if (!req.bss)
|
||||
return -ENOENT;
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = rdev->ops->auth(&rdev->wiphy, dev, &req);
|
||||
|
||||
out:
|
||||
cfg80211_put_bss(req.bss);
|
||||
return err;
|
||||
}
|
||||
@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
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);
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
if (was_connected)
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
|
||||
ssid, ssid_len, ie, ie_len, use_mfp, crypt,
|
||||
assoc_flags, ht_capa, ht_capa_mask);
|
||||
wdev_unlock(wdev);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -947,6 +963,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
|
||||
if (WARN_ON(!chan))
|
||||
goto out;
|
||||
|
||||
wdev->channel = chan;
|
||||
nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
|
||||
out:
|
||||
wdev_unlock(wdev);
|
||||
|
@ -921,6 +921,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
dev->wiphy.bands[band]->ht_cap.ampdu_density)))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* add VHT info */
|
||||
if (dev->wiphy.bands[band]->vht_cap.vht_supported &&
|
||||
(nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
|
||||
sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs),
|
||||
&dev->wiphy.bands[band]->vht_cap.vht_mcs) ||
|
||||
nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
|
||||
dev->wiphy.bands[band]->vht_cap.cap)))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* add frequencies */
|
||||
nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
|
||||
if (!nl_freqs)
|
||||
@ -1112,6 +1121,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
nla_nest_end(msg, nl_ifs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) {
|
||||
struct nlattr *nl_wowlan;
|
||||
|
||||
@ -1152,6 +1162,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
|
||||
nla_nest_end(msg, nl_wowlan);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
|
||||
dev->wiphy.software_iftypes))
|
||||
@ -1678,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
(cfg80211_rdev_list_generation << 2)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (rdev->ops->get_channel) {
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type);
|
||||
if (chan &&
|
||||
(nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
||||
chan->center_freq) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
|
||||
channel_type)))
|
||||
if (rdev->monitor_channel) {
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
||||
rdev->monitor_channel->center_freq) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
|
||||
rdev->monitor_channel_type))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
@ -2472,11 +2478,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
||||
params.channel_type))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
err = cfg80211_can_use_chan(rdev, wdev, params.channel,
|
||||
CHAN_MODE_SHARED);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms);
|
||||
if (!err) {
|
||||
wdev->preset_chan = params.channel;
|
||||
wdev->preset_chantype = params.channel_type;
|
||||
wdev->beacon_interval = params.beacon_interval;
|
||||
wdev->channel = params.channel;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -2510,23 +2525,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
if (!rdev->ops->stop_ap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!wdev->beacon_interval)
|
||||
return -ENOENT;
|
||||
|
||||
err = rdev->ops->stop_ap(&rdev->wiphy, dev);
|
||||
if (!err)
|
||||
wdev->beacon_interval = 0;
|
||||
return err;
|
||||
return cfg80211_stop_ap(rdev, dev);
|
||||
}
|
||||
|
||||
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
|
||||
@ -2618,7 +2618,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
int attr)
|
||||
{
|
||||
struct nlattr *rate;
|
||||
u16 bitrate;
|
||||
u32 bitrate;
|
||||
u16 bitrate_compat;
|
||||
|
||||
rate = nla_nest_start(msg, attr);
|
||||
if (!rate)
|
||||
@ -2626,8 +2627,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
|
||||
/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
|
||||
bitrate = cfg80211_calculate_bitrate(info);
|
||||
/* report 16-bit bitrate only if we can */
|
||||
bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
|
||||
if ((bitrate > 0 &&
|
||||
nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) ||
|
||||
nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) ||
|
||||
(bitrate_compat > 0 &&
|
||||
nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) ||
|
||||
((info->flags & RATE_INFO_FLAGS_MCS) &&
|
||||
nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) ||
|
||||
((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) &&
|
||||
@ -6276,6 +6281,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
|
||||
return cfg80211_leave_mesh(rdev, dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
@ -6504,6 +6510,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
kfree(new_triggers.patterns);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
@ -7158,6 +7165,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
#ifdef CONFIG_PM
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WOWLAN,
|
||||
.doit = nl80211_get_wowlan,
|
||||
@ -7174,6 +7182,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.internal_flags = NL80211_FLAG_NEED_WIPHY |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
|
||||
.doit = nl80211_set_rekey_data,
|
||||
|
@ -129,7 +129,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
|
||||
|
||||
/* We keep a static world regulatory domain in case of the absence of CRDA */
|
||||
static const struct ieee80211_regdomain world_regdom = {
|
||||
.n_reg_rules = 5,
|
||||
.n_reg_rules = 6,
|
||||
.alpha2 = "00",
|
||||
.reg_rules = {
|
||||
/* IEEE 802.11b/g, channels 1..11 */
|
||||
@ -156,6 +156,9 @@ static const struct ieee80211_regdomain world_regdom = {
|
||||
REG_RULE(5745-10, 5825+10, 40, 6, 20,
|
||||
NL80211_RRF_PASSIVE_SCAN |
|
||||
NL80211_RRF_NO_IBSS),
|
||||
|
||||
/* IEEE 802.11ad (60gHz), channels 1..3 */
|
||||
REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band)
|
||||
{
|
||||
/* see 802.11 17.3.8.3.2 and Annex J
|
||||
* there are overlapping channel numbers in 5GHz and 2GHz bands */
|
||||
if (band == IEEE80211_BAND_5GHZ) {
|
||||
if (chan >= 182 && chan <= 196)
|
||||
return 4000 + chan * 5;
|
||||
else
|
||||
return 5000 + chan * 5;
|
||||
} else { /* IEEE80211_BAND_2GHZ */
|
||||
if (chan <= 0)
|
||||
return 0; /* not supported */
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (chan == 14)
|
||||
return 2484;
|
||||
else if (chan < 14)
|
||||
return 2407 + chan * 5;
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
if (chan >= 182 && chan <= 196)
|
||||
return 4000 + chan * 5;
|
||||
else
|
||||
return 0; /* not supported */
|
||||
return 5000 + chan * 5;
|
||||
break;
|
||||
case IEEE80211_BAND_60GHZ:
|
||||
if (chan < 5)
|
||||
return 56160 + chan * 2160;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return 0; /* not supported */
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_channel_to_frequency);
|
||||
|
||||
@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq)
|
||||
return (freq - 2407) / 5;
|
||||
else if (freq >= 4910 && freq <= 4980)
|
||||
return (freq - 4000) / 5;
|
||||
else
|
||||
else if (freq <= 45000) /* DMG band lower limit */
|
||||
return (freq - 5000) / 5;
|
||||
else if (freq >= 58320 && freq <= 64800)
|
||||
return (freq - 56160) / 2160;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
|
||||
|
||||
@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
|
||||
}
|
||||
WARN_ON(want != 0 && want != 3 && want != 6);
|
||||
break;
|
||||
case IEEE80211_BAND_60GHZ:
|
||||
/* check for mandatory HT MCS 1..4 */
|
||||
WARN_ON(!sband->ht_cap.ht_supported);
|
||||
WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e);
|
||||
break;
|
||||
case IEEE80211_NUM_BANDS:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
return -EBUSY;
|
||||
|
||||
if (ntype != otype && netif_running(dev)) {
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
|
||||
ntype);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
dev->ieee80211_ptr->mesh_id_up_len = 0;
|
||||
|
||||
switch (otype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
cfg80211_stop_ap(rdev, dev);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
cfg80211_leave_ibss(rdev, dev, false);
|
||||
break;
|
||||
@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (!err && ntype != otype && netif_running(dev)) {
|
||||
cfg80211_update_iface_num(rdev, ntype, 1);
|
||||
cfg80211_update_iface_num(rdev, otype, -1);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
u16 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
|
||||
{
|
||||
static const u32 __mcs2bitrate[] = {
|
||||
/* control PHY */
|
||||
[0] = 275,
|
||||
/* SC PHY */
|
||||
[1] = 3850,
|
||||
[2] = 7700,
|
||||
[3] = 9625,
|
||||
[4] = 11550,
|
||||
[5] = 12512, /* 1251.25 mbps */
|
||||
[6] = 15400,
|
||||
[7] = 19250,
|
||||
[8] = 23100,
|
||||
[9] = 25025,
|
||||
[10] = 30800,
|
||||
[11] = 38500,
|
||||
[12] = 46200,
|
||||
/* OFDM PHY */
|
||||
[13] = 6930,
|
||||
[14] = 8662, /* 866.25 mbps */
|
||||
[15] = 13860,
|
||||
[16] = 17325,
|
||||
[17] = 20790,
|
||||
[18] = 27720,
|
||||
[19] = 34650,
|
||||
[20] = 41580,
|
||||
[21] = 45045,
|
||||
[22] = 51975,
|
||||
[23] = 62370,
|
||||
[24] = 67568, /* 6756.75 mbps */
|
||||
/* LP-SC PHY */
|
||||
[25] = 6260,
|
||||
[26] = 8340,
|
||||
[27] = 11120,
|
||||
[28] = 12510,
|
||||
[29] = 16680,
|
||||
[30] = 22240,
|
||||
[31] = 25030,
|
||||
};
|
||||
|
||||
if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate)))
|
||||
return 0;
|
||||
|
||||
return __mcs2bitrate[rate->mcs];
|
||||
}
|
||||
|
||||
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
{
|
||||
int modulation, streams, bitrate;
|
||||
|
||||
if (!(rate->flags & RATE_INFO_FLAGS_MCS))
|
||||
return rate->legacy;
|
||||
if (rate->flags & RATE_INFO_FLAGS_60G)
|
||||
return cfg80211_calculate_bitrate_60g(rate);
|
||||
|
||||
/* the formula below does only work for MCS values smaller than 32 */
|
||||
if (WARN_ON_ONCE(rate->mcs >= 32))
|
||||
@ -930,27 +1008,48 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
return res;
|
||||
}
|
||||
|
||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype)
|
||||
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode)
|
||||
{
|
||||
struct wireless_dev *wdev_iter;
|
||||
u32 used_iftypes = BIT(iftype);
|
||||
int num[NUM_NL80211_IFTYPES];
|
||||
struct ieee80211_channel
|
||||
*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
|
||||
struct ieee80211_channel *ch;
|
||||
enum cfg80211_chan_mode chmode;
|
||||
int num_different_channels = 0;
|
||||
int total = 1;
|
||||
int i, j;
|
||||
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_held(&rdev->devlist_mtx);
|
||||
|
||||
/* Always allow software iftypes */
|
||||
if (rdev->wiphy.software_iftypes & BIT(iftype))
|
||||
return 0;
|
||||
|
||||
memset(num, 0, sizeof(num));
|
||||
memset(used_channels, 0, sizeof(used_channels));
|
||||
|
||||
num[iftype] = 1;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
switch (chanmode) {
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
case CHAN_MODE_SHARED:
|
||||
WARN_ON(!chan);
|
||||
used_channels[0] = chan;
|
||||
num_different_channels++;
|
||||
break;
|
||||
case CHAN_MODE_EXCLUSIVE:
|
||||
num_different_channels++;
|
||||
break;
|
||||
}
|
||||
|
||||
list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
|
||||
if (wdev_iter == wdev)
|
||||
continue;
|
||||
@ -960,11 +1059,33 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
|
||||
continue;
|
||||
|
||||
cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode);
|
||||
|
||||
switch (chmode) {
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
case CHAN_MODE_SHARED:
|
||||
for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++)
|
||||
if (!used_channels[i] || used_channels[i] == ch)
|
||||
break;
|
||||
|
||||
if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS)
|
||||
return -EBUSY;
|
||||
|
||||
if (used_channels[i] == NULL) {
|
||||
used_channels[i] = ch;
|
||||
num_different_channels++;
|
||||
}
|
||||
break;
|
||||
case CHAN_MODE_EXCLUSIVE:
|
||||
num_different_channels++;
|
||||
break;
|
||||
}
|
||||
|
||||
num[wdev_iter->iftype]++;
|
||||
total++;
|
||||
used_iftypes |= BIT(wdev_iter->iftype);
|
||||
}
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
if (total == 1)
|
||||
return 0;
|
||||
@ -976,12 +1097,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
|
||||
c = &rdev->wiphy.iface_combinations[i];
|
||||
|
||||
if (total > c->max_interfaces)
|
||||
continue;
|
||||
if (num_different_channels > c->num_different_channels)
|
||||
continue;
|
||||
|
||||
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
|
||||
GFP_KERNEL);
|
||||
if (!limits)
|
||||
return -ENOMEM;
|
||||
if (total > c->max_interfaces)
|
||||
goto cont;
|
||||
|
||||
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
|
||||
if (rdev->wiphy.software_iftypes & BIT(iftype))
|
||||
|
@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (!rdev->ops->get_channel)
|
||||
if (!rdev->monitor_channel)
|
||||
return -EINVAL;
|
||||
|
||||
chan = rdev->ops->get_channel(wdev->wiphy, &channel_type);
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
freq->m = chan->center_freq;
|
||||
freq->m = rdev->monitor_channel->center_freq;
|
||||
freq->e = 6;
|
||||
return 0;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user