diff mbox series

[RFC] hostapd: Add support for APuP

Message ID mailman.35541.1715363437.1280.openwrt-devel@lists.openwrt.org
State New
Headers show
Series [RFC] hostapd: Add support for APuP | expand

Commit Message

gio--- via openwrt-devel May 10, 2024, 5:48 p.m. UTC
The sender domain has a DMARC Reject/Quarantine policy which disallows
sending mailing list messages using the original "From" header.

To mitigate this problem, the original message has been wrapped
automatically by the mailing list software.
From: Gioacchino Mazzurco <gio@polymathes.cc>

Add support for hostapd Access Point Micro Peering

Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
---
 .../wifi-scripts/files/lib/netifd/hostapd.sh  |  16 +-
 package/network/services/hostapd/Makefile     |   2 +-
 ...ment-APuP-Access-Point-Micro-Peering.patch | 426 ++++++++++++++++++
 ...us-notification-when-a-peer-comes-up.patch |  74 +++
 ...-ucode-hook-for-when-a-peer-comes-up.patch |  83 ++++
 5 files changed, 599 insertions(+), 2 deletions(-)
 create mode 100644 package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch
 create mode 100644 package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch
 create mode 100644 package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch

Comments

Paul Spooren May 13, 2024, 1:57 p.m. UTC | #1
Hi Gio,

> On 10. May 2024, at 19:48, gio--- via openwrt-devel <openwrt-devel@lists.openwrt.org> wrote:
> 
> The sender domain has a DMARC Reject/Quarantine policy which disallows
> sending mailing list messages using the original "From" header.
> 
> To mitigate this problem, the original message has been wrapped
> automatically by the mailing list software.
> From: gio@eigenlab.org
> Subject: [RFC PATCH] hostapd: Add support for APuP
> Date: 10. May 2024 at 19:48:35 GMT+2
> To: openwrt-devel@lists.openwrt.org
> Cc: Gioacchino Mazzurco <gio@polymathes.cc>

Just in time before the Battlemesh, I love it!

Looking forward to test it, thanks for your contribution!

Best,
Paul

> 
> 
> From: Gioacchino Mazzurco <gio@polymathes.cc>
> 
> Add support for hostapd Access Point Micro Peering
> 
> Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
> ---
> .../wifi-scripts/files/lib/netifd/hostapd.sh  |  16 +-
> package/network/services/hostapd/Makefile     |   2 +-
> ...ment-APuP-Access-Point-Micro-Peering.patch | 426 ++++++++++++++++++
> ...us-notification-when-a-peer-comes-up.patch |  74 +++
> ...-ucode-hook-for-when-a-peer-comes-up.patch |  83 ++++
> 5 files changed, 599 insertions(+), 2 deletions(-)
> create mode 100644 package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch
> create mode 100644 package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch
> create mode 100644 package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch
> 
> diff --git a/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh b/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
> index 763702e76b..40266db065 100644
> --- a/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
> +++ b/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
> @@ -383,6 +383,9 @@ hostapd_common_add_bss_config() {
> config_add_string fils_dhcp
> 
> config_add_int ocv
> +
> + config_add_boolean apup
> + config_add_string apup_peer_ifname_prefix
> }
> 
> hostapd_set_vlan_file() {
> @@ -569,7 +572,7 @@ hostapd_set_bss_options() {
> ppsk airtime_bss_weight airtime_bss_limit airtime_sta_weight \
> multicast_to_unicast_all proxy_arp per_sta_vif \
> eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \
> - vendor_elements fils ocv
> + vendor_elements fils ocv apup
> 
> set_default fils 0
> set_default isolate 0
> @@ -593,6 +596,7 @@ hostapd_set_bss_options() {
> set_default airtime_bss_weight 0
> set_default airtime_bss_limit 0
> set_default eap_server 0
> + set_default apup 0
> 
> /usr/sbin/hostapd -vfils || fils=0
> 
> @@ -1163,6 +1167,16 @@ hostapd_set_bss_options() {
> append bss_conf "per_sta_vif=$per_sta_vif" "$N"
> fi
> 
> + if [ "$apup" -gt 0 ]; then
> + append bss_conf "apup=$apup" "$N"
> +
> + local apup_peer_ifname_prefix
> + json_get_vars apup_peer_ifname_prefix
> + if [ -n "$apup_peer_ifname_prefix" ] ; then
> + append bss_conf "apup_peer_ifname_prefix=$apup_peer_ifname_prefix" "$N"
> + fi
> + fi
> +
> json_get_values opts hostapd_bss_options
> for val in $opts; do
> append bss_conf "$val" "$N"
> diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile
> index 0171bc0edc..1eaa67f992 100644
> --- a/package/network/services/hostapd/Makefile
> +++ b/package/network/services/hostapd/Makefile
> @@ -87,7 +87,7 @@ DRIVER_MAKEOPTS= \
> CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \
> CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \
> CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT) \
> - CONFIG_UCODE=y
> + CONFIG_UCODE=y CONFIG_APUP=y
> 
> ifeq ($(SSL_VARIANT),openssl)
>   DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y
> diff --git a/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch b/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch
> new file mode 100644
> index 0000000000..db3a05e3e6
> --- /dev/null
> +++ b/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch
> @@ -0,0 +1,426 @@
> +From 99a9a4e97b4964e12749766de9c57bb7e59e740e Mon Sep 17 00:00:00 2001
> +From: Gioacchino Mazzurco <gio@polymathes.cc>
> +Date: Mon, 6 May 2024 13:53:48 +0200
> +Subject: [PATCH 1/3] Implement APuP Access Point Micro Peering
> +
> +Access Point Micro Peering is a simpler and hopefully more useful successor to
> +Ad Hoc, Wireless Distribution System, 802.11s mesh mode, Multi-AP and EasyMesh.
> +When enabled almost plain APs communicate between them via 4-address mode,
> +like in WDS but all of them are AP, so they can eventually communicate also with
> +plain stations and more AP nodes in sight, without more trickery.
> +APuP has low hardware requirements, just AP mode support + 4-address mode, and
> +no more unnecessary complications, like hardcoded bridging or routing algorithm
> +in WiFi stack.
> +For each AP in sight an interface is created, and then it can be used as
> +convenient in each case, bridging, routing etc.
> +Those interfaces could be simply bridged in a trivial topology (which happens
> +automatically if wds_bridge is not an empty string), or feeded to a
> +routing daemon.
> +
> +Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
> +---
> + hostapd/Makefile             |   5 ++
> + hostapd/config_file.c        |   8 ++
> + src/ap/ap_config.h           |  29 +++++++
> + src/ap/ap_drv_ops.c          |  31 +++++++-
> + src/ap/ap_drv_ops.h          |   3 +
> + src/ap/apup.c                | 149 +++++++++++++++++++++++++++++++++++
> + src/ap/apup.h                |  25 ++++++
> + src/ap/ieee802_11.c          |  11 ++-
> + src/ap/ieee802_11.h          |   2 +
> + src/drivers/driver.h         |   2 +-
> + src/drivers/driver_nl80211.c |  14 +---
> + 11 files changed, 262 insertions(+), 17 deletions(-)
> + create mode 100644 src/ap/apup.c
> + create mode 100644 src/ap/apup.h
> +
> +--- a/hostapd/Makefile
> ++++ b/hostapd/Makefile
> +@@ -1415,6 +1415,11 @@ ifdef CONFIG_NO_TKIP
> + CFLAGS += -DCONFIG_NO_TKIP
> + endif
> + 
> ++ifdef CONFIG_APUP
> ++CFLAGS += -DCONFIG_APUP
> ++OBJS += ../src/ap/apup.o
> ++endif
> ++
> + $(DESTDIR)$(BINDIR)/%: %
> + install -D $(<) $(@)
> + 
> +--- a/hostapd/config_file.c
> ++++ b/hostapd/config_file.c
> +@@ -5058,6 +5058,14 @@ static int hostapd_config_fill(struct ho
> + bss->mld_indicate_disabled = atoi(pos);
> + #endif /* CONFIG_TESTING_OPTIONS */
> + #endif /* CONFIG_IEEE80211BE */
> ++#ifdef CONFIG_APUP
> ++ } else if (os_strcmp(buf, "apup") == 0) {
> ++ bss->apup = !!atoi(pos);
> ++ if(bss->apup) bss->wds_sta = 1;
> ++ } else if (os_strcmp(buf, "apup_peer_ifname_prefix") == 0) {
> ++ os_strlcpy( bss->apup_peer_ifname_prefix,
> ++            pos, sizeof(bss->apup_peer_ifname_prefix) );
> ++#endif // def CONFIG_APUP
> + } else {
> + wpa_printf(MSG_ERROR,
> +   "Line %d: unknown configuration item '%s'",
> +--- a/src/ap/ap_config.h
> ++++ b/src/ap/ap_config.h
> +@@ -970,6 +970,35 @@ struct hostapd_bss_config {
> + bool mld_indicate_disabled;
> + #endif /* CONFIG_TESTING_OPTIONS */
> + #endif /* CONFIG_IEEE80211BE */
> ++
> ++#ifdef CONFIG_APUP
> ++ /**
> ++ * Access Point Micro Peering
> ++ * A simpler and more useful successor to Ad Hoc,
> ++ * Wireless Distribution System, 802.11s mesh mode, Multi-AP and EasyMesh.
> ++ *
> ++ * Almost plain APs communicate between them via 4-address mode, like in WDS
> ++ * but all of them are AP, so they can eventually communicate also with
> ++ * plain stations and more AP nodes in sight.
> ++ * Low hardware requirements, just AP mode support + 4-address mode, and no
> ++ * more unnecessary complications, like hardcoded bridging or routing
> ++ * algorithm in WiFi stack.
> ++ * For each AP in sight an interface is created, and then it can be used as
> ++ * convenient in each case, bridging, routing etc.
> ++ */
> ++ bool apup;
> ++
> ++ /**
> ++ * In 4-address mode each peer AP in sight is associated to its own
> ++ * interface so we have more flexibility in "user-space".
> ++ * Those interfaces could be simply bridged in a trivial topology (which
> ++ * happens automatically if wds_bridge is not an empty string), or feeded to
> ++ * a routing daemon.
> ++ *
> ++ * If not defined interface names are generated following the WDS convention.
> ++ */
> ++ char apup_peer_ifname_prefix[IFNAMSIZ + 1];
> ++#endif /* CONFIG_APUP */
> + };
> + 
> + /**
> +--- a/src/ap/ap_drv_ops.c
> ++++ b/src/ap/ap_drv_ops.c
> +@@ -381,12 +381,39 @@ int hostapd_vlan_if_remove(struct hostap
> + int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
> + const u8 *addr, int aid, int val)
> + {
> +- const char *bridge = NULL;
> +-
> + if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
> + return -1;
> ++
> ++ const char *bridge = NULL;
> ++ char ifName[IFNAMSIZ + 1];
> ++
> ++ int mRet = 0;
> ++
> ++#ifdef CONFIG_APUP
> ++ if(hapd->conf->apup && hapd->conf->apup_peer_ifname_prefix[0])
> ++ {
> ++ mRet = os_snprintf(
> ++            ifName, sizeof(ifName), "%s%d",
> ++            hapd->conf->apup_peer_ifname_prefix, aid );
> ++ }
> ++ else
> ++#endif // def CONFIG_APUP
> ++ mRet = os_snprintf(
> ++            ifName, sizeof(ifName), "%s.sta%d",
> ++            hapd->conf->iface, aid );
> ++
> ++ if (mRet >= (int) sizeof(ifName))
> ++ wpa_printf( MSG_WARNING,
> ++            "nl80211: WDS interface name was truncated" );
> ++ else if (mRet < 0)
> ++ return mRet;
> ++
> ++ // Pass back to the caller the resulting interface name
> ++ if (ifname_wds) os_strlcpy(ifname_wds, ifName, IFNAMSIZ + 1);
> ++
> + if (hapd->conf->wds_bridge[0])
> + bridge = hapd->conf->wds_bridge;
> ++
> + return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
> + bridge, ifname_wds);
> + }
> +--- a/src/ap/ap_drv_ops.h
> ++++ b/src/ap/ap_drv_ops.h
> +@@ -33,6 +33,9 @@ int hostapd_set_drv_ieee8021x(struct hos
> +      int enabled);
> + int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
> + int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
> ++
> ++/** @param val as per nl80211 driver implementation, 1 means add 0 means remove
> ++ */
> + int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
> + const u8 *addr, int aid, int val);
> + int hostapd_sta_add(struct hostapd_data *hapd,
> +--- /dev/null
> ++++ b/src/ap/apup.c
> +@@ -0,0 +1,149 @@
> ++/*
> ++ * hostapd / APuP Access Point Micro Peering
> ++ *
> ++ * Copyright (C) 2023-2024  Gioacchino Mazzurco <gio@polymathes.cc>
> ++ * Copyright (C) 2023-2024  Asociación Civil Altermundi <info@altermundi.net>
> ++ *
> ++ * This software may be distributed under the terms of the BSD license.
> ++ * See README for more details.
> ++ */
> ++
> ++/* Be extremely careful altering include order, move just one in the wrong place
> ++ * and you will start getting a bunch of error of undefined bool, size_t etc. */
> ++
> ++#include "utils/includes.h"
> ++#include "utils/common.h"
> ++#include "utils/os.h"
> ++
> ++#include "apup.h"
> ++
> ++#include "drivers/driver.h"
> ++#include "wpa_auth.h"
> ++#include "ap_mlme.h"
> ++#include "ieee802_11.h"
> ++#include "ap_drv_ops.h"
> ++
> ++void apup_process_beacon(struct hostapd_data *hapd,
> ++              const struct ieee80211_mgmt *mgmt, size_t len,
> ++              const struct ieee802_11_elems *elems )
> ++{
> ++ if(!os_memcmp(hapd->own_addr, mgmt->bssid, ETH_ALEN))
> ++ {
> ++ wpa_printf( MSG_WARNING,
> ++            "apup_process_beacon(...) own beacon elems.ssid %.*s",
> ++            (int) elems->ssid_len, elems->ssid );
> ++ return;
> ++ }
> ++
> ++ if( elems->ssid_len != hapd->conf->ssid.ssid_len ||
> ++        os_memcmp(elems->ssid, hapd->conf->ssid.ssid, elems->ssid_len) )
> ++ return;
> ++
> ++ struct sta_info* sta_ret = ap_get_sta(hapd, mgmt->bssid);
> ++ if(sta_ret) return;
> ++
> ++ sta_ret = ap_sta_add(hapd, mgmt->bssid);
> ++
> ++ /* TODO: this has been added just to making compiler happy after breaking
> ++ * changes introduced in 11a607d121df512e010148bedcb4263a03329dc7 to support
> ++ * IEEE80211BE Multi Link Operation. Look at that commit with more time and
> ++ * understand what could be a proper implementation in this context too
> ++ */
> ++ const u8 *mld_link_addr = NULL;
> ++ bool mld_link_sta = false;
> ++
> ++ /* First add the station without more information */
> ++ int aRet = hostapd_sta_add(
> ++            hapd, mgmt->bssid, sta_ret->aid, 0,
> ++            NULL, 0, 0, NULL, NULL, NULL, 0, NULL, 0, NULL,
> ++            sta_ret->flags, 0, 0, 0,
> ++            0, // 0 add, 1 set
> ++            mld_link_addr, mld_link_sta );
> ++
> ++ sta_ret->flags |= WLAN_STA_AUTH;
> ++ wpa_auth_sm_event(sta_ret->wpa_sm, WPA_AUTH);
> ++
> ++ /* TODO: Investigate if supporting WPA or other encryption method is
> ++ * possible */
> ++ sta_ret->auth_alg = WLAN_AUTH_OPEN;
> ++ mlme_authenticate_indication(hapd, sta_ret);
> ++
> ++ sta_ret->capability = le_to_host16(mgmt->u.beacon.capab_info);
> ++
> ++ if (sta_ret->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
> ++ sta_ret->flags |= WLAN_STA_SHORT_PREAMBLE;
> ++ else
> ++ sta_ret->flags &= ~WLAN_STA_SHORT_PREAMBLE;
> ++
> ++ copy_supp_rates(hapd, sta_ret, elems);
> ++
> ++ /* Whithout this flag copy_sta_[v]ht_capab will disable [V]HT
> ++ * capabilities even if available */
> ++ if(elems->ht_capabilities || elems->vht_capabilities)
> ++ sta_ret->flags |= WLAN_STA_WMM;
> ++
> ++ copy_sta_ht_capab(hapd, sta_ret, elems->ht_capabilities);
> ++#ifdef CONFIG_IEEE80211AC
> ++ copy_sta_vht_capab(hapd, sta_ret, elems->vht_capabilities);
> ++ copy_sta_vht_oper(hapd, sta_ret, elems->vht_operation);
> ++ copy_sta_vendor_vht(hapd, sta_ret, elems->vendor_vht, elems->vendor_vht_len);
> ++#endif // def CONFIG_IEEE80211AC
> ++#ifdef CONFIG_IEEE80211AX
> ++ copy_sta_he_6ghz_capab(hapd, sta_ret,  elems->he_6ghz_band_cap);
> ++#endif // def CONFIG_IEEE80211AX
> ++#ifdef CONFIG_IEEE80211BE
> ++ copy_sta_eht_capab( hapd, sta_ret,
> ++                    IEEE80211_MODE_AP, // TODO: Make sure is the right value
> ++                    elems->he_capabilities, elems->he_capabilities_len,
> ++                    elems->eht_capabilities, elems->eht_capabilities_len);
> ++#endif //def CONFIG_IEEE80211BE
> ++
> ++ update_ht_state(hapd, sta_ret);
> ++
> ++ if (hostapd_get_aid(hapd, sta_ret) < 0)
> ++ {
> ++ wpa_printf( MSG_INFO, "apup_process_beacon(...) No room for more AIDs");
> ++ return;
> ++ }
> ++
> ++ sta_ret->flags |= WLAN_STA_ASSOC_REQ_OK;
> ++
> ++ /* Make sure that the previously registered inactivity timer will not
> ++ * remove the STA immediately. */
> ++ sta_ret->timeout_next = STA_NULLFUNC;
> ++
> ++ sta_ret->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
> ++
> ++ /* Then set the paramethers */
> ++ int sRet = hostapd_sta_add(
> ++            hapd, mgmt->bssid, sta_ret->aid,
> ++            sta_ret->capability,
> ++            sta_ret->supported_rates, sta_ret->supported_rates_len,
> ++            0, // u16 listen_interval TODO ?
> ++            sta_ret->ht_capabilities,
> ++            sta_ret->vht_capabilities,
> ++            sta_ret->he_capab, sta_ret->he_capab_len,
> ++            sta_ret->eht_capab, sta_ret->eht_capab_len,
> ++            sta_ret->he_6ghz_capab,
> ++            sta_ret->flags,
> ++            0, // u8 qosinfo
> ++            sta_ret->vht_opmode,
> ++            0, // int supp_p2p_ps
> ++            1, // 0 add, 1 set
> ++            mld_link_addr, mld_link_sta );
> ++
> ++ ap_sta_set_authorized(hapd, sta_ret, 1);
> ++ hostapd_set_sta_flags(hapd, sta_ret);
> ++
> ++ char mIfname[IFNAMSIZ + 1];
> ++ os_memset(mIfname, 0, IFNAMSIZ + 1);
> ++
> ++ // last param 1 means add 0 means remove
> ++ int mRet = hostapd_set_wds_sta(
> ++            hapd, mIfname, mgmt->bssid, sta_ret->aid, 1 );
> ++
> ++ wpa_printf( MSG_INFO,
> ++            "apup_process_beacon(...) Added APuP peer at %s with flags: %d,"
> ++            " capabilities %d",
> ++            mIfname, sta_ret->flags, sta_ret->capability );
> ++}
> +--- /dev/null
> ++++ b/src/ap/apup.h
> +@@ -0,0 +1,25 @@
> ++/*
> ++ * hostapd / APuP Access Point Micro Peering
> ++ *
> ++ * Copyright (C) 2023-2024  Gioacchino Mazzurco <gio@polymathes.cc>
> ++ * Copyright (C) 2023-2024  Asociación Civil Altermundi <info@altermundi.net>
> ++ *
> ++ * This software may be distributed under the terms of the BSD license.
> ++ * See README for more details.
> ++ */
> ++
> ++/* Be extremely careful altering include order, move just one in the wrong place
> ++ * and you will start getting a bunch of error of undefined bool, size_t etc. */
> ++
> ++#include "utils/includes.h"
> ++#include "utils/common.h"
> ++
> ++#include "hostapd.h"
> ++#include "common/ieee802_11_defs.h"
> ++
> ++/** When beacons from other Access Point are received, if the SSID is matching
> ++ * add them as APuP peers (aka WDS STA to our own AP) the same happens on the
> ++ * peer when receiving our beacons */
> ++void apup_process_beacon(struct hostapd_data *hapd,
> ++              const struct ieee80211_mgmt *mgmt, size_t len,
> ++              const struct ieee802_11_elems *elems );
> +--- a/src/ap/ieee802_11.c
> ++++ b/src/ap/ieee802_11.c
> +@@ -59,6 +59,9 @@
> + #include "nan_usd_ap.h"
> + #include "pasn/pasn_common.h"
> + 
> ++#ifdef CONFIG_APUP
> ++# include "apup.h"
> ++#endif // def CONFIG_APUP
> + 
> + #ifdef CONFIG_FILS
> + static struct wpabuf *
> +@@ -3469,8 +3472,8 @@ static u16 check_multi_ap(struct hostapd
> + }
> + 
> + 
> +-static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
> +-   struct ieee802_11_elems *elems)
> ++u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
> ++               const struct ieee802_11_elems *elems)
> + {
> + /* Supported rates not used in IEEE 802.11ad/DMG */
> + if (hapd->iface->current_mode &&
> +@@ -5927,6 +5930,10 @@ static void handle_beacon(struct hostapd
> +      0);
> + 
> + ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
> ++
> ++#ifdef CONFIG_APUP
> ++ if(hapd->conf->apup) apup_process_beacon(hapd, mgmt, len, &elems);
> ++#endif // def CONFIG_APUP
> + }
> + 
> + 
> +--- a/src/ap/ieee802_11.h
> ++++ b/src/ap/ieee802_11.h
> +@@ -108,6 +108,8 @@ int hostapd_process_ml_assoc_req_addr(st
> +      const u8 *basic_mle, size_t basic_mle_len,
> +      u8 *mld_addr);
> + int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
> ++u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
> ++               const struct ieee802_11_elems *elems);
> + u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
> +      const u8 *ht_capab);
> + u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
> +--- a/src/drivers/driver.h
> ++++ b/src/drivers/driver.h
> +@@ -3976,7 +3976,7 @@ struct wpa_driver_ops {
> + * Returns: 0 on success, -1 on failure
> + */
> + int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
> +-   const char *bridge_ifname, char *ifname_wds);
> ++           const char *bridge_ifname, const char *ifname_wds);
> + 
> + /**
> + * send_action - Transmit an Action frame
> +--- a/src/drivers/driver_nl80211.c
> ++++ b/src/drivers/driver_nl80211.c
> +@@ -8415,24 +8415,14 @@ static int have_ifidx(struct wpa_driver_
> + 
> + 
> + static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
> +-    const char *bridge_ifname, char *ifname_wds)
> ++                const char *bridge_ifname, const char *ifname_wds)
> + {
> + struct i802_bss *bss = priv;
> + struct wpa_driver_nl80211_data *drv = bss->drv;
> +- char name[IFNAMSIZ + 1];
> ++ const char *name = ifname_wds; // Kept to reduce changes to the minimum
> + union wpa_event_data event;
> + int ret;
> + 
> +- ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
> +- if (ret >= (int) sizeof(name))
> +- wpa_printf(MSG_WARNING,
> +-   "nl80211: WDS interface name was truncated");
> +- else if (ret < 0)
> +- return ret;
> +-
> +- if (ifname_wds)
> +- os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
> +-
> + wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
> +   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
> + if (val) {
> diff --git a/package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch b/package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch
> new file mode 100644
> index 0000000000..86da7d0e5e
> --- /dev/null
> +++ b/package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch
> @@ -0,0 +1,74 @@
> +From 82eddeb699fcdb041ad21f4dd6cd97cf674b9685 Mon Sep 17 00:00:00 2001
> +From: Gioacchino Mazzurco <gio@polymathes.cc>
> +Date: Tue, 7 May 2024 10:37:54 +0200
> +Subject: [PATCH 2/3] APuP add ubus notification when a peer comes up
> +
> +The notification ones get looks like
> +{ "apup-newpeer": {"address":"02:0a:ab:45:5a:ab","ifname":"wlan0.peer1"} }
> +
> +Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
> +---
> + src/ap/apup.c |  8 ++++++++
> + src/ap/ubus.c | 15 +++++++++++++++
> + src/ap/ubus.h |  5 +++++
> + 3 files changed, 28 insertions(+)
> +
> +--- a/src/ap/apup.c
> ++++ b/src/ap/apup.c
> +@@ -23,6 +23,10 @@
> + #include "ieee802_11.h"
> + #include "ap_drv_ops.h"
> + 
> ++#ifdef UBUS_SUPPORT
> ++# include "ubus.h"
> ++#endif
> ++
> + void apup_process_beacon(struct hostapd_data *hapd,
> +               const struct ieee80211_mgmt *mgmt, size_t len,
> +               const struct ieee802_11_elems *elems )
> +@@ -142,6 +146,10 @@ void apup_process_beacon(struct hostapd_
> + int mRet = hostapd_set_wds_sta(
> +            hapd, mIfname, mgmt->bssid, sta_ret->aid, 1 );
> + 
> ++#ifdef UBUS_SUPPORT
> ++ hostapd_ubus_notify_apup_newpeer(hapd, mgmt->bssid, mIfname);
> ++#endif
> ++
> + wpa_printf( MSG_INFO,
> +            "apup_process_beacon(...) Added APuP peer at %s with flags: %d,"
> +            " capabilities %d",
> +--- a/src/ap/ubus.c
> ++++ b/src/ap/ubus.c
> +@@ -2004,3 +2004,18 @@ int hostapd_ubus_notify_bss_transition_q
> + return ureq.resp;
> + #endif
> + }
> ++
> ++#ifdef CONFIG_APUP
> ++void hostapd_ubus_notify_apup_newpeer(
> ++        struct hostapd_data *hapd, const u8 *addr, const char *ifname )
> ++{
> ++ if (!hapd->ubus.obj.has_subscribers)
> ++ return;
> ++
> ++ blob_buf_init(&b, 0);
> ++ blobmsg_add_macaddr(&b, "address", addr);
> ++ blobmsg_add_string(&b, "ifname", ifname);
> ++
> ++ ubus_notify(ctx, &hapd->ubus.obj, "apup-newpeer", b.head, -1);
> ++}
> ++#endif // def CONFIG_APUP
> +--- a/src/ap/ubus.h
> ++++ b/src/ap/ubus.h
> +@@ -71,6 +71,11 @@ int hostapd_ubus_notify_bss_transition_q
> + void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
> +    const char *auth_alg);
> + 
> ++#ifdef CONFIG_APUP
> ++void hostapd_ubus_notify_apup_newpeer(
> ++        struct hostapd_data *hapd, const u8 *addr, const char *ifname );
> ++#endif // def CONFIG_APUP
> ++
> + #else
> + 
> + struct hostapd_ubus_bss {};
> diff --git a/package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch b/package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch
> new file mode 100644
> index 0000000000..ab89eb9543
> --- /dev/null
> +++ b/package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch
> @@ -0,0 +1,83 @@
> +From f5682a5f73108fa43977864351cd8f770f10aee0 Mon Sep 17 00:00:00 2001
> +From: Gioacchino Mazzurco <gio@polymathes.cc>
> +Date: Tue, 7 May 2024 11:54:23 +0200
> +Subject: [PATCH 3/3] APuP add ucode hook for when a peer comes up
> +
> +Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
> +---
> + src/ap/apup.c  | 16 ++++++++++++----
> + src/ap/ucode.c | 18 ++++++++++++++++++
> + src/ap/ucode.h |  4 ++++
> + 3 files changed, 34 insertions(+), 4 deletions(-)
> +
> +--- a/src/ap/apup.c
> ++++ b/src/ap/apup.c
> +@@ -27,6 +27,10 @@
> + # include "ubus.h"
> + #endif
> + 
> ++#ifdef UCODE_SUPPORT
> ++# include "ucode.h"
> ++#endif
> ++
> + void apup_process_beacon(struct hostapd_data *hapd,
> +               const struct ieee80211_mgmt *mgmt, size_t len,
> +               const struct ieee802_11_elems *elems )
> +@@ -146,12 +150,16 @@ void apup_process_beacon(struct hostapd_
> + int mRet = hostapd_set_wds_sta(
> +            hapd, mIfname, mgmt->bssid, sta_ret->aid, 1 );
> + 
> +-#ifdef UBUS_SUPPORT
> +- hostapd_ubus_notify_apup_newpeer(hapd, mgmt->bssid, mIfname);
> +-#endif
> +-
> + wpa_printf( MSG_INFO,
> +            "apup_process_beacon(...) Added APuP peer at %s with flags: %d,"
> +            " capabilities %d",
> +            mIfname, sta_ret->flags, sta_ret->capability );
> ++
> ++#ifdef UBUS_SUPPORT
> ++ hostapd_ubus_notify_apup_newpeer(hapd, mgmt->bssid, mIfname);
> ++#endif
> ++
> ++#ifdef UCODE_SUPPORT
> ++ hostapd_ucode_apup_newpeer(hapd, mIfname);
> ++#endif
> + }
> +--- a/src/ap/ucode.c
> ++++ b/src/ap/ucode.c
> +@@ -811,3 +811,21 @@ void hostapd_ucode_free_bss(struct hosta
> + ucv_put(wpa_ucode_call(2));
> + ucv_gc(vm);
> + }
> ++
> ++#ifdef CONFIG_APUP
> ++void hostapd_ucode_apup_newpeer(
> ++        struct hostapd_data *hapd, const char *ifname )
> ++{
> ++ uc_value_t *val;
> ++
> ++ if (wpa_ucode_call_prepare("apup_newpeer"))
> ++ return;
> ++
> ++ val = hostapd_ucode_bss_get_uval(hapd);
> ++ uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface))); // BSS ifname
> ++ uc_value_push(ucv_get(val));
> ++ uc_value_push(ucv_get(ucv_string_new(ifname))); // APuP peer ifname
> ++ ucv_put(wpa_ucode_call(2));
> ++ ucv_gc(vm);
> ++}
> ++#endif // def CONFIG_APUP
> +--- a/src/ap/ucode.h
> ++++ b/src/ap/ucode.h
> +@@ -27,6 +27,10 @@ void hostapd_ucode_add_bss(struct hostap
> + void hostapd_ucode_free_bss(struct hostapd_data *hapd);
> + void hostapd_ucode_reload_bss(struct hostapd_data *hapd);
> + 
> ++#ifdef CONFIG_APUP
> ++void hostapd_ucode_apup_newpeer(struct hostapd_data *hapd, const char *ifname);
> ++#endif // def CONFIG_APUP
> ++
> + #else
> + 
> + static inline int hostapd_ucode_init(struct hapd_interfaces *ifaces)
> -- 
> 2.43.2
> 
> 
> 
> 
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel@lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel
David Bauer May 21, 2024, 8:45 a.m. UTC | #2
Hi Gio,

thanks for sending this patch to the mailinglist. We've talked at last WCW in Berlin
(If i don't mistake you for something else).

I gave the patch a test-run yesterday with two MT7915 and radios and I've observed two
issues:

1. Neither the 2.4 nor 5 GHz radios enable 802.11ax capabilities. This is an easy fix,
    as you don't copy over the HE capabilities to the STA. I've added this and 802.11ax
    rates were negotiated. So this is an easy fix.

2. The connection does not establish a Block-Ack session (neither automatically nor manually).
    I did not look into this, but is this something which you can reproduce? The throughput is
    very low (~30 Mbit/s on HE20 5GHz).


Best
David
Gio May 28, 2024, 10:11 a.m. UTC | #3
The sender domain has a DMARC Reject/Quarantine policy which disallows
sending mailing list messages using the original "From" header.

To mitigate this problem, the original message has been wrapped
automatically by the mailing list software.
Hi!

Yeah it's me we have talked at WCW in Berlin ;-)

so about the 802.11ax capability, I guess I forgot to copy the non-6GHz 
capabilities, and this should fix it right?

#ifdef CONFIG_IEEE80211AX
+    copy_sta_he_capab( hapd, sta_ret,
+                       elems->he_capabilities, 
elems->he_capabilities_len );
     copy_sta_he_6ghz_capab(hapd, sta_ret, elems->he_6ghz_band_cap);
#endif // def CONFIG_IEEE80211AX


About the Block-Ack session, in the code I added nothing is done about 
that, if it is something that usually the station take initiative to do 
it I don't know well how to do that, but if something about that appears 
in the beacons like with capabilities and similar stuff it shouldn't be 
that hard to fix.

In my tests I could get high throughput about 200Mbit/s so I didn't 
notice this, I don't have the test setup ready now to reproduce, but I 
managed to find a picture (attached) I took of some iperf tests I made 
some time ago with a couple of AW7916-NPD WiFi 6e radios and APuP, it is 
curious that I could get such throughput without copy_sta_he_capab but 
just with copy_sta_he_6ghz_capab

Thanks for reviewing it ;)


Cheers

Gio

On 2024-05-21 10:45, David Bauer wrote:
> Hi Gio,
>
> thanks for sending this patch to the mailinglist. We've talked at last 
> WCW in Berlin
> (If i don't mistake you for something else).
>
> I gave the patch a test-run yesterday with two MT7915 and radios and 
> I've observed two
> issues:
>
> 1. Neither the 2.4 nor 5 GHz radios enable 802.11ax capabilities. This 
> is an easy fix,
>    as you don't copy over the HE capabilities to the STA. I've added 
> this and 802.11ax
>    rates were negotiated. So this is an easy fix.
>
> 2. The connection does not establish a Block-Ack session (neither 
> automatically nor manually).
>    I did not look into this, but is this something which you can 
> reproduce? The throughput is
>    very low (~30 Mbit/s on HE20 5GHz).
>
>
> Best
> David
diff mbox series

Patch

diff --git a/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh b/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
index 763702e76b..40266db065 100644
--- a/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
+++ b/package/network/config/wifi-scripts/files/lib/netifd/hostapd.sh
@@ -383,6 +383,9 @@  hostapd_common_add_bss_config() {
 	config_add_string fils_dhcp
 
 	config_add_int ocv
+
+	config_add_boolean apup
+	config_add_string apup_peer_ifname_prefix
 }
 
 hostapd_set_vlan_file() {
@@ -569,7 +572,7 @@  hostapd_set_bss_options() {
 		ppsk airtime_bss_weight airtime_bss_limit airtime_sta_weight \
 		multicast_to_unicast_all proxy_arp per_sta_vif \
 		eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \
-		vendor_elements fils ocv
+		vendor_elements fils ocv apup
 
 	set_default fils 0
 	set_default isolate 0
@@ -593,6 +596,7 @@  hostapd_set_bss_options() {
 	set_default airtime_bss_weight 0
 	set_default airtime_bss_limit 0
 	set_default eap_server 0
+	set_default apup 0
 
 	/usr/sbin/hostapd -vfils || fils=0
 
@@ -1163,6 +1167,16 @@  hostapd_set_bss_options() {
 		append bss_conf "per_sta_vif=$per_sta_vif" "$N"
 	fi
 
+	if [ "$apup" -gt 0 ]; then
+		append bss_conf "apup=$apup" "$N"
+
+		local apup_peer_ifname_prefix
+		json_get_vars apup_peer_ifname_prefix
+		if [ -n "$apup_peer_ifname_prefix" ] ; then
+			append bss_conf "apup_peer_ifname_prefix=$apup_peer_ifname_prefix" "$N"
+		fi
+	fi
+
 	json_get_values opts hostapd_bss_options
 	for val in $opts; do
 		append bss_conf "$val" "$N"
diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile
index 0171bc0edc..1eaa67f992 100644
--- a/package/network/services/hostapd/Makefile
+++ b/package/network/services/hostapd/Makefile
@@ -87,7 +87,7 @@  DRIVER_MAKEOPTS= \
 	CONFIG_IEEE80211AC=$(HOSTAPD_IEEE80211AC) \
 	CONFIG_IEEE80211AX=$(HOSTAPD_IEEE80211AX) \
 	CONFIG_MBO=$(CONFIG_WPA_MBO_SUPPORT) \
-	CONFIG_UCODE=y
+	CONFIG_UCODE=y CONFIG_APUP=y
 
 ifeq ($(SSL_VARIANT),openssl)
   DRIVER_MAKEOPTS += CONFIG_TLS=openssl CONFIG_SAE=y
diff --git a/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch b/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch
new file mode 100644
index 0000000000..db3a05e3e6
--- /dev/null
+++ b/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch
@@ -0,0 +1,426 @@ 
+From 99a9a4e97b4964e12749766de9c57bb7e59e740e Mon Sep 17 00:00:00 2001
+From: Gioacchino Mazzurco <gio@polymathes.cc>
+Date: Mon, 6 May 2024 13:53:48 +0200
+Subject: [PATCH 1/3] Implement APuP Access Point Micro Peering
+
+Access Point Micro Peering is a simpler and hopefully more useful successor to
+Ad Hoc, Wireless Distribution System, 802.11s mesh mode, Multi-AP and EasyMesh.
+When enabled almost plain APs communicate between them via 4-address mode,
+like in WDS but all of them are AP, so they can eventually communicate also with
+plain stations and more AP nodes in sight, without more trickery.
+APuP has low hardware requirements, just AP mode support + 4-address mode, and
+no more unnecessary complications, like hardcoded bridging or routing algorithm
+in WiFi stack.
+For each AP in sight an interface is created, and then it can be used as
+convenient in each case, bridging, routing etc.
+Those interfaces could be simply bridged in a trivial topology (which happens
+automatically if wds_bridge is not an empty string), or feeded to a
+routing daemon.
+
+Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
+---
+ hostapd/Makefile             |   5 ++
+ hostapd/config_file.c        |   8 ++
+ src/ap/ap_config.h           |  29 +++++++
+ src/ap/ap_drv_ops.c          |  31 +++++++-
+ src/ap/ap_drv_ops.h          |   3 +
+ src/ap/apup.c                | 149 +++++++++++++++++++++++++++++++++++
+ src/ap/apup.h                |  25 ++++++
+ src/ap/ieee802_11.c          |  11 ++-
+ src/ap/ieee802_11.h          |   2 +
+ src/drivers/driver.h         |   2 +-
+ src/drivers/driver_nl80211.c |  14 +---
+ 11 files changed, 262 insertions(+), 17 deletions(-)
+ create mode 100644 src/ap/apup.c
+ create mode 100644 src/ap/apup.h
+
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -1415,6 +1415,11 @@ ifdef CONFIG_NO_TKIP
+ CFLAGS += -DCONFIG_NO_TKIP
+ endif
+ 
++ifdef CONFIG_APUP
++CFLAGS += -DCONFIG_APUP
++OBJS += ../src/ap/apup.o
++endif
++
+ $(DESTDIR)$(BINDIR)/%: %
+ 	install -D $(<) $(@)
+ 
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -5058,6 +5058,14 @@ static int hostapd_config_fill(struct ho
+ 		bss->mld_indicate_disabled = atoi(pos);
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
++#ifdef CONFIG_APUP
++	} else if (os_strcmp(buf, "apup") == 0) {
++		bss->apup = !!atoi(pos);
++		if(bss->apup) bss->wds_sta = 1;
++	} else if (os_strcmp(buf, "apup_peer_ifname_prefix") == 0) {
++		os_strlcpy( bss->apup_peer_ifname_prefix,
++		            pos, sizeof(bss->apup_peer_ifname_prefix) );
++#endif // def CONFIG_APUP
+ 	} else {
+ 		wpa_printf(MSG_ERROR,
+ 			   "Line %d: unknown configuration item '%s'",
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -970,6 +970,35 @@ struct hostapd_bss_config {
+ 	bool mld_indicate_disabled;
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
++
++#ifdef CONFIG_APUP
++	/**
++	 * Access Point Micro Peering
++	 * A simpler and more useful successor to Ad Hoc,
++	 * Wireless Distribution System, 802.11s mesh mode, Multi-AP and EasyMesh.
++	 *
++	 * Almost plain APs communicate between them via 4-address mode, like in WDS
++	 * but all of them are AP, so they can eventually communicate also with
++	 * plain stations and more AP nodes in sight.
++	 * Low hardware requirements, just AP mode support + 4-address mode, and no
++	 * more unnecessary complications, like hardcoded bridging or routing
++	 * algorithm in WiFi stack.
++	 * For each AP in sight an interface is created, and then it can be used as
++	 * convenient in each case, bridging, routing etc.
++	 */
++	bool apup;
++
++	/**
++	 * In 4-address mode each peer AP in sight is associated to its own
++	 * interface so we have more flexibility in "user-space".
++	 * Those interfaces could be simply bridged in a trivial topology (which
++	 * happens automatically if wds_bridge is not an empty string), or feeded to
++	 * a routing daemon.
++	 *
++	 * If not defined interface names are generated following the WDS convention.
++	 */
++	char apup_peer_ifname_prefix[IFNAMSIZ + 1];
++#endif /* CONFIG_APUP */
+ };
+ 
+ /**
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -381,12 +381,39 @@ int hostapd_vlan_if_remove(struct hostap
+ int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
+ 			const u8 *addr, int aid, int val)
+ {
+-	const char *bridge = NULL;
+-
+ 	if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
+ 		return -1;
++
++	const char *bridge = NULL;
++	char ifName[IFNAMSIZ + 1];
++
++	int mRet = 0;
++
++#ifdef CONFIG_APUP
++	if(hapd->conf->apup && hapd->conf->apup_peer_ifname_prefix[0])
++	{
++		mRet = os_snprintf(
++		            ifName, sizeof(ifName), "%s%d",
++		            hapd->conf->apup_peer_ifname_prefix, aid );
++	}
++	else
++#endif // def CONFIG_APUP
++		mRet = os_snprintf(
++		            ifName, sizeof(ifName), "%s.sta%d",
++		            hapd->conf->iface, aid );
++
++	if (mRet >= (int) sizeof(ifName))
++		wpa_printf( MSG_WARNING,
++		            "nl80211: WDS interface name was truncated" );
++	else if (mRet < 0)
++		return mRet;
++
++	// Pass back to the caller the resulting interface name
++	if (ifname_wds) os_strlcpy(ifname_wds, ifName, IFNAMSIZ + 1);
++
+ 	if (hapd->conf->wds_bridge[0])
+ 		bridge = hapd->conf->wds_bridge;
++
+ 	return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
+ 					 bridge, ifname_wds);
+ }
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -33,6 +33,9 @@ int hostapd_set_drv_ieee8021x(struct hos
+ 			      int enabled);
+ int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
+ int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
++
++/** @param val as per nl80211 driver implementation, 1 means add 0 means remove
++ */
+ int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
+ 			const u8 *addr, int aid, int val);
+ int hostapd_sta_add(struct hostapd_data *hapd,
+--- /dev/null
++++ b/src/ap/apup.c
+@@ -0,0 +1,149 @@
++/*
++ * hostapd / APuP Access Point Micro Peering
++ *
++ * Copyright (C) 2023-2024  Gioacchino Mazzurco <gio@polymathes.cc>
++ * Copyright (C) 2023-2024  Asociación Civil Altermundi <info@altermundi.net>
++ *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
++ */
++
++/* Be extremely careful altering include order, move just one in the wrong place
++ * and you will start getting a bunch of error of undefined bool, size_t etc. */
++
++#include "utils/includes.h"
++#include "utils/common.h"
++#include "utils/os.h"
++
++#include "apup.h"
++
++#include "drivers/driver.h"
++#include "wpa_auth.h"
++#include "ap_mlme.h"
++#include "ieee802_11.h"
++#include "ap_drv_ops.h"
++
++void apup_process_beacon(struct hostapd_data *hapd,
++              const struct ieee80211_mgmt *mgmt, size_t len,
++              const struct ieee802_11_elems *elems )
++{
++	if(!os_memcmp(hapd->own_addr, mgmt->bssid, ETH_ALEN))
++	{
++		wpa_printf( MSG_WARNING,
++		            "apup_process_beacon(...) own beacon elems.ssid %.*s",
++		            (int) elems->ssid_len, elems->ssid );
++		return;
++	}
++
++	if( elems->ssid_len != hapd->conf->ssid.ssid_len ||
++	        os_memcmp(elems->ssid, hapd->conf->ssid.ssid, elems->ssid_len) )
++		return;
++
++	struct sta_info* sta_ret = ap_get_sta(hapd, mgmt->bssid);
++	if(sta_ret) return;
++
++	sta_ret = ap_sta_add(hapd, mgmt->bssid);
++
++	/* TODO: this has been added just to making compiler happy after breaking
++	 * changes introduced in 11a607d121df512e010148bedcb4263a03329dc7 to support
++	 * IEEE80211BE Multi Link Operation. Look at that commit with more time and
++	 * understand what could be a proper implementation in this context too
++	 */
++	const u8 *mld_link_addr = NULL;
++	bool mld_link_sta = false;
++
++	/* First add the station without more information */
++	int aRet = hostapd_sta_add(
++	            hapd, mgmt->bssid, sta_ret->aid, 0,
++	            NULL, 0, 0, NULL, NULL, NULL, 0, NULL, 0, NULL,
++	            sta_ret->flags, 0, 0, 0,
++	            0, // 0 add, 1 set
++	            mld_link_addr, mld_link_sta );
++
++	sta_ret->flags |= WLAN_STA_AUTH;
++	wpa_auth_sm_event(sta_ret->wpa_sm, WPA_AUTH);
++
++	/* TODO: Investigate if supporting WPA or other encryption method is
++	 * possible */
++	sta_ret->auth_alg = WLAN_AUTH_OPEN;
++	mlme_authenticate_indication(hapd, sta_ret);
++
++	sta_ret->capability = le_to_host16(mgmt->u.beacon.capab_info);
++
++	if (sta_ret->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
++		sta_ret->flags |= WLAN_STA_SHORT_PREAMBLE;
++	else
++		sta_ret->flags &= ~WLAN_STA_SHORT_PREAMBLE;
++
++	copy_supp_rates(hapd, sta_ret, elems);
++
++	/* Whithout this flag copy_sta_[v]ht_capab will disable [V]HT
++	 * capabilities even if available */
++	if(elems->ht_capabilities || elems->vht_capabilities)
++		sta_ret->flags |= WLAN_STA_WMM;
++
++	copy_sta_ht_capab(hapd, sta_ret, elems->ht_capabilities);
++#ifdef CONFIG_IEEE80211AC
++	copy_sta_vht_capab(hapd, sta_ret, elems->vht_capabilities);
++	copy_sta_vht_oper(hapd, sta_ret, elems->vht_operation);
++	copy_sta_vendor_vht(hapd, sta_ret, elems->vendor_vht, elems->vendor_vht_len);
++#endif // def CONFIG_IEEE80211AC
++#ifdef CONFIG_IEEE80211AX
++	copy_sta_he_6ghz_capab(hapd, sta_ret,  elems->he_6ghz_band_cap);
++#endif // def CONFIG_IEEE80211AX
++#ifdef CONFIG_IEEE80211BE
++	copy_sta_eht_capab( hapd, sta_ret,
++	                    IEEE80211_MODE_AP, // TODO: Make sure is the right value
++	                    elems->he_capabilities, elems->he_capabilities_len,
++	                    elems->eht_capabilities, elems->eht_capabilities_len);
++#endif //def CONFIG_IEEE80211BE
++
++	update_ht_state(hapd, sta_ret);
++
++	if (hostapd_get_aid(hapd, sta_ret) < 0)
++	{
++		wpa_printf( MSG_INFO, "apup_process_beacon(...) No room for more AIDs");
++		return;
++	}
++
++	sta_ret->flags |= WLAN_STA_ASSOC_REQ_OK;
++
++	/* Make sure that the previously registered inactivity timer will not
++	 * remove the STA immediately. */
++	sta_ret->timeout_next = STA_NULLFUNC;
++
++	sta_ret->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
++
++	/* Then set the paramethers */
++	int sRet = hostapd_sta_add(
++	            hapd, mgmt->bssid, sta_ret->aid,
++	            sta_ret->capability,
++	            sta_ret->supported_rates, sta_ret->supported_rates_len,
++	            0, // u16 listen_interval TODO ?
++	            sta_ret->ht_capabilities,
++	            sta_ret->vht_capabilities,
++	            sta_ret->he_capab, sta_ret->he_capab_len,
++	            sta_ret->eht_capab, sta_ret->eht_capab_len,
++	            sta_ret->he_6ghz_capab,
++	            sta_ret->flags,
++	            0, // u8 qosinfo
++	            sta_ret->vht_opmode,
++	            0, // int supp_p2p_ps
++	            1, // 0 add, 1 set
++	            mld_link_addr, mld_link_sta );
++
++	ap_sta_set_authorized(hapd, sta_ret, 1);
++	hostapd_set_sta_flags(hapd, sta_ret);
++
++	char mIfname[IFNAMSIZ + 1];
++	os_memset(mIfname, 0, IFNAMSIZ + 1);
++
++	// last param 1 means add 0 means remove
++	int mRet = hostapd_set_wds_sta(
++	            hapd, mIfname, mgmt->bssid, sta_ret->aid, 1 );
++
++	wpa_printf( MSG_INFO,
++	            "apup_process_beacon(...) Added APuP peer at %s with flags: %d,"
++	            " capabilities %d",
++	            mIfname, sta_ret->flags, sta_ret->capability );
++}
+--- /dev/null
++++ b/src/ap/apup.h
+@@ -0,0 +1,25 @@
++/*
++ * hostapd / APuP Access Point Micro Peering
++ *
++ * Copyright (C) 2023-2024  Gioacchino Mazzurco <gio@polymathes.cc>
++ * Copyright (C) 2023-2024  Asociación Civil Altermundi <info@altermundi.net>
++ *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
++ */
++
++/* Be extremely careful altering include order, move just one in the wrong place
++ * and you will start getting a bunch of error of undefined bool, size_t etc. */
++
++#include "utils/includes.h"
++#include "utils/common.h"
++
++#include "hostapd.h"
++#include "common/ieee802_11_defs.h"
++
++/** When beacons from other Access Point are received, if the SSID is matching
++ * add them as APuP peers (aka WDS STA to our own AP) the same happens on the
++ * peer when receiving our beacons */
++void apup_process_beacon(struct hostapd_data *hapd,
++              const struct ieee80211_mgmt *mgmt, size_t len,
++              const struct ieee802_11_elems *elems );
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -59,6 +59,9 @@
+ #include "nan_usd_ap.h"
+ #include "pasn/pasn_common.h"
+ 
++#ifdef CONFIG_APUP
++#	include "apup.h"
++#endif // def CONFIG_APUP
+ 
+ #ifdef CONFIG_FILS
+ static struct wpabuf *
+@@ -3469,8 +3472,8 @@ static u16 check_multi_ap(struct hostapd
+ }
+ 
+ 
+-static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
+-			   struct ieee802_11_elems *elems)
++u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
++               const struct ieee802_11_elems *elems)
+ {
+ 	/* Supported rates not used in IEEE 802.11ad/DMG */
+ 	if (hapd->iface->current_mode &&
+@@ -5927,6 +5930,10 @@ static void handle_beacon(struct hostapd
+ 				      0);
+ 
+ 	ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
++
++#ifdef CONFIG_APUP
++	if(hapd->conf->apup) apup_process_beacon(hapd, mgmt, len, &elems);
++#endif // def CONFIG_APUP
+ }
+ 
+ 
+--- a/src/ap/ieee802_11.h
++++ b/src/ap/ieee802_11.h
+@@ -108,6 +108,8 @@ int hostapd_process_ml_assoc_req_addr(st
+ 				      const u8 *basic_mle, size_t basic_mle_len,
+ 				      u8 *mld_addr);
+ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
++u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
++               const struct ieee802_11_elems *elems);
+ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ 		      const u8 *ht_capab);
+ u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -3976,7 +3976,7 @@ struct wpa_driver_ops {
+ 	 * Returns: 0 on success, -1 on failure
+ 	 */
+ 	int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
+-			   const char *bridge_ifname, char *ifname_wds);
++	           const char *bridge_ifname, const char *ifname_wds);
+ 
+ 	/**
+ 	 * send_action - Transmit an Action frame
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -8415,24 +8415,14 @@ static int have_ifidx(struct wpa_driver_
+ 
+ 
+ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
+-			    const char *bridge_ifname, char *ifname_wds)
++                const char *bridge_ifname, const char *ifname_wds)
+ {
+ 	struct i802_bss *bss = priv;
+ 	struct wpa_driver_nl80211_data *drv = bss->drv;
+-	char name[IFNAMSIZ + 1];
++	const char *name = ifname_wds; // Kept to reduce changes to the minimum
+ 	union wpa_event_data event;
+ 	int ret;
+ 
+-	ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+-	if (ret >= (int) sizeof(name))
+-		wpa_printf(MSG_WARNING,
+-			   "nl80211: WDS interface name was truncated");
+-	else if (ret < 0)
+-		return ret;
+-
+-	if (ifname_wds)
+-		os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
+-
+ 	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+ 		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+ 	if (val) {
diff --git a/package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch b/package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch
new file mode 100644
index 0000000000..86da7d0e5e
--- /dev/null
+++ b/package/network/services/hostapd/patches/790-APuP-add-ubus-notification-when-a-peer-comes-up.patch
@@ -0,0 +1,74 @@ 
+From 82eddeb699fcdb041ad21f4dd6cd97cf674b9685 Mon Sep 17 00:00:00 2001
+From: Gioacchino Mazzurco <gio@polymathes.cc>
+Date: Tue, 7 May 2024 10:37:54 +0200
+Subject: [PATCH 2/3] APuP add ubus notification when a peer comes up
+
+The notification ones get looks like
+{ "apup-newpeer": {"address":"02:0a:ab:45:5a:ab","ifname":"wlan0.peer1"} }
+
+Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
+---
+ src/ap/apup.c |  8 ++++++++
+ src/ap/ubus.c | 15 +++++++++++++++
+ src/ap/ubus.h |  5 +++++
+ 3 files changed, 28 insertions(+)
+
+--- a/src/ap/apup.c
++++ b/src/ap/apup.c
+@@ -23,6 +23,10 @@
+ #include "ieee802_11.h"
+ #include "ap_drv_ops.h"
+ 
++#ifdef UBUS_SUPPORT
++#	include "ubus.h"
++#endif
++
+ void apup_process_beacon(struct hostapd_data *hapd,
+               const struct ieee80211_mgmt *mgmt, size_t len,
+               const struct ieee802_11_elems *elems )
+@@ -142,6 +146,10 @@ void apup_process_beacon(struct hostapd_
+ 	int mRet = hostapd_set_wds_sta(
+ 	            hapd, mIfname, mgmt->bssid, sta_ret->aid, 1 );
+ 
++#ifdef UBUS_SUPPORT
++	hostapd_ubus_notify_apup_newpeer(hapd, mgmt->bssid, mIfname);
++#endif
++
+ 	wpa_printf( MSG_INFO,
+ 	            "apup_process_beacon(...) Added APuP peer at %s with flags: %d,"
+ 	            " capabilities %d",
+--- a/src/ap/ubus.c
++++ b/src/ap/ubus.c
+@@ -2004,3 +2004,18 @@ int hostapd_ubus_notify_bss_transition_q
+ 	return ureq.resp;
+ #endif
+ }
++
++#ifdef CONFIG_APUP
++void hostapd_ubus_notify_apup_newpeer(
++        struct hostapd_data *hapd, const u8 *addr, const char *ifname )
++{
++	if (!hapd->ubus.obj.has_subscribers)
++		return;
++
++	blob_buf_init(&b, 0);
++	blobmsg_add_macaddr(&b, "address", addr);
++	blobmsg_add_string(&b, "ifname", ifname);
++
++	ubus_notify(ctx, &hapd->ubus.obj, "apup-newpeer", b.head, -1);
++}
++#endif // def CONFIG_APUP
+--- a/src/ap/ubus.h
++++ b/src/ap/ubus.h
+@@ -71,6 +71,11 @@ int hostapd_ubus_notify_bss_transition_q
+ void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ 				    const char *auth_alg);
+ 
++#ifdef CONFIG_APUP
++void hostapd_ubus_notify_apup_newpeer(
++        struct hostapd_data *hapd, const u8 *addr, const char *ifname );
++#endif // def CONFIG_APUP
++
+ #else
+ 
+ struct hostapd_ubus_bss {};
diff --git a/package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch b/package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch
new file mode 100644
index 0000000000..ab89eb9543
--- /dev/null
+++ b/package/network/services/hostapd/patches/800-APuP-add-ucode-hook-for-when-a-peer-comes-up.patch
@@ -0,0 +1,83 @@ 
+From f5682a5f73108fa43977864351cd8f770f10aee0 Mon Sep 17 00:00:00 2001
+From: Gioacchino Mazzurco <gio@polymathes.cc>
+Date: Tue, 7 May 2024 11:54:23 +0200
+Subject: [PATCH 3/3] APuP add ucode hook for when a peer comes up
+
+Signed-off-by: Gioacchino Mazzurco <gio@polymathes.cc>
+---
+ src/ap/apup.c  | 16 ++++++++++++----
+ src/ap/ucode.c | 18 ++++++++++++++++++
+ src/ap/ucode.h |  4 ++++
+ 3 files changed, 34 insertions(+), 4 deletions(-)
+
+--- a/src/ap/apup.c
++++ b/src/ap/apup.c
+@@ -27,6 +27,10 @@
+ #	include "ubus.h"
+ #endif
+ 
++#ifdef UCODE_SUPPORT
++#	include "ucode.h"
++#endif
++
+ void apup_process_beacon(struct hostapd_data *hapd,
+               const struct ieee80211_mgmt *mgmt, size_t len,
+               const struct ieee802_11_elems *elems )
+@@ -146,12 +150,16 @@ void apup_process_beacon(struct hostapd_
+ 	int mRet = hostapd_set_wds_sta(
+ 	            hapd, mIfname, mgmt->bssid, sta_ret->aid, 1 );
+ 
+-#ifdef UBUS_SUPPORT
+-	hostapd_ubus_notify_apup_newpeer(hapd, mgmt->bssid, mIfname);
+-#endif
+-
+ 	wpa_printf( MSG_INFO,
+ 	            "apup_process_beacon(...) Added APuP peer at %s with flags: %d,"
+ 	            " capabilities %d",
+ 	            mIfname, sta_ret->flags, sta_ret->capability );
++
++#ifdef UBUS_SUPPORT
++	hostapd_ubus_notify_apup_newpeer(hapd, mgmt->bssid, mIfname);
++#endif
++
++#ifdef UCODE_SUPPORT
++	hostapd_ucode_apup_newpeer(hapd, mIfname);
++#endif
+ }
+--- a/src/ap/ucode.c
++++ b/src/ap/ucode.c
+@@ -811,3 +811,21 @@ void hostapd_ucode_free_bss(struct hosta
+ 	ucv_put(wpa_ucode_call(2));
+ 	ucv_gc(vm);
+ }
++
++#ifdef CONFIG_APUP
++void hostapd_ucode_apup_newpeer(
++        struct hostapd_data *hapd, const char *ifname )
++{
++	uc_value_t *val;
++
++	if (wpa_ucode_call_prepare("apup_newpeer"))
++		return;
++
++	val = hostapd_ucode_bss_get_uval(hapd);
++	uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface))); // BSS ifname
++	uc_value_push(ucv_get(val));
++	uc_value_push(ucv_get(ucv_string_new(ifname))); // APuP peer ifname
++	ucv_put(wpa_ucode_call(2));
++	ucv_gc(vm);
++}
++#endif // def CONFIG_APUP
+--- a/src/ap/ucode.h
++++ b/src/ap/ucode.h
+@@ -27,6 +27,10 @@ void hostapd_ucode_add_bss(struct hostap
+ void hostapd_ucode_free_bss(struct hostapd_data *hapd);
+ void hostapd_ucode_reload_bss(struct hostapd_data *hapd);
+ 
++#ifdef CONFIG_APUP
++void hostapd_ucode_apup_newpeer(struct hostapd_data *hapd, const char *ifname);
++#endif // def CONFIG_APUP
++
+ #else
+ 
+ static inline int hostapd_ucode_init(struct hapd_interfaces *ifaces)