Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/multi-arch-test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,18 @@ jobs:
build:
name: Feeds Package Test Build
uses: openwrt/actions-shared-workflows/.github/workflows/multi-arch-test-build.yml@main
with:
matrix: >-
{"include":[
{"arch":"aarch64_cortex-a53","target":"mediatek-mt7622","runtime_test":false},
{"arch":"aarch64_generic","target":"armsr-armv8","runtime_test":true},
{"arch":"arm_cortex-a15_neon-vfpv4","target":"armsr-armv7","runtime_test":true},
{"arch":"arm_cortex-a9_vfpv3-d16","target":"mvebu-cortexa9","runtime_test":false},
{"arch":"i386_pentium-mmx","target":"x86-geode","runtime_test":true},
{"arch":"mips_24kc","target":"ath79-generic","runtime_test":true},
{"arch":"mipsel_24kc","target":"mt7621","runtime_test":false},
{"arch":"powerpc_464fp","target":"apm821xx-nand","runtime_test":false},
{"arch":"powerpc_8548","target":"mpc85xx-p1010","runtime_test":false},
{"arch":"riscv64_generic","target":"sifiveu-generic","runtime_test":false},
{"arch":"x86_64","target":"x86-64","runtime_test":true}
]}
2 changes: 1 addition & 1 deletion net/prplmesh/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk

PKG_NAME:=prplmesh
PKG_VERSION:=6.0.1
PKG_RELEASE:=1
PKG_RELEASE:=9

PKG_SOURCE:=prplMesh-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://gitlab.com/prpl-foundation/prplmesh/prplMesh/-/archive/$(PKG_VERSION)/
Expand Down
33 changes: 33 additions & 0 deletions net/prplmesh/patches/175-set-imported-client-bssid.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--- a/common/beerocks/bwl/nl80211/ap_wlan_hal_nl80211.cpp
+++ b/common/beerocks/bwl/nl80211/ap_wlan_hal_nl80211.cpp
@@ -1392,7 +1392,8 @@ static void sta_caps_from_rates(const in
// notification. Returns nullptr on malformed input. A station that has not
// completed association carries no connected_time line; it is reported
// through @a associated so the caller can skip it but keep iterating.
-static std::shared_ptr<char> parse_sta_block(const std::string &reply, int vap_id, bool radio_5G,
+static std::shared_ptr<char> parse_sta_block(const std::string &reply, int vap_id,
+ const sMacAddr &bssid, bool radio_5G,
bool &associated, sMacAddr &mac_out)
{
std::istringstream stream(reply);
@@ -1433,6 +1434,7 @@ static std::shared_ptr<char> parse_sta_b

msg->params.vap_id = vap_id;
msg->params.mac = mac_out;
+ msg->params.bssid = bssid;
msg->params.capabilities = {};

int supported_rates[16] = {0};
@@ -1545,8 +1547,10 @@ bool ap_wlan_hal_nl80211::generate_conne

bool associated = false;
sMacAddr sta_mac;
- auto msg_buff = parse_sta_block(text, m_vap_id_in_progress, get_radio_info().is_5ghz,
- associated, sta_mac);
+ auto msg_buff =
+ parse_sta_block(text, m_vap_id_in_progress,
+ tlvf::mac_from_string(vap_it->second.mac),
+ get_radio_info().is_5ghz, associated, sta_mac);
if (!msg_buff) {
LOG(WARNING) << "Malformed station block on " << vap_iface
<< ", skipping the rest of this VAP";
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--- a/agent/src/beerocks/slave/son_slave_thread.cpp
+++ b/agent/src/beerocks/slave/son_slave_thread.cpp
@@ -2607,10 +2607,15 @@ bool slave_thread::process_client_associ
return false;
}

+ const auto association_frame_length = notification_in->association_frame_length();
+ uint8_t empty_association_frame = 0;
+ auto association_frame = association_frame_length > 0
+ ? notification_in->association_frame()
+ : &empty_association_frame;
radio->associated_clients.emplace(
- client_mac, AgentDB::sRadio::sClient{bssid, notification_in->association_frame_length(),
- notification_in->association_frame(),
- notification_in->capabilities().btm_supported});
+ client_mac,
+ AgentDB::sRadio::sClient{bssid, association_frame_length, association_frame,
+ notification_in->capabilities().btm_supported});

auto pending_wds_it = m_pending_wds_iface_notifications.find(client_mac);
if (pending_wds_it != m_pending_wds_iface_notifications.end()) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
From 4a53626de35419a859a071aa345a3eeb6bcb4b7d Mon Sep 17 00:00:00 2001
From: Andrei Ovcharenko <[email protected]>
Date: Mon, 14 Sep 2026 00:47:00 +0300
Subject: [PATCH] controller: mark topology-reported clients connected

Some agents send a topology notification without the optional client
association event. The controller then falls back to a topology query and
adds every station from the Associated Clients TLV, but add_station() leaves
new entries disconnected. Subsequent topology responses see the entry under
its BSS and skip it, so BML omits a client that remains associated in hostapd.

Reconcile the state of every currently reported station after applying the
topology snapshot, but only when it is attached to a BSS of the reporting
agent. add_station() can return an existing station even when BSS lookup
fails, so a non-null station alone is not enough to complete a connection.
Initialize the Wi-Fi interface type, channel and VAP ID as in the ordinary
association-notification path; new stations otherwise retain Ethernet
defaults and never receive wireless association handling.

Signed-off-by: Andrei Ovcharenko <[email protected]>
---
controller/src/beerocks/master/tasks/topology_task.cpp | 26 ++++++++++++++++++++
1 file changed, 26 insertions(+)

--- a/controller/src/beerocks/master/tasks/topology_task.cpp
+++ b/controller/src/beerocks/master/tasks/topology_task.cpp
@@ -884,6 +884,32 @@ bool topology_task::handle_associated_cl
database.add_station(agent.al_mac, sta_mac, current_bssid);
}

+ // A topology response is authoritative for the current association state. If the agent
+ // omitted the optional Client Association Event TLV, add_station() above creates the
+ // station but intentionally leaves it disconnected. The next topology response then sees
+ // the station under its BSS and would keep skipping it forever, which also hides it from
+ // BML. Reconcile every station in the reported snapshot, including stale entries created
+ // by an earlier response.
+ for (const auto &connected_pair : current_connected) {
+ auto station = database.get_station(connected_pair.first);
+ auto bss = database.get_bss(connected_pair.second, agent.al_mac);
+ if (!station || !bss || station->get_bss() != bss) {
+ // Do not complete a failed BSS lookup or a station attached to another agent.
+ continue;
+ }
+
+ const auto client_mac = tlvf::mac_to_string(connected_pair.first);
+ database.set_sta_backhaul_iface_type(connected_pair.first,
+ beerocks::IFACE_TYPE_WIFI_UNSPECIFIED);
+ database.set_sta_wifi_channel(connected_pair.first,
+ database.get_radio_wifi_channel(bss->radio.radio_uid));
+ database.set_sta_vap_id(client_mac, database.get_bss_vap_id(bss->bssid));
+
+ if (station->state != beerocks::STATE_CONNECTED) {
+ son_actions::handle_completed_connection(database, cmdu_tx, tasks, client_mac);
+ }
+ }
+
return true;
}

16 changes: 12 additions & 4 deletions net/prplmesh/test-version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
set -eu

case "$PKG_NAME" in
prplmesh)
grep -F "prplmesh_version=$PKG_VERSION" /usr/share/prplmesh/config/version
;;
prplmesh) ;;
*)
echo "Untested package: $PKG_NAME" >&2
echo "Unexpected package: $PKG_NAME" >&2
exit 1
;;
esac

[ -n "$PKG_VERSION" ]

# These entry points handle --version before configuration or daemon startup.
# In particular, ieee1905_transport ignores version flags and starts its broker;
# do not let the generic flag sweep start it repeatedly in the test container.
for binary in beerocks_agent beerocks_controller; do
output="$(timeout --kill-after=5s 10s "/usr/libexec/prplmesh/bin/$binary" --version 2>&1)"
printf '%s\n' "$output" | grep -F "$binary $PKG_VERSION ("
done
Loading