Compare commits

...

7 Commits

Author SHA1 Message Date
Kumiko18
216f8cece2 WIFI-14996: Support NAT logging
Add support to log NAT translation in kernel.

Signed-off-by: Kumiko18 <alex18_huang@accton.com>
2025-10-23 06:57:25 +00:00
John Crispin
1a3955554a ucentral-schema: update to latest HEAD
dc9cad9 Update state schema to add chanUtil field in radio

Signed-off-by: John Crispin <john@phrozen.org>
2025-10-16 11:10:03 +02:00
John Crispin
427ad99151 ucentral-schema: update to latest HEAD
c836eb5 ssid: fix roaming defaults for PSK and RADIUS configurations

Signed-off-by: John Crispin <john@phrozen.org>
2025-10-09 12:14:13 +02:00
John Crispin
02ed19e3ac ucentral-event: fix VLAN bridge membership during FT roaming
During 802.11r Fast Transition roaming, when a client moves between
APs (e.g., wlan0 to wlan1) with the same dynamic VLAN assignment, the
vlan_add handler's refcount mechanism prevented the new WiFi interface
from being added to the bridge.

When wlan0-v100 and wlan1-v100 exist simultaneously with VLAN ID 100,
the refcount becomes 2, causing vlan_add to exit early for wlan1-v100.
This left wlan1-v100 out of the bridge VLAN table, breaking connectivity
after roaming despite correct VLAN assignment via RADIUS and RRB frames.

Fix by detecting WiFi VLAN interfaces (wlan*-v*) and always adding them
to the bridge regardless of refcount. The refcount mechanism now only
controls WAN port VLAN configuration, which should only occur once per
VLAN ID.

Also reorganise vlan_add/vlan_remove to check swconfig early for clarity.

Signed-off-by: John Crispin <john@phrozen.org>
2025-10-09 12:14:13 +02:00
John Crispin
60968f8c89 profiles: fix syntax error / trailing spaces
Fixes: WIFI-15170
Signed-off-by: John Crispin <john@phrozen.org>
2025-10-08 17:45:53 +02:00
John Crispin
207a592896 ucentral-client: set version to v4.1.1
Signed-off-by: John Crispin <john@phrozen.org>
2025-10-07 11:31:11 +02:00
John Crispin
1bae90f681 ucentral-schema: set version to v4.1.1
Signed-off-by: John Crispin <john@phrozen.org>
2025-10-07 11:30:57 +02:00
12 changed files with 227 additions and 35 deletions

View File

@@ -0,0 +1,39 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=natlog
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_MAINTAINER:=kmk
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/kernel.mk
include $(INCLUDE_DIR)/package.mk
# Define dependencies
define KernelPackage/natlog
SUBMENU:=Netfilter Extensions
TITLE:=NFLOG NAT translation logger
FILES:=$(PKG_BUILD_DIR)/natlog.ko
DEPENDS:=+kmod-nf-conntrack +kmod-nf-ipt
endef
define KernelPackage/natlog/description
Kernel module for logging NAT translations via NFLOG.
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules
endef
define KernelPackage/natlog/install
$(CP) ./files/* $(1)/
endef
$(eval $(call KernelPackage,natlog))

View File

@@ -0,0 +1,2 @@
# config defaults
# option enabled '1'

View File

@@ -0,0 +1,35 @@
#!/bin/sh /etc/rc.common
# OpenWrt init script for natlog kernel module
START=15
STOP=90
USE_PROCD=1
modfile="/lib/modules/$(uname -r)/natlog.ko"
start_service() {
enabled=$(uci get natlog.@defaults[0].enabled 2>/dev/null)
if [ "$enabled" = "1" ]; then
if [ -f "$modfile" ]; then
echo "Loading natlog kernel module..."
insmod "$modfile" || {
echo "Failed to load $modfile"
return 1
}
else
echo "Kernel module not found: $modfile"
return 1
fi
else
echo "natlog disabled in UCI config"
fi
}
stop_service() {
if lsmod | grep -q "^natlog"; then
echo "Unloading natlog kernel module..."
rmmod natlog
fi
}

View File

@@ -0,0 +1 @@
obj-m += natlog.o

View File

@@ -0,0 +1,118 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/netfilter/nfnetlink.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_log.h>
#include <linux/etherdevice.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("KMK");
MODULE_DESCRIPTION("Kernel module to log client request SNAT and server response DNAT using nf_conntrack");
static struct nf_hook_ops nat_hook_ops_pre;
static struct nf_hook_ops nat_hook_ops_post;
static void log_nat_info(struct nf_conn *ct, struct sk_buff *skb, unsigned int hooknum)
{
struct nf_conntrack_tuple *orig_tuple, *reply_tuple;
char *proto_name;
__u16 sport, dport, nat_sport, nat_dport;
__u32 saddr, daddr, nat_saddr, nat_daddr;
unsigned char *mac_addr;
char mac_str[18];
if (!ct)
return;
orig_tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
reply_tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
switch (orig_tuple->dst.protonum) {
case IPPROTO_TCP:
proto_name = "TCP";
break;
case IPPROTO_UDP:
proto_name = "UDP";
break;
default:
return;
}
saddr = orig_tuple->src.u3.ip;
daddr = orig_tuple->dst.u3.ip;
sport = ntohs(orig_tuple->src.u.all);
dport = ntohs(orig_tuple->dst.u.all);
nat_saddr = reply_tuple->dst.u3.ip;
nat_daddr = reply_tuple->src.u3.ip;
nat_sport = ntohs(reply_tuple->dst.u.all);
nat_dport = ntohs(reply_tuple->src.u.all);
if (hooknum == NF_INET_POST_ROUTING && (ct->status & IPS_SRC_NAT)) {
if (!skb_mac_header_was_set(skb))
return;
mac_addr = skb_mac_header(skb);
snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[6], mac_addr[7], mac_addr[8], mac_addr[9], mac_addr[10], mac_addr[11]);
printk(KERN_INFO "NAT_LOG: %s SRC MAC: %s; Original: %pI4:%u -> %pI4:%u, NAT: %pI4:%u -> %pI4:%u\n",
proto_name, mac_str,
&saddr, sport, &daddr, dport,
&nat_saddr, nat_sport, &daddr, dport);
}
}
static unsigned int nat_hook_func(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct nf_conn *ct;
enum ip_conntrack_info ct_info;
ct = nf_ct_get(skb, &ct_info);
if (!ct) {
printk(KERN_DEBUG "NAT_LOG: No conntrack info for packet\n");
return NF_ACCEPT;
}
if (ct->status & IPS_NAT_MASK) {
log_nat_info(ct, skb, state->hook);
}
return NF_ACCEPT;
}
static int __init nat_logger_init(void)
{
int ret;
nat_hook_ops_post.hook = nat_hook_func;
nat_hook_ops_post.pf = PF_INET;
nat_hook_ops_post.hooknum = NF_INET_POST_ROUTING;
nat_hook_ops_post.priority = NF_IP_PRI_NAT_SRC;
ret = nf_register_net_hook(&init_net, &nat_hook_ops_post);
if (ret) {
printk(KERN_ERR "NAT_LOG: Failed to register POST_ROUTING hook: %d\n", ret);
nf_unregister_net_hook(&init_net, &nat_hook_ops_post);
return ret;
}
printk(KERN_INFO "NAT_LOG: Module loaded successfully\n");
return 0;
}
static void __exit nat_logger_exit(void)
{
nf_unregister_net_hook(&init_net, &nat_hook_ops_post);
printk(KERN_INFO "NAT_LOG: Module unloaded\n");
}
module_init(nat_logger_init);
module_exit(nat_logger_exit);

View File

@@ -1,5 +1,5 @@
{
"major": 4,
"minor": 1,
"patch": 0
"patch": 1
}

View File

@@ -275,23 +275,27 @@ handlers = {
},
vlan_add: function(notify) {
let vlan_id = `${notify.data.vlan_id}`;
vlan_refcount[vlan_id] = (vlan_refcount[vlan_id] || 0) + 1;
if (vlan_refcount[vlan_id] > 1) {
return;
}
if (config.config.swconfig)
return handlers.vlan_add_swconfig(notify);
for (let wan in wan_ports) {
let msg = {
name: wan,
vlan: [ `${notify.data.vlan_id}:t` ]
};
ubus.call('network.interface.up_none', 'add_device', msg);
ubus.call('udevstats', 'add_device', { device: wan, vlan: +notify.data.vlan_id });
let vlan_id = `${notify.data.vlan_id}`;
vlan_refcount[vlan_id] = (vlan_refcount[vlan_id] || 0) + 1;
let parts = split(notify.data.ifname, '-v');
let is_wifi_iface = (length(parts) == 2 && wildcard(parts[0], 'wlan*'));
if (vlan_refcount[vlan_id] > 1 && !is_wifi_iface)
return;
if (vlan_refcount[vlan_id] == 1) {
for (let wan in wan_ports) {
let msg = {
name: wan,
vlan: [ `${notify.data.vlan_id}:t` ]
};
ubus.call('network.interface.up_none', 'add_device', msg);
ubus.call('udevstats', 'add_device', { device: wan, vlan: +notify.data.vlan_id });
}
}
let msg = {
@@ -304,16 +308,16 @@ handlers = {
},
vlan_remove: function(notify) {
if (config.config.swconfig)
return;
let vlan_id = `${notify.data.vlan_id}`;
vlan_refcount[vlan_id] = (vlan_refcount[vlan_id] || 1) - 1;
if (vlan_refcount[vlan_id] > 0) {
if (vlan_refcount[vlan_id] > 0)
return;
}
delete vlan_refcount[vlan_id];
if (config.config.swconfig)
return;
for (let wan in wan_ports) {
let msg = {
name: wan,

View File

@@ -4,10 +4,10 @@ PKG_NAME:=ucentral-schema
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git
PKG_MIRROR_HASH:=f72d2e5b01ecb7a488d50d860da63664d992e50c7e046fed866be6733bab3c1c
PKG_MIRROR_HASH:=c0f43db0530a38eb424e81908ad47a14e1d4d8f8a86eb148e34f98187c79ba6b
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2025-09-29
PKG_SOURCE_VERSION:=676e1550c53b7d48a54aa759f65d341168627c5e
PKG_SOURCE_DATE:=2025-10-16
PKG_SOURCE_VERSION:=dc9cad95641266a08de73aab85d931d992090159
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -1,17 +1,12 @@
{
"uuid": 2,
"radios": [
{
"band": "6G",
"country": "CA",
"channel-mode": "HE",
"channel-width": 80
},
{
"band": "5G",
"country": "CA",
"channel-mode": "HE",
"channel-width": 80
"channel-width": 80,
"channel": 36
},
{
"band": "2G",
@@ -57,10 +52,7 @@
"key": "bbbbbbbb"
}
],
"roaming": {
"message-exchange": "ds",
"generate-psk": true
}
"roaming": true
}
]
},

View File

@@ -17,4 +17,4 @@ packages:
- sysstat
- kmod-cig-poe-judgment
diffconfig: |
CONFIG_KERNEL_IPQ_MEM_PROFILE=0
CONFIG_KERNEL_IPQ_MEM_PROFILE=0

View File

@@ -16,4 +16,4 @@ packages:
- sysstat
- kmod-cig-poe-judgment
diffconfig: |
CONFIG_KERNEL_IPQ_MEM_PROFILE=0
CONFIG_KERNEL_IPQ_MEM_PROFILE=0

View File

@@ -68,6 +68,7 @@ packages:
- wireless-regdb
- wpad-openssl
- cloud_discovery
- kmod-natlog
diffconfig: |
CONFIG_OPENSSL_ENGINE=y
CONFIG_OPENSSL_PREFER_CHACHA_OVER_GCM=y