fix: select monitor-channel callback from cfg80211 header type

Keep the internal monitor-channel API independent of kernel versions and select a correctly typed cfg80211 adapter at compile time. This covers Ubuntu 6.8.0-147 and stable/backports without release-string heuristics or function-pointer casts.

Validation: reproduced the original failure on Ubuntu 6.8.0-147; all three modules build on 6.8.0-146, 6.8.0-147 and 6.17.0-14. Fixes #107.
This commit is contained in:
Shen Mintao committed 2026-10-19 11:31:26 +08:00
1 parent 43db8006cb
commit a827d291bb
6 files changed
+16 -67

No files matched your search

+4 -2
View File
@@ -49,8 +49,10 @@ it to the host kernel version or redefine `LINUX_VERSION_CODE`.
## Compatibility scope ## Compatibility scope
The override selects the wireless API changes since Linux 6.12, including The override selects the wireless API changes since Linux 6.12, including
monitor-channel callbacks, radio/link arguments, radar notifications and radio/link arguments, radar notifications and newer cfg80211 callbacks.
newer cfg80211 callbacks. Timer, USB, memory-management and module namespace The monitor-channel callback is selected from the actual cfg80211 header type
so distribution backports also work without changing the version override.
Timer, USB, memory-management and module namespace
checks continue to use the target kernel version. Older target kernels with checks continue to use the target kernel version. Older target kernels with
newer backports may need additional wireless API adaptations. newer backports may need additional wireless API adaptations.
@@ -1832,19 +1832,10 @@ void set_vendor_extension_ie(char *command){
} }
#endif//CONFIG_SET_VENDOR_EXTENSION_IE #endif//CONFIG_SET_VENDOR_EXTENSION_IE
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef);
#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);
#endif
int rwnx_atoi2(char *value, int c_len); int rwnx_atoi2(char *value, int c_len);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter)
#else
void set_mon_chan(struct rwnx_vif *vif, char *parameter) void set_mon_chan(struct rwnx_vif *vif, char *parameter)
#endif
{ {
struct cfg80211_chan_def *chandef = NULL; struct cfg80211_chan_def *chandef = NULL;
int freq = 0; int freq = 0;
@@ -1867,11 +1858,7 @@ void set_mon_chan(struct rwnx_vif *vif, char *parameter)
chandef->center_freq1 = chandef->chan->center_freq; chandef->center_freq1 = chandef->chan->center_freq;
chandef->center_freq2 = 0; chandef->center_freq2 = 0;
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, dev, chandef);
#else
rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, chandef); rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, chandef);
#endif
vfree(chandef->chan); vfree(chandef->chan);
vfree(chandef); vfree(chandef);
@@ -2136,11 +2123,7 @@ int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
char *set_parameter; char *set_parameter;
skip = strlen(CMD_SET_MON_FREQ) + 1; skip = strlen(CMD_SET_MON_FREQ) + 1;
set_parameter = command + skip; set_parameter = command + skip;
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
set_mon_chan(vif, net, set_parameter);
#else
set_mon_chan(vif, set_parameter); set_mon_chan(vif, set_parameter);
#endif
ret = 0; ret = 0;
goto exit; goto exit;
} }
@@ -62,11 +62,7 @@ int get_cs_info(struct rwnx_vif *vif, u8 *mac_addr, u8 *val);
unsigned int command_strtoul(const char *cp, char **endp, unsigned int base); unsigned int command_strtoul(const char *cp, char **endp, unsigned int base);
int str_starts(const char *str, const char *start); int str_starts(const char *str, const char *start);
int handle_private_cmd(struct net_device *net, char *command, u32 cmd_len); int handle_private_cmd(struct net_device *net, char *command, u32 cmd_len);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter);
#else
void set_mon_chan(struct rwnx_vif *vif, char *parameter); void set_mon_chan(struct rwnx_vif *vif, char *parameter);
#endif
#endif /* _AIC_PRIV_CMD_H_ */ #endif /* _AIC_PRIV_CMD_H_ */
@@ -28,28 +28,6 @@
#define AICWF_CFG80211_VERSION_CODE LINUX_VERSION_CODE #define AICWF_CFG80211_VERSION_CODE LINUX_VERSION_CODE
#endif #endif
/*
* cfg80211_ops.set_monitor_channel() gained a "struct net_device *dev"
* parameter. The change went into mainline 6.13, but it was also
* backported to the 6.12 stable series starting with 6.12.101, so a
* plain ">= 6.13.0" test misses 6.12.101 and later. Those kernels then
* compile against the old prototype, which is fatal with
* -Wincompatible-pointer-types:
*
* rwnx_main.c: error: initialization of
* 'int (*)(struct wiphy *, struct net_device *, struct cfg80211_chan_def *)'
* from incompatible pointer type
* 'int (*)(struct wiphy *, struct cfg80211_chan_def *)'
*
* Debian 13 (6.12.107) is one such kernel. The 6.12.101 threshold
* covers both the backport and mainline, and leaves 6.11 and earlier
* 6.12.x on the old prototype. Keep the check in one place so every
* consumer stays in sync.
*/
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 12, 101)
#define AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
#error "Minimum kernel version supported is 3.10" #error "Minimum kernel version supported is 3.10"
#endif #endif
+12 -16
View File
@@ -4451,13 +4451,8 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
} }
#endif #endif
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
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, static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
#endif
{ {
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;
@@ -4511,21 +4506,19 @@ static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy,
} }
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV /* Newer cfg80211 stacks pass dev; the firmware still has one monitor vif. */
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, static int rwnx_cfg80211_set_monitor_channel_with_dev(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); return rwnx_cfg80211_set_monitor_channel(wiphy, chandef);
} }
#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(wiphy, chandef);
} }
#endif
/** /**
* @probe_peer: probe an associated client. Before 7.3 the driver returns a * @probe_peer: probe an associated client. Before 7.3 the driver returns a
@@ -5119,11 +5112,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
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
rwnx_cfg80211_set_monitor_channel(wiphy, wdev->netdev, NULL);
#else
rwnx_cfg80211_set_monitor_channel(wiphy, NULL); rwnx_cfg80211_set_monitor_channel(wiphy, NULL);
#endif
} }
//Check if channel context is valid //Check if channel context is valid
@@ -6677,7 +6666,14 @@ 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, /* Select the actual header ABI, including distro/stable backports such
* as Ubuntu 6.8.0-147 and Linux 6.12.101. No function-pointer casts. */
.set_monitor_channel = __builtin_choose_expr(
__builtin_types_compatible_p(
typeof(((struct cfg80211_ops *)0)->set_monitor_channel),
typeof(&rwnx_cfg80211_set_monitor_channel_with_dev)),
rwnx_cfg80211_set_monitor_channel_with_dev,
rwnx_cfg80211_set_monitor_channel),
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0) #if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
.probe_peer = rwnx_cfg80211_probe_client, .probe_peer = rwnx_cfg80211_probe_client,
#else #else
-6
View File
@@ -91,14 +91,8 @@ void aicwf_p2p_alive_timeout(struct timer_list *t);
int rwnx_send_check_p2p(struct cfg80211_scan_request *param); int rwnx_send_check_p2p(struct cfg80211_scan_request *param);
void apm_staloss_work_process(struct work_struct *work); void apm_staloss_work_process(struct work_struct *work);
void apm_probe_sta_work_process(struct work_struct *work); void apm_probe_sta_work_process(struct work_struct *work);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef);
#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);
#endif
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0) #if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev, int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 cookie); const u8 *peer, u64 cookie);