diff --git a/.github/workflows/multi-arch-test-build.yml b/.github/workflows/multi-arch-test-build.yml index aa45eb4bf830b..58613a01a6b58 100644 --- a/.github/workflows/multi-arch-test-build.yml +++ b/.github/workflows/multi-arch-test-build.yml @@ -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} + ]} diff --git a/net/prplmesh/Makefile b/net/prplmesh/Makefile index 09a0d76555be4..4613ed1260421 100644 --- a/net/prplmesh/Makefile +++ b/net/prplmesh/Makefile @@ -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)/ diff --git a/net/prplmesh/patches/175-set-imported-client-bssid.patch b/net/prplmesh/patches/175-set-imported-client-bssid.patch new file mode 100644 index 0000000000000..312b555e8c4f9 --- /dev/null +++ b/net/prplmesh/patches/175-set-imported-client-bssid.patch @@ -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 parse_sta_block(const std::string &reply, int vap_id, bool radio_5G, ++static std::shared_ptr 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 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"; diff --git a/net/prplmesh/patches/176-handle-empty-imported-association-frame.patch b/net/prplmesh/patches/176-handle-empty-imported-association-frame.patch new file mode 100644 index 0000000000000..179e32281a8b3 --- /dev/null +++ b/net/prplmesh/patches/176-handle-empty-imported-association-frame.patch @@ -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()) { diff --git a/net/prplmesh/patches/180-mark-topology-reported-clients-connected.patch b/net/prplmesh/patches/180-mark-topology-reported-clients-connected.patch new file mode 100644 index 0000000000000..cd1532d0c6615 --- /dev/null +++ b/net/prplmesh/patches/180-mark-topology-reported-clients-connected.patch @@ -0,0 +1,59 @@ +From 4a53626de35419a859a071aa345a3eeb6bcb4b7d Mon Sep 17 00:00:00 2001 +From: Andrei Ovcharenko +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 +--- + 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; + } + diff --git a/net/prplmesh/test-version.sh b/net/prplmesh/test-version.sh index 0edd7c654ec53..e04d577c0635d 100644 --- a/net/prplmesh/test-version.sh +++ b/net/prplmesh/test-version.sh @@ -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