Skip to content
Open
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
122 changes: 122 additions & 0 deletions net/prplmesh-stock/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=prplmesh-stock
PKG_VERSION:=6.0.1
PKG_RELEASE:=1
PKG_SOURCE:=prplMesh-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://gitlab.com/prpl-foundation/prplmesh/prplMesh/-/archive/$(PKG_VERSION)/
PKG_HASH:=68602c7bdf521de1797c0e58e66bb45cf105726dfd5a75d8429038012e19a702
PKG_BUILD_DIR:=$(BUILD_DIR)/prplMesh-$(PKG_VERSION)

HOSTAPD_SOURCE_DATE:=2025.08.26
HOSTAPD_SOURCE_VERSION:=ca266cc24d8705eb1a2a0857ad326e48b1408b20
HOSTAPD_SOURCE:=hostapd-$(HOSTAPD_SOURCE_DATE)~$(call version_abbrev,$(HOSTAPD_SOURCE_VERSION)).tar.zst
HOSTAPD_SOURCE_URL:=https://w1.fi/hostap.git
HOSTAPD_SOURCE_PROTO:=git
HOSTAPD_MIRROR_HASH:=59ac677093f524ff98588abd9f33805a336a6e929d6814222f0d784c854f2343
HOSTAPD_BUILD_ROOT:=$(BUILD_DIR)/$(PKG_NAME)-hostapd-source
HOSTAPD_BUILD_DIR:=$(HOSTAPD_BUILD_ROOT)/hostapd-$(HOSTAPD_SOURCE_DATE)~$(call version_abbrev,$(HOSTAPD_SOURCE_VERSION))
HOSTAPD_OPENWRT_CTRL_PATCH:=$(CURDIR)/files/610-hostapd_cli_ujail_permission.patch
HOSTAPD_WPA_CTRL_HASHER:=$(STAGING_DIR_HOST)/bin/mkhash
HOSTAPD_WPA_CTRL_RAW_SHA256:=482839d354b9c53e19e6a766ff5be054980607dd94e53efee9762dbda40f0f26
HOSTAPD_WPA_CTRL_PATCHED_SHA256:=ad925b710901b3f2f2188afdab5a7f181913e48b159a824c30e0c19d2acd53fa
Comment on lines +11 to +22

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have strong concerns regarding bundling/vendoring a custom, frozen copy of hostapd inside this package. As we can see, the version used here is already old and missing critical security fixes that are present in the core OpenWrt repo (see hostapd commits), where it is actively updated.

Additionally, it introduces unnecessary custom variables that shouldn't be there and just make the code harder to maintain.

Could you please consider another solution that fits your needs while reusing the system hostapd?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. To clarify, the package does not install or run the downloaded hostapd; that source is only used at build time for the control client, while runtime connects to the existing wpad. Still, I agree that freezing a second copy, duplicating OpenWrt's 610 patch, and installing under /opt are not acceptable maintenance choices here. I'll rework the integration to avoid the vendored hostapd source and use standard OpenWrt paths before requesting another review.


PKG_LICENSE:=BSD-2-Clause-Patent BSD-3-Clause ISC MIT
PKG_LICENSE_FILES:=LICENSE LICENSES/BSD-3-Clause.txt LICENSES/ISC.txt LICENSES/MIT.txt LICENSES/hostapd-COPYING
PKG_MAINTAINER:=Andrei Ovcharenko <a@krot.name>

PKG_BUILD_PARALLEL:=1
PKG_INSTALL:=1
PKG_BUILD_DEPENDS:=python-yaml/host
CMAKE_BINARY_SUBDIR:=build-openwrt-stock

include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
include ../../lang/python/python3-host.mk

EXTRA_CXXFLAGS += -Wno-error=deprecated-declarations

define Download/hostapd
FILE:=$(HOSTAPD_SOURCE)
URL:=$(HOSTAPD_SOURCE_URL)
PROTO:=$(HOSTAPD_SOURCE_PROTO)
SOURCE_VERSION:=$(HOSTAPD_SOURCE_VERSION)
SUBDIR:=hostapd-$(HOSTAPD_SOURCE_DATE)~$(call version_abbrev,$(HOSTAPD_SOURCE_VERSION))
MIRROR_HASH:=$(HOSTAPD_MIRROR_HASH)
endef
$(eval $(call Download,hostapd))

define Package/prplmesh-stock
SECTION:=net
CATEGORY:=Network
TITLE:=prplMesh controller and agent for stock OpenWrt
URL:=https://gitlab.com/prpl-foundation/prplmesh/prplMesh
DEPENDS:=+libstdcpp +libpthread +librt +libjson-c +libopenssl +libnl-core +libnl-genl +libnl-route +libuci +libubus +libubox
endef

define Package/prplmesh-stock/description
prplMesh controller and agent build for stock OpenWrt. It uses the existing
hostapd control sockets and never replaces the installed wpad.
Comment on lines +58 to +59

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Uses existing things, but it is using own custom copy of hostapd. :-)

endef

define Package/prplmesh-stock/conffiles
/etc/config/prplmesh
endef

CMAKE_OPTIONS += \
-DTARGET_PLATFORM=openwrt \
-DTARGET_PLATFORM_TYPE=stock \
-DBWL_TYPE=NL80211 \
-DENABLE_NBAPI=OFF \
-DUSE_PRPLMESH_WHM=OFF \
-DPRPLMESH_STOCK_OPENWRT_UCI=ON \
-DBUILD_AGENT=ON \
-DBUILD_CONTROLLER=ON \
-DBUILD_TESTS=OFF \
-DPRPLMESH_VERSION=$(PKG_VERSION) \
-DPRPLMESH_REVISION=openwrt-r$(PKG_RELEASE) \
-DBUILD_DATE=$(SOURCE_DATE_EPOCH) \
-DCMAKE_INSTALL_PREFIX=/opt/prplmesh \
-DPLATFORM_BUILD_DIR=$(BUILD_DIR) \
-DPLATFORM_STAGING_DIR=$(STAGING_DIR) \
-DPLATFORM_INCLUDE_DIR=$(STAGING_DIR)/usr/include \
-DPython3_EXECUTABLE=$(HOST_PYTHON3_BIN) \
-DHOSTAPD_INCLUDE_DIR=$(HOSTAPD_BUILD_DIR)

define Build/Prepare
$(call Build/Prepare/Default)
test "$(HOSTAPD_BUILD_ROOT)" = "$(BUILD_DIR)/$(PKG_NAME)-hostapd-source"
rm -rf -- "$(HOSTAPD_BUILD_ROOT)"
mkdir -p "$(HOSTAPD_BUILD_ROOT)"
$(STAGING_DIR_HOST)/bin/zstdcat $(DL_DIR)/$(HOSTAPD_SOURCE) | \
$(TAR) -C "$(HOSTAPD_BUILD_ROOT)" -xf -
test -f "$(HOSTAPD_BUILD_DIR)/src/common/wpa_ctrl.h"
test -f "$(HOSTAPD_OPENWRT_CTRL_PATCH)"
test -x "$(HOSTAPD_WPA_CTRL_HASHER)"
$(HOSTAPD_WPA_CTRL_HASHER) sha256 "$(HOSTAPD_BUILD_DIR)/src/common/wpa_ctrl.c" | \
grep -qxF "$(HOSTAPD_WPA_CTRL_RAW_SHA256)"
$(PATCH) -d "$(HOSTAPD_BUILD_DIR)" -p1 --forward < "$(HOSTAPD_OPENWRT_CTRL_PATCH)"
$(HOSTAPD_WPA_CTRL_HASHER) sha256 "$(HOSTAPD_BUILD_DIR)/src/common/wpa_ctrl.c" | \
grep -qxF "$(HOSTAPD_WPA_CTRL_PATCHED_SHA256)"
test -f "$(HOSTAPD_BUILD_DIR)/COPYING"
$(INSTALL_DATA) "$(HOSTAPD_BUILD_DIR)/COPYING" "$(PKG_BUILD_DIR)/LICENSES/hostapd-COPYING"
test -f "$(PKG_BUILD_DIR)/LICENSES/hostapd-COPYING"
endef

define Build/Clean
test "$(HOSTAPD_BUILD_ROOT)" = "$(BUILD_DIR)/$(PKG_NAME)-hostapd-source"
rm -rf -- "$(HOSTAPD_BUILD_ROOT)"
endef

define Package/prplmesh-stock/install
$(INSTALL_DIR) $(1)/opt/prplmesh $(1)/usr/lib $(1)/etc/init.d $(1)/etc/config
$(CP) $(PKG_INSTALL_DIR)/opt/prplmesh/bin $(1)/opt/prplmesh/
$(CP) $(PKG_INSTALL_DIR)/opt/prplmesh/scripts $(1)/opt/prplmesh/
$(CP) $(PKG_INSTALL_DIR)/opt/prplmesh/share $(1)/opt/prplmesh/
$(CP) $(PKG_INSTALL_DIR)/opt/prplmesh/config $(1)/opt/prplmesh/
Comment on lines +113 to +116

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Installing binaries and scripts into /opt/prplmesh goes against OpenWrt packaging standards.

$(CP) $(PKG_INSTALL_DIR)/opt/prplmesh/lib/*.so* $(1)/usr/lib/
$(INSTALL_BIN) ./files/prplmesh.init $(1)/etc/init.d/prplmesh
$(INSTALL_CONF) ./files/prplmesh.config $(1)/etc/config/prplmesh
endef

$(eval $(call BuildPackage,prplmesh-stock))
76 changes: 76 additions & 0 deletions net/prplmesh-stock/files/610-hostapd_cli_ujail_permission.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
From 398cbb76fa88f2d5dcc05b0ecc24ced1bbcad9ca Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@moxienet.com>
Date: Tue, 23 Nov 2021 12:28:55 -0500
Subject: [PATCH] hostapd: allow hostapd under ujail to communicate with
hostapd_cli
Comment on lines +1 to +5

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


When procd-ujail is available, 1f78538 runs hostapd as user
"network", with only limited additional capabilities (CAP_NET_ADMIN and
CAP_NET_RAW).

hostapd_cli (CONFIG_PACKAGE_hostapd-utils) communicates with hostapd
over a named UNIX-domain socket. hostapd_cli is responsible for creating
this socket at /tmp/wpa_ctrl_$pid_$counter. Since it typically runs as
root, this endpoint is normally created with uid root, gid root, mode
0755. As a result, hostapd running as uid network is able to receive
control messages sent through this interface, but is not able to respond
to them. If debug-level logging is enabled (CONFIG_WPA_MSG_MIN_PRIORITY
<= 2 at build, and log_level <= 2 in /etc/config/wireless wifi-device),
this message will appear from hostapd:

CTRL: sendto failed: Permission denied

As a fix, hostapd_cli should create the socket node in the filesystem
with uid network, gid network, mode 0770. This borrows the presently
Android-only strategy already in hostapd intended to solve the same
problem on Android.

If procd-ujail is not available and hostapd falls back to running as
root, it will still be able to read from and write to the socket even if
the node in the filesystem has been restricted to the network user and
group. This matches the logic in
package/network/services/hostapd/files/wpad.init, which sets the uid and
gid of /var/run/hostapd to network regardless of whether procd-ujail is
available.

As it appears that the "network" user and group are statically allocated
uid 101 and gid 101, respectively, per
package/base-files/files/etc/passwd and USERID in
package/network/services/hostapd/Makefile, this patch also uses a
constant 101 for the uid and gid.

Signed-off-by: Mark Mentovai <mark@moxienet.com>

--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -135,7 +135,7 @@ try_again:
return NULL;
}
tries++;
-#ifdef ANDROID
+
/* Set client socket file permissions so that bind() creates the client
* socket with these permissions and there is no need to try to change
* them with chmod() after bind() which would have potential issues with
@@ -147,7 +147,7 @@ try_again:
* operations to allow the response to go through. Those are using the
* no-deference-symlinks version to avoid races. */
fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-#endif /* ANDROID */
+
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
@@ -165,7 +165,11 @@ try_again:
return NULL;
}

-#ifdef ANDROID
+#ifndef ANDROID
+ /* Set group even if we do not have privileges to change owner */
+ lchown(ctrl->local.sun_path, -1, 101);
+ lchown(ctrl->local.sun_path, 101, 101);
+#else
/* Set group even if we do not have privileges to change owner */
lchown(ctrl->local.sun_path, -1, AID_WIFI);
lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
64 changes: 64 additions & 0 deletions net/prplmesh-stock/files/prplmesh.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
config prplmesh 'config'
option enabled '0'
option management_mode 'Multi-AP-Controller-and-Agent'
option enable '1'
option onboarding '0'
option master '1'
option gateway '1'
option passive_mode '0'
option wired_backhaul '1'
option operational '0'
option ssid 'REPLACE_WITH_SSID'
option mode_enabled 'WPA2-Personal'
option key_passphrase 'REPLACE_WITH_A_STRONG_PASSWORD'
option mem_only_psk '0'
option certification_mode '0'
option stop_on_failure_attempts '0'
option backhaul_wire_iface 'br-lan'
option backhaul_band 'auto'
option mandatory_interfaces 'wl0-ap0,wl1-ap0'
option band_steering '1'
option client_11k_roaming '1'
option client_roaming '1'
option load_balancing '0'
option dfs_reentry '1'
option roaming_hysteresis_percent_bonus '10'
option steering_disassoc_timer_msec '200'
option link_metrics_request_interval_sec '60'
option clients_measurement_mode '1'
option radio_stats_enable '1'
option unsuccessful_assoc_report_policy '1'
option unsuccessful_assoc_max_reporting_rate '30'
option ire_roaming '1'
option exclude_hostap_iface '0'
option use_explicit_bss_profiles '1'

config wifi-device 'radio0'
option hostap_iface 'wl0-ap0'
option wireless_section 'default_radio0'
option wireless_device 'radio0'
option hostap_iface_steer_vaps 'wl0-ap0'
option dcs_enable '0'

config wifi-device 'radio1'
option hostap_iface 'wl1-ap0'
option wireless_section 'default_radio1'
option wireless_device 'radio1'
option hostap_iface_steer_vaps 'wl1-ap0'
option dcs_enable '0'

config bss_profile 'main_24_5'
option ssid 'REPLACE_WITH_SSID'
option key 'REPLACE_WITH_A_STRONG_PASSWORD'
option encryption 'sae-mixed'
option bands '2g 5g'
option fronthaul '1'
option backhaul '0'

config bss_profile 'main_6'
option ssid 'REPLACE_WITH_SSID'
option key 'REPLACE_WITH_A_STRONG_PASSWORD'
option encryption 'sae'
option bands '6g'
option fronthaul '1'
option backhaul '0'
63 changes: 63 additions & 0 deletions net/prplmesh-stock/files/prplmesh.init
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/sh /etc/rc.common
# shellcheck disable=SC2034
# shellcheck disable=SC3043 # ash supports local

START=99
STOP=10
USE_PROCD=1

PRPLMESH_DIR=/opt/prplmesh

enabled() {
[ "$(uci -q get prplmesh.config.enabled)" = "1" ]
}

preflight() {
local interfaces interface old_ifs

[ -x "$PRPLMESH_DIR/bin/ieee1905_transport" ] || return 1
[ -x "$PRPLMESH_DIR/bin/beerocks_controller" ] || return 1
[ -x "$PRPLMESH_DIR/bin/beerocks_agent" ] || return 1

interfaces="$(uci -q get prplmesh.config.mandatory_interfaces)"
[ -n "$interfaces" ] || return 1
old_ifs="$IFS"
IFS=,
for interface in $interfaces; do
[ -n "$interface" ] || continue
[ -S "/var/run/hostapd/$interface" ] || {
IFS="$old_ifs"
return 1
}
done
IFS="$old_ifs"
return 0
}

register_process() {
local name="$1"
local executable="$2"
procd_open_instance "$name"
procd_set_param command "$executable"
procd_set_param env PRPLMESH_DIR="$PRPLMESH_DIR"
procd_set_param respawn 3600 5 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}

start_service() {
enabled || return 0
preflight || {
logger -t prplmesh "preflight failed; service left stopped"
return 1
}

register_process transport "$PRPLMESH_DIR/bin/ieee1905_transport"
register_process controller "$PRPLMESH_DIR/bin/beerocks_controller"
register_process agent "$PRPLMESH_DIR/bin/beerocks_agent"
}

service_triggers() {
procd_add_reload_trigger prplmesh wireless network
}
Loading