1
0
Fork 0

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

wifi-calibration
John W. Linville 2013-12-02 14:25:38 -05:00
commit 4b074b0762
81 changed files with 3012 additions and 1501 deletions

View File

@ -159,10 +159,10 @@ struct ieee80211_regdomain mydriver_jp_regdom = {
REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
/* IEEE 802.11a, channels 34..48 */
REG_RULE(5170-20, 5240+20, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN),
NL80211_RRF_NO_IR),
/* IEEE 802.11a, channels 52..64 */
REG_RULE(5260-20, 5320+20, 40, 6, 20,
NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR|
NL80211_RRF_DFS),
}
};

View File

@ -1351,12 +1351,12 @@ static int ath10k_update_channel_list(struct ath10k *ar)
ch->allow_vht = true;
ch->allow_ibss =
!(channel->flags & IEEE80211_CHAN_NO_IBSS);
!(channel->flags & IEEE80211_CHAN_NO_IR);
ch->ht40plus =
!(channel->flags & IEEE80211_CHAN_NO_HT40PLUS);
passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN;
passive = channel->flags & IEEE80211_CHAN_NO_IR;
ch->passive = passive;
ch->freq = channel->center_freq;

View File

@ -1109,7 +1109,9 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
(mode == WMI_11G_HT20) ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
mutex_lock(&vif->wdev.mtx);
cfg80211_ch_switch_notify(vif->ndev, &chandef);
mutex_unlock(&vif->wdev.mtx);
}
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
@ -3169,12 +3171,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
}
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
struct ath6kl *ar = ath6kl_priv(vif->ndev);
struct ieee80211_channel *chan = params->chan;
const u8 *buf = params->buf;
size_t len = params->len;
unsigned int wait = params->wait;
bool no_cck = params->no_cck;
u32 id, freq;
const struct ieee80211_mgmt *mgmt;
bool more_data, queued;

View File

@ -37,17 +37,18 @@ static int __ath_regd_init(struct ath_regulatory *reg);
/* We enable active scan on these a case by case basis by regulatory domain */
#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\
NL80211_RRF_PASSIVE_SCAN)
NL80211_RRF_NO_IR)
#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
NL80211_RRF_NO_IR | \
NL80211_RRF_NO_OFDM)
/* We allow IBSS on these on a case by case basis by regulatory domain */
#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \
ATH9K_2GHZ_CH12_13, \
@ -223,18 +224,11 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
* default during init, prior to calling our
* regulatory_hint().
*/
if (!(reg_rule->flags &
NL80211_RRF_NO_IBSS))
ch->flags &=
~IEEE80211_CHAN_NO_IBSS;
if (!(reg_rule->flags &
NL80211_RRF_PASSIVE_SCAN))
ch->flags &=
~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
ch->flags &= ~IEEE80211_CHAN_NO_IR;
} else {
if (ch->beacon_found)
ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN);
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
}
@ -260,11 +254,11 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
ch = &sband->channels[11]; /* CH 12 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
ch = &sband->channels[12]; /* CH 13 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
return;
}
@ -278,17 +272,17 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
ch = &sband->channels[11]; /* CH 12 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
ch = &sband->channels[12]; /* CH 13 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
@ -320,8 +314,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
}
}
@ -609,7 +602,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
const struct ieee80211_regdomain *regd;
wiphy->reg_notifier = reg_notifier;
wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
if (ath_is_world_regd(reg)) {
/*
@ -617,7 +610,8 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
* saved on the wiphy orig_* parameters
*/
regd = ath_world_regdomain(reg);
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_COUNTRY_IE_FOLLOW_POWER;
} else {
/*
* This gets applied in the case of the absence of CRDA,

View File

@ -812,7 +812,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
struct ieee80211_channel *chan = request->channels[i];
if (chan->flags & (IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_PASSIVE_SCAN))
IEEE80211_CHAN_NO_IR))
continue;
chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf,

View File

@ -202,9 +202,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
* By default world regulatory domain defined in reg.c puts the flags
* NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for
* 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't
* start p2p operations on 5GHz channels. All the changes in world regulatory
* NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
* With respect to these flags, wpa_supplicant doesn't * start p2p
* operations on 5GHz channels. All the changes in world regulatory
* domain are to be done here.
*/
static const struct ieee80211_regdomain brcmf_regdom = {
@ -3973,11 +3973,12 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
static int
brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct ieee80211_channel *chan = params->chan;
const u8 *buf = params->buf;
size_t len = params->len;
const struct ieee80211_mgmt *mgmt;
struct brcmf_cfg80211_vif *vif;
s32 err = 0;
@ -4341,7 +4342,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
wiphy->max_remain_on_channel_duration = 5000;
brcmf_wiphy_pno_params(wiphy);
brcmf_dbg(INFO, "Registering custom regulatory\n");
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
err = wiphy_register(wiphy);
if (err < 0) {
@ -5197,10 +5198,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
if (channel & WL_CHAN_RADAR)
band_chan_arr[index].flags |=
(IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS);
IEEE80211_CHAN_NO_IR);
if (channel & WL_CHAN_PASSIVE)
band_chan_arr[index].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
}
}
if (!update)

View File

@ -59,23 +59,18 @@
#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_DFS | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_DFS | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
static const struct ieee80211_regdomain brcms_regdom_x2 = {
.n_reg_rules = 6,
@ -395,7 +390,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
brcms_b_set_chanspec(wlc->hw, chanspec,
!!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN),
!!(ch->flags & IEEE80211_CHAN_NO_IR),
&txpwr);
}
@ -657,8 +652,8 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_IR;
}
}
@ -688,14 +683,10 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
if (IS_ERR(rule))
continue;
if (!(rule->flags & NL80211_RRF_NO_IBSS))
ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN))
ch->flags &=
~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(rule->flags & NL80211_RRF_NO_IR))
ch->flags &= ~IEEE80211_CHAN_NO_IR;
} else if (ch->beacon_found) {
ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN);
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
}
@ -775,8 +766,8 @@ void brcms_c_regd_init(struct brcms_c_info *wlc)
}
wlc->wiphy->reg_notifier = brcms_reg_notifier;
wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_STRICT_REGULATORY;
wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_STRICT_REG;
wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
}

View File

@ -125,13 +125,13 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = {
CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(12, 2467,
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(13, 2472,
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_HT40PLUS),
CHAN2GHZ(14, 2484,
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |
IEEE80211_CHAN_NO_OFDM)
};
@ -144,51 +144,51 @@ static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
/* UNII-2 */
CHAN5GHZ(52,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(56,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(60,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(64,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
/* MID */
CHAN5GHZ(100,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(104,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(108,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(112,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(116,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(120,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(124,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(128,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(132,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
CHAN5GHZ(136,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
CHAN5GHZ(140,
IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS |
IEEE80211_CHAN_NO_HT40MINUS),
/* UNII-3 */
CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),

View File

@ -197,9 +197,9 @@ void cw1200_scan_work(struct work_struct *work)
if ((*it)->band != first->band)
break;
if (((*it)->flags ^ first->flags) &
IEEE80211_CHAN_PASSIVE_SCAN)
IEEE80211_CHAN_NO_IR)
break;
if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
(*it)->max_power != first->max_power)
break;
}
@ -210,7 +210,7 @@ void cw1200_scan_work(struct work_struct *work)
else
scan.max_tx_rate = WSM_TRANSMIT_RATE_1;
scan.num_probes =
(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2;
(first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2;
scan.num_ssids = priv->scan.n_ssids;
scan.ssids = &priv->scan.ssids[0];
scan.num_channels = it - priv->scan.curr;
@ -233,7 +233,7 @@ void cw1200_scan_work(struct work_struct *work)
}
for (i = 0; i < scan.num_channels; ++i) {
scan.ch[i].number = priv->scan.curr[i]->hw_value;
if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) {
scan.ch[i].min_chan_time = 50;
scan.ch[i].max_chan_time = 100;
} else {
@ -241,7 +241,7 @@ void cw1200_scan_work(struct work_struct *work)
scan.ch[i].max_chan_time = 25;
}
}
if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
priv->scan.output_power != first->max_power) {
priv->scan.output_power = first->max_power;
wsm_set_output_power(priv,

View File

@ -1930,10 +1930,10 @@ static int ipw2100_wdev_init(struct net_device *dev)
bg_band->channels[i].max_power = geo->bg[i].max_power;
if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
bg_band->channels[i].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
bg_band->channels[i].flags |=
IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
bg_band->channels[i].flags |=
IEEE80211_CHAN_RADAR;

View File

@ -11472,10 +11472,10 @@ static int ipw_wdev_init(struct net_device *dev)
bg_band->channels[i].max_power = geo->bg[i].max_power;
if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
bg_band->channels[i].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
bg_band->channels[i].flags |=
IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IR;
if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
bg_band->channels[i].flags |=
IEEE80211_CHAN_RADAR;
@ -11511,10 +11511,10 @@ static int ipw_wdev_init(struct net_device *dev)
a_band->channels[i].max_power = geo->a[i].max_power;
if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
a_band->channels[i].flags |=
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
a_band->channels[i].flags |=
IEEE80211_CHAN_NO_IBSS;
IEEE80211_CHAN_NO_IR;
if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
a_band->channels[i].flags |=
IEEE80211_CHAN_RADAR;

View File

@ -1595,7 +1595,7 @@ il3945_get_channels_for_scan(struct il_priv *il, enum ieee80211_band band,
* and use long active_dwell time.
*/
if (!is_active || il_is_channel_passive(ch_info) ||
(chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
(chan->flags & IEEE80211_CHAN_NO_IR)) {
scan_ch->type = 0; /* passive */
if (IL_UCODE_API(il->ucode_ver) == 1)
scan_ch->active_dwell =
@ -3575,9 +3575,9 @@ il3945_setup_mac(struct il_priv *il)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |=
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;

View File

@ -805,7 +805,7 @@ il4965_get_channels_for_scan(struct il_priv *il, struct ieee80211_vif *vif,
}
if (!is_active || il_is_channel_passive(ch_info) ||
(chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
(chan->flags & IEEE80211_CHAN_NO_IR))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@ -5778,9 +5778,9 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |=
WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
/*
* For now, disable PS by default because it affects

View File

@ -3445,10 +3445,10 @@ il_init_geos(struct il_priv *il)
if (il_is_channel_valid(ch)) {
if (!(ch->flags & EEPROM_CHANNEL_IBSS))
geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
geo_ch->flags |= IEEE80211_CHAN_NO_IR;
if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
geo_ch->flags |= IEEE80211_CHAN_NO_IR;
if (ch->flags & EEPROM_CHANNEL_RADAR)
geo_ch->flags |= IEEE80211_CHAN_RADAR;

View File

@ -567,12 +567,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].
flags & IEEE80211_CHAN_NO_IBSS) ||
flags & IEEE80211_CHAN_NO_IR) ||
(channels[i].
flags & IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].
flags & IEEE80211_CHAN_PASSIVE_SCAN ?
flags & IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ);
@ -594,12 +594,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].
flags & IEEE80211_CHAN_NO_IBSS) ||
flags & IEEE80211_CHAN_NO_IR) ||
(channels[i].
flags & IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].
flags & IEEE80211_CHAN_PASSIVE_SCAN ?
flags & IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);

View File

@ -352,12 +352,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
((channels[i].flags & IEEE80211_CHAN_NO_IR)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
@ -375,12 +375,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
((channels[i].flags & IEEE80211_CHAN_NO_IR)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
IEEE80211_CHAN_NO_IR ?
"passive only" : "active/passive");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);

View File

@ -155,9 +155,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
}
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
#ifdef CONFIG_PM_SLEEP
if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&

View File

@ -544,7 +544,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
channel = chan->hw_value;
scan_ch->channel = cpu_to_le16(channel);
if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
if (!is_active || (chan->flags & IEEE80211_CHAN_NO_IR))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;

View File

@ -614,10 +614,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
channel->flags = IEEE80211_CHAN_NO_HT40;
if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS))
channel->flags |= IEEE80211_CHAN_NO_IBSS;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE))
channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR)
channel->flags |= IEEE80211_CHAN_RADAR;

View File

@ -223,10 +223,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
channel->flags |= IEEE80211_CHAN_NO_160MHZ;
if (!(ch_flags & NVM_CHANNEL_IBSS))
channel->flags |= IEEE80211_CHAN_NO_IBSS;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (!(ch_flags & NVM_CHANNEL_ACTIVE))
channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
channel->flags |= IEEE80211_CHAN_NO_IR;
if (ch_flags & NVM_CHANNEL_RADAR)
channel->flags |= IEEE80211_CHAN_RADAR;

View File

@ -199,9 +199,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS |
WIPHY_FLAG_IBSS_RSN;
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
hw->wiphy->n_iface_combinations =

View File

@ -192,7 +192,7 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
for (i = 0; i < cmd->channel_count; i++) {
chan->channel = cpu_to_le16(req->channels[i]->hw_value);
chan->type = cpu_to_le32(type);
if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
chan->active_dwell = cpu_to_le16(active_dwell);
chan->passive_dwell = cpu_to_le16(passive_dwell);
@ -642,7 +642,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
channels->iter_count[index] = cpu_to_le16(1);
channels->iter_interval[index] = 0;
if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR))
channels->type[index] |=
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);

View File

@ -159,7 +159,7 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = {
.reg_rules = {
REG_RULE(2412-10, 2462+10, 40, 0, 20, 0),
REG_RULE(5725-10, 5850+10, 40, 0, 30,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
}
};
@ -353,7 +353,6 @@ struct mac80211_hwsim_data {
} ps;
bool ps_poll_pending;
struct dentry *debugfs;
struct dentry *debugfs_ps;
struct sk_buff_head pending; /* packets pending */
/*
@ -362,7 +361,6 @@ struct mac80211_hwsim_data {
* radio can be in more then one group.
*/
u64 group;
struct dentry *debugfs_group;
int power_level;
@ -1485,7 +1483,7 @@ static void hw_scan_work(struct work_struct *work)
req->channels[hwsim->scan_chan_idx]->center_freq);
hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR ||
!req->n_ssids) {
dwell = 120;
} else {
@ -1734,9 +1732,7 @@ static void mac80211_hwsim_free(void)
spin_unlock_bh(&hwsim_radio_lock);
list_for_each_entry_safe(data, tmpdata, &tmplist, list) {
debugfs_remove(data->debugfs_group);
debugfs_remove(data->debugfs_ps);
debugfs_remove(data->debugfs);
debugfs_remove_recursive(data->debugfs);
ieee80211_unregister_hw(data->hw);
device_release_driver(data->dev);
device_unregister(data->dev);
@ -1893,6 +1889,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
"%llu\n");
static int hwsim_write_simulate_radar(void *dat, u64 val)
{
struct mac80211_hwsim_data *data = dat;
ieee80211_radar_detected(data->hw);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL,
hwsim_write_simulate_radar, "%llu\n");
static int hwsim_fops_group_read(void *dat, u64 *val)
{
@ -2193,11 +2200,28 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
};
static struct ieee80211_iface_combination hwsim_if_comb = {
.limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
{ .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
};
static struct ieee80211_iface_combination hwsim_if_comb[] = {
{
.limits = hwsim_if_limits,
.n_limits = ARRAY_SIZE(hwsim_if_limits),
.max_interfaces = 2048,
.num_different_channels = 1,
},
{
.limits = hwsim_if_dfs_limits,
.n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
.max_interfaces = 8,
.num_different_channels = 1,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160),
}
};
static int __init init_mac80211_hwsim(void)
@ -2215,7 +2239,7 @@ static int __init init_mac80211_hwsim(void)
return -EINVAL;
if (channels > 1) {
hwsim_if_comb.num_different_channels = channels;
hwsim_if_comb[0].num_different_channels = channels;
mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
mac80211_hwsim_ops.cancel_hw_scan =
mac80211_hwsim_cancel_hw_scan;
@ -2295,13 +2319,15 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->n_addresses = 2;
hw->wiphy->addresses = data->addresses;
hw->wiphy->iface_combinations = &hwsim_if_comb;
hw->wiphy->n_iface_combinations = 1;
hw->wiphy->iface_combinations = hwsim_if_comb;
hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
if (channels > 1) {
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->max_remain_on_channel_duration = 1000;
/* For channels > 1 DFS is not allowed */
hw->wiphy->n_iface_combinations = 1;
}
INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
@ -2325,7 +2351,8 @@ static int __init init_mac80211_hwsim(void)
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_QUEUE_CONTROL;
IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
if (rctbl)
hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
@ -2385,6 +2412,7 @@ static int __init init_mac80211_hwsim(void)
sband->vht_cap.cap =
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
IEEE80211_VHT_CAP_RXLDPC |
IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_SHORT_GI_160 |
@ -2427,46 +2455,53 @@ static int __init init_mac80211_hwsim(void)
break;
case HWSIM_REGTEST_WORLD_ROAM:
if (i == 0) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
}
break;
case HWSIM_REGTEST_CUSTOM_WORLD:
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
break;
case HWSIM_REGTEST_CUSTOM_WORLD_2:
if (i == 0) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
} else if (i == 1) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_02);
}
break;
case HWSIM_REGTEST_STRICT_ALL:
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
break;
case HWSIM_REGTEST_STRICT_FOLLOW:
case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
if (i == 0)
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_STRICT_REG;
break;
case HWSIM_REGTEST_ALL:
if (i == 0) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_01);
} else if (i == 1) {
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(hw->wiphy,
&hwsim_world_regdom_custom_02);
} else if (i == 4)
hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
hw->wiphy->regulatory_flags |=
REGULATORY_STRICT_REG;
break;
default:
break;
@ -2533,16 +2568,18 @@ static int __init init_mac80211_hwsim(void)
data->debugfs = debugfs_create_dir("hwsim",
hw->wiphy->debugfsdir);
data->debugfs_ps = debugfs_create_file("ps", 0666,
data->debugfs, data,
&hwsim_fops_ps);
data->debugfs_group = debugfs_create_file("group", 0666,
data->debugfs, data,
&hwsim_fops_group);
debugfs_create_file("ps", 0666, data->debugfs, data,
&hwsim_fops_ps);
debugfs_create_file("group", 0666, data->debugfs, data,
&hwsim_fops_group);
if (channels == 1)
debugfs_create_file("dfs_simulate_radar", 0222,
data->debugfs,
data, &hwsim_simulate_radar);
tasklet_hrtimer_init(&data->beacon_timer,
mac80211_hwsim_beacon,
CLOCK_REALTIME, HRTIMER_MODE_ABS);
CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
list_add_tail(&data->list, &hwsim_radios);
}

View File

@ -50,24 +50,24 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = {
REG_RULE(2412-10, 2462+10, 40, 3, 20, 0),
/* Channel 12 - 13 */
REG_RULE(2467-10, 2472+10, 20, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
/* Channel 14 */
REG_RULE(2484-10, 2484+10, 20, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR |
NL80211_RRF_NO_OFDM),
/* Channel 36 - 48 */
REG_RULE(5180-10, 5240+10, 40, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
/* Channel 149 - 165 */
REG_RULE(5745-10, 5825+10, 40, 3, 20,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
NL80211_RRF_NO_IR),
/* Channel 52 - 64 */
REG_RULE(5260-10, 5320+10, 40, 3, 30,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR |
NL80211_RRF_DFS),
/* Channel 100 - 140 */
REG_RULE(5500-10, 5700+10, 40, 3, 30,
NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_IR |
NL80211_RRF_DFS),
}
};
@ -184,10 +184,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
*/
static int
mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
const u8 *buf = params->buf;
size_t len = params->len;
struct sk_buff *skb;
u16 pkt_len;
const struct ieee80211_mgmt *mgmt;
@ -1968,7 +1968,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
user_scan_cfg->chan_list[i].radio_type = chan->band;
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
if (chan->flags & IEEE80211_CHAN_NO_IR)
user_scan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_PASSIVE;
else
@ -2702,9 +2702,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_STRICT_REGULATORY |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
wiphy->regulatory_flags |=
REGULATORY_CUSTOM_REG |
REGULATORY_STRICT_REG;
wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);

View File

@ -515,14 +515,14 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16((u16) user_scan_in->
chan_list[0].scan_time);
else if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
else if (ch->flags & IEEE80211_CHAN_NO_IR)
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16(adapter->passive_scan_time);
else
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16(adapter->active_scan_time);
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
if (ch->flags & IEEE80211_CHAN_NO_IR)
scan_chan_list[chan_idx].chan_scan_mode_bitmap
|= MWIFIEX_PASSIVE_SCAN;
else

View File

@ -59,30 +59,26 @@ static struct country_code_to_enum_rd allCountries[] = {
*/
#define RTL819x_2GHZ_CH12_13 \
REG_RULE(2467-10, 2472+10, 40, 0, 20,\
NL80211_RRF_PASSIVE_SCAN)
NL80211_RRF_NO_IR)
#define RTL819x_2GHZ_CH14 \
REG_RULE(2484-10, 2484+10, 40, 0, 20, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_OFDM)
NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM)
/* 5G chan 36 - chan 64*/
#define RTL819x_5GHZ_5150_5350 \
REG_RULE(5150-10, 5350+10, 40, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
/* 5G chan 100 - chan 165*/
#define RTL819x_5GHZ_5470_5850 \
REG_RULE(5470-10, 5850+10, 40, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
/* 5G chan 149 - chan 165*/
#define RTL819x_5GHZ_5725_5850 \
REG_RULE(5725-10, 5850+10, 40, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
NL80211_RRF_NO_IR)
#define RTL819x_5GHZ_ALL \
(RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
@ -185,16 +181,11 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
*regulatory_hint().
*/
if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
if (!(reg_rule->
flags & NL80211_RRF_PASSIVE_SCAN))
ch->flags &=
~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
ch->flags &= ~IEEE80211_CHAN_NO_IR;
} else {
if (ch->beacon_found)
ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN);
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
}
@ -219,11 +210,11 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
ch = &sband->channels[11]; /* CH 12 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
ch = &sband->channels[12]; /* CH 13 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
return;
}
@ -237,17 +228,17 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
ch = &sband->channels[11]; /* CH 12 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
ch = &sband->channels[12]; /* CH 13 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
if (!(reg_rule->flags & NL80211_RRF_NO_IR))
if (ch->flags & IEEE80211_CHAN_NO_IR)
ch->flags &= ~IEEE80211_CHAN_NO_IR;
}
}
@ -284,8 +275,7 @@ static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
IEEE80211_CHAN_NO_IR;
}
}
@ -354,9 +344,9 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
wiphy->reg_notifier = reg_notifier;
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
regd = _rtl_regdomain_select(reg);
wiphy_apply_custom_regulatory(wiphy, regd);

View File

@ -47,7 +47,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
* In active scans, we only scan channels not
* marked as passive.
*/
(passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
(passive || !(flags & IEEE80211_CHAN_NO_IR))) {
wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
req->channels[i]->band,
req->channels[i]->center_freq);

View File

@ -1688,7 +1688,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
if (channel->flags & (IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_PASSIVE_SCAN))
IEEE80211_CHAN_NO_IR))
continue;
ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);

View File

@ -91,8 +91,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy,
continue;
if (ch->flags & IEEE80211_CHAN_RADAR)
ch->flags |= IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
ch->flags |= IEEE80211_CHAN_NO_IR;
}

View File

@ -188,16 +188,14 @@ wlcore_scan_get_channels(struct wl1271 *wl,
flags = req_channels[i]->flags;
if (force_passive)
flags |= IEEE80211_CHAN_PASSIVE_SCAN;
flags |= IEEE80211_CHAN_NO_IR;
if ((req_channels[i]->band == band) &&
!(flags & IEEE80211_CHAN_DISABLED) &&
(!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
/* if radar is set, we ignore the passive flag */
(radar ||
!!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
!!(flags & IEEE80211_CHAN_NO_IR) == passive)) {
if (flags & IEEE80211_CHAN_RADAR) {
channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
@ -220,7 +218,7 @@ wlcore_scan_get_channels(struct wl1271 *wl,
(band == IEEE80211_BAND_2GHZ) &&
(channels[j].channel >= 12) &&
(channels[j].channel <= 14) &&
(flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
(flags & IEEE80211_CHAN_NO_IR) &&
!force_passive) {
/* pactive channels treated as DFS */
channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
@ -243,8 +241,8 @@ wlcore_scan_get_channels(struct wl1271 *wl,
max_dwell_time_active,
flags & IEEE80211_CHAN_RADAR ?
", DFS" : "",
flags & IEEE80211_CHAN_PASSIVE_SCAN ?
", PASSIVE" : "");
flags & IEEE80211_CHAN_NO_IR ?
", NO-IR" : "");
j++;
}
}

View File

@ -1411,8 +1411,12 @@ struct ieee80211_vht_operation {
#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX 0x0000e000
#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX 0x00070000
#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13
#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK \
(7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT)
#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16
#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK \
(7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT)
#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000

View File

@ -91,9 +91,8 @@ enum ieee80211_band {
* Channel flags set by the regulatory control code.
*
* @IEEE80211_CHAN_DISABLED: This channel is disabled.
* @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
* on this channel.
* @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
* @IEEE80211_CHAN_NO_IR: do not initiate radiation, this includes
* sending probe requests or beaconing.
* @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
* @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel
* is not permitted.
@ -113,8 +112,8 @@ enum ieee80211_band {
*/
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
IEEE80211_CHAN_PASSIVE_SCAN = 1<<1,
IEEE80211_CHAN_NO_IBSS = 1<<2,
IEEE80211_CHAN_NO_IR = 1<<1,
/* hole at 1<<2 */
IEEE80211_CHAN_RADAR = 1<<3,
IEEE80211_CHAN_NO_HT40PLUS = 1<<4,
IEEE80211_CHAN_NO_HT40MINUS = 1<<5,
@ -1944,6 +1943,29 @@ struct cfg80211_update_ft_ies_params {
size_t ie_len;
};
/**
* struct cfg80211_mgmt_tx_params - mgmt tx parameters
*
* This structure provides information needed to transmit a mgmt frame
*
* @chan: channel to use
* @offchan: indicates wether off channel operation is required
* @wait: duration for ROC
* @buf: buffer to transmit
* @len: buffer length
* @no_cck: don't use cck rates for this frame
* @dont_wait_for_ack: tells the low level not to wait for an ack
*/
struct cfg80211_mgmt_tx_params {
struct ieee80211_channel *chan;
bool offchan;
unsigned int wait;
const u8 *buf;
size_t len;
bool no_cck;
bool dont_wait_for_ack;
};
/**
* struct cfg80211_ops - backend description for wireless configuration
*
@ -2342,9 +2364,8 @@ struct cfg80211_ops {
u64 cookie);
int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie);
struct cfg80211_mgmt_tx_params *params,
u64 *cookie);
int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
struct wireless_dev *wdev,
u64 cookie);
@ -2438,27 +2459,6 @@ struct cfg80211_ops {
/**
* enum wiphy_flags - wiphy capability flags
*
* @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device
* has its own custom regulatory domain and cannot identify the
* ISO / IEC 3166 alpha2 it belongs to. When this is enabled
* we will disregard the first regulatory hint (when the
* initiator is %REGDOM_SET_BY_CORE).
* @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
* ignore regulatory domain settings until it gets its own regulatory
* domain via its regulatory_hint() unless the regulatory hint is
* from a country IE. After its gets its own regulatory domain it will
* only allow further regulatory domain settings to further enhance
* compliance. For example if channel 13 and 14 are disabled by this
* regulatory domain no user regulatory domain can enable these channels
* at a later time. This can be used for devices which do not have
* calibration information guaranteed for frequencies or settings
* outside of its regulatory domain. If used in combination with
* WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings
* will be followed.
* @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
* that passive scan flags and beaconing flags may not be lifted by
* cfg80211 due to regulatory beacon hints. For more information on beacon
* hints read the documenation for regulatory_hint_found_beacon()
* @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
* wiphy at all
* @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
@ -2497,9 +2497,9 @@ struct cfg80211_ops {
* beaconing mode (AP, IBSS, Mesh, ...).
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
WIPHY_FLAG_STRICT_REGULATORY = BIT(1),
WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
/* use hole at 0 */
/* use hole at 1 */
/* use hole at 2 */
WIPHY_FLAG_NETNS_OK = BIT(3),
WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
WIPHY_FLAG_4ADDR_AP = BIT(5),
@ -2721,6 +2721,8 @@ struct wiphy_coalesce_support {
* @software_iftypes: bitmask of software interface types, these are not
* subject to any restrictions since they are purely managed in SW.
* @flags: wiphy flags, see &enum wiphy_flags
* @regulatory_flags: wiphy regulatory flags, see
* &enum ieee80211_regulatory_flags
* @features: features advertised to nl80211, see &enum nl80211_feature_flags.
* @bss_priv_size: each BSS struct has private data allocated with it,
* this variable determines its size
@ -2809,7 +2811,7 @@ struct wiphy {
u16 max_acl_mac_addrs;
u32 flags, features;
u32 flags, regulatory_flags, features;
u32 ap_sme_capa;
@ -3472,6 +3474,9 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
* custom regulatory domain will be trusted completely and as such previous
* default channel settings will be disregarded. If no rule is found for a
* channel on the regulatory domain the channel will be disabled.
* Drivers using this for a wiphy should also set the wiphy flag
* WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy
* that called this helper.
*/
void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
const struct ieee80211_regdomain *regd);
@ -4146,6 +4151,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
/**
* cfg80211_cac_event - Channel availability check (CAC) event
* @netdev: network device
* @chandef: chandef for the current channel
* @event: type of event
* @gfp: context flags
*
@ -4154,6 +4160,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
* also by full-MAC drivers.
*/
void cfg80211_cac_event(struct net_device *netdev,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event, gfp_t gfp);
@ -4279,7 +4286,8 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
* @dev: the device which switched channels
* @chandef: the new channel definition
*
* Acquires wdev_lock, so must only be called from sleepable driver context!
* Caller must acquire wdev_lock, therefore must only be called from sleepable
* driver context!
*/
void cfg80211_ch_switch_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef);

View File

@ -154,12 +154,14 @@ struct ieee80211_low_level_stats {
* @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed
* @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,
* this is used only with channel switching with CSA
* @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed
*/
enum ieee80211_chanctx_change {
IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0),
IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1),
IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2),
IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3),
IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4),
};
/**
@ -169,6 +171,7 @@ enum ieee80211_chanctx_change {
* that contains it is visible in mac80211 only.
*
* @def: the channel definition
* @min_def: the minimum channel definition currently required.
* @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
@ -180,6 +183,7 @@ enum ieee80211_chanctx_change {
*/
struct ieee80211_chanctx_conf {
struct cfg80211_chan_def def;
struct cfg80211_chan_def min_def;
u8 rx_chains_static, rx_chains_dynamic;
@ -1228,6 +1232,36 @@ struct ieee80211_key_conf {
u8 key[0];
};
/**
* struct ieee80211_cipher_scheme - cipher scheme
*
* This structure contains a cipher scheme information defining
* the secure packet crypto handling.
*
* @cipher: a cipher suite selector
* @iftype: a cipher iftype bit mask indicating an allowed cipher usage
* @hdr_len: a length of a security header used the cipher
* @pn_len: a length of a packet number in the security header
* @pn_off: an offset of pn from the beginning of the security header
* @key_idx_off: an offset of key index byte in the security header
* @key_idx_mask: a bit mask of key_idx bits
* @key_idx_shift: a bit shift needed to get key_idx
* key_idx value calculation:
* (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift
* @mic_len: a mic length in bytes
*/
struct ieee80211_cipher_scheme {
u32 cipher;
u16 iftype;
u8 hdr_len;
u8 pn_len;
u8 pn_off;
u8 key_idx_off;
u8 key_idx_mask;
u8 key_idx_shift;
u8 mic_len;
};
/**
* enum set_key_cmd - key command
*
@ -1636,6 +1670,10 @@ enum ieee80211_hw_flags {
* @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may
* deliver to a WMM STA during any Service Period triggered by the WMM STA.
* Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
*
* @n_cipher_schemes: a size of an array of cipher schemes definitions.
* @cipher_schemes: a pointer to an array of cipher scheme definitions
* supported by HW.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
@ -1663,6 +1701,8 @@ struct ieee80211_hw {
netdev_features_t netdev_features;
u8 uapsd_queues;
u8 uapsd_max_sp_len;
u8 n_cipher_schemes;
const struct ieee80211_cipher_scheme *cipher_schemes;
};
/**

View File

@ -38,17 +38,17 @@ enum environment_cap {
*
* @rcu_head: RCU head struct used to free the request
* @wiphy_idx: this is set if this request's initiator is
* %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
* can be used by the wireless core to deal with conflicts
* and potentially inform users of which devices specifically
* cased the conflicts.
* %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
* can be used by the wireless core to deal with conflicts
* and potentially inform users of which devices specifically
* cased the conflicts.
* @initiator: indicates who sent this request, could be any of
* of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
* of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
* @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
* regulatory domain. We have a few special codes:
* 00 - World regulatory domain
* 99 - built by driver but a specific alpha2 cannot be determined
* 98 - result of an intersection between two regulatory domains
* regulatory domain. We have a few special codes:
* 00 - World regulatory domain
* 99 - built by driver but a specific alpha2 cannot be determined
* 98 - result of an intersection between two regulatory domains
* 97 - regulatory domain has not yet been configured
* @dfs_region: If CRDA responded with a regulatory domain that requires
* DFS master operation on a known DFS region (NL80211_DFS_*),
@ -59,8 +59,8 @@ enum environment_cap {
* of hint passed. This could be any of the %NL80211_USER_REG_HINT_*
* types.
* @intersect: indicates whether the wireless core should intersect
* the requested regulatory domain with the presently set regulatory
* domain.
* the requested regulatory domain with the presently set regulatory
* domain.
* @processed: indicates whether or not this requests has already been
* processed. When the last request is processed it means that the
* currently regulatory domain set on cfg80211 is updated from
@ -68,9 +68,9 @@ enum environment_cap {
* the last request is not yet processed we must yield until it
* is processed before processing any new requests.
* @country_ie_checksum: checksum of the last processed and accepted
* country IE
* country IE
* @country_ie_env: lets us know if the AP is telling us we are outdoor,
* indoor, or if it doesn't matter
* indoor, or if it doesn't matter
* @list: used to insert into the reg_requests_list linked list
*/
struct regulatory_request {
@ -79,13 +79,63 @@ struct regulatory_request {
enum nl80211_reg_initiator initiator;
enum nl80211_user_reg_hint_type user_reg_hint_type;
char alpha2[2];
u8 dfs_region;
enum nl80211_dfs_regions dfs_region;
bool intersect;
bool processed;
enum environment_cap country_ie_env;
struct list_head list;
};
/**
* enum ieee80211_regulatory_flags - device regulatory flags
*
* @REGULATORY_CUSTOM_REG: tells us the driver for this device
* has its own custom regulatory domain and cannot identify the
* ISO / IEC 3166 alpha2 it belongs to. When this is enabled
* we will disregard the first regulatory hint (when the
* initiator is %REGDOM_SET_BY_CORE). Drivers that use
* wiphy_apply_custom_regulatory() should have this flag set
* or the regulatory core will set it for the wiphy.
* @REGULATORY_STRICT_REG: tells us that the wiphy for this device
* has regulatory domain that it wishes to be considered as the
* superset for regulatory rules. After this device gets its regulatory
* domain programmed further regulatory hints shall only be considered
* for this device to enhance regulatory compliance, forcing the
* device to only possibly use subsets of the original regulatory
* rules. For example if channel 13 and 14 are disabled by this
* device's regulatory domain no user specified regulatory hint which
* has these channels enabled would enable them for this wiphy,
* the device's original regulatory domain will be trusted as the
* base. You can program the superset of regulatory rules for this
* wiphy with regulatory_hint() for cards programmed with an
* ISO3166-alpha2 country code. wiphys that use regulatory_hint()
* will have their wiphy->regd programmed once the regulatory
* domain is set, and all other regulatory hints will be ignored
* until their own regulatory domain gets programmed.
* @REGULATORY_DISABLE_BEACON_HINTS: enable this if your driver needs to
* ensure that passive scan flags and beaconing flags may not be lifted by
* cfg80211 due to regulatory beacon hints. For more information on beacon
* hints read the documenation for regulatory_hint_found_beacon()
* @REGULATORY_COUNTRY_IE_FOLLOW_POWER: for devices that have a preference
* that even though they may have programmed their own custom power
* setting prior to wiphy registration, they want to ensure their channel
* power settings are updated for this connection with the power settings
* derived from the regulatory domain. The regulatory domain used will be
* based on the ISO3166-alpha2 from country IE provided through
* regulatory_hint_country_ie()
* @REGULATORY_COUNTRY_IE_IGNORE: for devices that have a preference to ignore
* all country IE information processed by the regulatory core. This will
* override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will
* be ignored.
*/
enum ieee80211_regulatory_flags {
REGULATORY_CUSTOM_REG = BIT(0),
REGULATORY_STRICT_REG = BIT(1),
REGULATORY_DISABLE_BEACON_HINTS = BIT(2),
REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3),
REGULATORY_COUNTRY_IE_IGNORE = BIT(4),
};
struct ieee80211_freq_range {
u32 start_freq_khz;
u32 end_freq_khz;
@ -107,7 +157,7 @@ struct ieee80211_regdomain {
struct rcu_head rcu_head;
u32 n_reg_rules;
char alpha2[2];
u8 dfs_region;
enum nl80211_dfs_regions dfs_region;
struct ieee80211_reg_rule reg_rules[];
};

View File

@ -581,7 +581,14 @@
* operation, %NL80211_ATTR_MAC contains the peer MAC address, and
* %NL80211_ATTR_REASON_CODE the reason code to be used (only with
* %NL80211_TDLS_TEARDOWN).
* @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
* @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The
* %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be
* sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as
* 802.11 management frames, while TDLS action codes (802.11-2012
* 8.5.13.1) will be encapsulated and sent as data frames. The currently
* supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES
* and the currently supported TDLS actions codes are given in
* &enum ieee80211_tdls_actioncode.
*
* @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
* (or GO) interface (i.e. hostapd) to ask for unexpected frames to
@ -1508,6 +1515,11 @@ enum nl80211_commands {
* to react to radar events, e.g. initiate a channel switch or leave the
* IBSS network.
*
* @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports
* 5 MHz channel bandwidth.
* @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports
* 10 MHz channel bandwidth.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@ -1824,6 +1836,9 @@ enum nl80211_attrs {
NL80211_ATTR_HANDLE_DFS,
NL80211_ATTR_SUPPORT_5_MHZ,
NL80211_ATTR_SUPPORT_10_MHZ,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -2224,10 +2239,9 @@ enum nl80211_band_attr {
* @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
* @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
* regulatory domain.
* @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
* permitted on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation
* are permitted on this channel, this includes sending probe
* requests, or modes of operation that require beaconing.
* @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
@ -2254,8 +2268,8 @@ enum nl80211_frequency_attr {
__NL80211_FREQUENCY_ATTR_INVALID,
NL80211_FREQUENCY_ATTR_FREQ,
NL80211_FREQUENCY_ATTR_DISABLED,
NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_NO_IR,
__NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
NL80211_FREQUENCY_ATTR_DFS_STATE,
@ -2271,6 +2285,9 @@ enum nl80211_frequency_attr {
};
#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR
#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR
#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR
/**
* enum nl80211_bitrate_attr - bitrate attributes
@ -2413,8 +2430,9 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_DFS: DFS support is required to be used
* @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
* @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
* @NL80211_RRF_PASSIVE_SCAN: passive scan is required
* @NL80211_RRF_NO_IBSS: no IBSS is allowed
* @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
* this includes probe requests or modes of operation that require
* beaconing.
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@ -2424,10 +2442,17 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_DFS = 1<<4,
NL80211_RRF_PTP_ONLY = 1<<5,
NL80211_RRF_PTMP_ONLY = 1<<6,
NL80211_RRF_PASSIVE_SCAN = 1<<7,
NL80211_RRF_NO_IBSS = 1<<8,
NL80211_RRF_NO_IR = 1<<7,
__NL80211_RRF_NO_IBSS = 1<<8,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR
#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR
/* For backport compatibility with older userspace */
#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
/**
* enum nl80211_dfs_regions - regulatory DFS regions
*

View File

@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
struct key_params *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta = NULL;
const struct ieee80211_cipher_scheme *cs = NULL;
struct ieee80211_key *key;
int err;
@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_WEP104:
if (IS_ERR(sdata->local->wep_tx_tfm))
if (IS_ERR(local->wep_tx_tfm))
return -EINVAL;
break;
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_GCMP:
break;
default:
cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type);
break;
}
key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
params->key, params->seq_len, params->seq);
params->key, params->seq_len, params->seq,
cs);
if (IS_ERR(key))
return PTR_ERR(key);
if (pairwise)
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
mutex_lock(&sdata->local->sta_mtx);
mutex_lock(&local->sta_mtx);
if (mac_addr) {
if (ieee80211_vif_is_mesh(&sdata->vif))
@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
break;
}
if (sta)
sta->cipher_scheme = cs;
err = ieee80211_key_link(key, sdata, sta);
out_unlock:
mutex_unlock(&sdata->local->sta_mtx);
mutex_unlock(&local->sta_mtx);
return err;
}
@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
goto out_unlock;
if (pairwise)
key = key_mtx_dereference(local, sta->ptk);
key = key_mtx_dereference(local, sta->ptk[key_idx]);
else
key = key_mtx_dereference(local, sta->gtk[key_idx]);
} else
@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
goto out;
if (pairwise)
key = rcu_dereference(sta->ptk);
key = rcu_dereference(sta->ptk[key_idx]);
else if (key_idx < NUM_DEFAULT_KEYS)
key = rcu_dereference(sta->gtk[key_idx]);
} else
@ -521,8 +532,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
STATION_INFO_PEER_PM |
STATION_INFO_NONPEER_PM;
sinfo->llid = le16_to_cpu(sta->llid);
sinfo->plid = le16_to_cpu(sta->plid);
sinfo->llid = sta->llid;
sinfo->plid = sta->plid;
sinfo->plink_state = sta->plink_state;
if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
sinfo->filled |= STATION_INFO_T_OFFSET;
@ -846,7 +857,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
if (!resp || !resp_len)
return 1;
old = rtnl_dereference(sdata->u.ap.probe_resp);
old = sdata_dereference(sdata->u.ap.probe_resp, sdata);
new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);
if (!new)
@ -870,7 +881,8 @@ int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
int size, err;
u32 changed = BSS_CHANGED_BEACON;
old = rtnl_dereference(sdata->u.ap.beacon);
old = sdata_dereference(sdata->u.ap.beacon, sdata);
/* Need to have a beacon head if we don't have one yet */
if (!params->head && !old)
@ -947,7 +959,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
BSS_CHANGED_P2P_PS;
int err;
old = rtnl_dereference(sdata->u.ap.beacon);
old = sdata_dereference(sdata->u.ap.beacon, sdata);
if (old)
return -EALREADY;
@ -968,11 +980,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
*/
sdata->control_port_protocol = params->crypto.control_port_ethertype;
sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
&params->crypto,
sdata->vif.type);
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
vlan->control_port_protocol =
params->crypto.control_port_ethertype;
vlan->control_port_no_encrypt =
params->crypto.control_port_no_encrypt;
vlan->encrypt_headroom =
ieee80211_cs_headroom(sdata->local,
&params->crypto,
vlan->vif.type);
}
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
@ -1001,7 +1021,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
err = drv_start_ap(sdata->local, sdata);
if (err) {
old = rtnl_dereference(sdata->u.ap.beacon);
old = sdata_dereference(sdata->u.ap.beacon, sdata);
if (old)
kfree_rcu(old, rcu_head);
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
@ -1032,7 +1053,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
if (sdata->vif.csa_active)
return -EBUSY;
old = rtnl_dereference(sdata->u.ap.beacon);
old = sdata_dereference(sdata->u.ap.beacon, sdata);
if (!old)
return -ENOENT;
@ -1050,15 +1071,18 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
struct ieee80211_local *local = sdata->local;
struct beacon_data *old_beacon;
struct probe_resp *old_probe_resp;
struct cfg80211_chan_def chandef;
old_beacon = rtnl_dereference(sdata->u.ap.beacon);
old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
if (!old_beacon)
return -ENOENT;
old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
/* abort any running channel switch */
sdata->vif.csa_active = false;
cancel_work_sync(&sdata->csa_finalize_work);
kfree(sdata->u.ap.next_beacon);
sdata->u.ap.next_beacon = NULL;
cancel_work_sync(&sdata->u.ap.request_smps_work);
/* turn off carrier for this interface and dependent VLANs */
@ -1091,8 +1115,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
if (sdata->wdev.cac_started) {
chandef = sdata->vif.bss_conf.chandef;
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
cfg80211_cac_event(sdata->dev, &chandef,
NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
}
@ -1953,7 +1979,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
enum ieee80211_band band;
u32 changed = 0;
if (!rtnl_dereference(sdata->u.ap.beacon))
if (!sdata_dereference(sdata->u.ap.beacon, sdata))
return -ENOENT;
band = ieee80211_get_sdata_band(sdata);
@ -2964,27 +2990,33 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
struct ieee80211_local *local = sdata->local;
int err, changed = 0;
sdata_lock(sdata);
/* AP might have been stopped while waiting for the lock. */
if (!sdata->vif.csa_active)
goto unlock;
if (!ieee80211_sdata_running(sdata))
return;
goto unlock;
sdata->radar_required = sdata->csa_radar_required;
err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
&changed);
err = ieee80211_vif_change_channel(sdata, &changed);
if (WARN_ON(err < 0))
return;
goto unlock;
if (!local->use_chanctx) {
local->_oper_chandef = local->csa_chandef;
local->_oper_chandef = sdata->csa_chandef;
ieee80211_hw_config(local, 0);
}
ieee80211_bss_info_change_notify(sdata, changed);
sdata->vif.csa_active = false;
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
if (err < 0)
return;
goto unlock;
changed |= err;
kfree(sdata->u.ap.next_beacon);
sdata->u.ap.next_beacon = NULL;
@ -2998,20 +3030,22 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
case NL80211_IFTYPE_MESH_POINT:
err = ieee80211_mesh_finish_csa(sdata);
if (err < 0)
return;
goto unlock;
break;
#endif
default:
WARN_ON(1);
return;
goto unlock;
}
sdata->vif.csa_active = false;
ieee80211_wake_queues_by_reason(&sdata->local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
unlock:
sdata_unlock(sdata);
}
static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
@ -3024,6 +3058,8 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_if_mesh __maybe_unused *ifmsh;
int err, num_chanctx;
lockdep_assert_held(&sdata->wdev.mtx);
if (!list_empty(&local->roc_list) || local->scanning)
return -EBUSY;
@ -3136,7 +3172,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
local->csa_chandef = params->chandef;
sdata->csa_chandef = params->chandef;
sdata->vif.csa_active = true;
ieee80211_bss_info_change_notify(sdata, err);
@ -3146,26 +3182,25 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params,
u64 *cookie)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct sta_info *sta;
const struct ieee80211_mgmt *mgmt = (void *)buf;
const struct ieee80211_mgmt *mgmt = (void *)params->buf;
bool need_offchan = false;
u32 flags;
int ret;
if (dont_wait_for_ack)
if (params->dont_wait_for_ack)
flags = IEEE80211_TX_CTL_NO_ACK;
else
flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
IEEE80211_TX_CTL_REQ_TX_STATUS;
if (no_cck)
if (params->no_cck)
flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
switch (sdata->vif.type) {
@ -3213,7 +3248,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
/* configurations requiring offchan cannot work if no channel has been
* specified
*/
if (need_offchan && !chan)
if (need_offchan && !params->chan)
return -EINVAL;
mutex_lock(&local->mtx);
@ -3226,8 +3261,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
need_offchan = chan && (chan != chanctx_conf->def.chan);
} else if (!chan) {
need_offchan = params->chan &&
(params->chan !=
chanctx_conf->def.chan);
} else if (!params->chan) {
ret = -EINVAL;
rcu_read_unlock();
goto out_unlock;
@ -3237,19 +3274,19 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
rcu_read_unlock();
}
if (need_offchan && !offchan) {
if (need_offchan && !params->offchan) {
ret = -EBUSY;
goto out_unlock;
}
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len);
if (!skb) {
ret = -ENOMEM;
goto out_unlock;
}
skb_reserve(skb, local->hw.extra_tx_headroom);
memcpy(skb_put(skb, len), buf, len);
memcpy(skb_put(skb, params->len), params->buf, params->len);
IEEE80211_SKB_CB(skb)->flags = flags;
@ -3269,8 +3306,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
local->hw.offchannel_tx_hw_queue;
/* This will handle all kinds of coalescing and immediate TX */
ret = ieee80211_start_roc_work(local, sdata, chan,
wait, cookie, skb,
ret = ieee80211_start_roc_work(local, sdata, params->chan,
params->wait, cookie, skb,
IEEE80211_ROC_TYPE_MGMT_TX);
if (ret)
kfree_skb(skb);

View File

@ -9,6 +9,140 @@
#include "ieee80211_i.h"
#include "driver-ops.h"
static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
{
switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_20:
if (sta->ht_cap.ht_supported)
return NL80211_CHAN_WIDTH_20;
else
return NL80211_CHAN_WIDTH_20_NOHT;
case IEEE80211_STA_RX_BW_40:
return NL80211_CHAN_WIDTH_40;
case IEEE80211_STA_RX_BW_80:
return NL80211_CHAN_WIDTH_80;
case IEEE80211_STA_RX_BW_160:
/*
* This applied for both 160 and 80+80. since we use
* the returned value to consider degradation of
* ctx->conf.min_def, we have to make sure to take
* the bigger one (NL80211_CHAN_WIDTH_160).
* Otherwise we might try degrading even when not
* needed, as the max required sta_bw returned (80+80)
* might be smaller than the configured bw (160).
*/
return NL80211_CHAN_WIDTH_160;
default:
WARN_ON(1);
return NL80211_CHAN_WIDTH_20;
}
}
static enum nl80211_chan_width
ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
{
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
struct sta_info *sta;
rcu_read_lock();
list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
if (sdata != sta->sdata &&
!(sta->sdata->bss && sta->sdata->bss == sdata->bss))
continue;
if (!sta->uploaded)
continue;
max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
}
rcu_read_unlock();
return max_bw;
}
static enum nl80211_chan_width
ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
struct ieee80211_chanctx_conf *conf)
{
struct ieee80211_sub_if_data *sdata;
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
struct ieee80211_vif *vif = &sdata->vif;
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
if (!ieee80211_sdata_running(sdata))
continue;
if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
continue;
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
width = ieee80211_get_max_required_bw(sdata);
break;
case NL80211_IFTYPE_P2P_DEVICE:
continue;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
width = vif->bss_conf.chandef.width;
break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
WARN_ON_ONCE(1);
}
max_bw = max(max_bw, width);
}
rcu_read_unlock();
return max_bw;
}
/*
* recalc the min required chan width of the channel context, which is
* the max of min required widths of all the interfaces bound to this
* channel context.
*/
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
enum nl80211_chan_width max_bw;
struct cfg80211_chan_def min_def;
lockdep_assert_held(&local->chanctx_mtx);
/* don't optimize 5MHz, 10MHz, and radar_enabled confs */
if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
ctx->conf.radar_enabled) {
ctx->conf.min_def = ctx->conf.def;
return;
}
max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);
/* downgrade chandef up to max_bw */
min_def = ctx->conf.def;
while (min_def.width > max_bw)
ieee80211_chandef_downgrade(&min_def);
if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
return;
ctx->conf.min_def = min_def;
if (!ctx->driver_present)
return;
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
}
static void ieee80211_change_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *chandef)
@ -20,6 +154,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
ctx->conf.def = *chandef;
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
ieee80211_recalc_chanctx_min_def(local, ctx);
if (!local->use_chanctx) {
local->_oper_chandef = *chandef;
@ -93,6 +228,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
ieee80211_recalc_chanctx_min_def(local, ctx);
if (!local->use_chanctx)
local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
@ -179,6 +315,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
ctx->refcount++;
ieee80211_recalc_txpower(sdata);
ieee80211_recalc_chanctx_min_def(local, ctx);
sdata->vif.bss_conf.idle = false;
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
@ -243,6 +380,7 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);
}
}
@ -411,12 +549,12 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
}
int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
u32 *changed)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *conf;
struct ieee80211_chanctx *ctx;
const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
int ret;
u32 chanctx_changed = 0;
@ -456,6 +594,7 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_chanctx_chantype(local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);
ret = 0;
out:

View File

@ -17,6 +17,172 @@
#define DEBUGFS_FORMAT_BUFFER_SIZE 100
#define TX_LATENCY_BIN_DELIMTER_C ','
#define TX_LATENCY_BIN_DELIMTER_S ","
#define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n"
#define TX_LATENCY_DISABLED "disable\n"
/*
* Display if Tx latency statistics & bins are enabled/disabled
*/
static ssize_t sta_tx_latency_stat_read(struct file *file,
char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
struct ieee80211_tx_latency_bin_ranges *tx_latency;
char *buf;
int bufsz, i, ret;
int pos = 0;
rcu_read_lock();
tx_latency = rcu_dereference(local->tx_latency);
if (tx_latency && tx_latency->n_ranges) {
bufsz = tx_latency->n_ranges * 15;
buf = kzalloc(bufsz, GFP_ATOMIC);
if (!buf)
goto err;
for (i = 0; i < tx_latency->n_ranges; i++)
pos += scnprintf(buf + pos, bufsz - pos, "%d,",
tx_latency->ranges[i]);
pos += scnprintf(buf + pos, bufsz - pos, "\n");
} else if (tx_latency) {
bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1;
buf = kzalloc(bufsz, GFP_ATOMIC);
if (!buf)
goto err;
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
TX_LATENCY_BINS_DISABLED);
} else {
bufsz = sizeof(TX_LATENCY_DISABLED) + 1;
buf = kzalloc(bufsz, GFP_ATOMIC);
if (!buf)
goto err;
pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
TX_LATENCY_DISABLED);
}
rcu_read_unlock();
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
kfree(buf);
return ret;
err:
rcu_read_unlock();
return -ENOMEM;
}
/*
* Receive input from user regarding Tx latency statistics
* The input should indicate if Tx latency statistics and bins are
* enabled/disabled.
* If bins are enabled input should indicate the amount of different bins and
* their ranges. Each bin will count how many Tx frames transmitted within the
* appropriate latency.
* Legal input is:
* a) "enable(bins disabled)" - to enable only general statistics
* b) "a,b,c,d,...z" - to enable general statistics and bins, where all are
* numbers and a < b < c < d.. < z
* c) "disable" - disable all statistics
* NOTE: must configure Tx latency statistics bins before stations connected.
*/
static ssize_t sta_tx_latency_stat_write(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
char buf[128] = {};
char *bins = buf;
char *token;
int buf_size, i, alloc_size;
int prev_bin = 0;
int n_ranges = 0;
int ret = count;
struct ieee80211_tx_latency_bin_ranges *tx_latency;
if (sizeof(buf) <= count)
return -EINVAL;
buf_size = count;
if (copy_from_user(buf, userbuf, buf_size))
return -EFAULT;
mutex_lock(&local->sta_mtx);
/* cannot change config once we have stations */
if (local->num_sta)
goto unlock;
tx_latency =
rcu_dereference_protected(local->tx_latency,
lockdep_is_held(&local->sta_mtx));
/* disable Tx statistics */
if (!strcmp(buf, TX_LATENCY_DISABLED)) {
if (!tx_latency)
goto unlock;
rcu_assign_pointer(local->tx_latency, NULL);
synchronize_rcu();
kfree(tx_latency);
goto unlock;
}
/* Tx latency already enabled */
if (tx_latency)
goto unlock;
if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) {
/* check how many bins and between what ranges user requested */
token = buf;
while (*token != '\0') {
if (*token == TX_LATENCY_BIN_DELIMTER_C)
n_ranges++;
token++;
}
n_ranges++;
}
alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) +
n_ranges * sizeof(u32);
tx_latency = kzalloc(alloc_size, GFP_ATOMIC);
if (!tx_latency) {
ret = -ENOMEM;
goto unlock;
}
tx_latency->n_ranges = n_ranges;
for (i = 0; i < n_ranges; i++) { /* setting bin ranges */
token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S);
sscanf(token, "%d", &tx_latency->ranges[i]);
/* bins values should be in ascending order */
if (prev_bin >= tx_latency->ranges[i]) {
ret = -EINVAL;
kfree(tx_latency);
goto unlock;
}
prev_bin = tx_latency->ranges[i];
}
rcu_assign_pointer(local->tx_latency, tx_latency);
unlock:
mutex_unlock(&local->sta_mtx);
return ret;
}
static const struct file_operations stats_tx_latency_ops = {
.write = sta_tx_latency_stat_write,
.read = sta_tx_latency_stat_read,
.open = simple_open,
.llseek = generic_file_llseek,
};
int mac80211_format_buffer(char __user *userbuf, size_t count,
loff_t *ppos, char *fmt, ...)
{
@ -315,4 +481,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
DEBUGFS_DEVSTATS_ADD(tx_latency);
}

View File

@ -38,6 +38,13 @@ static const struct file_operations sta_ ##name## _ops = { \
.llseek = generic_file_llseek, \
}
#define STA_OPS_W(name) \
static const struct file_operations sta_ ##name## _ops = { \
.write = sta_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define STA_OPS_RW(name) \
static const struct file_operations sta_ ##name## _ops = { \
.read = sta_##name##_read, \
@ -388,6 +395,131 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf,
}
STA_OPS(last_rx_rate);
static int
sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency,
char *buf, int pos, int bufsz)
{
int i;
int range_count = tx_latency->n_ranges;
u32 *bin_ranges = tx_latency->ranges;
pos += scnprintf(buf + pos, bufsz - pos,
"Station\t\t\tTID\tMax\tAvg");
if (range_count) {
pos += scnprintf(buf + pos, bufsz - pos,
"\t<=%d", bin_ranges[0]);
for (i = 0; i < range_count - 1; i++)
pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d",
bin_ranges[i], bin_ranges[i+1]);
pos += scnprintf(buf + pos, bufsz - pos,
"\t%d<", bin_ranges[range_count - 1]);
}
pos += scnprintf(buf + pos, bufsz - pos, "\n");
return pos;
}
static int
sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range,
struct ieee80211_tx_latency_stat *tx_lat,
char *buf, int pos, int bufsz, int tid)
{
u32 avg = 0;
int j;
int bin_count = tx_lat->bin_count;
pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid);
/* make sure you don't divide in 0 */
if (tx_lat->counter)
avg = tx_lat->sum / tx_lat->counter;
pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d",
tx_lat->max, avg);
if (tx_lat_range->n_ranges && tx_lat->bins)
for (j = 0; j < bin_count; j++)
pos += scnprintf(buf + pos, bufsz - pos,
"\t%d", tx_lat->bins[j]);
pos += scnprintf(buf + pos, bufsz - pos, "\n");
return pos;
}
/*
* Output Tx latency statistics station && restart all statistics information
*/
static ssize_t sta_tx_latency_stat_read(struct file *file,
char __user *userbuf,
size_t count, loff_t *ppos)
{
struct sta_info *sta = file->private_data;
struct ieee80211_local *local = sta->local;
struct ieee80211_tx_latency_bin_ranges *tx_latency;
char *buf;
int bufsz, ret, i;
int pos = 0;
bufsz = 20 * IEEE80211_NUM_TIDS *
sizeof(struct ieee80211_tx_latency_stat);
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
rcu_read_lock();
tx_latency = rcu_dereference(local->tx_latency);
if (!sta->tx_lat) {
pos += scnprintf(buf + pos, bufsz - pos,
"Tx latency statistics are not enabled\n");
goto unlock;
}
pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr);
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i],
buf, pos, bufsz, i);
unlock:
rcu_read_unlock();
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
kfree(buf);
return ret;
}
STA_OPS(tx_latency_stat);
static ssize_t sta_tx_latency_stat_reset_write(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
u32 *bins;
int bin_count;
struct sta_info *sta = file->private_data;
int i;
if (!sta->tx_lat)
return -EINVAL;
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
bins = sta->tx_lat[i].bins;
bin_count = sta->tx_lat[i].bin_count;
sta->tx_lat[i].max = 0;
sta->tx_lat[i].sum = 0;
sta->tx_lat[i].counter = 0;
if (bin_count)
memset(bins, 0, bin_count * sizeof(u32));
}
return count;
}
STA_OPS_W(tx_latency_stat_reset);
#define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, \
sta->debugfs.dir, sta, &sta_ ##name## _ops);
@ -441,6 +573,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(last_ack_signal);
DEBUGFS_ADD(current_tx_rate);
DEBUGFS_ADD(last_rx_rate);
DEBUGFS_ADD(tx_latency_stat);
DEBUGFS_ADD(tx_latency_stat_reset);
DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);

View File

@ -550,12 +550,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
capability);
/* XXX: should not really modify cfg80211 data */
if (cbss) {
cbss->channel = sdata->local->csa_chandef.chan;
cbss->channel = sdata->csa_chandef.chan;
cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
}
}
ifibss->chandef = sdata->local->csa_chandef;
ifibss->chandef = sdata->csa_chandef;
/* generate the beacon */
err = ieee80211_ibss_csa_beacon(sdata, NULL);
@ -922,7 +922,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
sdata->local->csa_chandef = params.chandef;
sdata->csa_chandef = params.chandef;
sdata->vif.csa_active = true;
ieee80211_bss_info_change_notify(sdata, err);

View File

@ -728,6 +728,7 @@ struct ieee80211_sub_if_data {
u16 sequence_number;
__be16 control_port_protocol;
bool control_port_no_encrypt;
int encrypt_headroom;
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
@ -735,6 +736,7 @@ struct ieee80211_sub_if_data {
int csa_counter_offset_beacon;
int csa_counter_offset_presp;
bool csa_radar_required;
struct cfg80211_chan_def csa_chandef;
/* used to reconfigure hardware SM PS */
struct work_struct recalc_smps;
@ -811,6 +813,9 @@ static inline void sdata_unlock(struct ieee80211_sub_if_data *sdata)
__release(&sdata->wdev.mtx);
}
#define sdata_dereference(p, sdata) \
rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx))
static inline void
sdata_assert_lock(struct ieee80211_sub_if_data *sdata)
{
@ -896,6 +901,24 @@ struct tpt_led_trigger {
};
#endif
/*
* struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges
*
* Measuring Tx latency statistics. Counts how many Tx frames transmitted in a
* certain latency range (in Milliseconds). Each station that uses these
* ranges will have bins to count the amount of frames received in that range.
* The user can configure the ranges via debugfs.
* If ranges is NULL then Tx latency statistics bins are disabled for all
* stations.
*
* @n_ranges: number of ranges that are taken in account
* @ranges: the ranges that the user requested or NULL if disabled.
*/
struct ieee80211_tx_latency_bin_ranges {
int n_ranges;
u32 ranges[];
};
/**
* mac80211 scan flags - currently active scan mode
*
@ -1048,6 +1071,12 @@ struct ieee80211_local {
struct timer_list sta_cleanup;
int sta_generation;
/*
* Tx latency statistics parameters for all stations.
* Can enable via debugfs (NULL when disabled).
*/
struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
@ -1093,7 +1122,6 @@ struct ieee80211_local {
enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
struct ieee80211_sub_if_data __rcu *scan_sdata;
struct cfg80211_chan_def csa_chandef;
/* For backward compatibility only -- do not use */
struct cfg80211_chan_def _oper_chandef;
@ -1692,6 +1720,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_min_chandef(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);
@ -1730,7 +1759,6 @@ ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
/* NOTE: only use ieee80211_vif_change_channel() for channel switch */
int __must_check
ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
u32 *changed);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
@ -1741,6 +1769,8 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx);
void ieee80211_dfs_cac_timer(unsigned long data);
void ieee80211_dfs_cac_timer_work(struct work_struct *work);
@ -1749,6 +1779,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work);
int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *csa_settings);
bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs);
bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n);
const struct ieee80211_cipher_scheme *
ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
enum nl80211_iftype iftype);
int ieee80211_cs_headroom(struct ieee80211_local *local,
struct cfg80211_crypto_settings *crypto,
enum nl80211_iftype iftype);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
#else

View File

@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
wiphy_name(local->hw.wiphy));
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
ieee80211_set_default_queues(sdata);
ret = drv_add_interface(local, sdata);
@ -749,6 +751,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
u32 hw_reconf_flags = 0;
int i, flushed;
struct ps_data *ps;
struct cfg80211_chan_def chandef;
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
@ -823,11 +826,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
if (sdata->wdev.cac_started) {
chandef = sdata->vif.bss_conf.chandef;
WARN_ON(local->suspended);
mutex_lock(&local->iflist_mtx);
ieee80211_vif_release_channel(sdata);
mutex_unlock(&local->iflist_mtx);
cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
cfg80211_cac_event(sdata->dev, &chandef,
NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
}
@ -1036,7 +1041,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
*/
static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
{
int flushed;
int i;
/* free extra data */
@ -1050,9 +1054,6 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_rmc_free(sdata);
flushed = sta_info_flush(sdata);
WARN_ON(flushed);
}
static void ieee80211_uninit(struct net_device *dev)
@ -1270,6 +1271,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
sdata->control_port_no_encrypt = false;
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
sdata->noack_map = 0;
@ -1686,6 +1688,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
sdata->user_power_level = local->user_power_level;
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
/* setup type-dependent data */
ieee80211_setup_sdata(sdata, type);

View File

@ -260,25 +260,29 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
int idx;
bool defunikey, defmultikey, defmgmtkey;
/* caller must provide at least one old/new */
if (WARN_ON(!new && !old))
return;
if (new)
list_add_tail(&new->list, &sdata->key_list);
if (sta && pairwise) {
rcu_assign_pointer(sta->ptk, new);
} else if (sta) {
if (old)
idx = old->conf.keyidx;
else
idx = new->conf.keyidx;
rcu_assign_pointer(sta->gtk[idx], new);
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
if (old)
idx = old->conf.keyidx;
else
idx = new->conf.keyidx;
if (sta) {
if (pairwise) {
rcu_assign_pointer(sta->ptk[idx], new);
sta->ptk_idx = idx;
} else {
rcu_assign_pointer(sta->gtk[idx], new);
sta->gtk_idx = idx;
}
} else {
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
if (old)
idx = old->conf.keyidx;
else
idx = new->conf.keyidx;
defunikey = old &&
old == key_mtx_dereference(sdata->local,
sdata->default_unicast_key);
@ -312,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
list_del(&old->list);
}
struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
const u8 *key_data,
size_t seq_len, const u8 *seq)
struct ieee80211_key *
ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
const u8 *key_data,
size_t seq_len, const u8 *seq,
const struct ieee80211_cipher_scheme *cs)
{
struct ieee80211_key *key;
int i, j, err;
@ -393,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
return ERR_PTR(err);
}
break;
default:
if (cs) {
size_t len = (seq_len > MAX_PN_LEN) ?
MAX_PN_LEN : seq_len;
key->conf.iv_len = cs->hdr_len;
key->conf.icv_len = cs->mic_len;
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
for (j = 0; j < len; j++)
key->u.gen.rx_pn[i][j] =
seq[len - j - 1];
}
}
memcpy(key->conf.key, key_data, key_len);
INIT_LIST_HEAD(&key->list);
@ -475,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
mutex_lock(&sdata->local->key_mtx);
if (sta && pairwise)
old_key = key_mtx_dereference(sdata->local, sta->ptk);
old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
else if (sta)
old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
else
@ -625,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
list_add(&key->list, &keys);
}
key = key_mtx_dereference(local, sta->ptk);
if (key) {
for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
key = key_mtx_dereference(local, sta->ptk[i]);
if (!key)
continue;
ieee80211_key_replace(key->sdata, key->sta,
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
key, NULL);
@ -877,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
keyconf->keylen, keyconf->key,
0, NULL);
0, NULL, NULL);
if (IS_ERR(key))
return ERR_CAST(key);

View File

@ -18,6 +18,7 @@
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
#define MAX_PN_LEN 16
struct ieee80211_local;
struct ieee80211_sub_if_data;
@ -93,6 +94,10 @@ struct ieee80211_key {
u32 replays; /* dot11RSNAStatsCMACReplays */
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
} aes_cmac;
struct {
/* generic cipher scheme */
u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
} gen;
} u;
/* number of times this key has been used */
@ -113,9 +118,11 @@ struct ieee80211_key {
struct ieee80211_key_conf conf;
};
struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
const u8 *key_data,
size_t seq_len, const u8 *seq);
struct ieee80211_key *
ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
const u8 *key_data,
size_t seq_len, const u8 *seq,
const struct ieee80211_cipher_scheme *cs);
/*
* Insert a key into data structures (sdata, sta if necessary)
* to make it used, free old key. On failure, also free the new key.

View File

@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
int ieee80211_register_hw(struct ieee80211_hw *hw)
static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
{
struct ieee80211_local *local = hw_to_local(hw);
int result, i;
enum ieee80211_band band;
int channels, max_bitrates;
bool supp_ht, supp_vht;
netdev_features_t feature_whitelist;
struct cfg80211_chan_def dflt_chandef = {};
bool have_wep = !(IS_ERR(local->wep_tx_tfm) ||
IS_ERR(local->wep_rx_tfm));
bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE;
const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes;
int n_suites = 0, r = 0, w = 0;
u32 *suites;
static const u32 cipher_suites[] = {
/* keep WEP first, it may be removed below */
WLAN_CIPHER_SUITE_WEP40,
@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
WLAN_CIPHER_SUITE_AES_CMAC
};
/* Driver specifies the ciphers, we have nothing to do... */
if (local->hw.wiphy->cipher_suites && have_wep)
return 0;
/* Set up cipher suites if driver relies on mac80211 cipher defs */
if (!local->hw.wiphy->cipher_suites && !cs) {
local->hw.wiphy->cipher_suites = cipher_suites;
local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
if (!have_mfp)
local->hw.wiphy->n_cipher_suites--;
if (!have_wep) {
local->hw.wiphy->cipher_suites += 2;
local->hw.wiphy->n_cipher_suites -= 2;
}
return 0;
}
if (!local->hw.wiphy->cipher_suites) {
/*
* Driver specifies cipher schemes only
* We start counting ciphers defined by schemes, TKIP and CCMP
*/
n_suites = local->hw.n_cipher_schemes + 2;
/* check if we have WEP40 and WEP104 */
if (have_wep)
n_suites += 2;
/* check if we have AES_CMAC */
if (have_mfp)
n_suites++;
suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL);
if (!suites)
return -ENOMEM;
suites[w++] = WLAN_CIPHER_SUITE_CCMP;
suites[w++] = WLAN_CIPHER_SUITE_TKIP;
if (have_wep) {
suites[w++] = WLAN_CIPHER_SUITE_WEP40;
suites[w++] = WLAN_CIPHER_SUITE_WEP104;
}
if (have_mfp)
suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC;
for (r = 0; r < local->hw.n_cipher_schemes; r++)
suites[w++] = cs[r].cipher;
} else {
/* Driver provides cipher suites, but we need to exclude WEP */
suites = kmemdup(local->hw.wiphy->cipher_suites,
sizeof(u32) * local->hw.wiphy->n_cipher_suites,
GFP_KERNEL);
if (!suites)
return -ENOMEM;
for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
u32 suite = local->hw.wiphy->cipher_suites[r];
if (suite == WLAN_CIPHER_SUITE_WEP40 ||
suite == WLAN_CIPHER_SUITE_WEP104)
continue;
suites[w++] = suite;
}
}
local->hw.wiphy->cipher_suites = suites;
local->hw.wiphy->n_cipher_suites = w;
local->wiphy_ciphers_allocated = true;
return 0;
}
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
int result, i;
enum ieee80211_band band;
int channels, max_bitrates;
bool supp_ht, supp_vht;
netdev_features_t feature_whitelist;
struct cfg80211_chan_def dflt_chandef = {};
if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&
(local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||
local->hw.offchannel_tx_hw_queue >= local->hw.queues))
@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (local->hw.wiphy->max_scan_ie_len)
local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
/* Set up cipher suites unless driver already did */
if (!local->hw.wiphy->cipher_suites) {
local->hw.wiphy->cipher_suites = cipher_suites;
local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
local->hw.wiphy->n_cipher_suites--;
}
if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
if (local->hw.wiphy->cipher_suites == cipher_suites) {
local->hw.wiphy->cipher_suites += 2;
local->hw.wiphy->n_cipher_suites -= 2;
} else {
u32 *suites;
int r, w = 0;
WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,
local->hw.n_cipher_schemes));
/* Filter out WEP */
suites = kmemdup(
local->hw.wiphy->cipher_suites,
sizeof(u32) * local->hw.wiphy->n_cipher_suites,
GFP_KERNEL);
if (!suites) {
result = -ENOMEM;
goto fail_wiphy_register;
}
for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
u32 suite = local->hw.wiphy->cipher_suites[r];
if (suite == WLAN_CIPHER_SUITE_WEP40 ||
suite == WLAN_CIPHER_SUITE_WEP104)
continue;
suites[w++] = suite;
}
local->hw.wiphy->cipher_suites = suites;
local->hw.wiphy->n_cipher_suites = w;
local->wiphy_ciphers_allocated = true;
}
}
result = ieee80211_init_cipher_suites(local);
if (result < 0)
goto fail_wiphy_register;
if (!local->ops->remain_on_channel)
local->hw.wiphy->max_remain_on_channel_duration = 5000;
@ -1087,6 +1142,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
ieee80211_free_ack_frame, NULL);
idr_destroy(&local->ack_status_frames);
kfree(rcu_access_pointer(local->tx_latency));
wiphy_free(local->hw.wiphy);
}
EXPORT_SYMBOL(ieee80211_free_hw);

View File

@ -674,8 +674,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
rcu_read_lock();
csa = rcu_dereference(ifmsh->csa);
if (csa) {
__le16 pre_value;
pos = skb_put(skb, 13);
memset(pos, 0, 13);
*pos++ = WLAN_EID_CHANNEL_SWITCH;
@ -697,8 +695,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
pos += 2;
pre_value = cpu_to_le16(ifmsh->pre_value);
memcpy(pos, &pre_value, 2);
put_unaligned_le16(ifmsh->pre_value, pos);
pos += 2;
}
rcu_read_unlock();
@ -959,7 +956,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
sdata->local->csa_chandef = params.chandef;
sdata->csa_chandef = params.chandef;
sdata->vif.csa_active = true;
ieee80211_bss_info_change_notify(sdata, err);

View File

@ -215,8 +215,6 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *ie);
void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata,
@ -303,8 +301,8 @@ void mesh_mpath_table_grow(void);
void mesh_mpp_table_grow(void);
/* Mesh paths */
int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
u8 ttl, const u8 *target, __le32 target_sn,
__le16 target_rcode, const u8 *ra);
u8 ttl, const u8 *target, u32 target_sn,
u16 target_rcode, const u8 *ra);
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
void mesh_path_flush_pending(struct mesh_path *mpath);
void mesh_path_tx_pending(struct mesh_path *mpath);

View File

@ -102,12 +102,11 @@ enum mpath_frame_type {
static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
const u8 *orig_addr, __le32 orig_sn,
const u8 *orig_addr, u32 orig_sn,
u8 target_flags, const u8 *target,
__le32 target_sn, const u8 *da,
u32 target_sn, const u8 *da,
u8 hop_count, u8 ttl,
__le32 lifetime, __le32 metric,
__le32 preq_id,
u32 lifetime, u32 metric, u32 preq_id,
struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@ -167,33 +166,33 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
if (action == MPATH_PREP) {
memcpy(pos, target, ETH_ALEN);
pos += ETH_ALEN;
memcpy(pos, &target_sn, 4);
put_unaligned_le32(target_sn, pos);
pos += 4;
} else {
if (action == MPATH_PREQ) {
memcpy(pos, &preq_id, 4);
put_unaligned_le32(preq_id, pos);
pos += 4;
}
memcpy(pos, orig_addr, ETH_ALEN);
pos += ETH_ALEN;
memcpy(pos, &orig_sn, 4);
put_unaligned_le32(orig_sn, pos);
pos += 4;
}
memcpy(pos, &lifetime, 4); /* interval for RANN */
put_unaligned_le32(lifetime, pos); /* interval for RANN */
pos += 4;
memcpy(pos, &metric, 4);
put_unaligned_le32(metric, pos);
pos += 4;
if (action == MPATH_PREQ) {
*pos++ = 1; /* destination count */
*pos++ = target_flags;
memcpy(pos, target, ETH_ALEN);
pos += ETH_ALEN;
memcpy(pos, &target_sn, 4);
put_unaligned_le32(target_sn, pos);
pos += 4;
} else if (action == MPATH_PREP) {
memcpy(pos, orig_addr, ETH_ALEN);
pos += ETH_ALEN;
memcpy(pos, &orig_sn, 4);
put_unaligned_le32(orig_sn, pos);
pos += 4;
}
@ -239,8 +238,8 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
* frame directly but add it to the pending queue instead.
*/
int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
u8 ttl, const u8 *target, __le32 target_sn,
__le16 target_rcode, const u8 *ra)
u8 ttl, const u8 *target, u32 target_sn,
u16 target_rcode, const u8 *ra)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
@ -254,13 +253,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
return -EAGAIN;
skb = dev_alloc_skb(local->tx_headroom +
IEEE80211_ENCRYPT_HEADROOM +
sdata->encrypt_headroom +
IEEE80211_ENCRYPT_TAILROOM +
hdr_len +
2 + 15 /* PERR IE */);
if (!skb)
return -1;
skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
memset(mgmt, 0, hdr_len);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
@ -293,9 +292,9 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
pos++;
memcpy(pos, target, ETH_ALEN);
pos += ETH_ALEN;
memcpy(pos, &target_sn, 4);
put_unaligned_le32(target_sn, pos);
pos += 4;
memcpy(pos, &target_rcode, 2);
put_unaligned_le16(target_rcode, pos);
/* see note in function header */
prepare_frame_for_deferred_tx(sdata, skb);
@ -592,10 +591,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
if (ttl != 0) {
mhwmp_dbg(sdata, "replying to the PREQ\n");
mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
cpu_to_le32(orig_sn), 0, target_addr,
cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
cpu_to_le32(lifetime), cpu_to_le32(metric),
0, sdata);
orig_sn, 0, target_addr,
target_sn, mgmt->sa, 0, ttl,
lifetime, metric, 0, sdata);
} else {
ifmsh->mshstats.dropped_frames_ttl++;
}
@ -625,11 +623,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
}
mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
cpu_to_le32(orig_sn), target_flags, target_addr,
cpu_to_le32(target_sn), da,
hopcount, ttl, cpu_to_le32(lifetime),
cpu_to_le32(metric), cpu_to_le32(preq_id),
sdata);
orig_sn, target_flags, target_addr,
target_sn, da, hopcount, ttl, lifetime,
metric, preq_id, sdata);
if (!is_multicast_ether_addr(da))
ifmsh->mshstats.fwded_unicast++;
else
@ -695,11 +691,9 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
target_sn = PREP_IE_TARGET_SN(prep_elem);
orig_sn = PREP_IE_ORIG_SN(prep_elem);
mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
cpu_to_le32(orig_sn), 0, target_addr,
cpu_to_le32(target_sn), next_hop, hopcount,
ttl, cpu_to_le32(lifetime), cpu_to_le32(metric),
0, sdata);
mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, orig_sn, 0,
target_addr, target_sn, next_hop, hopcount,
ttl, lifetime, metric, 0, sdata);
rcu_read_unlock();
sdata->u.mesh.mshstats.fwded_unicast++;
@ -750,8 +744,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
if (!ifmsh->mshcfg.dot11MeshForwarding)
goto endperr;
mesh_path_error_tx(sdata, ttl, target_addr,
cpu_to_le32(target_sn),
cpu_to_le16(target_rcode),
target_sn, target_rcode,
broadcast_addr);
} else
spin_unlock_bh(&mpath->state_lock);
@ -847,11 +840,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
if (ifmsh->mshcfg.dot11MeshForwarding) {
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn),
0, NULL, 0, broadcast_addr,
hopcount, ttl, cpu_to_le32(interval),
cpu_to_le32(metric + metric_txsta),
0, sdata);
orig_sn, 0, NULL, 0, broadcast_addr,
hopcount, ttl, interval,
metric + metric_txsta, 0, sdata);
}
rcu_read_unlock();
@ -1049,11 +1040,9 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
spin_unlock_bh(&mpath->state_lock);
da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr;
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
cpu_to_le32(mpath->sn), da, 0,
ttl, cpu_to_le32(lifetime), 0,
cpu_to_le32(ifmsh->preq_id++), sdata);
mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, ifmsh->sn,
target_flags, mpath->dst, mpath->sn, da, 0,
ttl, lifetime, 0, ifmsh->preq_id++, sdata);
mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
enddiscovery:
@ -1212,10 +1201,9 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) {
case IEEE80211_PROACTIVE_RANN:
mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
cpu_to_le32(++ifmsh->sn),
0, NULL, 0, broadcast_addr,
0, ifmsh->mshcfg.element_ttl,
cpu_to_le32(interval), 0, 0, sdata);
++ifmsh->sn, 0, NULL, 0, broadcast_addr,
0, ifmsh->mshcfg.element_ttl,
interval, 0, 0, sdata);
break;
case IEEE80211_PROACTIVE_PREQ_WITH_PREP:
flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG;
@ -1224,11 +1212,10 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
target_flags |= IEEE80211_PREQ_TO_FLAG |
IEEE80211_PREQ_USN_FLAG;
mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr,
cpu_to_le32(++ifmsh->sn), target_flags,
(u8 *) broadcast_addr, 0, broadcast_addr,
0, ifmsh->mshcfg.element_ttl,
cpu_to_le32(interval),
0, cpu_to_le32(ifmsh->preq_id++), sdata);
++ifmsh->sn, target_flags,
(u8 *) broadcast_addr, 0, broadcast_addr,
0, ifmsh->mshcfg.element_ttl, interval,
0, ifmsh->preq_id++, sdata);
break;
default:
mhwmp_dbg(sdata, "Proactive mechanism not supported\n");

View File

@ -722,7 +722,6 @@ void mesh_plink_broken(struct sta_info *sta)
struct mpath_node *node;
struct ieee80211_sub_if_data *sdata = sta->sdata;
int i;
__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
rcu_read_lock();
tbl = rcu_dereference(mesh_paths);
@ -736,9 +735,9 @@ void mesh_plink_broken(struct sta_info *sta)
++mpath->sn;
spin_unlock_bh(&mpath->state_lock);
mesh_path_error_tx(sdata,
sdata->u.mesh.mshcfg.element_ttl,
mpath->dst, cpu_to_le32(mpath->sn),
reason, bcast);
sdata->u.mesh.mshcfg.element_ttl,
mpath->dst, mpath->sn,
WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
}
}
rcu_read_unlock();

File diff suppressed because it is too large Load Diff

View File

@ -576,10 +576,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
int ac, buffer_local = 0;
bool has_buffered = false;
/* TIM map only for LLID <= IEEE80211_MAX_AID */
if (sta->plink_state == NL80211_PLINK_ESTAB)
has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len,
le16_to_cpu(sta->llid) % IEEE80211_MAX_AID);
sta->llid);
if (has_buffered)
mps_dbg(sta->sdata, "%pM indicates buffered frames\n",

View File

@ -92,12 +92,20 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (stype != IEEE80211_STYPE_BEACON)
return;
/* The current tsf is a first approximation for the timestamp
* for the received beacon. Further down we try to get a
* better value from the rx_status->mactime field if
* available. Also we have to call drv_get_tsf() before
* entering the rcu-read section.*/
t_r = drv_get_tsf(local, sdata);
/*
* Get time when timestamp field was received. If we don't
* have rx timestamps, then use current tsf as an approximation.
* drv_get_tsf() must be called before entering the rcu-read
* section.
*/
if (ieee80211_have_rx_timestamp(rx_status))
t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
24 + 12 +
elems->total_len +
FCS_LEN,
24);
else
t_r = drv_get_tsf(local, sdata);
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->sa);
@ -117,14 +125,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
goto no_sync;
}
if (ieee80211_have_rx_timestamp(rx_status))
/* time when timestamp field was received */
t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
24 + 12 +
elems->total_len +
FCS_LEN,
24);
/* Timing offset calculation (see 13.13.2.2.2) */
t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
sta->t_offset = t_t - t_r;

View File

@ -330,6 +330,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
if (WARN_ON_ONCE(!sta))
return -EINVAL;
/*
* if bss configuration changed store the new one -
* this may be applicable even if channel is identical
*/
ht_opmode = le16_to_cpu(ht_oper->operation_mode);
if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
*changed |= BSS_CHANGED_HT;
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
}
chan = sdata->vif.bss_conf.chandef.chan;
sband = local->hw.wiphy->bands[chan->band];
@ -416,14 +426,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
IEEE80211_RC_BW_CHANGED);
}
ht_opmode = le16_to_cpu(ht_oper->operation_mode);
/* if bss configuration changed store the new one */
if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
*changed |= BSS_CHANGED_HT;
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
}
return 0;
}
@ -714,7 +716,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}
/* if present, add any custom IEs that go before HT */
if (assoc_data->ie_len && assoc_data->ie) {
if (assoc_data->ie_len) {
static const u8 before_ht[] = {
WLAN_EID_SSID,
WLAN_EID_SUPP_RATES,
@ -748,7 +750,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
&assoc_data->ap_vht_cap);
/* if present, add any custom non-vendor IEs that go after HT */
if (assoc_data->ie_len && assoc_data->ie) {
if (assoc_data->ie_len) {
noffset = ieee80211_ie_split_vendor(assoc_data->ie,
assoc_data->ie_len,
offset);
@ -779,7 +781,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
}
/* add any remaining custom (i.e. vendor specific here) IEs */
if (assoc_data->ie_len && assoc_data->ie) {
if (assoc_data->ie_len) {
noffset = assoc_data->ie_len;
pos = skb_put(skb, noffset - offset);
memcpy(pos, assoc_data->ie + offset, noffset - offset);
@ -886,8 +888,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
if (!ifmgd->associated)
goto out;
ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
&changed);
ret = ieee80211_vif_change_channel(sdata, &changed);
if (ret) {
sdata_info(sdata,
"vif channel switch failed, disconnecting\n");
@ -897,7 +898,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
}
if (!local->use_chanctx) {
local->_oper_chandef = local->csa_chandef;
local->_oper_chandef = sdata->csa_chandef;
/* Call "hw_config" only if doing sw channel switch.
* Otherwise update the channel directly
*/
@ -908,7 +909,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
}
/* XXX: shouldn't really modify cfg80211-owned data! */
ifmgd->associated->channel = local->csa_chandef.chan;
ifmgd->associated->channel = sdata->csa_chandef.chan;
/* XXX: wait for a beacon first? */
ieee80211_wake_queues_by_reason(&local->hw,
@ -1035,7 +1036,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
mutex_unlock(&local->chanctx_mtx);
local->csa_chandef = csa_ie.chandef;
sdata->csa_chandef = csa_ie.chandef;
if (csa_ie.mode)
ieee80211_stop_queues_by_reason(&local->hw,
@ -1398,10 +1399,12 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
struct ieee80211_sub_if_data *sdata =
container_of(delayed_work, struct ieee80211_sub_if_data,
dfs_cac_timer_work);
struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
ieee80211_vif_release_channel(sdata);
cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
cfg80211_cac_event(sdata->dev, &chandef,
NL80211_RADAR_CAC_FINISHED,
GFP_KERNEL);
}
/* MLME */
@ -1745,6 +1748,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ifmgd->flags = 0;
ieee80211_vif_release_channel(sdata);
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
}
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@ -4189,6 +4194,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
sdata->control_port_protocol = req->crypto.control_port_ethertype;
sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
sdata->vif.type);
/* kick off associate process */

View File

@ -54,6 +54,8 @@ static inline void rate_control_rate_init(struct sta_info *sta)
struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf;
ieee80211_sta_set_rx_nss(sta);
if (!ref)
return;
@ -67,8 +69,6 @@ static inline void rate_control_rate_init(struct sta_info *sta)
sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
ieee80211_sta_set_rx_nss(sta);
ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
priv_sta);
rcu_read_unlock();

View File

@ -422,10 +422,9 @@ init_sample_table(struct minstrel_sta_info *mi)
memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
for (col = 0; col < SAMPLE_COLUMNS; col++) {
prandom_bytes(rnd, sizeof(rnd));
for (i = 0; i < mi->n_rates; i++) {
get_random_bytes(rnd, sizeof(rnd));
new_idx = (i + rnd[i & 7]) % mi->n_rates;
while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
new_idx = (new_idx + 1) % mi->n_rates;

View File

@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
static int
minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
{
return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
return GROUP_IDX((rate->idx / 8) + 1,
!!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
!!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
}
@ -148,7 +148,7 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
if (rate->flags & IEEE80211_TX_RC_MCS) {
group = minstrel_ht_get_group_idx(rate);
idx = rate->idx % MCS_GROUP_RATES;
idx = rate->idx % 8;
} else {
group = MINSTREL_CCK_GROUP;
@ -636,8 +636,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
flags = 0;
} else {
idx = index % MCS_GROUP_RATES +
(group->streams - 1) * MCS_GROUP_RATES;
idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8;
flags = IEEE80211_TX_RC_MCS | group->flags;
}
@ -701,13 +700,17 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
if (!mi->sample_tries)
return -1;
mg = &mi->groups[mi->sample_group];
sample_idx = sample_table[mg->column][mg->index];
mr = &mg->rates[sample_idx];
sample_group = mi->sample_group;
sample_idx += sample_group * MCS_GROUP_RATES;
mg = &mi->groups[sample_group];
sample_idx = sample_table[mg->column][mg->index];
minstrel_next_sample_idx(mi);
if (!(mg->supported & BIT(sample_idx)))
return -1;
mr = &mg->rates[sample_idx];
sample_idx += sample_group * MCS_GROUP_RATES;
/*
* Sampling might add some overhead (RTS, no aggregation)
* to the frame. Hence, don't use sampling for the currently
@ -817,7 +820,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
}
rate->idx = sample_idx % MCS_GROUP_RATES +
(sample_group->streams - 1) * MCS_GROUP_RATES;
(sample_group->streams - 1) * 8;
rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
}
@ -1052,10 +1055,9 @@ init_sample_table(void)
memset(sample_table, 0xff, sizeof(sample_table));
for (col = 0; col < SAMPLE_COLUMNS; col++) {
prandom_bytes(rnd, sizeof(rnd));
for (i = 0; i < MCS_GROUP_RATES; i++) {
get_random_bytes(rnd, sizeof(rnd));
new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
while (sample_table[col][new_idx] != 0xff)
new_idx = (new_idx + 1) % MCS_GROUP_RATES;

View File

@ -54,8 +54,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
int r = bitrates[j % 4];
p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
} else {
p += sprintf(p, " MCS%-2u", (mg->streams - 1) *
MCS_GROUP_RATES + j);
p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j);
}
tp = mr->cur_tp / 10;

View File

@ -638,6 +638,27 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
return le16_to_cpu(mmie->key_id);
}
static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc;
int hdrlen;
u8 keyid;
fc = hdr->frame_control;
hdrlen = ieee80211_hdrlen(fc);
if (skb->len < hdrlen + cs->hdr_len)
return -EINVAL;
skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);
keyid &= cs->key_idx_mask;
keyid >>= cs->key_idx_shift;
return keyid;
}
static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@ -729,9 +750,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
lockdep_assert_held(&tid_agg_rx->reorder_lock);
while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
frames);
}
@ -757,8 +776,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&tid_agg_rx->reorder_lock);
/* release the buffer until next missing frame */
index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
tid_agg_rx->ssn) % tid_agg_rx->buf_size;
index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
if (!tid_agg_rx->reorder_buf[index] &&
tid_agg_rx->stored_mpdu_num) {
/*
@ -793,15 +811,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
} else while (tid_agg_rx->reorder_buf[index]) {
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
frames);
index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
}
if (tid_agg_rx->stored_mpdu_num) {
j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
for (; j != (index - 1) % tid_agg_rx->buf_size;
j = (j + 1) % tid_agg_rx->buf_size) {
@ -861,8 +875,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
/* Now the new frame is always in the range of the reordering buffer */
index = ieee80211_sn_sub(mpdu_seq_num,
tid_agg_rx->ssn) % tid_agg_rx->buf_size;
index = mpdu_seq_num % tid_agg_rx->buf_size;
/* check if we already stored this frame */
if (tid_agg_rx->reorder_buf[index]) {
@ -1368,6 +1381,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
struct ieee80211_key *sta_ptk = NULL;
int mmie_keyidx = -1;
__le16 fc;
const struct ieee80211_cipher_scheme *cs = NULL;
/*
* Key selection 101
@ -1405,12 +1419,20 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
/* start without a key */
rx->key = NULL;
if (rx->sta)
sta_ptk = rcu_dereference(rx->sta->ptk);
fc = hdr->frame_control;
if (rx->sta) {
int keyid = rx->sta->ptk_idx;
if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {
cs = rx->sta->cipher_scheme;
keyid = iwl80211_get_cs_keyid(cs, rx->skb);
if (unlikely(keyid < 0))
return RX_DROP_UNUSABLE;
}
sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
}
if (!ieee80211_has_protected(fc))
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
@ -1471,6 +1493,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
} else {
u8 keyid;
/*
* The device doesn't give us the IV so we won't be
* able to look up the key. That's ok though, we
@ -1486,15 +1509,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
hdrlen = ieee80211_hdrlen(fc);
if (rx->skb->len < 8 + hdrlen)
return RX_DROP_UNUSABLE; /* TODO: count this? */
if (cs) {
keyidx = iwl80211_get_cs_keyid(cs, rx->skb);
/*
* no need to call ieee80211_wep_get_keyidx,
* it verifies a bunch of things we've done already
*/
skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
keyidx = keyid >> 6;
if (unlikely(keyidx < 0))
return RX_DROP_UNUSABLE;
} else {
if (rx->skb->len < 8 + hdrlen)
return RX_DROP_UNUSABLE; /* TODO: count this? */
/*
* no need to call ieee80211_wep_get_keyidx,
* it verifies a bunch of things we've done already
*/
skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
keyidx = keyid >> 6;
}
/* check per-station GTK first, if multicast packet */
if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
@ -1542,11 +1571,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
result = ieee80211_crypto_aes_cmac_decrypt(rx);
break;
default:
/*
* We can reach here only with HW-only algorithms
* but why didn't it decrypt the frame?!
*/
return RX_DROP_UNUSABLE;
result = ieee80211_crypto_hw_decrypt(rx);
}
/* the hdr variable is invalid after the decrypt handlers */
@ -2056,7 +2081,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
u16 q, hdrlen;
hdr = (struct ieee80211_hdr *) skb->data;
@ -2164,7 +2188,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
} else {
/* unable to resolve next hop */
mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
fwd_hdr->addr3, 0, reason, fwd_hdr->addr2);
fwd_hdr->addr3, 0,
WLAN_REASON_MESH_PATH_NOFORWARD,
fwd_hdr->addr2);
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
kfree_skb(fwd_skb);
return RX_DROP_MONITOR;

View File

@ -526,7 +526,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
ieee80211_hw_config(local, 0);
if ((req->channels[0]->flags &
IEEE80211_CHAN_PASSIVE_SCAN) ||
IEEE80211_CHAN_NO_IR) ||
!local->scan_req->n_ssids) {
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
} else {
@ -572,7 +572,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
* TODO: channel switching also consumes quite some time,
* add that delay as well to get a better estimation
*/
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
if (chan->flags & IEEE80211_CHAN_NO_IR)
return IEEE80211_PASSIVE_CHANNEL_TIME;
return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
}
@ -696,7 +696,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
*
* In any case, it is not necessary for a passive scan.
*/
if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
if (chan->flags & IEEE80211_CHAN_NO_IR ||
!local->scan_req->n_ssids) {
*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
local->next_scan_state = SCAN_DECISION;
@ -881,7 +881,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *tmp_ch =
&local->hw.wiphy->bands[band]->channels[i];
if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS |
if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_DISABLED))
continue;
@ -895,7 +895,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
local->int_scan_req->n_channels = n_ch;
} else {
if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS |
if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_DISABLED)))
goto unlock;

View File

@ -266,9 +266,17 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
*/
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
{
int i;
if (sta->rate_ctrl)
rate_control_free_sta(sta);
if (sta->tx_lat) {
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
kfree(sta->tx_lat[i].bins);
kfree(sta->tx_lat);
}
sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
kfree(sta);
@ -333,6 +341,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct timespec uptime;
struct ieee80211_tx_latency_bin_ranges *tx_latency;
int i;
sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
@ -410,6 +419,31 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
}
}
rcu_read_lock();
tx_latency = rcu_dereference(local->tx_latency);
/* init stations Tx latency statistics && TID bins */
if (tx_latency)
sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
sizeof(struct ieee80211_tx_latency_stat),
GFP_ATOMIC);
/*
* if Tx latency and bins are enabled and the previous allocation
* succeeded
*/
if (tx_latency && tx_latency->n_ranges && sta->tx_lat)
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
/* size of bins is size of the ranges +1 */
sta->tx_lat[i].bin_count =
tx_latency->n_ranges + 1;
sta->tx_lat[i].bins = kcalloc(sta->tx_lat[i].bin_count,
sizeof(u32),
GFP_ATOMIC);
}
rcu_read_unlock();
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
return sta;
@ -507,6 +541,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
set_sta_flag(sta, WLAN_STA_INSERTED);
ieee80211_recalc_min_chandef(sdata);
ieee80211_sta_debugfs_add(sta);
rate_control_add_sta_debugfs(sta);
@ -630,8 +665,8 @@ void sta_info_recalc_tim(struct sta_info *sta)
#ifdef CONFIG_MAC80211_MESH
} else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
ps = &sta->sdata->u.mesh.ps;
/* TIM map only for PLID <= IEEE80211_MAX_AID */
id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID;
/* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */
id = sta->plid % (IEEE80211_MAX_AID + 1);
#endif
} else {
return;
@ -869,6 +904,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
rate_control_remove_sta_debugfs(sta);
ieee80211_sta_debugfs_remove(sta);
ieee80211_recalc_min_chandef(sdata);
call_rcu(&sta->rcu_head, free_sta_rcu);

View File

@ -220,6 +220,25 @@ struct sta_ampdu_mlme {
u8 dialog_token_allocator;
};
/*
* struct ieee80211_tx_latency_stat - Tx latency statistics
*
* Measures TX latency and jitter for a station per TID.
*
* @max: worst case latency
* @sum: sum of all latencies
* @counter: amount of Tx frames sent from interface
* @bins: each bin counts how many frames transmitted within a certain
* latency range. when disabled it is NULL.
* @bin_count: amount of bins.
*/
struct ieee80211_tx_latency_stat {
u32 max;
u32 sum;
u32 counter;
u32 *bins;
u32 bin_count;
};
/**
* struct sta_info - STA information
@ -231,8 +250,10 @@ struct sta_ampdu_mlme {
* @hnext: hash table linked list pointer
* @local: pointer to the global information
* @sdata: virtual interface this station belongs to
* @ptk: peer key negotiated with this station, if any
* @ptk: peer keys negotiated with this station, if any
* @ptk_idx: last installed peer key index
* @gtk: group keys negotiated with this station, if any
* @gtk_idx: last installed group key index
* @rate_ctrl: rate control algorithm reference
* @rate_ctrl_priv: rate control private per-STA pointer
* @last_tx_rate: rate used for last transmit, to report to userspace as
@ -274,6 +295,7 @@ struct sta_ampdu_mlme {
* @tid_seq: per-TID sequence numbers for sending to this STA
* @ampdu_mlme: A-MPDU state machine state
* @timer_to_tid: identity mapping to ID timers
* @tx_lat: Tx latency statistics
* @llid: Local link ID
* @plid: Peer link ID
* @reason: Cancel reason on PLINK_HOLDING state
@ -303,6 +325,7 @@ struct sta_ampdu_mlme {
* @chain_signal_avg: signal average (per chain)
* @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
* AP only.
* @cipher_scheme: optional cipher scheme for this station
*/
struct sta_info {
/* General information, mostly static */
@ -312,7 +335,9 @@ struct sta_info {
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
struct ieee80211_key __rcu *ptk;
struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS];
u8 gtk_idx;
u8 ptk_idx;
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
spinlock_t lock;
@ -380,14 +405,16 @@ struct sta_info {
struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[IEEE80211_NUM_TIDS];
struct ieee80211_tx_latency_stat *tx_lat;
#ifdef CONFIG_MAC80211_MESH
/*
* Mesh peer link attributes
* TODO: move to a sub-structure that is referenced with pointer?
*/
__le16 llid;
__le16 plid;
__le16 reason;
u16 llid;
u16 plid;
u16 reason;
u8 plink_retries;
bool ignore_plink_timer;
enum nl80211_plink_state plink_state;
@ -414,6 +441,7 @@ struct sta_info {
unsigned int beacon_loss_count;
enum ieee80211_smps_mode known_smps_mode;
const struct ieee80211_cipher_scheme *cipher_scheme;
/* keep last! */
struct ieee80211_sta sta;

View File

@ -11,6 +11,7 @@
#include <linux/export.h>
#include <linux/etherdevice.h>
#include <linux/time.h>
#include <net/mac80211.h>
#include <asm/unaligned.h>
#include "ieee80211_i.h"
@ -462,6 +463,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
}
}
/*
* Measure Tx frame completion and removal time for Tx latency statistics
* calculation. A single Tx frame latency should be measured from when it
* is entering the Kernel until we receive Tx complete confirmation indication
* and remove the skb.
*/
static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
struct sk_buff *skb,
struct sta_info *sta,
struct ieee80211_hdr *hdr)
{
ktime_t skb_dprt;
struct timespec dprt_time;
u32 msrmnt;
u16 tid;
u8 *qc;
int i, bin_range_count, bin_count;
u32 *bin_ranges;
__le16 fc;
struct ieee80211_tx_latency_stat *tx_lat;
struct ieee80211_tx_latency_bin_ranges *tx_latency;
ktime_t skb_arv = skb->tstamp;
tx_latency = rcu_dereference(local->tx_latency);
/* assert Tx latency stats are enabled & frame arrived when enabled */
if (!tx_latency || !ktime_to_ns(skb_arv))
return;
fc = hdr->frame_control;
if (!ieee80211_is_data(fc)) /* make sure it is a data frame */
return;
/* get frame tid */
if (ieee80211_is_data_qos(hdr->frame_control)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
} else {
tid = 0;
}
tx_lat = &sta->tx_lat[tid];
ktime_get_ts(&dprt_time); /* time stamp completion time */
skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec);
msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv));
if (tx_lat->max < msrmnt) /* update stats */
tx_lat->max = msrmnt;
tx_lat->counter++;
tx_lat->sum += msrmnt;
if (!tx_lat->bins) /* bins not activated */
return;
/* count how many Tx frames transmitted with the appropriate latency */
bin_range_count = tx_latency->n_ranges;
bin_ranges = tx_latency->ranges;
bin_count = tx_lat->bin_count;
for (i = 0; i < bin_range_count; i++) {
if (msrmnt <= bin_ranges[i]) {
tx_lat->bins[i]++;
break;
}
}
if (i == bin_range_count) /* msrmnt is bigger than the biggest range */
tx_lat->bins[i]++;
}
/*
* Use a static threshold for now, best value to be determined
* by testing ...
@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (acked)
sta->last_ack_signal = info->status.ack_signal;
/*
* Measure frame removal for tx latency
* statistics calculation
*/
ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);
}
rcu_read_unlock();

View File

@ -41,14 +41,31 @@
#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
__entry->center_freq1, __entry->center_freq2
#define MIN_CHANDEF_ENTRY \
__field(u32, min_control_freq) \
__field(u32, min_chan_width) \
__field(u32, min_center_freq1) \
__field(u32, min_center_freq2)
#define MIN_CHANDEF_ASSIGN(c) \
__entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \
__entry->min_chan_width = (c)->width; \
__entry->min_center_freq1 = (c)->center_freq1; \
__entry->min_center_freq2 = (c)->center_freq2;
#define MIN_CHANDEF_PR_FMT " min_control:%d MHz min_width:%d min_center: %d/%d MHz"
#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_chan_width, \
__entry->min_center_freq1, __entry->min_center_freq2
#define CHANCTX_ENTRY CHANDEF_ENTRY \
MIN_CHANDEF_ENTRY \
__field(u8, rx_chains_static) \
__field(u8, rx_chains_dynamic)
#define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \
MIN_CHANDEF_ASSIGN(&ctx->conf.min_def) \
__entry->rx_chains_static = ctx->conf.rx_chains_static; \
__entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d"
#define CHANCTX_PR_ARG CHANDEF_PR_ARG, \
#define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d"
#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, \
__entry->rx_chains_static, __entry->rx_chains_dynamic

View File

@ -19,6 +19,7 @@
#include <linux/bitmap.h>
#include <linux/rcupdate.h>
#include <linux/export.h>
#include <linux/time.h>
#include <net/net_namespace.h>
#include <net/ieee80211_radiotap.h>
#include <net/cfg80211.h>
@ -557,7 +558,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
else if (tx->sta &&
(key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
tx->key = key;
else if (ieee80211_is_mgmt(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) &&
@ -840,15 +842,16 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
rem -= fraglen;
tmp = dev_alloc_skb(local->tx_headroom +
frag_threshold +
IEEE80211_ENCRYPT_HEADROOM +
tx->sdata->encrypt_headroom +
IEEE80211_ENCRYPT_TAILROOM);
if (!tmp)
return -ENOMEM;
__skb_queue_tail(&tx->skbs, tmp);
skb_reserve(tmp, local->tx_headroom +
IEEE80211_ENCRYPT_HEADROOM);
skb_reserve(tmp,
local->tx_headroom + tx->sdata->encrypt_headroom);
/* copy control information */
memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
@ -1485,7 +1488,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
headroom = local->tx_headroom;
if (may_encrypt)
headroom += IEEE80211_ENCRYPT_HEADROOM;
headroom += sdata->encrypt_headroom;
headroom -= skb_headroom(skb);
headroom = max_t(int, 0, headroom);
@ -1724,8 +1727,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
* 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)))
if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)))
goto fail_rcu;
ieee80211_xmit(sdata, skb, chan->band);
@ -1740,6 +1742,26 @@ fail:
return NETDEV_TX_OK; /* meaning, we dealt with the skb */
}
/*
* Measure Tx frame arrival time for Tx latency statistics calculation
* A single Tx frame latency should be measured from when it is entering the
* Kernel until we receive Tx complete confirmation indication and the skb is
* freed.
*/
static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
struct sk_buff *skb)
{
struct timespec skb_arv;
struct ieee80211_tx_latency_bin_ranges *tx_latency;
tx_latency = rcu_dereference(local->tx_latency);
if (!tx_latency)
return;
ktime_get_ts(&skb_arv);
skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec);
}
/**
* ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
* subinterfaces (wlan#, WDS, and VLAN interfaces)
@ -1790,6 +1812,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
rcu_read_lock();
/* Measure frame arrival for Tx latency statistics calculation */
ieee80211_tx_latency_start_msrmnt(local, skb);
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
sta = rcu_dereference(sdata->u.vlan.sta);
@ -2109,7 +2134,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
*/
if (head_need > 0 || skb_cloned(skb)) {
head_need += IEEE80211_ENCRYPT_HEADROOM;
head_need += sdata->encrypt_headroom;
head_need += local->tx_headroom;
head_need = max_t(int, 0, head_need);
if (ieee80211_skb_resize(sdata, skb, head_need, true)) {

View File

@ -1804,6 +1804,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&local->chanctx_mtx);
}
void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
mutex_lock(&local->chanctx_mtx);
chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
lockdep_is_held(&local->chanctx_mtx));
if (WARN_ON_ONCE(!chanctx_conf))
goto unlock;
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
ieee80211_recalc_chanctx_min_def(local, chanctx);
unlock:
mutex_unlock(&local->chanctx_mtx);
}
static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
{
int i;
@ -2259,14 +2279,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
struct cfg80211_chan_def chandef;
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
if (sdata->wdev.cac_started) {
chandef = sdata->vif.bss_conf.chandef;
ieee80211_vif_release_channel(sdata);
cfg80211_cac_event(sdata->dev,
&chandef,
NL80211_RADAR_CAC_ABORTED,
GFP_KERNEL);
}
@ -2447,7 +2470,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
if (ieee80211_vif_is_mesh(&sdata->vif)) {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
__le16 pre_value;
skb_put(skb, 8);
*pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */
@ -2463,8 +2485,7 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
ifmsh->pre_value = 1;
else
ifmsh->pre_value++;
pre_value = cpu_to_le16(ifmsh->pre_value);
memcpy(pos, &pre_value, 2); /* Precedence Value */
put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */
pos += 2;
ifmsh->chsw_init = true;
}
@ -2472,3 +2493,71 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb(sdata, skb);
return 0;
}
bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
{
return !(cs == NULL || cs->cipher == 0 ||
cs->hdr_len < cs->pn_len + cs->pn_off ||
cs->hdr_len <= cs->key_idx_off ||
cs->key_idx_shift > 7 ||
cs->key_idx_mask == 0);
}
bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
{
int i;
/* Ensure we have enough iftype bitmap space for all iftype values */
WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
for (i = 0; i < n; i++)
if (!ieee80211_cs_valid(&cs[i]))
return false;
return true;
}
const struct ieee80211_cipher_scheme *
ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
enum nl80211_iftype iftype)
{
const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
int n = local->hw.n_cipher_schemes;
int i;
const struct ieee80211_cipher_scheme *cs = NULL;
for (i = 0; i < n; i++) {
if (l[i].cipher == cipher) {
cs = &l[i];
break;
}
}
if (!cs || !(cs->iftype & BIT(iftype)))
return NULL;
return cs;
}
int ieee80211_cs_headroom(struct ieee80211_local *local,
struct cfg80211_crypto_settings *crypto,
enum nl80211_iftype iftype)
{
const struct ieee80211_cipher_scheme *cs;
int headroom = IEEE80211_ENCRYPT_HEADROOM;
int i;
for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
iftype);
if (cs && headroom < cs->hdr_len)
headroom = cs->hdr_len;
}
cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
if (cs && headroom < cs->hdr_len)
headroom = cs->hdr_len;
return headroom;
}

View File

@ -182,16 +182,15 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
IEEE80211_VHT_CAP_SHORT_GI_160);
/* remaining ones */
if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)
vht_cap->cap |= cap_info &
(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
}
IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
vht_cap->cap |= cap_info &
(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX);
IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
vht_cap->cap |= cap_info &

View File

@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}
static ieee80211_tx_result
ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key *key = tx->key;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme;
int hdrlen;
u8 *pos;
if (info->control.hw_key &&
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
/* hwaccel has no need for preallocated head room */
return TX_CONTINUE;
}
if (unlikely(skb_headroom(skb) < cs->hdr_len &&
pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC)))
return TX_DROP;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
pos = skb_push(skb, cs->hdr_len);
memmove(pos, pos + cs->hdr_len, hdrlen);
skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len);
return TX_CONTINUE;
}
static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len)
{
int i;
/* pn is little endian */
for (i = len - 1; i >= 0; i--) {
if (pn1[i] < pn2[i])
return -1;
else if (pn1[i] > pn2[i])
return 1;
}
return 0;
}
static ieee80211_rx_result
ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
{
struct ieee80211_key *key = rx->key;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
const struct ieee80211_cipher_scheme *cs = NULL;
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
int data_len;
u8 *rx_pn;
u8 *skb_pn;
u8 qos_tid;
if (!rx->sta || !rx->sta->cipher_scheme ||
!(status->flag & RX_FLAG_DECRYPTED))
return RX_DROP_UNUSABLE;
if (!ieee80211_is_data(hdr->frame_control))
return RX_CONTINUE;
cs = rx->sta->cipher_scheme;
data_len = rx->skb->len - hdrlen - cs->hdr_len;
if (data_len < 0)
return RX_DROP_UNUSABLE;
if (ieee80211_is_data_qos(hdr->frame_control))
qos_tid = *ieee80211_get_qos_ctl(hdr) &
IEEE80211_QOS_CTL_TID_MASK;
else
qos_tid = 0;
if (skb_linearize(rx->skb))
return RX_DROP_UNUSABLE;
hdr = (struct ieee80211_hdr *)rx->skb->data;
rx_pn = key->u.gen.rx_pn[qos_tid];
skb_pn = rx->skb->data + hdrlen + cs->pn_off;
if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0)
return RX_DROP_UNUSABLE;
memcpy(rx_pn, skb_pn, cs->pn_len);
/* remove security header and MIC */
if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len))
return RX_DROP_UNUSABLE;
memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen);
skb_pull(rx->skb, cs->hdr_len);
return RX_CONTINUE;
}
static void bip_aad(struct sk_buff *skb, u8 *aad)
{
@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb;
struct ieee80211_tx_info *info = NULL;
ieee80211_tx_result res;
skb_queue_walk(&tx->skbs, skb) {
info = IEEE80211_SKB_CB(skb);
@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
/* handle hw-only algorithm */
if (!info->control.hw_key)
return TX_DROP;
if (tx->key->sta->cipher_scheme) {
res = ieee80211_crypto_cs_encrypt(tx, skb);
if (res != TX_CONTINUE)
return res;
}
}
ieee80211_tx_set_protected(tx);
return TX_CONTINUE;
}
ieee80211_rx_result
ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx)
{
if (rx->sta->cipher_scheme)
return ieee80211_crypto_cs_decrypt(rx);
return RX_DROP_UNUSABLE;
}

View File

@ -34,5 +34,7 @@ ieee80211_rx_result
ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx);
ieee80211_tx_result
ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx);
ieee80211_rx_result
ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx);
#endif /* WPA_H */

View File

@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
width, dfs_state);
}
static u32 cfg80211_get_start_freq(u32 center_freq,
u32 bandwidth)
{
u32 start_freq;
if (bandwidth <= 20)
start_freq = center_freq;
else
start_freq = center_freq - bandwidth/2 + 10;
return start_freq;
}
static u32 cfg80211_get_end_freq(u32 center_freq,
u32 bandwidth)
{
u32 end_freq;
if (bandwidth <= 20)
end_freq = center_freq;
else
end_freq = center_freq + bandwidth/2 - 10;
return end_freq;
}
static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
u32 center_freq,
u32 bandwidth)
@ -284,13 +310,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
struct ieee80211_channel *c;
u32 freq, start_freq, end_freq;
if (bandwidth <= 20) {
start_freq = center_freq;
end_freq = center_freq;
} else {
start_freq = center_freq - bandwidth/2 + 10;
end_freq = center_freq + bandwidth/2 - 10;
}
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
@ -330,6 +351,146 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
u32 center_freq,
u32 bandwidth)
{
struct ieee80211_channel *c;
u32 freq, start_freq, end_freq;
int count = 0;
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
/*
* Check entire range of channels for the bandwidth.
* Check all channels are DFS channels (DFS_USABLE or
* DFS_AVAILABLE). Return number of usable channels
* (require CAC). Allow DFS and non-DFS channel mix.
*/
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c)
return -EINVAL;
if (c->flags & IEEE80211_CHAN_DISABLED)
return -EINVAL;
if (c->flags & IEEE80211_CHAN_RADAR) {
if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
return -EINVAL;
if (c->dfs_state == NL80211_DFS_USABLE)
count++;
}
}
return count;
}
bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
{
int width;
int r1, r2 = 0;
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return false;
width = cfg80211_chandef_get_width(chandef);
if (width < 0)
return false;
r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
width);
if (r1 < 0)
return false;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2);
r2 = cfg80211_get_chans_dfs_usable(wiphy,
chandef->center_freq2,
width);
if (r2 < 0)
return false;
break;
default:
WARN_ON(chandef->center_freq2);
break;
}
return (r1 + r2 > 0);
}
static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
u32 center_freq,
u32 bandwidth)
{
struct ieee80211_channel *c;
u32 freq, start_freq, end_freq;
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
/*
* Check entire range of channels for the bandwidth.
* If any channel in between is disabled or has not
* had gone through CAC return false
*/
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c)
return false;
if (c->flags & IEEE80211_CHAN_DISABLED)
return false;
if ((c->flags & IEEE80211_CHAN_RADAR) &&
(c->dfs_state != NL80211_DFS_AVAILABLE))
return false;
}
return true;
}
static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
{
int width;
int r;
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return false;
width = cfg80211_chandef_get_width(chandef);
if (width < 0)
return false;
r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
width);
/* If any of channels unavailable for cf1 just return */
if (!r)
return r;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2);
r = cfg80211_get_chans_dfs_available(wiphy,
chandef->center_freq2,
width);
default:
WARN_ON(chandef->center_freq2);
break;
}
return r;
}
static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
u32 center_freq, u32 bandwidth,
u32 prohibited_flags)
@ -337,26 +498,12 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
struct ieee80211_channel *c;
u32 freq, start_freq, end_freq;
if (bandwidth <= 20) {
start_freq = center_freq;
end_freq = center_freq;
} else {
start_freq = center_freq - bandwidth/2 + 10;
end_freq = center_freq + bandwidth/2 - 10;
}
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c)
return false;
/* check for radar flags */
if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
(c->dfs_state != NL80211_DFS_AVAILABLE))
return false;
/* check for the other flags */
if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
if (!c || c->flags & prohibited_flags)
return false;
}
@ -462,14 +609,19 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
bool res;
u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_RADAR;
trace_cfg80211_reg_can_beacon(wiphy, chandef);
res = cfg80211_chandef_usable(wiphy, chandef,
IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_PASSIVE_SCAN |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_RADAR);
if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
cfg80211_chandef_dfs_available(wiphy, chandef)) {
/* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
prohibited_flags = IEEE80211_CHAN_DISABLED;
}
res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
trace_cfg80211_return_bool(res);
return res;
@ -510,6 +662,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
: CHAN_MODE_EXCLUSIVE;
return;
}
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
if (wdev->current_bss) {

View File

@ -357,8 +357,6 @@ 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);
@ -566,6 +564,8 @@ int wiphy_register(struct wiphy *wiphy)
/* check and set up bitrates */
ieee80211_set_bitrate_flags(wiphy);
rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH;
rtnl_lock();
res = device_add(&rdev->wiphy.dev);
if (res) {
@ -586,7 +586,7 @@ int wiphy_register(struct wiphy *wiphy)
if (IS_ERR(rdev->wiphy.debugfsdir))
rdev->wiphy.debugfsdir = NULL;
if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
struct regulatory_request request;
request.wiphy_idx = get_wiphy_idx(wiphy);

View File

@ -317,9 +317,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie);
struct cfg80211_mgmt_tx_params *params,
u64 *cookie);
void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
const struct ieee80211_ht_cap *ht_capa_mask);
void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
@ -382,6 +381,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
enum cfg80211_chan_mode chanmode,
u8 radar_detect);
/**
* cfg80211_chandef_dfs_usable - checks if chandef is DFS usable
* @wiphy: the wiphy to validate against
* @chandef: the channel definition to check
*
* Checks if chandef is usable and we can/need start CAC on such channel.
*
* Return: Return true if all channels available and at least
* one channel require CAC (NL80211_DFS_USABLE)
*/
bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef);
void cfg80211_set_dfs_state(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef,
enum nl80211_dfs_state dfs_state);

View File

@ -33,15 +33,7 @@ BEGIN {
regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
}
/^[ \t]*#/ {
# Ignore
}
!active && /^[ \t]*$/ {
# Ignore
}
!active && /country/ {
function parse_country_head() {
country=$2
sub(/:/, "", country)
printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
@ -57,7 +49,8 @@ BEGIN {
regdb = regdb "\t&regdom_" country ",\n"
}
active && /^[ \t]*\(/ {
function parse_reg_rule()
{
start = $1
sub(/\(/, "", start)
end = $3
@ -107,17 +100,21 @@ active && /^[ \t]*\(/ {
} else if (flagarray[arg] == "PTMP-ONLY") {
flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | "
} else if (flagarray[arg] == "PASSIVE-SCAN") {
flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | "
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
} else if (flagarray[arg] == "NO-IBSS") {
flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | "
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
} else if (flagarray[arg] == "NO-IR") {
flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
}
}
flags = flags "0"
printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags
rules++
}
active && /^[ \t]*$/ {
function print_tail_country()
{
active = 0
printf "\t},\n"
printf "\t.n_reg_rules = %d\n", rules
@ -125,7 +122,29 @@ active && /^[ \t]*$/ {
rules = 0;
}
/^[ \t]*#/ {
# Ignore
}
!active && /^[ \t]*$/ {
# Ignore
}
!active && /country/ {
parse_country_head()
}
active && /^[ \t]*\(/ {
parse_reg_rule()
}
active && /^[ \t]*$/ {
print_tail_country()
}
END {
if (active)
print_tail_country()
print regdb "};"
print ""
print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"

View File

@ -274,7 +274,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
for (i = 0; i < sband->n_channels; i++) {
chan = &sband->channels[i];
if (chan->flags & IEEE80211_CHAN_NO_IBSS)
if (chan->flags & IEEE80211_CHAN_NO_IR)
continue;
if (chan->flags & IEEE80211_CHAN_DISABLED)
continue;
@ -345,7 +345,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
chan = ieee80211_get_channel(wdev->wiphy, freq);
if (!chan)
return -EINVAL;
if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
if (chan->flags & IEEE80211_CHAN_NO_IR ||
chan->flags & IEEE80211_CHAN_DISABLED)
return -EINVAL;
}

View File

@ -141,8 +141,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
for (i = 0; i < sband->n_channels; i++) {
chan = &sband->channels[i];
if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN |
if (chan->flags & (IEEE80211_CHAN_NO_IR |
IEEE80211_CHAN_DISABLED |
IEEE80211_CHAN_RADAR))
continue;

View File

@ -520,9 +520,7 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params, u64 *cookie)
{
const struct ieee80211_mgmt *mgmt;
u16 stype;
@ -533,10 +531,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
if (!rdev->ops->mgmt_tx)
return -EOPNOTSUPP;
if (len < 24 + 1)
if (params->len < 24 + 1)
return -EINVAL;
mgmt = (const struct ieee80211_mgmt *) buf;
mgmt = (const struct ieee80211_mgmt *)params->buf;
if (!ieee80211_is_mgmt(mgmt->frame_control))
return -EINVAL;
@ -615,9 +613,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return -EINVAL;
/* Transmit the Action frame as requested by user space */
return rdev_mgmt_tx(rdev, wdev, chan, offchan,
wait, buf, len, no_cck, dont_wait_for_ack,
cookie);
return rdev_mgmt_tx(rdev, wdev, params, cookie);
}
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
@ -763,12 +759,12 @@ void cfg80211_radar_event(struct wiphy *wiphy,
EXPORT_SYMBOL(cfg80211_radar_event);
void cfg80211_cac_event(struct net_device *netdev,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event, gfp_t gfp)
{
struct wireless_dev *wdev = netdev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_chan_def chandef;
unsigned long timeout;
trace_cfg80211_cac_event(netdev, event);
@ -779,14 +775,12 @@ void cfg80211_cac_event(struct net_device *netdev,
if (WARN_ON(!wdev->channel))
return;
cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT);
switch (event) {
case NL80211_RADAR_CAC_FINISHED:
timeout = wdev->cac_start_time +
msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
WARN_ON(!time_after_eq(jiffies, timeout));
cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE);
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
break;
case NL80211_RADAR_CAC_ABORTED:
break;
@ -796,6 +790,6 @@ void cfg80211_cac_event(struct net_device *netdev,
}
wdev->cac_started = false;
nl80211_radar_notify(rdev, &chandef, event, netdev, gfp);
nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
}
EXPORT_SYMBOL(cfg80211_cac_event);

View File

@ -564,12 +564,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
goto nla_put_failure;
if (chan->flags & IEEE80211_CHAN_NO_IR) {
if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
goto nla_put_failure;
if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
goto nla_put_failure;
}
if (chan->flags & IEEE80211_CHAN_RADAR) {
if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
goto nla_put_failure;
@ -1247,10 +1247,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
goto nla_put_failure;
if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
goto nla_put_failure;
state->split_start++;
if (state->split)
break;
@ -1579,6 +1575,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
if (nl80211_send_coalesce(msg, dev))
goto nla_put_failure;
if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
(nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
goto nla_put_failure;
/* done */
state->split_start = 0;
break;
@ -2187,7 +2188,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
}
static int nl80211_send_chandef(struct sk_buff *msg,
struct cfg80211_chan_def *chandef)
const struct cfg80211_chan_def *chandef)
{
WARN_ON(!cfg80211_chandef_valid(chandef));
@ -3236,6 +3237,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
return PTR_ERR(params.acl);
}
wdev_lock(wdev);
err = rdev_start_ap(rdev, dev, &params);
if (!err) {
wdev->preset_chandef = params.chandef;
@ -3244,6 +3246,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
wdev->ssid_len = params.ssid_len;
memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
}
wdev_unlock(wdev);
kfree(params.acl);
@ -3272,7 +3275,11 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
return rdev_change_beacon(rdev, dev, &params);
wdev_lock(wdev);
err = rdev_change_beacon(rdev, dev, &params);
wdev_unlock(wdev);
return err;
}
static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
@ -4478,7 +4485,9 @@ static int nl80211_set_bss(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;
struct bss_parameters params;
int err;
memset(&params, 0, sizeof(params));
/* default to not changing parameters */
@ -4544,7 +4553,11 @@ 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_change_bss(rdev, dev, &params);
wdev_lock(wdev);
err = rdev_change_bss(rdev, dev, &params);
wdev_unlock(wdev);
return err;
}
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@ -5098,7 +5111,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
char *alpha2 = NULL;
int rem_reg_rules = 0, r = 0;
u32 num_rules = 0, rule_idx = 0, size_of_regd;
u8 dfs_region = 0;
enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
struct ieee80211_regdomain *rd = NULL;
if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
@ -5119,6 +5132,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
if (!reg_is_valid_request(alpha2))
return -EINVAL;
size_of_regd = sizeof(struct ieee80211_regdomain) +
num_rules * sizeof(struct ieee80211_reg_rule);
@ -5361,10 +5377,8 @@ 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))) {
if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
err = -EOPNOTSUPP;
goto out_free;
}
@ -5604,10 +5618,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
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))) {
if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
err = -EOPNOTSUPP;
goto out_free;
}
@ -5670,7 +5682,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
if (err == 0)
return -EINVAL;
if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
return -EINVAL;
if (!rdev->ops->start_radar_detection)
@ -5810,7 +5822,11 @@ skip_beacons:
if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
params.block_tx = true;
return rdev_channel_switch(rdev, dev, &params);
wdev_lock(wdev);
err = rdev_channel_switch(rdev, dev, &params);
wdev_unlock(wdev);
return err;
}
static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
@ -7443,10 +7459,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
void *hdr = NULL;
u64 cookie;
struct sk_buff *msg = NULL;
unsigned int wait = 0;
bool offchan, no_cck, dont_wait_for_ack;
dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
struct cfg80211_mgmt_tx_params params = {
.dont_wait_for_ack =
info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
};
if (!info->attrs[NL80211_ATTR_FRAME])
return -EINVAL;
@ -7473,24 +7489,24 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_DURATION]) {
if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
return -EINVAL;
wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
/*
* We should wait on the channel for at least a minimum amount
* of time (10ms) but no longer than the driver supports.
*/
if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
wait > rdev->wiphy.max_remain_on_channel_duration)
if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
params.wait > rdev->wiphy.max_remain_on_channel_duration)
return -EINVAL;
}
offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
return -EINVAL;
no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
/* get the channel if any has been specified, otherwise pass NULL to
* the driver. The latter will use the current one
@ -7502,10 +7518,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
return err;
}
if (!chandef.chan && offchan)
if (!chandef.chan && params.offchan)
return -EINVAL;
if (!dont_wait_for_ack) {
if (!params.dont_wait_for_ack) {
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
@ -7518,10 +7534,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
}
}
err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
no_cck, dont_wait_for_ack, &cookie);
params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
params.chan = chandef.chan;
err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
if (err)
goto free_msg;
@ -10805,21 +10821,18 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
trace_cfg80211_ch_switch_notify(dev, chandef);
ASSERT_WDEV_LOCK(wdev);
wdev_lock(wdev);
trace_cfg80211_ch_switch_notify(dev, chandef);
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO &&
wdev->iftype != NL80211_IFTYPE_ADHOC &&
wdev->iftype != NL80211_IFTYPE_MESH_POINT))
goto out;
return;
wdev->channel = chandef->chan;
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
out:
wdev_unlock(wdev);
return;
}
EXPORT_SYMBOL(cfg80211_ch_switch_notify);
@ -10878,7 +10891,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event,
struct net_device *netdev, gfp_t gfp)
{

View File

@ -70,7 +70,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event,
struct net_device *netdev, gfp_t gfp);

View File

@ -624,16 +624,12 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev,
static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, const u8 *buf, size_t len,
bool no_cck, bool dont_wait_for_ack, u64 *cookie)
struct cfg80211_mgmt_tx_params *params,
u64 *cookie)
{
int ret;
trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
wait, no_cck, dont_wait_for_ack);
ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
wait, buf, len, no_cck,
dont_wait_for_ack, cookie);
trace_rdev_mgmt_tx(&rdev->wiphy, wdev, params);
ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, params, cookie);
trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,9 @@
extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
bool reg_is_valid_request(const char *alpha2);
bool is_world_regdom(const char *alpha2);
bool reg_supported_dfs_region(u8 dfs_region);
bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);

View File

@ -1653,9 +1653,8 @@ TRACE_EVENT(rdev_cancel_remain_on_channel,
TRACE_EVENT(rdev_mgmt_tx,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
unsigned int wait, bool no_cck, bool dont_wait_for_ack),
TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack),
struct cfg80211_mgmt_tx_params *params),
TP_ARGS(wiphy, wdev, params),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
@ -1668,11 +1667,11 @@ TRACE_EVENT(rdev_mgmt_tx,
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
CHAN_ASSIGN(chan);
__entry->offchan = offchan;
__entry->wait = wait;
__entry->no_cck = no_cck;
__entry->dont_wait_for_ack = dont_wait_for_ack;
CHAN_ASSIGN(params->chan);
__entry->offchan = params->offchan;
__entry->wait = params->wait;
__entry->no_cck = params->no_cck;
__entry->dont_wait_for_ack = params->dont_wait_for_ack;
),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s,"
" wait: %u, no cck: %s, dont wait for ack: %s",