fix: harden cfg80211 backport ABI handling

This commit is contained in:
Shen Mintao
2026-08-05 10:38:26 +08:00
parent d9688590c2
commit bef3cc252f
2 changed files with 213 additions and 53 deletions
+162 -35
View File
@@ -4420,13 +4420,29 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
}
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef)
#else
static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
#endif
#define RWNX_CFG80211_OP_TYPE(_member) \
typeof(((struct cfg80211_ops *)0)->_member)
#define RWNX_CFG80211_OP_MATCH(_member, _type) \
__builtin_types_compatible_p(RWNX_CFG80211_OP_TYPE(_member), _type)
#define RWNX_CFG80211_OP_ASSERT(_member, _callback) \
typedef char rwnx_cfg80211_##_member##_signature_must_match[ \
__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_vif *rwnx_vif;
@@ -4479,19 +4495,40 @@ static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy,
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))
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct net_device *dev,
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
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
return rwnx_cfg80211_set_monitor_channel(wiphy, chandef);
return rwnx_cfg80211_set_monitor_channel_common(wiphy, chandef);
}
#endif
@@ -4558,11 +4595,6 @@ typedef int (*rwnx_set_wiphy_params_legacy_t)(struct wiphy *wiphy,
typedef int (*rwnx_set_wiphy_params_radio_t)(struct wiphy *wiphy,
int radio_idx, u32 changed);
#define RWNX_CFG80211_OP_TYPE(_member) \
typeof(((struct cfg80211_ops *)0)->_member)
#define RWNX_CFG80211_OP_MATCH(_member, _type) \
__builtin_types_compatible_p(RWNX_CFG80211_OP_TYPE(_member), _type)
typedef char rwnx_set_wiphy_params_signature_must_be_supported[
(RWNX_CFG80211_OP_MATCH(set_wiphy_params,
rwnx_set_wiphy_params_legacy_t) ||
@@ -5122,11 +5154,7 @@ static int rwnx_cfg80211_get_channel(struct wiphy *wiphy,
if (rwnx_vif->vif_index == rwnx_hw->monitor_vif)
{
//retrieve channel from firmware
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
rwnx_cfg80211_set_monitor_channel(wiphy, wdev->netdev, NULL);
#else
rwnx_cfg80211_set_monitor_channel(wiphy, NULL);
#endif
rwnx_cfg80211_set_monitor_channel_common(wiphy, NULL);
}
//Check if channel context is valid
@@ -5313,17 +5341,28 @@ send_frame:
/**
* @start_radar_detection: Start radar detection in the driver.
*/
static
int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
, u32 cac_time_ms
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0))
, int link_id
#endif
)
typedef int (*rwnx_start_radar_detection_legacy_t)(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef);
typedef int (*rwnx_start_radar_detection_cac_t)(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef, u32 cac_time_ms);
typedef int (*rwnx_start_radar_detection_link_t)(
struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef, u32 cac_time_ms, int link_id);
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_vif *rwnx_vif = netdev_priv(dev);
@@ -5331,9 +5370,8 @@ int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy,
printk("%s\n", __func__);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
rwnx_radar_start_cac(&rwnx_hw->radar, cac_time_ms, rwnx_vif);
#endif
if (start_cac_timer)
rwnx_radar_start_cac(&rwnx_hw->radar, cac_time_ms, rwnx_vif);
rwnx_send_apm_start_cac_req(rwnx_hw, rwnx_vif, chandef, &cfm);
if (cfm.status == CO_OK) {
@@ -5351,6 +5389,42 @@ int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy,
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
* driver. If the SME is in the driver/firmware, this information can be
@@ -6643,6 +6717,59 @@ static int rwnx_cfg80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
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 = {
.add_virtual_intf = rwnx_cfg80211_add_iface,
.del_virtual_intf = rwnx_cfg80211_del_iface,
@@ -6664,7 +6791,7 @@ static struct cfg80211_ops rwnx_cfg80211_ops = {
.start_ap = rwnx_cfg80211_start_ap,
.change_beacon = rwnx_cfg80211_change_beacon,
.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,
// .mgmt_frame_register = rwnx_cfg80211_mgmt_frame_register,
.set_wiphy_params = RWNX_CFG80211_SET_WIPHY_PARAMS_CB,
@@ -6677,7 +6804,7 @@ static struct cfg80211_ops rwnx_cfg80211_ops = {
.cancel_remain_on_channel = rwnx_cfg80211_cancel_remain_on_channel,
.dump_survey = rwnx_cfg80211_dump_survey,
.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,
.set_cqm_rssi_config = rwnx_cfg80211_set_cqm_rssi_config,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+51 -18
View File
@@ -22,6 +22,52 @@
#include "rwnx_events.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
* 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];
cfg80211_cac_event(radar->cac_vif->ndev,
#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);
#endif
rwnx_cfg80211_cac_event_compat(radar->cac_vif->ndev, &ctxt->chan_def,
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
rwnx_send_apm_stop_cac_req(rwnx_hw, 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;
ctxt = &rwnx_hw->chanctx_table[radar->cac_vif->ch_index];
rwnx_send_apm_stop_cac_req(rwnx_hw, radar->cac_vif);
cfg80211_cac_event(radar->cac_vif->ndev,
#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_ABORTED, GFP_KERNEL);
#endif
rwnx_cfg80211_cac_event_compat(radar->cac_vif->ndev,
&ctxt->chan_def,
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
rwnx_chanctx_unlink(radar->cac_vif);
}