Skip to content
Snippets Groups Projects
Commit 384d079f authored by Felix Fietkau's avatar Felix Fietkau
Browse files

mac80211: update to version 6.11


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent d23e0a00
No related branches found
No related tags found
No related merge requests found
Showing
with 281 additions and 1841 deletions
......@@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -101,6 +101,8 @@ ieee80211_sta_keep_active(struct sta_inf
@@ -103,6 +103,8 @@ ieee80211_sta_keep_active(struct sta_inf
return time_before_eq(jiffies, sta->airtime[ac].last_active + HZ / 10);
}
......@@ -23,7 +23,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4082,7 +4082,7 @@ struct ieee80211_txq *ieee80211_next_txq
@@ -4081,7 +4081,7 @@ struct ieee80211_txq *ieee80211_next_txq
if (deficit < 0)
sta->airtime[txqi->txq.ac].deficit +=
......@@ -32,7 +32,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (deficit < 0 || !aql_check) {
list_move_tail(&txqi->schedule_order,
@@ -4225,7 +4225,8 @@ bool ieee80211_txq_may_transmit(struct i
@@ -4224,7 +4224,8 @@ bool ieee80211_txq_may_transmit(struct i
}
sta = container_of(iter->txq.sta, struct sta_info, sta);
if (ieee80211_sta_deficit(sta, ac) < 0)
......@@ -42,7 +42,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
}
@@ -4233,7 +4234,7 @@ bool ieee80211_txq_may_transmit(struct i
@@ -4232,7 +4233,7 @@ bool ieee80211_txq_may_transmit(struct i
if (sta->airtime[ac].deficit >= 0)
goto out;
......
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 3 Jul 2024 12:10:01 +0200
Subject: [PATCH] wifi: mac80211: clear vif drv_priv after calling
remove_interface
Avoid reusing stale driver data when an interface is brought down and up
again. In order to avoid having to duplicate the memset in every single
driver, do it here.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -693,8 +693,12 @@ static void ieee80211_do_stop(struct iee
fallthrough;
default:
- if (going_down)
- drv_remove_interface(local, sdata);
+ if (!going_down)
+ break;
+ drv_remove_interface(local, sdata);
+
+ /* Clear private driver data to prevent reuse */
+ memset(sdata->vif.drv_priv, 0, local->hw.vif_data_size);
}
ieee80211_recalc_ps(local);
......@@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -189,6 +189,8 @@ enum ieee80211_channel_flags {
@@ -187,6 +187,8 @@ enum ieee80211_channel_flags {
* @dfs_state: current state of this channel. Only relevant if radar is required
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
......@@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
* @psd: power spectral density (in dBm)
*/
@@ -206,6 +208,7 @@ struct ieee80211_channel {
@@ -204,6 +206,7 @@ struct ieee80211_channel {
int orig_mag, orig_mpwr;
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
......@@ -52,7 +52,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -560,6 +560,8 @@ static void cfg80211_set_chans_dfs_state
@@ -598,6 +598,8 @@ static void cfg80211_set_chans_dfs_state
c->dfs_state = dfs_state;
c->dfs_state_entered = jiffies;
......@@ -61,7 +61,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
}
@@ -1049,6 +1051,49 @@ static bool cfg80211_get_chans_dfs_avail
@@ -1087,6 +1089,49 @@ static bool cfg80211_get_chans_dfs_avail
return true;
}
......
......@@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3416,6 +3416,7 @@ enum wiphy_params_flags {
@@ -3423,6 +3423,7 @@ enum wiphy_params_flags {
/* The per TXQ device queue limit in airtime */
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
......@@ -70,7 +70,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1338,10 +1338,12 @@ struct ieee80211_local {
@@ -1351,10 +1351,12 @@ struct ieee80211_local {
spinlock_t handle_wake_tx_queue_lock;
u16 airtime_flags;
......@@ -85,7 +85,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
const struct ieee80211_ops *ops;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -944,6 +944,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
@@ -952,6 +952,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
spin_lock_init(&local->rx_path_lock);
spin_lock_init(&local->queue_stop_reason_lock);
......@@ -136,7 +136,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
spin_unlock_irqrestore(&local->ack_status_lock, flags);
if (id >= 0) {
@@ -3983,20 +3983,20 @@ begin:
@@ -3982,20 +3982,20 @@ begin:
encap_out:
info->control.vif = vif;
......@@ -167,7 +167,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
return skb;
@@ -4048,6 +4048,7 @@ struct ieee80211_txq *ieee80211_next_txq
@@ -4047,6 +4047,7 @@ struct ieee80211_txq *ieee80211_next_txq
struct ieee80211_txq *ret = NULL;
struct txq_info *txqi = NULL, *head = NULL;
bool found_eligible_txq = false;
......@@ -175,7 +175,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
spin_lock_bh(&local->active_txq_lock[ac]);
@@ -4071,26 +4072,26 @@ struct ieee80211_txq *ieee80211_next_txq
@@ -4070,26 +4071,26 @@ struct ieee80211_txq *ieee80211_next_txq
if (!head)
head = txqi;
......@@ -214,7 +214,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (txqi->schedule_round == local->schedule_round[ac])
goto out;
@@ -4155,7 +4156,8 @@ bool ieee80211_txq_airtime_check(struct
@@ -4154,7 +4155,8 @@ bool ieee80211_txq_airtime_check(struct
return true;
if (!txq->sta)
......@@ -224,7 +224,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
return true;
@@ -4204,15 +4206,15 @@ bool ieee80211_txq_may_transmit(struct i
@@ -4203,15 +4205,15 @@ bool ieee80211_txq_may_transmit(struct i
spin_lock_bh(&local->active_txq_lock[ac]);
......@@ -245,7 +245,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (iter == txqi)
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1180,8 +1180,8 @@ struct ieee80211_tx_info {
@@ -1221,8 +1221,8 @@ struct ieee80211_tx_info {
status_data_idr:1,
status_data:13,
hw_queue:4,
......@@ -269,7 +269,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -717,7 +717,7 @@ static void ieee80211_report_used_skb(st
@@ -734,7 +734,7 @@ static void ieee80211_report_used_skb(st
ieee80211_sta_update_pending_airtime(local, sta,
skb_get_queue_mapping(skb),
tx_time_est,
......@@ -278,7 +278,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
rcu_read_unlock();
}
@@ -1138,10 +1138,11 @@ void ieee80211_tx_status_ext(struct ieee
@@ -1158,10 +1158,11 @@ void ieee80211_tx_status_ext(struct ieee
/* Do this here to avoid the expensive lookup of the sta
* in ieee80211_report_used_skb().
*/
......
From: Michael-CY Lee <michael-cy.lee@mediatek.com>
Date: Tue, 26 Mar 2024 08:30:36 +0800
Subject: [PATCH] wifi: mac80211: extend IEEE80211_KEY_FLAG_GENERATE_MMIE to
other ciphers
Extend the flag IEEE80211_KEY_FLAG_GENERATE_MMIE to BIP-CMAC-256,
BIP-GMAC-128 and BIP-GMAC-256 for the same reason and in the same
way that the flag was added originally in commit a0b4496a4368
("mac80211: add IEEE80211_KEY_FLAG_GENERATE_MMIE to ieee80211_key_flags").
Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
Link: https://msgid.link/20240326003036.15215-1-michael-cy.lee@mediatek.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2123,8 +2123,8 @@ static inline bool lockdep_vif_wiphy_mut
* @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key.
* @IEEE80211_KEY_FLAG_NO_AUTO_TX: Key needs explicit Tx activation.
* @IEEE80211_KEY_FLAG_GENERATE_MMIE: This flag should be set by the driver
- * for a AES_CMAC key to indicate that it requires sequence number
- * generation only
+ * for a AES_CMAC or a AES_GMAC key to indicate that it requires sequence
+ * number generation only
* @IEEE80211_KEY_FLAG_SPP_AMSDU: SPP A-MSDUs can be used with this key
* (set by mac80211 from the sta->spp_amsdu flag)
*/
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -895,7 +895,8 @@ ieee80211_crypto_aes_cmac_256_encrypt(st
info = IEEE80211_SKB_CB(skb);
- if (info->control.hw_key)
+ if (info->control.hw_key &&
+ !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE))
return TX_CONTINUE;
if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
@@ -911,6 +912,9 @@ ieee80211_crypto_aes_cmac_256_encrypt(st
bip_ipn_set64(mmie->sequence_number, pn64);
+ if (info->control.hw_key)
+ return TX_CONTINUE;
+
bip_aad(skb, aad);
/* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128)
@@ -1040,7 +1044,8 @@ ieee80211_crypto_aes_gmac_encrypt(struct
info = IEEE80211_SKB_CB(skb);
- if (info->control.hw_key)
+ if (info->control.hw_key &&
+ !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE))
return TX_CONTINUE;
if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
@@ -1056,6 +1061,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct
bip_ipn_set64(mmie->sequence_number, pn64);
+ if (info->control.hw_key)
+ return TX_CONTINUE;
+
bip_aad(skb, aad);
hdr = (struct ieee80211_hdr *)skb->data;
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 4 Jun 2024 14:31:09 +0200
Subject: [PATCH] wifi: nl80211: split helper function from
nl80211_put_iface_combinations
Create a helper function that puts the data from struct
ieee80211_iface_combination to a nl80211 message.
This will be used for adding per-radio interface combination data.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1620,71 +1620,78 @@ nla_put_failure:
return -ENOBUFS;
}
-static int nl80211_put_iface_combinations(struct wiphy *wiphy,
- struct sk_buff *msg,
- bool large)
+static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx,
+ const struct ieee80211_iface_combination *c)
{
- struct nlattr *nl_combis;
- int i, j;
+ struct nlattr *nl_combi, *nl_limits;
+ int i;
- nl_combis = nla_nest_start_noflag(msg,
- NL80211_ATTR_INTERFACE_COMBINATIONS);
- if (!nl_combis)
+ nl_combi = nla_nest_start_noflag(msg, idx);
+ if (!nl_combi)
goto nla_put_failure;
- for (i = 0; i < wiphy->n_iface_combinations; i++) {
- const struct ieee80211_iface_combination *c;
- struct nlattr *nl_combi, *nl_limits;
+ nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS);
+ if (!nl_limits)
+ goto nla_put_failure;
- c = &wiphy->iface_combinations[i];
+ for (i = 0; i < c->n_limits; i++) {
+ struct nlattr *nl_limit;
- nl_combi = nla_nest_start_noflag(msg, i + 1);
- if (!nl_combi)
+ nl_limit = nla_nest_start_noflag(msg, i + 1);
+ if (!nl_limit)
goto nla_put_failure;
-
- nl_limits = nla_nest_start_noflag(msg,
- NL80211_IFACE_COMB_LIMITS);
- if (!nl_limits)
+ if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX, c->limits[i].max))
goto nla_put_failure;
+ if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
+ c->limits[i].types))
+ goto nla_put_failure;
+ nla_nest_end(msg, nl_limit);
+ }
- for (j = 0; j < c->n_limits; j++) {
- struct nlattr *nl_limit;
+ nla_nest_end(msg, nl_limits);
- nl_limit = nla_nest_start_noflag(msg, j + 1);
- if (!nl_limit)
- goto nla_put_failure;
- if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
- c->limits[j].max))
- goto nla_put_failure;
- if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
- c->limits[j].types))
- goto nla_put_failure;
- nla_nest_end(msg, nl_limit);
- }
+ if (c->beacon_int_infra_match &&
+ nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
+ goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
+ c->num_different_channels) ||
+ nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
+ c->max_interfaces))
+ goto nla_put_failure;
+ if (large &&
+ (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
+ c->radar_detect_widths) ||
+ nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
+ c->radar_detect_regions)))
+ goto nla_put_failure;
+ if (c->beacon_int_min_gcd &&
+ nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
+ c->beacon_int_min_gcd))
+ goto nla_put_failure;
- nla_nest_end(msg, nl_limits);
+ nla_nest_end(msg, nl_combi);
- if (c->beacon_int_infra_match &&
- nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
- goto nla_put_failure;
- if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
- c->num_different_channels) ||
- nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
- c->max_interfaces))
- goto nla_put_failure;
- if (large &&
- (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
- c->radar_detect_widths) ||
- nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
- c->radar_detect_regions)))
- goto nla_put_failure;
- if (c->beacon_int_min_gcd &&
- nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
- c->beacon_int_min_gcd))
- goto nla_put_failure;
+ return 0;
+nla_put_failure:
+ return -ENOBUFS;
+}
- nla_nest_end(msg, nl_combi);
- }
+static int nl80211_put_iface_combinations(struct wiphy *wiphy,
+ struct sk_buff *msg,
+ bool large)
+{
+ struct nlattr *nl_combis;
+ int i;
+
+ nl_combis = nla_nest_start_noflag(msg,
+ NL80211_ATTR_INTERFACE_COMBINATIONS);
+ if (!nl_combis)
+ goto nla_put_failure;
+
+ for (i = 0; i < wiphy->n_iface_combinations; i++)
+ if (nl80211_put_ifcomb_data(msg, large, i + 1,
+ &wiphy->iface_combinations[i]))
+ goto nla_put_failure;
nla_nest_end(msg, nl_combis);
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 22 May 2024 11:42:57 +0200
Subject: [PATCH] wifi: cfg80211: add support for advertising multiple
radios belonging to a wiphy
The prerequisite for MLO support in cfg80211/mac80211 is that all the links
participating in MLO must be from the same wiphy/ieee80211_hw. To meet this
expectation, some drivers may need to group multiple discrete hardware each
acting as a link in MLO under single wiphy.
With this change, supported frequencies and interface combinations of each
individual radio are reported to user space. This allows user space to figure
out the limitations of what combination of channels can be used concurrently.
Even for non-MLO devices, this improves support for devices capable of
running on multiple channels at the same time.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5045,7 +5045,9 @@ struct ieee80211_iface_limit {
* struct ieee80211_iface_combination - possible interface combination
*
* With this structure the driver can describe which interface
- * combinations it supports concurrently.
+ * combinations it supports concurrently. When set in a struct wiphy_radio,
+ * the combinations refer to combinations of interfaces currently active on
+ * that radio.
*
* Examples:
*
@@ -5403,6 +5405,38 @@ struct wiphy_iftype_akm_suites {
int n_akm_suites;
};
+/**
+ * struct wiphy_radio_freq_range - wiphy frequency range
+ * @start_freq: start range edge frequency (kHz)
+ * @end_freq: end range edge frequency (kHz)
+ */
+struct wiphy_radio_freq_range {
+ u32 start_freq;
+ u32 end_freq;
+};
+
+
+/**
+ * struct wiphy_radio - physical radio of a wiphy
+ * This structure describes a physical radio belonging to a wiphy.
+ * It is used to describe concurrent-channel capabilities. Only one channel
+ * can be active on the radio described by struct wiphy_radio.
+ *
+ * @freq_range: frequency range that the radio can operate on.
+ * @n_freq_range: number of elements in @freq_range
+ *
+ * @iface_combinations: Valid interface combinations array, should not
+ * list single interface types.
+ * @n_iface_combinations: number of entries in @iface_combinations array.
+ */
+struct wiphy_radio {
+ const struct wiphy_radio_freq_range *freq_range;
+ int n_freq_range;
+
+ const struct ieee80211_iface_combination *iface_combinations;
+ int n_iface_combinations;
+};
+
#define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff
/**
@@ -5621,6 +5655,9 @@ struct wiphy_iftype_akm_suites {
* A value of %CFG80211_HW_TIMESTAMP_ALL_PEERS indicates the driver
* supports enabling HW timestamping for all peers (i.e. no need to
* specify a mac address).
+ *
+ * @radio: radios belonging to this wiphy
+ * @n_radio: number of radios
*/
struct wiphy {
struct mutex mtx;
@@ -5771,6 +5808,9 @@ struct wiphy {
u16 hw_timestamp_max_peers;
+ int n_radio;
+ const struct wiphy_radio *radio;
+
char priv[] __aligned(NETDEV_ALIGN);
};
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2061,6 +2061,10 @@ enum nl80211_commands {
* @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
* interface combinations. In each nested item, it contains attributes
* defined in &enum nl80211_if_combination_attrs.
+ * If the wiphy uses multiple radios (@NL80211_ATTR_WIPHY_RADIOS is set),
+ * this attribute contains the interface combinations of the first radio.
+ * See @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS for the global wiphy
+ * combinations for the sum of all radios.
* @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
* %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
* are managed in software: interfaces of these types aren't subject to
@@ -2856,6 +2860,14 @@ enum nl80211_commands {
* %NL80211_CMD_ASSOCIATE indicating the SPP A-MSDUs
* are used on this connection
*
+ * @NL80211_ATTR_WIPHY_RADIOS: Nested attribute describing physical radios
+ * belonging to this wiphy. See &enum nl80211_wiphy_radio_attrs.
+ *
+ * @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS: Nested attribute listing the
+ * supported interface combinations for all radios combined. In each
+ * nested item, it contains attributes defined in
+ * &enum nl80211_if_combination_attrs.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3401,6 +3413,9 @@ enum nl80211_attrs {
NL80211_ATTR_ASSOC_SPP_AMSDU,
+ NL80211_ATTR_WIPHY_RADIOS,
+ NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -7987,4 +8002,54 @@ enum nl80211_ap_settings_flags {
NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1,
};
+/**
+ * enum nl80211_wiphy_radio_attrs - wiphy radio attributes
+ *
+ * @__NL80211_WIPHY_RADIO_ATTR_INVALID: Invalid
+ *
+ * @NL80211_WIPHY_RADIO_ATTR_INDEX: Index of this radio (u32)
+ * @NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE: Frequency range supported by this
+ * radio. Attribute may be present multiple times.
+ * @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface
+ * combination for this radio. Attribute may be present multiple times
+ * and contains attributes defined in &enum nl80211_if_combination_attrs.
+ *
+ * @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal
+ * @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute
+ */
+enum nl80211_wiphy_radio_attrs {
+ __NL80211_WIPHY_RADIO_ATTR_INVALID,
+
+ NL80211_WIPHY_RADIO_ATTR_INDEX,
+ NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE,
+ NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
+
+ /* keep last */
+ __NL80211_WIPHY_RADIO_ATTR_LAST,
+ NL80211_WIPHY_RADIO_ATTR_MAX = __NL80211_WIPHY_RADIO_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_wiphy_radio_freq_range - wiphy radio frequency range
+ *
+ * @__NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID: Invalid
+ *
+ * @NL80211_WIPHY_RADIO_FREQ_ATTR_START: Frequency range start (u32).
+ * The unit is kHz.
+ * @NL80211_WIPHY_RADIO_FREQ_ATTR_END: Frequency range end (u32).
+ * The unit is kHz.
+ *
+ * @__NL80211_WIPHY_RADIO_FREQ_ATTR_LAST: Internal
+ * @NL80211_WIPHY_RADIO_FREQ_ATTR_MAX: Highest attribute
+ */
+enum nl80211_wiphy_radio_freq_range {
+ __NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID,
+
+ NL80211_WIPHY_RADIO_FREQ_ATTR_START,
+ NL80211_WIPHY_RADIO_FREQ_ATTR_END,
+
+ __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST,
+ NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST - 1,
+};
+
#endif /* __LINUX_NL80211_H */
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1621,16 +1621,18 @@ nla_put_failure:
}
static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx,
- const struct ieee80211_iface_combination *c)
+ const struct ieee80211_iface_combination *c,
+ u16 nested)
{
struct nlattr *nl_combi, *nl_limits;
int i;
- nl_combi = nla_nest_start_noflag(msg, idx);
+ nl_combi = nla_nest_start_noflag(msg, idx | nested);
if (!nl_combi)
goto nla_put_failure;
- nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS);
+ nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS |
+ nested);
if (!nl_limits)
goto nla_put_failure;
@@ -1678,19 +1680,26 @@ nla_put_failure:
static int nl80211_put_iface_combinations(struct wiphy *wiphy,
struct sk_buff *msg,
- bool large)
+ int attr, int radio,
+ bool large, u16 nested)
{
+ const struct ieee80211_iface_combination *c;
struct nlattr *nl_combis;
- int i;
+ int i, n;
- nl_combis = nla_nest_start_noflag(msg,
- NL80211_ATTR_INTERFACE_COMBINATIONS);
+ nl_combis = nla_nest_start_noflag(msg, attr | nested);
if (!nl_combis)
goto nla_put_failure;
- for (i = 0; i < wiphy->n_iface_combinations; i++)
- if (nl80211_put_ifcomb_data(msg, large, i + 1,
- &wiphy->iface_combinations[i]))
+ if (radio >= 0) {
+ c = wiphy->radio[0].iface_combinations;
+ n = wiphy->radio[0].n_iface_combinations;
+ } else {
+ c = wiphy->iface_combinations;
+ n = wiphy->n_iface_combinations;
+ }
+ for (i = 0; i < n; i++)
+ if (nl80211_put_ifcomb_data(msg, large, i + 1, &c[i], nested))
goto nla_put_failure;
nla_nest_end(msg, nl_combis);
@@ -2397,6 +2406,80 @@ fail:
return -ENOBUFS;
}
+static int nl80211_put_radio(struct wiphy *wiphy, struct sk_buff *msg, int idx)
+{
+ const struct wiphy_radio *r = &wiphy->radio[idx];
+ struct nlattr *radio, *freq;
+ int i;
+
+ radio = nla_nest_start(msg, idx);
+ if (!radio)
+ return -ENOBUFS;
+
+ if (nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_INDEX, idx))
+ goto nla_put_failure;
+
+ for (i = 0; i < r->n_freq_range; i++) {
+ const struct wiphy_radio_freq_range *range = &r->freq_range[i];
+
+ freq = nla_nest_start(msg, NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE);
+ if (!freq)
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, NL80211_WIPHY_RADIO_FREQ_ATTR_START,
+ range->start_freq) ||
+ nla_put_u32(msg, NL80211_WIPHY_RADIO_FREQ_ATTR_END,
+ range->end_freq))
+ goto nla_put_failure;
+
+ nla_nest_end(msg, freq);
+ }
+
+ for (i = 0; i < r->n_iface_combinations; i++)
+ if (nl80211_put_ifcomb_data(msg, true,
+ NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
+ &r->iface_combinations[i],
+ NLA_F_NESTED))
+ goto nla_put_failure;
+
+ nla_nest_end(msg, radio);
+
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+static int nl80211_put_radios(struct wiphy *wiphy, struct sk_buff *msg)
+{
+ struct nlattr *radios;
+ int i;
+
+ if (!wiphy->n_radio)
+ return 0;
+
+ radios = nla_nest_start(msg, NL80211_ATTR_WIPHY_RADIOS);
+ if (!radios)
+ return -ENOBUFS;
+
+ for (i = 0; i < wiphy->n_radio; i++)
+ if (nl80211_put_radio(wiphy, msg, i))
+ goto fail;
+
+ nla_nest_end(msg, radios);
+
+ if (nl80211_put_iface_combinations(wiphy, msg,
+ NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
+ -1, true, NLA_F_NESTED))
+ return -ENOBUFS;
+
+ return 0;
+
+fail:
+ nla_nest_cancel(msg, radios);
+ return -ENOBUFS;
+}
+
struct nl80211_dump_wiphy_state {
s64 filter_wiphy;
long start;
@@ -2692,7 +2775,9 @@ static int nl80211_send_wiphy(struct cfg
goto nla_put_failure;
if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
- state->split))
+ NL80211_ATTR_INTERFACE_COMBINATIONS,
+ rdev->wiphy.n_radio ? 0 : -1,
+ state->split, 0))
goto nla_put_failure;
state->split_start++;
@@ -3006,6 +3091,12 @@ static int nl80211_send_wiphy(struct cfg
rdev->wiphy.hw_timestamp_max_peers))
goto nla_put_failure;
+ state->split_start++;
+ break;
+ case 17:
+ if (nl80211_put_radios(&rdev->wiphy, msg))
+ goto nla_put_failure;
+
/* done */
state->split_start = 0;
break;
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 4 Jun 2024 21:01:50 +0200
Subject: [PATCH] wifi: cfg80211: extend interface combination check for
multi-radio
Add a field in struct iface_combination_params to check per-radio
interface combinations instead of per-wiphy ones.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1598,6 +1598,7 @@ struct cfg80211_color_change_settings {
*
* Used to pass interface combination parameters
*
+ * @radio_idx: wiphy radio index or -1 for global
* @num_different_channels: the number of different channels we want
* to use for verification
* @radar_detect: a bitmap where each bit corresponds to a channel
@@ -1611,6 +1612,7 @@ struct cfg80211_color_change_settings {
* the verification
*/
struct iface_combination_params {
+ int radio_idx;
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
@@ -4579,6 +4581,8 @@ struct mgmt_frame_regs {
*
* @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
* @set_ttlm: set the TID to link mapping.
+ * @get_radio_mask: get bitmask of radios in use.
+ * (invoked with the wiphy mutex held)
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4940,6 +4944,7 @@ struct cfg80211_ops {
struct cfg80211_set_hw_timestamp *hwts);
int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ttlm_params *params);
+ u32 (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev);
};
/*
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3930,6 +3930,7 @@ int ieee80211_check_combinations(struct
int total = 1;
struct iface_combination_params params = {
.radar_detect = radar_detect,
+ .radio_idx = -1,
};
lockdep_assert_wiphy(local->hw.wiphy);
@@ -4020,7 +4021,9 @@ int ieee80211_max_num_channels(struct ie
struct ieee80211_chanctx *ctx;
u32 max_num_different_channels = 1;
int err;
- struct iface_combination_params params = {0};
+ struct iface_combination_params params = {
+ .radio_idx = -1,
+ };
lockdep_assert_wiphy(local->hw.wiphy);
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1542,4 +1542,16 @@ rdev_set_ttlm(struct cfg80211_registered
return ret;
}
+
+static inline u32
+rdev_get_radio_mask(struct cfg80211_registered_device *rdev,
+ struct net_device *dev)
+{
+ struct wiphy *wiphy = &rdev->wiphy;
+
+ if (!rdev->ops->get_radio_mask)
+ return 0;
+
+ return rdev->ops->get_radio_mask(wiphy, dev);
+}
#endif /* __CFG80211_RDEV_OPS */
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2305,13 +2305,16 @@ static int cfg80211_wdev_bi(struct wirel
static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
u32 *beacon_int_gcd,
- bool *beacon_int_different)
+ bool *beacon_int_different,
+ int radio_idx)
{
+ struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
*beacon_int_gcd = 0;
*beacon_int_different = false;
+ rdev = wiphy_to_rdev(wiphy);
list_for_each_entry(wdev, &wiphy->wdev_list, list) {
int wdev_bi;
@@ -2319,6 +2322,11 @@ static void cfg80211_calculate_bi_data(s
if (wdev->valid_links)
continue;
+ /* skip wdevs not active on the given wiphy radio */
+ if (radio_idx >= 0 &&
+ !(rdev_get_radio_mask(rdev, wdev->netdev) & BIT(radio_idx)))
+ continue;
+
wdev_bi = cfg80211_wdev_bi(wdev);
if (!wdev_bi)
@@ -2366,14 +2374,19 @@ int cfg80211_iter_combinations(struct wi
void *data),
void *data)
{
+ const struct wiphy_radio *radio = NULL;
+ const struct ieee80211_iface_combination *c, *cs;
const struct ieee80211_regdomain *regdom;
enum nl80211_dfs_regions region = 0;
- int i, j, iftype;
+ int i, j, n, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;
u32 beacon_int_gcd;
bool beacon_int_different;
+ if (params->radio_idx >= 0)
+ radio = &wiphy->radio[params->radio_idx];
+
/*
* This is a bit strange, since the iteration used to rely only on
* the data given by the driver, but here it now relies on context,
@@ -2385,7 +2398,8 @@ int cfg80211_iter_combinations(struct wi
* interfaces (while being brought up) and channel/radar data.
*/
cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
- &beacon_int_gcd, &beacon_int_different);
+ &beacon_int_gcd, &beacon_int_different,
+ params->radio_idx);
if (params->radar_detect) {
rcu_read_lock();
@@ -2402,13 +2416,18 @@ int cfg80211_iter_combinations(struct wi
used_iftypes |= BIT(iftype);
}
- for (i = 0; i < wiphy->n_iface_combinations; i++) {
- const struct ieee80211_iface_combination *c;
+ if (radio) {
+ cs = radio->iface_combinations;
+ n = radio->n_iface_combinations;
+ } else {
+ cs = wiphy->iface_combinations;
+ n = wiphy->n_iface_combinations;
+ }
+ for (i = 0; i < n; i++) {
struct ieee80211_iface_limit *limits;
u32 all_iftypes = 0;
- c = &wiphy->iface_combinations[i];
-
+ c = &cs[i];
if (num_interfaces > c->max_interfaces)
continue;
if (params->num_different_channels > c->num_different_channels)
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 7 Jun 2024 17:58:54 +0200
Subject: [PATCH] wifi: cfg80211: add helper for checking if a chandef is
valid on a radio
Check if the full channel width is in the radio's frequency range.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6485,6 +6485,15 @@ static inline bool cfg80211_channel_is_p
}
/**
+ * cfg80211_radio_chandef_valid - Check if the radio supports the chandef
+ *
+ * @radio: wiphy radio
+ * @chandef: chandef for current channel
+ */
+bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
+ const struct cfg80211_chan_def *chandef);
+
+/**
* ieee80211_get_response_rate - get basic rate for a given rate
*
* @sband: the band to look for rates in
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2884,3 +2884,38 @@ cfg80211_get_iftype_ext_capa(struct wiph
return NULL;
}
EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa);
+
+static bool
+ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
+ u32 freq, u32 width)
+{
+ const struct wiphy_radio_freq_range *r;
+ int i;
+
+ for (i = 0; i < radio->n_freq_range; i++) {
+ r = &radio->freq_range[i];
+ if (freq - width / 2 >= r->start_freq &&
+ freq + width / 2 <= r->end_freq)
+ return true;
+ }
+
+ return false;
+}
+
+bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
+ const struct cfg80211_chan_def *chandef)
+{
+ u32 freq, width;
+
+ freq = ieee80211_chandef_to_khz(chandef);
+ width = nl80211_chan_width_to_mhz(chandef->width);
+ if (!ieee80211_radio_freq_range_valid(radio, freq, width))
+ return false;
+
+ freq = MHZ_TO_KHZ(chandef->center_freq2);
+ if (freq && !ieee80211_radio_freq_range_valid(radio, freq, width))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL(cfg80211_radio_chandef_valid);
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 6 Jun 2024 12:19:08 +0200
Subject: [PATCH] wifi: mac80211: add support for DFS with multiple
radios
DFS can be supported with multi-channel combinations, as long as each DFS
capable radio only supports one channel.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1084,6 +1084,27 @@ static int ieee80211_init_cipher_suites(
return 0;
}
+static bool
+ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb)
+{
+ int i, j;
+
+ for (i = 0; i < n_comb; i++, c++) {
+ /* DFS is not supported with multi-channel combinations yet */
+ if (c->radar_detect_widths &&
+ c->num_different_channels > 1)
+ return false;
+
+ /* mac80211 doesn't support more than one IBSS interface */
+ for (j = 0; j < c->n_limits; j++)
+ if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
+ c->limits[j].max > 1)
+ return false;
+ }
+
+ return true;
+}
+
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -1173,17 +1194,20 @@ int ieee80211_register_hw(struct ieee802
if (comb->num_different_channels > 1)
return -EINVAL;
}
- } else {
- /* DFS is not supported with multi-channel combinations yet */
- for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
- const struct ieee80211_iface_combination *comb;
+ }
- comb = &local->hw.wiphy->iface_combinations[i];
+ if (hw->wiphy->n_radio) {
+ for (i = 0; i < hw->wiphy->n_radio; i++) {
+ const struct wiphy_radio *radio = &hw->wiphy->radio[i];
- if (comb->radar_detect_widths &&
- comb->num_different_channels > 1)
+ if (!ieee80211_ifcomb_check(radio->iface_combinations,
+ radio->n_iface_combinations))
return -EINVAL;
}
+ } else {
+ if (!ieee80211_ifcomb_check(hw->wiphy->iface_combinations,
+ hw->wiphy->n_iface_combinations))
+ return -EINVAL;
}
/* Only HW csum features are currently compatible with mac80211 */
@@ -1313,18 +1337,6 @@ int ieee80211_register_hw(struct ieee802
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
- /* mac80211 doesn't support more than one IBSS interface right now */
- for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
- const struct ieee80211_iface_combination *c;
- int j;
-
- c = &hw->wiphy->iface_combinations[i];
-
- for (j = 0; j < c->n_limits; j++)
- if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
- c->limits[j].max > 1)
- return -EINVAL;
- }
local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
sizeof(void *) * channels, GFP_KERNEL);
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 5 Jun 2024 10:41:34 +0200
Subject: [PATCH] wifi: mac80211: add radio index to
ieee80211_chanctx_conf
Will be used to explicitly assign a channel context to a wiphy radio.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -250,6 +250,7 @@ struct ieee80211_chan_req {
* @min_def: the minimum channel definition currently required.
* @ap: the channel definition the AP actually is operating as,
* for use with (wider bandwidth) OFDMA
+ * @radio_idx: index of the wiphy radio used used for this channel
* @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
@@ -264,6 +265,7 @@ struct ieee80211_chanctx_conf {
struct cfg80211_chan_def min_def;
struct cfg80211_chan_def ap;
+ int radio_idx;
u8 rx_chains_static, rx_chains_dynamic;
bool radar_enabled;
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -623,7 +623,8 @@ ieee80211_chanctx_radar_required(struct
static struct ieee80211_chanctx *
ieee80211_alloc_chanctx(struct ieee80211_local *local,
const struct ieee80211_chan_req *chanreq,
- enum ieee80211_chanctx_mode mode)
+ enum ieee80211_chanctx_mode mode,
+ int radio_idx)
{
struct ieee80211_chanctx *ctx;
@@ -641,6 +642,7 @@ ieee80211_alloc_chanctx(struct ieee80211
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
ctx->conf.radar_enabled = false;
+ ctx->conf.radio_idx = radio_idx;
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL);
return ctx;
@@ -680,7 +682,7 @@ ieee80211_new_chanctx(struct ieee80211_l
lockdep_assert_wiphy(local->hw.wiphy);
- ctx = ieee80211_alloc_chanctx(local, chanreq, mode);
+ ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
if (!ctx)
return ERR_PTR(-ENOMEM);
@@ -1098,7 +1100,7 @@ int ieee80211_link_reserve_chanctx(struc
!list_empty(&curr_ctx->reserved_links))
return -EBUSY;
- new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode);
+ new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
if (!new_ctx)
return -ENOMEM;
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 4 Jun 2024 21:48:48 +0200
Subject: [PATCH] wifi: mac80211: extend ifcomb check functions for
multi-radio
Add support for counting global and per-radio max/current number of
channels, as well as checking radio-specific interface combinations.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -263,7 +263,7 @@ static int ieee80211_start_p2p_device(st
lockdep_assert_wiphy(sdata->local->hw.wiphy);
- ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
+ ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
if (ret < 0)
return ret;
@@ -285,7 +285,7 @@ static int ieee80211_start_nan(struct wi
lockdep_assert_wiphy(sdata->local->hw.wiphy);
- ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
+ ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
if (ret < 0)
return ret;
@@ -3992,7 +3992,7 @@ __ieee80211_channel_switch(struct wiphy
goto out;
/* if reservation is invalid then this will fail */
- err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
+ err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0, -1);
if (err) {
ieee80211_link_unreserve_chanctx(link_data);
goto out;
@@ -5161,4 +5161,5 @@ const struct cfg80211_ops mac80211_confi
.del_link_station = ieee80211_del_link_station,
.set_hw_timestamp = ieee80211_set_hw_timestamp,
.set_ttlm = ieee80211_set_ttlm,
+ .get_radio_mask = ieee80211_get_radio_mask,
};
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -47,24 +47,29 @@ int ieee80211_chanctx_refcount(struct ie
ieee80211_chanctx_num_reserved(local, ctx);
}
-static int ieee80211_num_chanctx(struct ieee80211_local *local)
+static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
{
struct ieee80211_chanctx *ctx;
int num = 0;
lockdep_assert_wiphy(local->hw.wiphy);
- list_for_each_entry(ctx, &local->chanctx_list, list)
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
+ if (radio_idx >= 0 && ctx->conf.radio_idx != radio_idx)
+ continue;
num++;
+ }
return num;
}
-static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
+static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local,
+ int radio_idx)
{
lockdep_assert_wiphy(local->hw.wiphy);
- return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
+ return ieee80211_num_chanctx(local, radio_idx) <
+ ieee80211_max_num_channels(local, radio_idx);
}
static struct ieee80211_chanctx *
@@ -1045,7 +1050,7 @@ int ieee80211_link_reserve_chanctx(struc
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
if (!new_ctx) {
- if (ieee80211_can_create_new_chanctx(local)) {
+ if (ieee80211_can_create_new_chanctx(local, -1)) {
new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
if (IS_ERR(new_ctx))
return PTR_ERR(new_ctx);
@@ -1736,7 +1741,7 @@ int ieee80211_link_use_channel(struct ie
link->radar_required = ret;
ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
- radar_detect_width);
+ radar_detect_width, -1);
if (ret < 0)
goto out;
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1745,7 +1745,7 @@ int ieee80211_ibss_join(struct ieee80211
IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
ret = ieee80211_check_combinations(sdata, &params->chandef, chanmode,
- radar_detect_width);
+ radar_detect_width, -1);
if (ret < 0)
return ret;
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2596,8 +2596,9 @@ void ieee80211_recalc_dtim(struct ieee80
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode chanmode,
- u8 radar_detect);
-int ieee80211_max_num_channels(struct ieee80211_local *local);
+ u8 radar_detect, int radio_idx);
+int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx);
+u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev);
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx);
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -397,7 +397,7 @@ static int ieee80211_check_concurrent_if
}
}
- return ieee80211_check_combinations(sdata, NULL, 0, 0);
+ return ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
}
static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3918,20 +3918,103 @@ static u8 ieee80211_chanctx_radar_detect
return radar_detect;
}
+static u32
+__ieee80211_get_radio_mask(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_chanctx_conf *conf;
+ unsigned int link_id;
+ u32 mask = 0;
+
+ for_each_vif_active_link(&sdata->vif, link_conf, link_id) {
+ conf = sdata_dereference(link_conf->chanctx_conf, sdata);
+ if (!conf || conf->radio_idx < 0)
+ continue;
+
+ mask |= BIT(conf->radio_idx);
+ }
+
+ return mask;
+}
+
+u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ return __ieee80211_get_radio_mask(sdata);
+}
+
+static bool
+ieee80211_sdata_uses_radio(struct ieee80211_sub_if_data *sdata, int radio_idx)
+{
+ if (radio_idx < 0)
+ return true;
+
+ return __ieee80211_get_radio_mask(sdata) & BIT(radio_idx);
+}
+
+static int
+ieee80211_fill_ifcomb_params(struct ieee80211_local *local,
+ struct iface_combination_params *params,
+ const struct cfg80211_chan_def *chandef,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_sub_if_data *sdata_iter;
+ struct ieee80211_chanctx *ctx;
+ int total = !!sdata;
+
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
+ if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
+ continue;
+
+ if (params->radio_idx >= 0 &&
+ ctx->conf.radio_idx != params->radio_idx)
+ continue;
+
+ params->radar_detect |=
+ ieee80211_chanctx_radar_detect(local, ctx);
+
+ if (chandef && ctx->mode != IEEE80211_CHANCTX_EXCLUSIVE &&
+ cfg80211_chandef_compatible(chandef, &ctx->conf.def))
+ continue;
+
+ params->num_different_channels++;
+ }
+
+ list_for_each_entry(sdata_iter, &local->interfaces, list) {
+ struct wireless_dev *wdev_iter;
+
+ wdev_iter = &sdata_iter->wdev;
+
+ if (sdata_iter == sdata ||
+ !ieee80211_sdata_running(sdata_iter) ||
+ cfg80211_iftype_allowed(local->hw.wiphy,
+ wdev_iter->iftype, 0, 1))
+ continue;
+
+ if (!ieee80211_sdata_uses_radio(sdata_iter, params->radio_idx))
+ continue;
+
+ params->iftype_num[wdev_iter->iftype]++;
+ total++;
+ }
+
+ return total;
+}
+
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode chanmode,
- u8 radar_detect)
+ u8 radar_detect, int radio_idx)
{
+ bool shared = chanmode == IEEE80211_CHANCTX_SHARED;
struct ieee80211_local *local = sdata->local;
- struct ieee80211_sub_if_data *sdata_iter;
enum nl80211_iftype iftype = sdata->wdev.iftype;
- struct ieee80211_chanctx *ctx;
- int total = 1;
struct iface_combination_params params = {
.radar_detect = radar_detect,
- .radio_idx = -1,
+ .radio_idx = radio_idx,
};
+ int total;
lockdep_assert_wiphy(local->hw.wiphy);
@@ -3968,37 +4051,9 @@ int ieee80211_check_combinations(struct
if (iftype != NL80211_IFTYPE_UNSPECIFIED)
params.iftype_num[iftype] = 1;
- list_for_each_entry(ctx, &local->chanctx_list, list) {
- if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
- continue;
- params.radar_detect |=
- ieee80211_chanctx_radar_detect(local, ctx);
- if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
- params.num_different_channels++;
- continue;
- }
- if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
- cfg80211_chandef_compatible(chandef,
- &ctx->conf.def))
- continue;
- params.num_different_channels++;
- }
-
- list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
- struct wireless_dev *wdev_iter;
-
- wdev_iter = &sdata_iter->wdev;
-
- if (sdata_iter == sdata ||
- !ieee80211_sdata_running(sdata_iter) ||
- cfg80211_iftype_allowed(local->hw.wiphy,
- wdev_iter->iftype, 0, 1))
- continue;
-
- params.iftype_num[wdev_iter->iftype]++;
- total++;
- }
-
+ total = ieee80211_fill_ifcomb_params(local, &params,
+ shared ? chandef : NULL,
+ sdata);
if (total == 1 && !params.radar_detect)
return 0;
@@ -4015,30 +4070,17 @@ ieee80211_iter_max_chans(const struct ie
c->num_different_channels);
}
-int ieee80211_max_num_channels(struct ieee80211_local *local)
+int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx)
{
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_chanctx *ctx;
u32 max_num_different_channels = 1;
int err;
struct iface_combination_params params = {
- .radio_idx = -1,
+ .radio_idx = radio_idx,
};
lockdep_assert_wiphy(local->hw.wiphy);
- list_for_each_entry(ctx, &local->chanctx_list, list) {
- if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
- continue;
-
- params.num_different_channels++;
-
- params.radar_detect |=
- ieee80211_chanctx_radar_detect(local, ctx);
- }
-
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- params.iftype_num[sdata->wdev.iftype]++;
+ ieee80211_fill_ifcomb_params(local, &params, NULL, NULL);
err = cfg80211_iter_combinations(local->hw.wiphy, &params,
ieee80211_iter_max_chans,
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 5 Jun 2024 10:49:22 +0200
Subject: [PATCH] wifi: mac80211: move code in
ieee80211_link_reserve_chanctx to a helper
Reduces indentation in preparation for further changes
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1033,6 +1033,71 @@ int ieee80211_link_unreserve_chanctx(str
return 0;
}
+static struct ieee80211_chanctx *
+ieee80211_replace_chanctx(struct ieee80211_local *local,
+ const struct ieee80211_chan_req *chanreq,
+ enum ieee80211_chanctx_mode mode,
+ struct ieee80211_chanctx *curr_ctx)
+{
+ struct ieee80211_chanctx *new_ctx, *ctx;
+
+ if (!curr_ctx || (curr_ctx->replace_state ==
+ IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
+ !list_empty(&curr_ctx->reserved_links)) {
+ /*
+ * Another link already requested this context for a
+ * reservation. Find another one hoping all links assigned
+ * to it will also switch soon enough.
+ *
+ * TODO: This needs a little more work as some cases
+ * (more than 2 chanctx capable devices) may fail which could
+ * otherwise succeed provided some channel context juggling was
+ * performed.
+ *
+ * Consider ctx1..3, link1..6, each ctx has 2 links. link1 and
+ * link2 from ctx1 request new different chandefs starting 2
+ * in-place reserations with ctx4 and ctx5 replacing ctx1 and
+ * ctx2 respectively. Next link5 and link6 from ctx3 reserve
+ * ctx4. If link3 and link4 remain on ctx2 as they are then this
+ * fails unless `replace_ctx` from ctx5 is replaced with ctx3.
+ */
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
+ if (ctx->replace_state !=
+ IEEE80211_CHANCTX_REPLACE_NONE)
+ continue;
+
+ if (!list_empty(&ctx->reserved_links))
+ continue;
+
+ curr_ctx = ctx;
+ break;
+ }
+ }
+
+ /*
+ * If that's true then all available contexts already have reservations
+ * and cannot be used.
+ */
+ if (!curr_ctx || (curr_ctx->replace_state ==
+ IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
+ !list_empty(&curr_ctx->reserved_links))
+ return ERR_PTR(-EBUSY);
+
+ new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
+ if (!new_ctx)
+ return ERR_PTR(-ENOMEM);
+
+ new_ctx->replace_ctx = curr_ctx;
+ new_ctx->replace_state = IEEE80211_CHANCTX_REPLACES_OTHER;
+
+ curr_ctx->replace_ctx = new_ctx;
+ curr_ctx->replace_state = IEEE80211_CHANCTX_WILL_BE_REPLACED;
+
+ list_add_rcu(&new_ctx->list, &local->chanctx_list);
+
+ return new_ctx;
+}
+
int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
const struct ieee80211_chan_req *chanreq,
enum ieee80211_chanctx_mode mode,
@@ -1040,7 +1105,7 @@ int ieee80211_link_reserve_chanctx(struc
{
struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
- struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx;
+ struct ieee80211_chanctx *new_ctx, *curr_ctx;
lockdep_assert_wiphy(local->hw.wiphy);
@@ -1050,75 +1115,13 @@ int ieee80211_link_reserve_chanctx(struc
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
if (!new_ctx) {
- if (ieee80211_can_create_new_chanctx(local, -1)) {
+ if (ieee80211_can_create_new_chanctx(local, -1))
new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
- if (IS_ERR(new_ctx))
- return PTR_ERR(new_ctx);
- } else {
- if (!curr_ctx ||
- (curr_ctx->replace_state ==
- IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
- !list_empty(&curr_ctx->reserved_links)) {
- /*
- * Another link already requested this context
- * for a reservation. Find another one hoping
- * all links assigned to it will also switch
- * soon enough.
- *
- * TODO: This needs a little more work as some
- * cases (more than 2 chanctx capable devices)
- * may fail which could otherwise succeed
- * provided some channel context juggling was
- * performed.
- *
- * Consider ctx1..3, link1..6, each ctx has 2
- * links. link1 and link2 from ctx1 request new
- * different chandefs starting 2 in-place
- * reserations with ctx4 and ctx5 replacing
- * ctx1 and ctx2 respectively. Next link5 and
- * link6 from ctx3 reserve ctx4. If link3 and
- * link4 remain on ctx2 as they are then this
- * fails unless `replace_ctx` from ctx5 is
- * replaced with ctx3.
- */
- list_for_each_entry(ctx, &local->chanctx_list,
- list) {
- if (ctx->replace_state !=
- IEEE80211_CHANCTX_REPLACE_NONE)
- continue;
-
- if (!list_empty(&ctx->reserved_links))
- continue;
-
- curr_ctx = ctx;
- break;
- }
- }
-
- /*
- * If that's true then all available contexts already
- * have reservations and cannot be used.
- */
- if (!curr_ctx ||
- (curr_ctx->replace_state ==
- IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
- !list_empty(&curr_ctx->reserved_links))
- return -EBUSY;
-
- new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
- if (!new_ctx)
- return -ENOMEM;
-
- new_ctx->replace_ctx = curr_ctx;
- new_ctx->replace_state =
- IEEE80211_CHANCTX_REPLACES_OTHER;
-
- curr_ctx->replace_ctx = new_ctx;
- curr_ctx->replace_state =
- IEEE80211_CHANCTX_WILL_BE_REPLACED;
-
- list_add_rcu(&new_ctx->list, &local->chanctx_list);
- }
+ else
+ new_ctx = ieee80211_replace_chanctx(local, chanreq,
+ mode, curr_ctx);
+ if (IS_ERR(new_ctx))
+ return PTR_ERR(new_ctx);
}
list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 5 Jun 2024 18:39:55 +0200
Subject: [PATCH] wifi: mac80211: add wiphy radio assignment and
validation
Validate number of channels and interface combinations per radio.
Assign each channel context to a radio.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -680,14 +680,15 @@ static int ieee80211_add_chanctx(struct
static struct ieee80211_chanctx *
ieee80211_new_chanctx(struct ieee80211_local *local,
const struct ieee80211_chan_req *chanreq,
- enum ieee80211_chanctx_mode mode)
+ enum ieee80211_chanctx_mode mode,
+ int radio_idx)
{
struct ieee80211_chanctx *ctx;
int err;
lockdep_assert_wiphy(local->hw.wiphy);
- ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
+ ctx = ieee80211_alloc_chanctx(local, chanreq, mode, radio_idx);
if (!ctx)
return ERR_PTR(-ENOMEM);
@@ -1040,6 +1041,8 @@ ieee80211_replace_chanctx(struct ieee802
struct ieee80211_chanctx *curr_ctx)
{
struct ieee80211_chanctx *new_ctx, *ctx;
+ struct wiphy *wiphy = local->hw.wiphy;
+ const struct wiphy_radio *radio;
if (!curr_ctx || (curr_ctx->replace_state ==
IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
@@ -1069,6 +1072,12 @@ ieee80211_replace_chanctx(struct ieee802
if (!list_empty(&ctx->reserved_links))
continue;
+ if (ctx->conf.radio_idx >= 0) {
+ radio = &wiphy->radio[ctx->conf.radio_idx];
+ if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
+ continue;
+ }
+
curr_ctx = ctx;
break;
}
@@ -1098,6 +1107,34 @@ ieee80211_replace_chanctx(struct ieee802
return new_ctx;
}
+static bool
+ieee80211_find_available_radio(struct ieee80211_local *local,
+ const struct ieee80211_chan_req *chanreq,
+ int *radio_idx)
+{
+ struct wiphy *wiphy = local->hw.wiphy;
+ const struct wiphy_radio *radio;
+ int i;
+
+ *radio_idx = -1;
+ if (!wiphy->n_radio)
+ return true;
+
+ for (i = 0; i < wiphy->n_radio; i++) {
+ radio = &wiphy->radio[i];
+ if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
+ continue;
+
+ if (!ieee80211_can_create_new_chanctx(local, i))
+ continue;
+
+ *radio_idx = i;
+ return true;
+ }
+
+ return false;
+}
+
int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
const struct ieee80211_chan_req *chanreq,
enum ieee80211_chanctx_mode mode,
@@ -1106,6 +1143,7 @@ int ieee80211_link_reserve_chanctx(struc
struct ieee80211_sub_if_data *sdata = link->sdata;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *new_ctx, *curr_ctx;
+ int radio_idx;
lockdep_assert_wiphy(local->hw.wiphy);
@@ -1115,8 +1153,10 @@ int ieee80211_link_reserve_chanctx(struc
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
if (!new_ctx) {
- if (ieee80211_can_create_new_chanctx(local, -1))
- new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
+ if (ieee80211_can_create_new_chanctx(local, -1) &&
+ ieee80211_find_available_radio(local, chanreq, &radio_idx))
+ new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
+ radio_idx);
else
new_ctx = ieee80211_replace_chanctx(local, chanreq,
mode, curr_ctx);
@@ -1724,6 +1764,7 @@ int ieee80211_link_use_channel(struct ie
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx *ctx;
u8 radar_detect_width = 0;
+ int radio_idx;
int ret;
lockdep_assert_wiphy(local->hw.wiphy);
@@ -1751,8 +1792,12 @@ int ieee80211_link_use_channel(struct ie
__ieee80211_link_release_channel(link);
ctx = ieee80211_find_chanctx(local, chanreq, mode);
- if (!ctx)
- ctx = ieee80211_new_chanctx(local, chanreq, mode);
+ if (!ctx) {
+ if (!ieee80211_find_available_radio(local, chanreq, &radio_idx))
+ ctx = ERR_PTR(-EBUSY);
+ else
+ ctx = ieee80211_new_chanctx(local, chanreq, mode, radio_idx);
+ }
if (IS_ERR(ctx)) {
ret = PTR_ERR(ctx);
goto out;
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 11 Jun 2024 09:02:55 +0200
Subject: [PATCH] wifi: mac80211_hwsim: add support for multi-radio wiphy
This registers one wiphy radio per supported band. Number of different
channels is set per radio.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -69,6 +69,10 @@ static bool mlo;
module_param(mlo, bool, 0444);
MODULE_PARM_DESC(mlo, "Support MLO");
+static bool multi_radio;
+module_param(multi_radio, bool, 0444);
+MODULE_PARM_DESC(mlo, "Support Multiple Radios per wiphy");
+
/**
* enum hwsim_regtest - the type of regulatory tests we offer
*
@@ -669,6 +673,10 @@ struct mac80211_hwsim_data {
struct ieee80211_iface_limit if_limits[3];
int n_if_limits;
+ struct ieee80211_iface_combination if_combination_radio;
+ struct wiphy_radio_freq_range radio_range[NUM_NL80211_BANDS];
+ struct wiphy_radio radio[NUM_NL80211_BANDS];
+
u32 ciphers[ARRAY_SIZE(hwsim_ciphers)];
struct mac_address addresses[2];
@@ -917,6 +925,7 @@ static const struct nla_policy hwsim_gen
[HWSIM_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
[HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy),
[HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy),
+ [HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG },
};
#if IS_REACHABLE(CONFIG_VIRTIO)
@@ -4007,6 +4016,7 @@ struct hwsim_new_radio_params {
bool reg_strict;
bool p2p_device;
bool use_chanctx;
+ bool multi_radio;
bool destroy_on_close;
const char *hwname;
bool no_vif;
@@ -4083,6 +4093,12 @@ static int append_radio_msg(struct sk_bu
return ret;
}
+ if (param->multi_radio) {
+ ret = nla_put_flag(skb, HWSIM_ATTR_MULTI_RADIO);
+ if (ret < 0)
+ return ret;
+ }
+
if (param->hwname) {
ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME,
strlen(param->hwname), param->hwname);
@@ -5099,6 +5115,7 @@ static int mac80211_hwsim_new_radio(stru
struct net *net;
int idx, i;
int n_limits = 0;
+ int n_bands = 0;
if (WARN_ON(param->channels > 1 && !param->use_chanctx))
return -EINVAL;
@@ -5202,22 +5219,22 @@ static int mac80211_hwsim_new_radio(stru
n_limits++;
}
+ data->if_combination.radar_detect_widths =
+ BIT(NL80211_CHAN_WIDTH_5) |
+ BIT(NL80211_CHAN_WIDTH_10) |
+ 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);
+
if (data->use_chanctx) {
hw->wiphy->max_scan_ssids = 255;
hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
hw->wiphy->max_remain_on_channel_duration = 1000;
- data->if_combination.radar_detect_widths = 0;
data->if_combination.num_different_channels = data->channels;
} else {
data->if_combination.num_different_channels = 1;
- data->if_combination.radar_detect_widths =
- BIT(NL80211_CHAN_WIDTH_5) |
- BIT(NL80211_CHAN_WIDTH_10) |
- 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);
}
if (!n_limits) {
@@ -5333,6 +5350,9 @@ static int mac80211_hwsim_new_radio(stru
for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
struct ieee80211_supported_band *sband = &data->bands[band];
+ struct wiphy_radio_freq_range *radio_range;
+ const struct ieee80211_channel *c;
+ struct wiphy_radio *radio;
sband->band = band;
@@ -5406,8 +5426,36 @@ static int mac80211_hwsim_new_radio(stru
mac80211_hwsim_sband_capab(sband);
hw->wiphy->bands[band] = sband;
+
+ if (!param->multi_radio)
+ continue;
+
+ c = sband->channels;
+ radio_range = &data->radio_range[n_bands];
+ radio_range->start_freq = ieee80211_channel_to_khz(c) - 10000;
+
+ c += sband->n_channels - 1;
+ radio_range->end_freq = ieee80211_channel_to_khz(c) + 10000;
+
+ radio = &data->radio[n_bands++];
+ radio->freq_range = radio_range;
+ radio->n_freq_range = 1;
+ radio->iface_combinations = &data->if_combination_radio;
+ radio->n_iface_combinations = 1;
}
+ if (param->multi_radio) {
+ hw->wiphy->radio = data->radio;
+ hw->wiphy->n_radio = n_bands;
+
+ memcpy(&data->if_combination_radio, &data->if_combination,
+ sizeof(data->if_combination));
+ data->if_combination.num_different_channels *= n_bands;
+ }
+
+ if (data->use_chanctx)
+ data->if_combination.radar_detect_widths = 0;
+
/* By default all radios belong to the first group */
data->group = 1;
mutex_init(&data->mutex);
@@ -6025,6 +6073,9 @@ static int hwsim_new_radio_nl(struct sk_
else
param.use_chanctx = (param.channels > 1);
+ if (info->attrs[HWSIM_ATTR_MULTI_RADIO])
+ param.multi_radio = true;
+
if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
param.reg_alpha2 =
nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
@@ -6105,7 +6156,7 @@ static int hwsim_new_radio_nl(struct sk_
param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT];
- if (param.mlo)
+ if (param.mlo || param.multi_radio)
param.use_chanctx = true;
if (info->attrs[HWSIM_ATTR_RADIO_NAME]) {
@@ -6802,7 +6853,8 @@ static int __init init_mac80211_hwsim(vo
param.p2p_device = support_p2p_device;
param.mlo = mlo;
- param.use_chanctx = channels > 1 || mlo;
+ param.multi_radio = multi_radio;
+ param.use_chanctx = channels > 1 || mlo || multi_radio;
param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK;
if (param.p2p_device)
param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
--- a/drivers/net/wireless/virtual/mac80211_hwsim.h
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.h
@@ -157,6 +157,9 @@ enum hwsim_commands {
* to provide details about peer measurement request (nl80211_peer_measurement_attrs)
* @HWSIM_ATTR_PMSR_RESULT: nested attributed used with %HWSIM_CMD_REPORT_PMSR
* to provide peer measurement result (nl80211_peer_measurement_attrs)
+ * @HWSIM_ATTR_MULTI_RADIO: Register multiple wiphy radios (flag).
+ * Adds one radio for each band. Number of supported channels will be set for
+ * each radio instead of for the wiphy.
* @__HWSIM_ATTR_MAX: enum limit
*/
enum hwsim_attrs {
@@ -189,6 +192,7 @@ enum hwsim_attrs {
HWSIM_ATTR_PMSR_SUPPORT,
HWSIM_ATTR_PMSR_REQUEST,
HWSIM_ATTR_PMSR_RESULT,
+ HWSIM_ATTR_MULTI_RADIO,
__HWSIM_ATTR_MAX,
};
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
......@@ -16,7 +16,7 @@ and we should ignore this.
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -651,21 +651,6 @@ static int wiphy_verify_combinations(str
@@ -654,21 +654,6 @@ static int wiphy_verify_combinations(str
c->limits[j].max > 1))
return -EINVAL;
......
PKG_DRIVERS += \
rtlwifi rtlwifi-pci rtlwifi-btcoexist rtlwifi-usb rtl8192c-common \
rtlwifi rtlwifi-pci rtlwifi-btcoexist rtlwifi-usb rtl8192c-common rtl8192d-common \
rtl8192ce rtl8192se rtl8192de rtl8192cu rtl8723-common rtl8723be rtl8723bs rtl8821ae \
rtl8xxxu rtw88 rtw88-pci rtw88-usb rtw88-sdio rtw88-8821c rtw88-8822b rtw88-8822c \
rtw88-8723d rtw88-8821ce rtw88-8821cu rtw88-8822be rtw88-8822bu \
rtw88-8723x rtw88-8723d rtw88-8821ce rtw88-8821cu rtw88-8822be rtw88-8822bu \
rtw88-8822ce rtw88-8822cu rtw88-8723de rtw88-8723ds rtw88-8723du \
rtw89 rtw89-pci rtw89-8851be rtw89-8852ae rtw89-8852be rtw89-8852ce
rtw89 rtw89-pci rtw89-8851be rtw89-8852ae rtw89-8852b-common rtw89-8852be rtw89-8852ce
config-$(call config_package,rtlwifi) += RTL_CARDS RTLWIFI
config-$(call config_package,rtlwifi-pci) += RTLWIFI_PCI
......@@ -13,6 +13,7 @@ config-$(call config_package,rtlwifi-usb) += RTLWIFI_USB
config-$(call config_package,rtl8192c-common) += RTL8192C_COMMON
config-$(call config_package,rtl8192ce) += RTL8192CE
config-$(call config_package,rtl8192se) += RTL8192SE
config-$(call config_package,rtl8192d-common) += RTL8192D_COMMON
config-$(call config_package,rtl8192de) += RTL8192DE
config-$(call config_package,rtl8192cu) += RTL8192CU
config-$(call config_package,rtl8821ae) += RTL8821AE
......@@ -40,6 +41,7 @@ config-$(call config_package,rtw88-8822bu) += RTW88_8822BU
config-$(call config_package,rtw88-8822c) += RTW88_8822C
config-$(call config_package,rtw88-8822ce) += RTW88_8822CE
config-$(call config_package,rtw88-8822cu) += RTW88_8822CU
config-$(call config_package,rtw88-8723x) += RTW88_8723X
config-$(call config_package,rtw88-8723d) += RTW88_8723D
config-$(call config_package,rtw88-8723de) += RTW88_8723DE
config-$(call config_package,rtw88-8723ds) += RTW88_8723DS
......@@ -51,6 +53,7 @@ config-$(call config_package,rtw89) += RTW89 RTW89_CORE
config-$(call config_package,rtw89-pci) += RTW89_PCI
config-$(call config_package,rtw89-8851be) += RTW89_8851B RTW89_8851BE
config-$(call config_package,rtw89-8852ae) += RTW89_8852A RTW89_8852AE
config-$(call config_package,rtw89-8852b-common) += RTW89_8852B_COMMON
config-$(call config_package,rtw89-8852be) += RTW89_8852B RTW89_8852BE
config-$(call config_package,rtw89-8852ce) += RTW89_8852C RTW89_8852CE
config-$(CONFIG_PACKAGE_RTW89_DEBUG) += RTW89_DEBUG
......@@ -125,10 +128,18 @@ define KernelPackage/rtl8192se
AUTOLOAD:=$(call AutoProbe,rtl8192se)
endef
define KernelPackage/rtl8192d-common
$(call KernelPackage/mac80211/Default)
TITLE:=Realtek RTL8192DE/RTL8192DU common support module
DEPENDS+= +kmod-rtlwifi
FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtlwifi/rtl8192d/rtl8192d-common.ko
HIDDEN:=1
endef
define KernelPackage/rtl8192de
$(call KernelPackage/mac80211/Default)
TITLE:=Realtek RTL8192DE/RTL8188DE support
DEPENDS+= +kmod-rtlwifi-pci +rtl8192de-firmware
DEPENDS+= +kmod-rtlwifi-pci +kmod-rtl8192d-common +rtl8192de-firmware
FILES:= $(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rtl8192de.ko
AUTOLOAD:=$(call AutoProbe,rtl8192de)
endef
......@@ -260,10 +271,19 @@ define KernelPackage/rtw88-8822c
HIDDEN:=1
endef
define KernelPackage/rtw88-8723x
$(call KernelPackage/mac80211/Default)
TITLE:=Realtek RTL8723x family support
DEPENDS+= +kmod-rtw88
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtw88/rtw88_8723x.ko
AUTOLOAD:=$(call AutoProbe,rtw88_8723x)
HIDDEN:=1
endef
define KernelPackage/rtw88-8723d
$(call KernelPackage/mac80211/Default)
TITLE:=Realtek RTL8723D family support
DEPENDS+= +kmod-rtw88 +rtl8723de-firmware
DEPENDS+= +kmod-rtw88-8723x +rtl8723de-firmware
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtw88/rtw88_8723d.ko
AUTOLOAD:=$(call AutoProbe,rtw88_8723d)
HIDDEN:=1
......@@ -431,10 +451,20 @@ define KernelPackage/rtw89-8852ae
AUTOLOAD:=$(call AutoProbe,rtw89_8852ae)
endef
define KernelPackage/rtw89-8852b-common
$(call KernelPackage/mac80211/Default)
TITLE:=Realtek RTL8852B family support
DEPENDS+= +kmod-rtw89-pci
FILES:= \
$(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtw89/rtw89_8852b_common.ko
AUTOLOAD:=$(call AutoProbe,rtw89_8852b_common)
HIDDEN:=1
endef
define KernelPackage/rtw89-8852be
$(call KernelPackage/mac80211/Default)
TITLE:=Realtek RTL8852BE support
DEPENDS+= +kmod-rtw89-pci +rtl8852be-firmware
DEPENDS+= +kmod-rtw89-8852b-common +rtl8852be-firmware
FILES:= \
$(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtw89/rtw89_8852b.ko \
$(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtw89/rtw89_8852be.ko
......
--- a/mt76.h
+++ b/mt76.h
@@ -14,6 +14,7 @@
#include <linux/usb.h>
#include <linux/average.h>
#include <linux/soc/mediatek/mtk_wed.h>
+#include <net/netlink.h>
#include <net/mac80211.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,6,0)
#include <net/page_pool.h>
@@ -1475,6 +1476,7 @@ static inline void mt76_testmode_reset(s
#endif
}
+extern const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS];
/* internal */
static inline struct ieee80211_hw *
--- a/mt7603/main.c
+++ b/mt7603/main.c
@@ -23,7 +23,7 @@ mt7603_start(struct ieee80211_hw *hw)
}
static void
-mt7603_stop(struct ieee80211_hw *hw)
+mt7603_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt7603_dev *dev = hw->priv;
--- a/mt7615/main.c
+++ b/mt7615/main.c
@@ -91,7 +91,7 @@ out:
return ret;
}
-static void mt7615_stop(struct ieee80211_hw *hw)
+static void mt7615_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
--- a/mt7615/usb.c
+++ b/mt7615/usb.c
@@ -79,7 +79,7 @@ static void mt7663u_copy(struct mt76_dev
mutex_unlock(&usb->usb_ctrl_mtx);
}
-static void mt7663u_stop(struct ieee80211_hw *hw)
+static void mt7663u_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt7615_phy *phy = mt7615_hw_phy(hw);
struct mt7615_dev *dev = hw->priv;
--- a/mt76x0/pci.c
+++ b/mt76x0/pci.c
@@ -44,7 +44,7 @@ static void mt76x0e_stop_hw(struct mt76x
mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN);
}
-static void mt76x0e_stop(struct ieee80211_hw *hw)
+static void mt76x0e_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt76x02_dev *dev = hw->priv;
--- a/mt76x0/usb.c
+++ b/mt76x0/usb.c
@@ -77,7 +77,7 @@ static void mt76x0u_cleanup(struct mt76x
mt76u_queues_deinit(&dev->mt76);
}
-static void mt76x0u_stop(struct ieee80211_hw *hw)
+static void mt76x0u_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt76x02_dev *dev = hw->priv;
--- a/mt76x2/pci_main.c
+++ b/mt76x2/pci_main.c
@@ -24,7 +24,7 @@ mt76x2_start(struct ieee80211_hw *hw)
}
static void
-mt76x2_stop(struct ieee80211_hw *hw)
+mt76x2_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt76x02_dev *dev = hw->priv;
--- a/mt76x2/usb_main.c
+++ b/mt76x2/usb_main.c
@@ -22,7 +22,7 @@ static int mt76x2u_start(struct ieee8021
return 0;
}
-static void mt76x2u_stop(struct ieee80211_hw *hw)
+static void mt76x2u_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt76x02_dev *dev = hw->priv;
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -108,7 +108,7 @@ static int mt7915_start(struct ieee80211
return ret;
}
-static void mt7915_stop(struct ieee80211_hw *hw)
+static void mt7915_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -335,7 +335,7 @@ mt7915_mcu_cca_finish(void *priv, u8 *ma
if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION)
return;
- ieee80211_color_change_finish(vif);
+ ieee80211_color_change_finish(vif, 0);
}
static void
--- a/mt7921/main.c
+++ b/mt7921/main.c
@@ -268,7 +268,7 @@ static int mt7921_start(struct ieee80211
return err;
}
-static void mt7921_stop(struct ieee80211_hw *hw)
+static void mt7921_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
int err = 0;
@@ -281,7 +281,7 @@ static void mt7921_stop(struct ieee80211
return;
}
- mt792x_stop(hw);
+ mt792x_stop(hw, false);
}
static int
--- a/mt792x.h
+++ b/mt792x.h
@@ -337,7 +337,7 @@ static inline bool mt792x_dma_need_reini
#define mt792x_mutex_release(dev) \
mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm)
-void mt792x_stop(struct ieee80211_hw *hw);
+void mt792x_stop(struct ieee80211_hw *hw, bool suspend);
void mt792x_pm_wake_work(struct work_struct *work);
void mt792x_pm_power_save_work(struct work_struct *work);
void mt792x_reset(struct mt76_dev *mdev);
@@ -457,7 +457,7 @@ void mt792xu_wr(struct mt76_dev *dev, u3
u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val);
void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len);
void mt792xu_disconnect(struct usb_interface *usb_intf);
-void mt792xu_stop(struct ieee80211_hw *hw);
+void mt792xu_stop(struct ieee80211_hw *hw, bool suspend);
static inline void
mt792x_skb_add_usb_sdio_hdr(struct mt792x_dev *dev, struct sk_buff *skb,
--- a/mt792x_core.c
+++ b/mt792x_core.c
@@ -113,7 +113,7 @@ void mt792x_tx(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(mt792x_tx);
-void mt792x_stop(struct ieee80211_hw *hw)
+void mt792x_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_phy *phy = mt792x_hw_phy(hw);
--- a/mt792x_usb.c
+++ b/mt792x_usb.c
@@ -285,12 +285,12 @@ int mt792xu_init_reset(struct mt792x_dev
}
EXPORT_SYMBOL_GPL(mt792xu_init_reset);
-void mt792xu_stop(struct ieee80211_hw *hw)
+void mt792xu_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
mt76u_stop_tx(&dev->mt76);
- mt792x_stop(hw);
+ mt792x_stop(hw, false);
}
EXPORT_SYMBOL_GPL(mt792xu_stop);
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -93,7 +93,7 @@ static int mt7996_start(struct ieee80211
return ret;
}
-static void mt7996_stop(struct ieee80211_hw *hw)
+static void mt7996_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_hw_phy(hw);
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -421,7 +421,7 @@ mt7996_mcu_cca_finish(void *priv, u8 *ma
if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION)
return;
- ieee80211_color_change_finish(vif);
+ ieee80211_color_change_finish(vif, 0);
}
static void
--- a/testmode.h
+++ b/testmode.h
@@ -193,6 +193,4 @@ enum mt76_testmode_tx_mode {
MT76_TM_TX_MODE_MAX = NUM_MT76_TM_TX_MODES - 1,
};
-extern const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS];
-
#endif
......@@ -358,6 +358,15 @@
+}
--- a/mac80211.c
+++ b/mac80211.c
@@ -159,7 +159,7 @@ fwcmd_fail:
return rc;
}
-static void mwl_mac80211_stop(struct ieee80211_hw *hw)
+static void mwl_mac80211_stop(struct ieee80211_hw *hw, bool suspend)
{
mwl_fwcmd_radio_disable(hw);
@@ -368,15 +368,15 @@ static void mwl_mac80211_bss_info_change
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment