3 changed files with 430 additions and 101 deletions
+319 -69
View File
@@ -4420,13 +4420,29 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
} }
#endif #endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0)) #define RWNX_CFG80211_OP_TYPE(_member) \
static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy, struct net_device *dev, typeof(((struct cfg80211_ops *)0)->_member)
struct cfg80211_chan_def *chandef) #define RWNX_CFG80211_OP_MATCH(_member, _type) \
#else __builtin_types_compatible_p(RWNX_CFG80211_OP_TYPE(_member), _type)
static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy, #define RWNX_CFG80211_OP_ASSERT(_member, _callback) \
struct cfg80211_chan_def *chandef) typedef char rwnx_cfg80211_##_member##_signature_must_match[ \
#endif __builtin_types_compatible_p(RWNX_CFG80211_OP_TYPE(_member), \
typeof(&(_callback))) ? 1 : -1]
typedef int (*rwnx_set_monitor_channel_legacy_t)(
struct wiphy *wiphy, struct cfg80211_chan_def *chandef);
typedef int (*rwnx_set_monitor_channel_dev_t)(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef);
typedef char rwnx_set_monitor_channel_signature_must_be_supported[
(RWNX_CFG80211_OP_MATCH(set_monitor_channel,
rwnx_set_monitor_channel_legacy_t) ||
RWNX_CFG80211_OP_MATCH(set_monitor_channel,
rwnx_set_monitor_channel_dev_t)) ? 1 : -1];
static int rwnx_cfg80211_set_monitor_channel_common(
struct wiphy *wiphy, struct cfg80211_chan_def *chandef)
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct rwnx_vif *rwnx_vif; struct rwnx_vif *rwnx_vif;
@@ -4479,19 +4495,40 @@ static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy,
return 0; return 0;
} }
static int rwnx_cfg80211_set_monitor_channel_legacy(
struct wiphy *wiphy, struct cfg80211_chan_def *chandef)
{
return rwnx_cfg80211_set_monitor_channel_common(wiphy, chandef);
}
static int rwnx_cfg80211_set_monitor_channel_dev(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
(void)dev;
return rwnx_cfg80211_set_monitor_channel_common(wiphy, chandef);
}
#define RWNX_CFG80211_SET_MONITOR_CHANNEL_CB \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(set_monitor_channel, \
rwnx_set_monitor_channel_dev_t), \
rwnx_cfg80211_set_monitor_channel_dev, \
rwnx_cfg80211_set_monitor_channel_legacy)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
return rwnx_cfg80211_set_monitor_channel(wiphy, dev, chandef); (void)dev;
return rwnx_cfg80211_set_monitor_channel_common(wiphy, chandef);
} }
#else #else
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
return rwnx_cfg80211_set_monitor_channel(wiphy, chandef); return rwnx_cfg80211_set_monitor_channel_common(wiphy, chandef);
} }
#endif #endif
@@ -4553,15 +4590,45 @@ void rwnx_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
* have changed. The actual parameter values are available in * have changed. The actual parameter values are available in
* struct wiphy. If returning an error, no value should be changed. * struct wiphy. If returning an error, no value should be changed.
*/ */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) typedef int (*rwnx_set_wiphy_params_legacy_t)(struct wiphy *wiphy,
static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, u32 changed) u32 changed);
#else typedef int (*rwnx_set_wiphy_params_radio_t)(struct wiphy *wiphy,
static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) int radio_idx, u32 changed);
#endif
typedef char rwnx_set_wiphy_params_signature_must_be_supported[
(RWNX_CFG80211_OP_MATCH(set_wiphy_params,
rwnx_set_wiphy_params_legacy_t) ||
RWNX_CFG80211_OP_MATCH(set_wiphy_params,
rwnx_set_wiphy_params_radio_t)) ? 1 : -1];
static int rwnx_cfg80211_set_wiphy_params_common(struct wiphy *wiphy,
u32 changed)
{ {
(void)wiphy;
(void)changed;
return 0; return 0;
} }
static int rwnx_cfg80211_set_wiphy_params_legacy(struct wiphy *wiphy,
u32 changed)
{
return rwnx_cfg80211_set_wiphy_params_common(wiphy, changed);
}
static int rwnx_cfg80211_set_wiphy_params_radio(struct wiphy *wiphy,
int radio_idx, u32 changed)
{
(void)radio_idx;
return rwnx_cfg80211_set_wiphy_params_common(wiphy, changed);
}
#define RWNX_CFG80211_SET_WIPHY_PARAMS_CB \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(set_wiphy_params, \
rwnx_set_wiphy_params_radio_t), \
rwnx_cfg80211_set_wiphy_params_radio, \
rwnx_cfg80211_set_wiphy_params_legacy)
/** /**
* @set_tx_power: set the transmit power according to the parameters, * @set_tx_power: set the transmit power according to the parameters,
@@ -4570,18 +4637,25 @@ static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
* always be %NULL unless the driver supports per-vif TX power * always be %NULL unless the driver supports per-vif TX power
* (as advertised by the nl80211 feature flag.) * (as advertised by the nl80211 feature flag.)
*/ */
static int rwnx_cfg80211_set_tx_power(struct wiphy *wiphy, typedef int (*rwnx_set_tx_power_no_wdev_t)(
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) struct wiphy *wiphy, enum nl80211_tx_power_setting type, int mbm);
struct wireless_dev *wdev, typedef int (*rwnx_set_tx_power_wdev_t)(
#endif struct wiphy *wiphy, struct wireless_dev *wdev,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) enum nl80211_tx_power_setting type, int mbm);
int radio_idx, typedef int (*rwnx_set_tx_power_radio_t)(
#endif struct wiphy *wiphy, struct wireless_dev *wdev, int radio_idx,
enum nl80211_tx_power_setting type, int mbm);
typedef char rwnx_set_tx_power_signature_must_be_supported[
(RWNX_CFG80211_OP_MATCH(set_tx_power, rwnx_set_tx_power_no_wdev_t) ||
RWNX_CFG80211_OP_MATCH(set_tx_power, rwnx_set_tx_power_wdev_t) ||
RWNX_CFG80211_OP_MATCH(set_tx_power,
rwnx_set_tx_power_radio_t)) ? 1 : -1];
static int rwnx_cfg80211_set_tx_power_common(
struct wiphy *wiphy, struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, int mbm) enum nl80211_tx_power_setting type, int mbm)
{ {
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
struct wireless_dev *wdev = NULL;
#endif
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct rwnx_vif *vif; struct rwnx_vif *vif;
s8 pwr; s8 pwr;
@@ -4607,31 +4681,112 @@ int radio_idx,
return res; return res;
} }
static int rwnx_cfg80211_get_tx_power(struct wiphy *wiphy, static int rwnx_cfg80211_set_tx_power_no_wdev(
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) struct wiphy *wiphy, enum nl80211_tx_power_setting type, int mbm)
struct wireless_dev *wdev,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
int radio_idx,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0)
unsigned int link_id,
#endif
int *mbm)
{ {
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) return rwnx_cfg80211_set_tx_power_common(wiphy, NULL, type, mbm);
struct wireless_dev *wdev = NULL;
#endif
//struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
//struct rwnx_vif *vif;
s8 pwr = 0;
int res = 0;
*mbm = get_txpwr_max(pwr);
return res;
} }
static int rwnx_cfg80211_set_tx_power_wdev(
struct wiphy *wiphy, struct wireless_dev *wdev,
enum nl80211_tx_power_setting type, int mbm)
{
return rwnx_cfg80211_set_tx_power_common(wiphy, wdev, type, mbm);
}
static int rwnx_cfg80211_set_tx_power_radio(
struct wiphy *wiphy, struct wireless_dev *wdev, int radio_idx,
enum nl80211_tx_power_setting type, int mbm)
{
(void)radio_idx;
return rwnx_cfg80211_set_tx_power_common(wiphy, wdev, type, mbm);
}
#define RWNX_CFG80211_SET_TX_POWER_CB \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(set_tx_power, rwnx_set_tx_power_radio_t), \
rwnx_cfg80211_set_tx_power_radio, \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(set_tx_power, rwnx_set_tx_power_wdev_t), \
rwnx_cfg80211_set_tx_power_wdev, \
rwnx_cfg80211_set_tx_power_no_wdev))
typedef int (*rwnx_get_tx_power_no_wdev_t)(struct wiphy *wiphy, int *dbm);
typedef int (*rwnx_get_tx_power_wdev_t)(struct wiphy *wiphy,
struct wireless_dev *wdev, int *dbm);
typedef int (*rwnx_get_tx_power_link_t)(struct wiphy *wiphy,
struct wireless_dev *wdev,
unsigned int link_id, int *dbm);
typedef int (*rwnx_get_tx_power_radio_link_t)(
struct wiphy *wiphy, struct wireless_dev *wdev, int radio_idx,
unsigned int link_id, int *dbm);
typedef char rwnx_get_tx_power_signature_must_be_supported[
(RWNX_CFG80211_OP_MATCH(get_tx_power, rwnx_get_tx_power_no_wdev_t) ||
RWNX_CFG80211_OP_MATCH(get_tx_power, rwnx_get_tx_power_wdev_t) ||
RWNX_CFG80211_OP_MATCH(get_tx_power, rwnx_get_tx_power_link_t) ||
RWNX_CFG80211_OP_MATCH(get_tx_power,
rwnx_get_tx_power_radio_link_t)) ? 1 : -1];
static int rwnx_cfg80211_get_tx_power_common(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm)
{
s8 pwr = 0;
(void)wiphy;
(void)wdev;
if (!dbm)
return -EINVAL;
*dbm = get_txpwr_max(pwr);
return 0;
}
static int rwnx_cfg80211_get_tx_power_no_wdev(struct wiphy *wiphy, int *dbm)
{
return rwnx_cfg80211_get_tx_power_common(wiphy, NULL, dbm);
}
static int rwnx_cfg80211_get_tx_power_wdev(struct wiphy *wiphy,
struct wireless_dev *wdev,
int *dbm)
{
return rwnx_cfg80211_get_tx_power_common(wiphy, wdev, dbm);
}
static int rwnx_cfg80211_get_tx_power_link(struct wiphy *wiphy,
struct wireless_dev *wdev,
unsigned int link_id, int *dbm)
{
(void)link_id;
return rwnx_cfg80211_get_tx_power_common(wiphy, wdev, dbm);
}
static int rwnx_cfg80211_get_tx_power_radio_link(
struct wiphy *wiphy, struct wireless_dev *wdev, int radio_idx,
unsigned int link_id, int *dbm)
{
(void)radio_idx;
(void)link_id;
return rwnx_cfg80211_get_tx_power_common(wiphy, wdev, dbm);
}
#define RWNX_CFG80211_GET_TX_POWER_CB \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(get_tx_power, \
rwnx_get_tx_power_radio_link_t), \
rwnx_cfg80211_get_tx_power_radio_link, \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(get_tx_power, \
rwnx_get_tx_power_link_t), \
rwnx_cfg80211_get_tx_power_link, \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(get_tx_power, \
rwnx_get_tx_power_wdev_t), \
rwnx_cfg80211_get_tx_power_wdev, \
rwnx_cfg80211_get_tx_power_no_wdev)))
/** /**
* @set_power_mgmt: set the power save to one of those two modes: * @set_power_mgmt: set the power save to one of those two modes:
* Power-save off * Power-save off
@@ -4999,11 +5154,7 @@ static int rwnx_cfg80211_get_channel(struct wiphy *wiphy,
if (rwnx_vif->vif_index == rwnx_hw->monitor_vif) if (rwnx_vif->vif_index == rwnx_hw->monitor_vif)
{ {
//retrieve channel from firmware //retrieve channel from firmware
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0)) rwnx_cfg80211_set_monitor_channel_common(wiphy, NULL);
rwnx_cfg80211_set_monitor_channel(wiphy, wdev->netdev, NULL);
#else
rwnx_cfg80211_set_monitor_channel(wiphy, NULL);
#endif
} }
//Check if channel context is valid //Check if channel context is valid
@@ -5190,17 +5341,28 @@ send_frame:
/** /**
* @start_radar_detection: Start radar detection in the driver. * @start_radar_detection: Start radar detection in the driver.
*/ */
static typedef int (*rwnx_start_radar_detection_legacy_t)(
int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy, struct wiphy *wiphy, struct net_device *dev,
struct net_device *dev, struct cfg80211_chan_def *chandef);
struct cfg80211_chan_def *chandef typedef int (*rwnx_start_radar_detection_cac_t)(
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) struct wiphy *wiphy, struct net_device *dev,
, u32 cac_time_ms struct cfg80211_chan_def *chandef, u32 cac_time_ms);
#endif typedef int (*rwnx_start_radar_detection_link_t)(
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)) struct wiphy *wiphy, struct net_device *dev,
, int link_id struct cfg80211_chan_def *chandef, u32 cac_time_ms, int link_id);
#endif
) typedef char rwnx_start_radar_detection_signature_must_be_supported[
(RWNX_CFG80211_OP_MATCH(start_radar_detection,
rwnx_start_radar_detection_legacy_t) ||
RWNX_CFG80211_OP_MATCH(start_radar_detection,
rwnx_start_radar_detection_cac_t) ||
RWNX_CFG80211_OP_MATCH(start_radar_detection,
rwnx_start_radar_detection_link_t)) ? 1 : -1];
static int rwnx_cfg80211_start_radar_detection_common(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef, u32 cac_time_ms,
bool start_cac_timer)
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct rwnx_vif *rwnx_vif = netdev_priv(dev); struct rwnx_vif *rwnx_vif = netdev_priv(dev);
@@ -5208,9 +5370,8 @@ int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy,
printk("%s\n", __func__); printk("%s\n", __func__);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) if (start_cac_timer)
rwnx_radar_start_cac(&rwnx_hw->radar, cac_time_ms, rwnx_vif); rwnx_radar_start_cac(&rwnx_hw->radar, cac_time_ms, rwnx_vif);
#endif
rwnx_send_apm_start_cac_req(rwnx_hw, rwnx_vif, chandef, &cfm); rwnx_send_apm_start_cac_req(rwnx_hw, rwnx_vif, chandef, &cfm);
if (cfm.status == CO_OK) { if (cfm.status == CO_OK) {
@@ -5228,6 +5389,42 @@ int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy,
return 0; return 0;
} }
static int rwnx_cfg80211_start_radar_detection_legacy(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
return rwnx_cfg80211_start_radar_detection_common(
wiphy, dev, chandef, 0, false);
}
static int rwnx_cfg80211_start_radar_detection_cac(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef, u32 cac_time_ms)
{
return rwnx_cfg80211_start_radar_detection_common(
wiphy, dev, chandef, cac_time_ms, true);
}
static int rwnx_cfg80211_start_radar_detection_link(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef, u32 cac_time_ms, int link_id)
{
(void)link_id;
return rwnx_cfg80211_start_radar_detection_common(
wiphy, dev, chandef, cac_time_ms, true);
}
#define RWNX_CFG80211_START_RADAR_DETECTION_CB \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(start_radar_detection, \
rwnx_start_radar_detection_link_t), \
rwnx_cfg80211_start_radar_detection_link, \
__builtin_choose_expr( \
RWNX_CFG80211_OP_MATCH(start_radar_detection, \
rwnx_start_radar_detection_cac_t), \
rwnx_cfg80211_start_radar_detection_cac, \
rwnx_cfg80211_start_radar_detection_legacy))
/** /**
* @update_ft_ies: Provide updated Fast BSS Transition information to the * @update_ft_ies: Provide updated Fast BSS Transition information to the
* driver. If the SME is in the driver/firmware, this information can be * driver. If the SME is in the driver/firmware, this information can be
@@ -6520,6 +6717,59 @@ static int rwnx_cfg80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
return 0; return 0;
} }
/*
* Keep every direct cfg80211_ops assignment as a hard compile-time check.
* OpenWrt can backport cfg80211 APIs without changing LINUX_VERSION_CODE, and
* an incompatible callback must remain a build failure even when warnings are
* relaxed by an external package.
*/
RWNX_CFG80211_OP_ASSERT(add_virtual_intf, rwnx_cfg80211_add_iface);
RWNX_CFG80211_OP_ASSERT(del_virtual_intf, rwnx_cfg80211_del_iface);
RWNX_CFG80211_OP_ASSERT(change_virtual_intf, rwnx_cfg80211_change_iface);
RWNX_CFG80211_OP_ASSERT(start_p2p_device, rwnx_cfgp2p_start_p2p_device);
RWNX_CFG80211_OP_ASSERT(stop_p2p_device, rwnx_cfgp2p_stop_p2p_device);
RWNX_CFG80211_OP_ASSERT(scan, rwnx_cfg80211_scan);
RWNX_CFG80211_OP_ASSERT(connect, rwnx_cfg80211_connect);
RWNX_CFG80211_OP_ASSERT(disconnect, rwnx_cfg80211_disconnect);
RWNX_CFG80211_OP_ASSERT(add_key, rwnx_cfg80211_add_key);
RWNX_CFG80211_OP_ASSERT(get_key, rwnx_cfg80211_get_key);
RWNX_CFG80211_OP_ASSERT(del_key, rwnx_cfg80211_del_key);
RWNX_CFG80211_OP_ASSERT(set_default_key, rwnx_cfg80211_set_default_key);
RWNX_CFG80211_OP_ASSERT(set_default_mgmt_key,
rwnx_cfg80211_set_default_mgmt_key);
RWNX_CFG80211_OP_ASSERT(add_station, rwnx_cfg80211_add_station);
RWNX_CFG80211_OP_ASSERT(del_station, rwnx_cfg80211_del_station_compat);
RWNX_CFG80211_OP_ASSERT(change_station, rwnx_cfg80211_change_station);
RWNX_CFG80211_OP_ASSERT(mgmt_tx, rwnx_cfg80211_mgmt_tx);
RWNX_CFG80211_OP_ASSERT(start_ap, rwnx_cfg80211_start_ap);
RWNX_CFG80211_OP_ASSERT(change_beacon, rwnx_cfg80211_change_beacon);
RWNX_CFG80211_OP_ASSERT(stop_ap, rwnx_cfg80211_stop_ap);
RWNX_CFG80211_OP_ASSERT(probe_client, rwnx_cfg80211_probe_client);
RWNX_CFG80211_OP_ASSERT(set_txq_params, rwnx_cfg80211_set_txq_params);
RWNX_CFG80211_OP_ASSERT(set_power_mgmt, rwnx_cfg80211_set_power_mgmt);
RWNX_CFG80211_OP_ASSERT(get_station, rwnx_cfg80211_get_station);
RWNX_CFG80211_OP_ASSERT(remain_on_channel,
rwnx_cfg80211_remain_on_channel);
RWNX_CFG80211_OP_ASSERT(cancel_remain_on_channel,
rwnx_cfg80211_cancel_remain_on_channel);
RWNX_CFG80211_OP_ASSERT(dump_survey, rwnx_cfg80211_dump_survey);
RWNX_CFG80211_OP_ASSERT(get_channel, rwnx_cfg80211_get_channel);
RWNX_CFG80211_OP_ASSERT(update_ft_ies, rwnx_cfg80211_update_ft_ies);
RWNX_CFG80211_OP_ASSERT(set_cqm_rssi_config,
rwnx_cfg80211_set_cqm_rssi_config);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
RWNX_CFG80211_OP_ASSERT(channel_switch, rwnx_cfg80211_channel_switch);
#endif
RWNX_CFG80211_OP_ASSERT(change_bss, rwnx_cfg80211_change_bss);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || \
defined(CONFIG_WPA3_FOR_OLD_KERNEL)
RWNX_CFG80211_OP_ASSERT(external_auth, rwnx_cfg80211_external_auth);
#endif
#ifdef CONFIG_SCHED_SCAN
RWNX_CFG80211_OP_ASSERT(sched_scan_start, rwnx_cfg80211_sched_scan_start);
RWNX_CFG80211_OP_ASSERT(sched_scan_stop, rwnx_cfg80211_sched_scan_stop);
#endif
static struct cfg80211_ops rwnx_cfg80211_ops = { static struct cfg80211_ops rwnx_cfg80211_ops = {
.add_virtual_intf = rwnx_cfg80211_add_iface, .add_virtual_intf = rwnx_cfg80211_add_iface,
.del_virtual_intf = rwnx_cfg80211_del_iface, .del_virtual_intf = rwnx_cfg80211_del_iface,
@@ -6541,20 +6791,20 @@ static struct cfg80211_ops rwnx_cfg80211_ops = {
.start_ap = rwnx_cfg80211_start_ap, .start_ap = rwnx_cfg80211_start_ap,
.change_beacon = rwnx_cfg80211_change_beacon, .change_beacon = rwnx_cfg80211_change_beacon,
.stop_ap = rwnx_cfg80211_stop_ap, .stop_ap = rwnx_cfg80211_stop_ap,
.set_monitor_channel = rwnx_cfg80211_set_monitor_channel, .set_monitor_channel = RWNX_CFG80211_SET_MONITOR_CHANNEL_CB,
.probe_client = rwnx_cfg80211_probe_client, .probe_client = rwnx_cfg80211_probe_client,
// .mgmt_frame_register = rwnx_cfg80211_mgmt_frame_register, // .mgmt_frame_register = rwnx_cfg80211_mgmt_frame_register,
.set_wiphy_params = rwnx_cfg80211_set_wiphy_params, .set_wiphy_params = RWNX_CFG80211_SET_WIPHY_PARAMS_CB,
.set_txq_params = rwnx_cfg80211_set_txq_params, .set_txq_params = rwnx_cfg80211_set_txq_params,
.set_tx_power = rwnx_cfg80211_set_tx_power, .set_tx_power = RWNX_CFG80211_SET_TX_POWER_CB,
.get_tx_power = rwnx_cfg80211_get_tx_power, .get_tx_power = RWNX_CFG80211_GET_TX_POWER_CB,
.set_power_mgmt = rwnx_cfg80211_set_power_mgmt, .set_power_mgmt = rwnx_cfg80211_set_power_mgmt,
.get_station = rwnx_cfg80211_get_station, .get_station = rwnx_cfg80211_get_station,
.remain_on_channel = rwnx_cfg80211_remain_on_channel, .remain_on_channel = rwnx_cfg80211_remain_on_channel,
.cancel_remain_on_channel = rwnx_cfg80211_cancel_remain_on_channel, .cancel_remain_on_channel = rwnx_cfg80211_cancel_remain_on_channel,
.dump_survey = rwnx_cfg80211_dump_survey, .dump_survey = rwnx_cfg80211_dump_survey,
.get_channel = rwnx_cfg80211_get_channel, .get_channel = rwnx_cfg80211_get_channel,
.start_radar_detection = rwnx_cfg80211_start_radar_detection, .start_radar_detection = RWNX_CFG80211_START_RADAR_DETECTION_CB,
.update_ft_ies = rwnx_cfg80211_update_ft_ies, .update_ft_ies = rwnx_cfg80211_update_ft_ies,
.set_cqm_rssi_config = rwnx_cfg80211_set_cqm_rssi_config, .set_cqm_rssi_config = rwnx_cfg80211_set_cqm_rssi_config,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+48 -15
View File
@@ -22,6 +22,52 @@
#include "rwnx_events.h" #include "rwnx_events.h"
#include "rwnx_compat.h" #include "rwnx_compat.h"
#ifdef CONFIG_RWNX_FULLMAC
/* OpenWrt can backport cfg80211 helpers without changing LINUX_VERSION_CODE. */
typedef void (*rwnx_cfg80211_cac_event_no_chandef_t)(
struct net_device *netdev, enum nl80211_radar_event event, gfp_t gfp);
typedef void (*rwnx_cfg80211_cac_event_chandef_t)(
struct net_device *netdev, const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event, gfp_t gfp);
typedef void (*rwnx_cfg80211_cac_event_link_t)(
struct net_device *netdev, const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event, gfp_t gfp, unsigned int link_id);
#define RWNX_CFG80211_CAC_EVENT_MATCH(_type) \
__builtin_types_compatible_p(typeof(&cfg80211_cac_event), _type)
typedef char rwnx_cfg80211_cac_event_signature_must_be_supported[
(RWNX_CFG80211_CAC_EVENT_MATCH(
rwnx_cfg80211_cac_event_no_chandef_t) ||
RWNX_CFG80211_CAC_EVENT_MATCH(rwnx_cfg80211_cac_event_chandef_t) ||
RWNX_CFG80211_CAC_EVENT_MATCH(rwnx_cfg80211_cac_event_link_t)) ? 1 : -1];
static void rwnx_cfg80211_cac_event_compat(
struct net_device *netdev, const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event, gfp_t gfp)
{
union {
typeof(&cfg80211_cac_event) actual;
rwnx_cfg80211_cac_event_no_chandef_t no_chandef;
rwnx_cfg80211_cac_event_chandef_t chandef;
rwnx_cfg80211_cac_event_link_t link;
} helper = { .actual = &cfg80211_cac_event };
if (RWNX_CFG80211_CAC_EVENT_MATCH(
rwnx_cfg80211_cac_event_no_chandef_t)) {
helper.no_chandef(netdev, event, gfp);
return;
}
if (RWNX_CFG80211_CAC_EVENT_MATCH(rwnx_cfg80211_cac_event_link_t)) {
helper.link(netdev, chandef, event, gfp, 0);
return;
}
helper.chandef(netdev, chandef, event, gfp);
}
#endif
/* /*
* tolerated deviation of radar time stamp in usecs on both sides * tolerated deviation of radar time stamp in usecs on both sides
* TODO: this might need to be HW-dependent * TODO: this might need to be HW-dependent
@@ -1471,15 +1517,8 @@ static void rwnx_radar_cac_work(struct work_struct *ws)
} }
ctxt = &rwnx_hw->chanctx_table[radar->cac_vif->ch_index]; ctxt = &rwnx_hw->chanctx_table[radar->cac_vif->ch_index];
cfg80211_cac_event(radar->cac_vif->ndev, rwnx_cfg80211_cac_event_compat(radar->cac_vif->ndev, &ctxt->chan_def,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
&ctxt->chan_def,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0);
#else
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
#endif
rwnx_send_apm_stop_cac_req(rwnx_hw, radar->cac_vif); rwnx_send_apm_stop_cac_req(rwnx_hw, radar->cac_vif);
rwnx_chanctx_unlink(radar->cac_vif); rwnx_chanctx_unlink(radar->cac_vif);
@@ -1613,15 +1652,9 @@ void rwnx_radar_cancel_cac(struct rwnx_radar *radar)
struct rwnx_chanctx *ctxt; struct rwnx_chanctx *ctxt;
ctxt = &rwnx_hw->chanctx_table[radar->cac_vif->ch_index]; ctxt = &rwnx_hw->chanctx_table[radar->cac_vif->ch_index];
rwnx_send_apm_stop_cac_req(rwnx_hw, radar->cac_vif); rwnx_send_apm_stop_cac_req(rwnx_hw, radar->cac_vif);
cfg80211_cac_event(radar->cac_vif->ndev, rwnx_cfg80211_cac_event_compat(radar->cac_vif->ndev,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
&ctxt->chan_def, &ctxt->chan_def,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0);
#else
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
#endif
rwnx_chanctx_unlink(radar->cac_vif); rwnx_chanctx_unlink(radar->cac_vif);
} }
+58 -12
View File
@@ -34,6 +34,60 @@
#define IEEE80211_MAX_CHAINS 4 #define IEEE80211_MAX_CHAINS 4
#endif #endif
/* OpenWrt can backport these helpers without changing LINUX_VERSION_CODE. */
typedef bool (*rwnx_cfg80211_rx_frame_legacy_t)(struct net_device *dev,
const u8 *addr, gfp_t gfp);
typedef bool (*rwnx_cfg80211_rx_frame_link_t)(struct net_device *dev,
const u8 *addr, int link_id,
gfp_t gfp);
#define RWNX_CFG80211_HELPER_MATCH(_helper, _type) \
__builtin_types_compatible_p(typeof(&(_helper)), _type)
typedef char rwnx_cfg80211_rx_spurious_frame_signature_must_be_supported[
(RWNX_CFG80211_HELPER_MATCH(cfg80211_rx_spurious_frame,
rwnx_cfg80211_rx_frame_legacy_t) ||
RWNX_CFG80211_HELPER_MATCH(cfg80211_rx_spurious_frame,
rwnx_cfg80211_rx_frame_link_t)) ? 1 : -1];
typedef char rwnx_cfg80211_rx_unexpected_4addr_frame_signature_must_be_supported[
(RWNX_CFG80211_HELPER_MATCH(cfg80211_rx_unexpected_4addr_frame,
rwnx_cfg80211_rx_frame_legacy_t) ||
RWNX_CFG80211_HELPER_MATCH(cfg80211_rx_unexpected_4addr_frame,
rwnx_cfg80211_rx_frame_link_t)) ? 1 : -1];
static bool rwnx_cfg80211_rx_spurious_frame_compat(struct net_device *dev,
const u8 *addr, gfp_t gfp)
{
union {
typeof(&cfg80211_rx_spurious_frame) actual;
rwnx_cfg80211_rx_frame_legacy_t legacy;
rwnx_cfg80211_rx_frame_link_t link;
} helper = { .actual = &cfg80211_rx_spurious_frame };
if (RWNX_CFG80211_HELPER_MATCH(cfg80211_rx_spurious_frame,
rwnx_cfg80211_rx_frame_link_t))
return helper.link(dev, addr, -1, gfp);
return helper.legacy(dev, addr, gfp);
}
static bool rwnx_cfg80211_rx_unexpected_4addr_frame_compat(
struct net_device *dev, const u8 *addr, gfp_t gfp)
{
union {
typeof(&cfg80211_rx_unexpected_4addr_frame) actual;
rwnx_cfg80211_rx_frame_legacy_t legacy;
rwnx_cfg80211_rx_frame_link_t link;
} helper = { .actual = &cfg80211_rx_unexpected_4addr_frame };
if (RWNX_CFG80211_HELPER_MATCH(cfg80211_rx_unexpected_4addr_frame,
rwnx_cfg80211_rx_frame_link_t))
return helper.link(dev, addr, -1, gfp);
return helper.legacy(dev, addr, gfp);
}
u8 dhcped = 0; u8 dhcped = 0;
u16 tx_legrates_lut_rate[] = { u16 tx_legrates_lut_rate[] = {
@@ -2394,11 +2448,8 @@ check_len_update:
hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset); hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset);
rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx); rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx);
if (rwnx_vif) { if (rwnx_vif) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) rwnx_cfg80211_rx_spurious_frame_compat(rwnx_vif->ndev,
cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, -1, GFP_ATOMIC); hdr->addr2, GFP_ATOMIC);
#else
cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, GFP_ATOMIC);
#endif
} }
goto end; goto end;
} }
@@ -2741,13 +2792,8 @@ check_len_update:
if (hw_rxhdr->flags_is_4addr && !rwnx_vif->use_4addr) { if (hw_rxhdr->flags_is_4addr && !rwnx_vif->use_4addr) {
printk("aicwf: 4addr flag error\n"); printk("aicwf: 4addr flag error\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) rwnx_cfg80211_rx_unexpected_4addr_frame_compat(
cfg80211_rx_unexpected_4addr_frame(rwnx_vif->ndev, rwnx_vif->ndev, sta->mac_addr, GFP_ATOMIC);
sta->mac_addr, -1, GFP_ATOMIC);
#else
cfg80211_rx_unexpected_4addr_frame(rwnx_vif->ndev,
sta->mac_addr, GFP_ATOMIC);
#endif
} }
} }