[rdkb][common][bsp][Refactor and sync wifi from openwrt]

[Description]
28f44ba8 [MAC80211][WiFi6/7][hostapd][Fix vht bw160 support / ht bw40 support beacon IE missing issue during channel switch]
1450b198 [MAC80211][WiFi7][Rebase Patches][Fix patch fail issue]
7627b2ea [MAC80211][WiFi6][mt76][Fix dfs cert tx emission issue during bootup]
4b48853d [MAC80211][WiFi7][misc][Sync up-to-date .config and remove crypto-eip package]
a674222a [MAC80211][mt76][Establish BA in VO queue for Panther & Harrier]
96d077d1 [MAC80211][hostapd][Fix hostapd mbssid aid and rnr ie issue]
c01f78d1 [MAC80211][core][Fix channel switch failed issue while switching to the same control channel but different bw]
2cf29232 [MAC80211][WiFi6][MT76][Correct 0009-wifi-mt76-mt7915-fix-txpower-issue]
ad4536e7 [MAC80211][hostapd][Fix rnr ie length when no need to report bss]
a8432cf9 [MAC80211][misc][Enable OFDMA UL in Panther]
773dc1d3 [MAC80211][hostapd][fix patch failed]
15dc641b [MAC80211][mt76][Fix ibf cal phase issue for mt7915D]

[Release-log]

Change-Id: I7d261732d53a8260ce3fd59459807277d5c18534
diff --git a/recipes-wifi/wpa-supplicant/files/002-rdkb-add-ucode-support.patch b/recipes-wifi/wpa-supplicant/files/002-rdkb-add-ucode-support.patch
new file mode 100644
index 0000000..16e099a
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/002-rdkb-add-ucode-support.patch
@@ -0,0 +1,21 @@
+--- a/hostapd/Makefile	2023-08-14 14:07:55.808647300 +0800
++++ b/hostapd/Makefile	2023-08-14 14:09:14.222019605 +0800
+@@ -182,6 +182,7 @@
+ OBJS += ../src/utils/ucode.o
+ OBJS += ../src/ap/ucode.o
+ NEED_ULOOP:=y
++LIBS += -lblobmsg_json -lucode
+ endif
+ 
+ ifdef NEED_ULOOP
+
+--- a/wpa_supplicant/Makefile	2023-08-14 17:51:44.351944100 +0800
++++ b/wpa_supplicant/Makefile	2023-08-14 17:54:54.232111091 +0800
+@@ -206,6 +206,7 @@
+ OBJS += ../src/utils/ucode.o
+ OBJS += ucode.o
+ NEED_ULOOP:=y
++LIBS += -lblobmsg_json -lucode
+ endif
+ 
+ ifdef NEED_ULOOP
\ No newline at end of file
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
similarity index 66%
rename from recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
rename to recipes-wifi/wpa-supplicant/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
index 7196118..7b0435a 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
@@ -1,23 +1,32 @@
-From ce585467d784d1015b5a40ec09895d0949690b04 Mon Sep 17 00:00:00 2001
-From: Michael Lee <michael-cy.lee@mediatek.com>
-Date: Wed, 3 May 2023 14:55:18 +0800
-Subject: [PATCH 29/32] hostapd: mtk: Fix CCA issue
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 7 Aug 2023 21:55:57 +0200
+Subject: [PATCH] BSS coloring: fix CCA with multiple BSS
 
-When receiving CCA-related nl80211 commands, hostapd used to work on
-struct wpa_driver_nl80211_data, whose ctx always points to
-hostpad_iface->bss[0]. However, CCA commands are sent on a per-BSS based.
-This patch makes hostapd handle CCA-related commands on a per-BSS based.
+Pass bss->ctx instead of drv->ctx in order to avoid multiple reports for
+the first bss. The first report would otherwise clear hapd->cca_color and
+subsequent reports would cause the iface bss color to be set to 0.
+In order to avoid any issues with cancellations, only overwrite the color
+based on hapd->cca_color if it was actually set.
 
-Signed-off-by: Michael Lee <michael-cy.lee@mediatek.com>
+Fixes: 33c4dd26cd11 ("BSS coloring: Handle the collision and CCA events coming from the kernel")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
 ---
- src/drivers/driver_nl80211_event.c | 24 ++++++++++++------------
- 1 file changed, 12 insertions(+), 12 deletions(-)
 
-diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
-index 3d0d9b7bb..ab988fad7 100644
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -2260,7 +2260,8 @@ void wpa_supplicant_event(void *ctx, enu
+ 	case EVENT_CCA_NOTIFY:
+ 		wpa_printf(MSG_DEBUG, "CCA finished on on %s",
+ 			   hapd->conf->iface);
+-		hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
++		if (hapd->cca_color)
++			hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
+ 		hostapd_cleanup_cca_params(hapd);
+ 		break;
+ #endif /* CONFIG_IEEE80211AX */
 --- a/src/drivers/driver_nl80211_event.c
 +++ b/src/drivers/driver_nl80211_event.c
-@@ -3662,7 +3662,7 @@ static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv,
+@@ -3653,7 +3653,7 @@ static void nl80211_assoc_comeback(struc
  
  #ifdef CONFIG_IEEE80211AX
  
@@ -26,7 +35,7 @@
  					 struct nlattr *tb[])
  {
  	union wpa_event_data data;
-@@ -3676,37 +3676,37 @@ static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv,
+@@ -3667,37 +3667,37 @@ static void nl80211_obss_color_collision
  
  	wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08llx",
  		   (long long unsigned int) data.bss_color_collision.bitmap);
@@ -71,7 +80,7 @@
  }
  
  #endif /* CONFIG_IEEE80211AX */
-@@ -3968,16 +3968,16 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
+@@ -3957,16 +3957,16 @@ static void do_process_drv_event(struct
  		break;
  #ifdef CONFIG_IEEE80211AX
  	case NL80211_CMD_OBSS_COLOR_COLLISION:
@@ -92,6 +101,3 @@
  		break;
  #endif /* CONFIG_IEEE80211AX */
  	default:
--- 
-2.39.2
-
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch
index f7e797a..8ebbed0 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch
@@ -189,7 +189,7 @@
  {
  	struct hostapd_data *hapd = ctx;
  #ifndef CONFIG_NO_STDOUT_DEBUG
-@@ -2271,7 +2271,7 @@ void wpa_supplicant_event(void *ctx, enu
+@@ -2272,7 +2272,7 @@ void wpa_supplicant_event(void *ctx, enu
  }
  
  
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch
index f393634..f420c18 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch
@@ -1,11 +1,12 @@
 --- a/hostapd/Makefile
 +++ b/hostapd/Makefile
-@@ -166,6 +166,11 @@ OBJS += ../src/common/hw_features_common
+@@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common
  
  OBJS += ../src/eapol_auth/eapol_auth_sm.o
  
 +ifdef CONFIG_UBUS
 +CFLAGS += -DUBUS_SUPPORT
++OBJS += ../src/utils/uloop.o
 +OBJS += ../src/ap/ubus.o
 +LIBS += -lubox -lubus
 +endif
@@ -22,15 +23,6 @@
  
  #define OCE_STA_CFON_ENABLED(hapd) \
  	((hapd->conf->oce & OCE_STA_CFON) && \
-@@ -92,7 +93,7 @@ struct hapd_interfaces {
- #ifdef CONFIG_CTRL_IFACE_UDP
-        unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
- #endif /* CONFIG_CTRL_IFACE_UDP */
--
-+	struct ubus_object ubus;
- };
- 
- enum hostapd_chan_status {
 @@ -184,6 +185,7 @@ struct hostapd_data {
  	struct hostapd_iface *iface;
  	struct hostapd_config *iconf;
@@ -330,20 +322,21 @@
  
 --- a/wpa_supplicant/Makefile
 +++ b/wpa_supplicant/Makefile
-@@ -194,6 +194,12 @@ ifdef CONFIG_EAPOL_TEST
+@@ -194,6 +194,13 @@ ifdef CONFIG_EAPOL_TEST
  CFLAGS += -Werror -DEAPOL_TEST
  endif
  
 +ifdef CONFIG_UBUS
 +CFLAGS += -DUBUS_SUPPORT
 +OBJS += ubus.o
++OBJS += ../src/utils/uloop.o
 +LIBS += -lubox -lubus
 +endif
 +
  ifdef CONFIG_CODE_COVERAGE
  CFLAGS += -O0 -fprofile-arcs -ftest-coverage
  LIBS += -lgcov
-@@ -989,6 +995,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
+@@ -989,6 +996,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
  CFLAGS += -DCONFIG_CTRL_IFACE_MIB
  endif
  OBJS += ../src/ap/ctrl_iface_ap.o
@@ -432,24 +425,6 @@
  	if (wpa_s->conf->wps_cred_processing == 1)
  		return 0;
  
---- a/hostapd/main.c
-+++ b/hostapd/main.c
-@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
- 	}
- 
- 	hostapd_global_ctrl_iface_init(&interfaces);
-+	hostapd_ubus_add(&interfaces);
- 
- 	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
- 		wpa_printf(MSG_ERROR, "Failed to start eloop");
-@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
- 	ret = 0;
- 
-  out:
-+	hostapd_ubus_free(&interfaces);
- 	hostapd_global_ctrl_iface_deinit(&interfaces);
- 	/* Deinitialize all interfaces */
- 	for (i = 0; i < interfaces.count; i++) {
 --- a/wpa_supplicant/main.c
 +++ b/wpa_supplicant/main.c
 @@ -204,7 +204,7 @@ int main(int argc, char *argv[])
@@ -623,3 +598,151 @@
  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
  		    pos, end - pos);
  }
+--- a/src/utils/eloop.c
++++ b/src/utils/eloop.c
+@@ -77,6 +77,9 @@ struct eloop_sock_table {
+ struct eloop_data {
+ 	int max_sock;
+ 
++	eloop_timeout_poll_handler timeout_poll_cb;
++	eloop_poll_handler poll_cb;
++
+ 	size_t count; /* sum of all table counts */
+ #ifdef CONFIG_ELOOP_POLL
+ 	size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+@@ -1121,6 +1124,12 @@ void eloop_run(void)
+ 				os_reltime_sub(&timeout->time, &now, &tv);
+ 			else
+ 				tv.sec = tv.usec = 0;
++		}
++
++		if (eloop.timeout_poll_cb && eloop.timeout_poll_cb(&tv, !!timeout))
++			timeout = (void *)1;
++
++		if (timeout) {
+ #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
+ 			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
+ #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
+@@ -1190,7 +1199,8 @@ void eloop_run(void)
+ 		eloop.exceptions.changed = 0;
+ 
+ 		eloop_process_pending_signals();
+-
++		if (eloop.poll_cb)
++			eloop.poll_cb();
+ 
+ 		/* check if some registered timeouts have occurred */
+ 		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+@@ -1252,6 +1262,14 @@ out:
+ 	return;
+ }
+ 
++int eloop_register_cb(eloop_poll_handler poll_cb,
++		      eloop_timeout_poll_handler timeout_cb)
++{
++	eloop.poll_cb = poll_cb;
++	eloop.timeout_poll_cb = timeout_cb;
++
++	return 0;
++}
+ 
+ void eloop_terminate(void)
+ {
+--- a/src/utils/eloop.h
++++ b/src/utils/eloop.h
+@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo
+  */
+ typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
+ 
++typedef bool (*eloop_timeout_poll_handler)(struct os_reltime *tv, bool tv_set);
++typedef void (*eloop_poll_handler)(void);
++
+ /**
+  * eloop_init() - Initialize global event loop data
+  * Returns: 0 on success, -1 on failure
+@@ -73,6 +76,9 @@ typedef void (*eloop_signal_handler)(int
+  */
+ int eloop_init(void);
+ 
++int eloop_register_cb(eloop_poll_handler poll_cb,
++		      eloop_timeout_poll_handler timeout_cb);
++
+ /**
+  * eloop_register_read_sock - Register handler for read events
+  * @sock: File descriptor number for the socket
+@@ -320,6 +326,8 @@ int eloop_register_signal_reconfig(eloop
+  */
+ int eloop_sock_requeue(void);
+ 
++void eloop_add_uloop(void);
++
+ /**
+  * eloop_run - Start the event loop
+  *
+--- /dev/null
++++ b/src/utils/uloop.c
+@@ -0,0 +1,64 @@
++#include <libubox/uloop.h>
++#include "includes.h"
++#include "common.h"
++#include "eloop.h"
++
++static void eloop_uloop_event_cb(int sock, void *eloop_ctx, void *sock_ctx)
++{
++}
++
++static void eloop_uloop_fd_cb(struct uloop_fd *fd, unsigned int events)
++{
++	unsigned int changed = events ^ fd->flags;
++
++	if (changed & ULOOP_READ) {
++		if (events & ULOOP_READ)
++			eloop_register_sock(fd->fd, EVENT_TYPE_READ, eloop_uloop_event_cb, fd, fd);
++		else
++			eloop_unregister_sock(fd->fd, EVENT_TYPE_READ);
++	}
++
++	if (changed & ULOOP_WRITE) {
++		if (events & ULOOP_WRITE)
++			eloop_register_sock(fd->fd, EVENT_TYPE_WRITE, eloop_uloop_event_cb, fd, fd);
++		else
++			eloop_unregister_sock(fd->fd, EVENT_TYPE_WRITE);
++	}
++}
++
++static bool uloop_timeout_poll_handler(struct os_reltime *tv, bool tv_set)
++{
++	struct os_reltime tv_uloop;
++	int timeout_ms = uloop_get_next_timeout();
++
++	if (timeout_ms < 0)
++		return false;
++
++	tv_uloop.sec = timeout_ms / 1000;
++	tv_uloop.usec = (timeout_ms % 1000) * 1000;
++
++	if (!tv_set || os_reltime_before(&tv_uloop, tv)) {
++		*tv = tv_uloop;
++		return true;
++	}
++
++	return false;
++}
++
++static void uloop_poll_handler(void)
++{
++	uloop_run_timeout(0);
++}
++
++void eloop_add_uloop(void)
++{
++	static bool init_done = false;
++
++	if (!init_done) {
++		uloop_init();
++		uloop_fd_set_cb = eloop_uloop_fd_cb;
++		init_done = true;
++	}
++
++	eloop_register_cb(uloop_poll_handler, uloop_timeout_poll_handler);
++}
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/601-ucode_support.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/601-ucode_support.patch
new file mode 100644
index 0000000..ff1a9dd
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/601-ucode_support.patch
@@ -0,0 +1,234 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -168,9 +168,21 @@ OBJS += ../src/eapol_auth/eapol_auth_sm.
+ 
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+-OBJS += ../src/utils/uloop.o
+ OBJS += ../src/ap/ubus.o
+-LIBS += -lubox -lubus
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ../src/ap/ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
++OBJS += ../src/utils/uloop.o
++LIBS += -lubox
+ endif
+ 
+ ifdef CONFIG_CODE_COVERAGE
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
+ 	}
+ 
+ 	hostapd_global_ctrl_iface_init(&interfaces);
++	hostapd_ucode_init(&interfaces);
+ 
+ 	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+ 		wpa_printf(MSG_ERROR, "Failed to start eloop");
+@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
+ 	ret = 0;
+ 
+  out:
++	hostapd_ucode_free();
+ 	hostapd_global_ctrl_iface_deinit(&interfaces);
+ 	/* Deinitialize all interfaces */
+ 	for (i = 0; i < interfaces.count; i++) {
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -19,6 +19,7 @@
+ #include "ap_config.h"
+ #include "drivers/driver.h"
+ #include "ubus.h"
++#include "ucode.h"
+ 
+ #define OCE_STA_CFON_ENABLED(hapd) \
+ 	((hapd->conf->oce & OCE_STA_CFON) && \
+@@ -51,6 +52,10 @@ struct hapd_interfaces {
+ 	struct hostapd_config * (*config_read_cb)(const char *config_fname);
+ 	int (*ctrl_iface_init)(struct hostapd_data *hapd);
+ 	void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
++	int (*ctrl_iface_recv)(struct hostapd_data *hapd,
++			       char *buf, char *reply, int reply_size,
++			       struct sockaddr_storage *from,
++			       socklen_t fromlen);
+ 	int (*for_each_interface)(struct hapd_interfaces *interfaces,
+ 				  int (*cb)(struct hostapd_iface *iface,
+ 					    void *ctx), void *ctx);
+@@ -186,6 +191,7 @@ struct hostapd_data {
+ 	struct hostapd_config *iconf;
+ 	struct hostapd_bss_config *conf;
+ 	struct hostapd_ubus_bss ubus;
++	struct hostapd_ucode_bss ucode;
+ 	int interface_added; /* virtual interface added for this BSS */
+ 	unsigned int started:1;
+ 	unsigned int disabled:1;
+@@ -506,6 +512,7 @@ struct hostapd_sta_info {
+  */
+ struct hostapd_iface {
+ 	struct hapd_interfaces *interfaces;
++	struct hostapd_ucode_iface ucode;
+ 	void *owner;
+ 	char *config_fname;
+ 	struct hostapd_config *conf;
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -276,6 +276,8 @@ int hostapd_reload_config(struct hostapd
+ 	size_t j;
+ 	int i;
+ 
++	hostapd_ucode_reload_bss(hapd, reconf);
++
+ 	if (iface->config_fname == NULL) {
+ 		/* Only in-memory config in use - assume it has been updated */
+ 		hostapd_clear_old(iface);
+@@ -455,6 +457,7 @@ void hostapd_free_hapd_data(struct hosta
+ 	hapd->beacon_set_done = 0;
+ 
+ 	wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
++	hostapd_ucode_free_bss(hapd);
+ 	hostapd_ubus_free_bss(hapd);
+ 	accounting_deinit(hapd);
+ 	hostapd_deinit_wpa(hapd);
+@@ -619,6 +622,7 @@ void hostapd_cleanup_iface_partial(struc
+ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+ {
+ 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
++	hostapd_ucode_free_iface(iface);
+ 	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ 	eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+ 			     NULL);
+@@ -1209,6 +1213,7 @@ static int hostapd_start_beacon(struct h
+ 		hapd->driver->set_operstate(hapd->drv_priv, 1);
+ 
+ 	hostapd_ubus_add_bss(hapd);
++	hostapd_ucode_add_bss(hapd);
+ 
+ 	return 0;
+ }
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -197,8 +197,20 @@ endif
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+ OBJS += ubus.o
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
+ OBJS += ../src/utils/uloop.o
+-LIBS += -lubox -lubus
++LIBS += -lubox
+ endif
+ 
+ ifdef CONFIG_CODE_COVERAGE
+@@ -999,6 +1011,9 @@ OBJS += ../src/ap/ctrl_iface_ap.o
+ ifdef CONFIG_UBUS
+ OBJS += ../src/ap/ubus.o
+ endif
++ifdef CONFIG_UCODE
++OBJS += ../src/ap/ucode.o
++endif
+ endif
+ 
+ CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -7636,6 +7636,7 @@ struct wpa_supplicant * wpa_supplicant_a
+ #endif /* CONFIG_P2P */
+ 
+ 	wpas_ubus_add_bss(wpa_s);
++	wpas_ucode_add_bss(wpa_s);
+ 
+ 	return wpa_s;
+ }
+@@ -7663,6 +7664,7 @@ int wpa_supplicant_remove_iface(struct w
+ 	struct wpa_supplicant *parent = wpa_s->parent;
+ #endif /* CONFIG_MESH */
+ 
++	wpas_ucode_free_bss(wpa_s);
+ 	wpas_ubus_free_bss(wpa_s);
+ 
+ 	/* Remove interface from the global list of interfaces */
+@@ -7973,6 +7975,7 @@ struct wpa_global * wpa_supplicant_init(
+ 
+ 	eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
+ 			       wpas_periodic, global, NULL);
++	wpas_ucode_init(global);
+ 
+ 	return global;
+ }
+@@ -8011,12 +8014,8 @@ int wpa_supplicant_run(struct wpa_global
+ 	eloop_register_signal_terminate(wpa_supplicant_terminate, global);
+ 	eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
+ 
+-	wpas_ubus_add(global);
+-
+ 	eloop_run();
+ 
+-	wpas_ubus_free(global);
+-
+ 	return 0;
+ }
+ 
+@@ -8049,6 +8048,8 @@ void wpa_supplicant_deinit(struct wpa_gl
+ 
+ 	wpas_notify_supplicant_deinitialized(global);
+ 
++	wpas_ucode_free();
++
+ 	eap_peer_unregister_methods();
+ #ifdef CONFIG_AP
+ 	eap_server_unregister_methods();
+--- a/wpa_supplicant/wpa_supplicant_i.h
++++ b/wpa_supplicant/wpa_supplicant_i.h
+@@ -22,6 +22,7 @@
+ #include "wmm_ac.h"
+ #include "pasn/pasn_common.h"
+ #include "ubus.h"
++#include "ucode.h"
+ 
+ extern const char *const wpa_supplicant_version;
+ extern const char *const wpa_supplicant_license;
+@@ -659,6 +660,7 @@ struct wpa_supplicant {
+ 	unsigned char perm_addr[ETH_ALEN];
+ 	char ifname[100];
+ 	struct wpas_ubus_bss ubus;
++	struct wpas_ucode_bss ucode;
+ #ifdef CONFIG_MATCH_IFACE
+ 	int matched;
+ #endif /* CONFIG_MATCH_IFACE */
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -4921,6 +4921,7 @@ try_again:
+ 		return -1;
+ 	}
+ 
++	interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ 	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+ 
+ 	return 0;
+@@ -5022,6 +5023,7 @@ fail:
+ 	os_free(fname);
+ 
+ 	interface->global_ctrl_sock = s;
++	interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ 	eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+ 				 interface, NULL);
+ 
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch
index 0c76276..c0e7e4d 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch
@@ -40,6 +40,15 @@
  	int rts_threshold;
 --- a/src/ap/hostapd.c
 +++ b/src/ap/hostapd.c
+@@ -127,7 +127,7 @@ void hostapd_reconfig_encryption(struct
+ }
+ 
+ 
+-static void hostapd_reload_bss(struct hostapd_data *hapd)
++void hostapd_reload_bss(struct hostapd_data *hapd)
+ {
+ 	struct hostapd_ssid *ssid;
+ 
 @@ -255,6 +255,10 @@ static int hostapd_iface_conf_changed(st
  {
  	size_t i;
@@ -60,7 +69,7 @@
  {
  	struct hapd_interfaces *interfaces = iface->interfaces;
  	struct hostapd_data *hapd = iface->bss[0];
-@@ -296,6 +300,9 @@ int hostapd_reload_config(struct hostapd
+@@ -298,6 +302,9 @@ int hostapd_reload_config(struct hostapd
  		char *fname;
  		int res;
  
@@ -70,7 +79,7 @@
  		hostapd_clear_old(iface);
  
  		wpa_printf(MSG_DEBUG,
-@@ -322,6 +329,24 @@ int hostapd_reload_config(struct hostapd
+@@ -324,6 +331,24 @@ int hostapd_reload_config(struct hostapd
  			wpa_printf(MSG_ERROR,
  				   "Failed to enable interface on config reload");
  		return res;
@@ -95,7 +104,7 @@
  	}
  	iface->conf = newconf;
  
-@@ -338,6 +363,12 @@ int hostapd_reload_config(struct hostapd
+@@ -340,6 +365,12 @@ int hostapd_reload_config(struct hostapd
  
  	for (j = 0; j < iface->num_bss; j++) {
  		hapd = iface->bss[j];
@@ -108,7 +117,17 @@
  		if (!hapd->conf->config_id || !newconf->bss[j]->config_id ||
  		    os_strcmp(hapd->conf->config_id,
  			      newconf->bss[j]->config_id) != 0)
-@@ -2700,6 +2731,10 @@ hostapd_alloc_bss_data(struct hostapd_if
+@@ -1236,8 +1267,7 @@ static int hostapd_start_beacon(struct h
+  * initialized. Most of the modules that are initialized here will be
+  * deinitialized in hostapd_cleanup().
+  */
+-static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+-			     bool start_beacon)
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
+ {
+ 	struct hostapd_bss_config *conf = hapd->conf;
+ 	u8 ssid[SSID_MAX_LEN + 1];
+@@ -2705,6 +2735,10 @@ hostapd_alloc_bss_data(struct hostapd_if
  	hapd->iconf = conf;
  	hapd->conf = bss;
  	hapd->iface = hapd_iface;
@@ -119,9 +138,18 @@
  	if (conf)
  		hapd->driver = conf->driver;
  	hapd->ctrl_sock = -1;
+@@ -2723,7 +2757,7 @@ hostapd_alloc_bss_data(struct hostapd_if
+ }
+ 
+ 
+-static void hostapd_bss_deinit(struct hostapd_data *hapd)
++void hostapd_bss_deinit(struct hostapd_data *hapd)
+ {
+ 	if (!hapd)
+ 		return;
 --- a/src/ap/hostapd.h
 +++ b/src/ap/hostapd.h
-@@ -47,7 +47,7 @@ struct mesh_conf;
+@@ -48,7 +48,7 @@ struct mesh_conf;
  struct hostapd_iface;
  
  struct hapd_interfaces {
@@ -130,23 +158,33 @@
  	struct hostapd_config * (*config_read_cb)(const char *config_fname);
  	int (*ctrl_iface_init)(struct hostapd_data *hapd);
  	void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
-@@ -186,6 +186,7 @@ struct hostapd_data {
- 	struct hostapd_config *iconf;
+@@ -192,6 +192,7 @@ struct hostapd_data {
  	struct hostapd_bss_config *conf;
  	struct hostapd_ubus_bss ubus;
+ 	struct hostapd_ucode_bss ucode;
 +	char *config_id;
  	int interface_added; /* virtual interface added for this BSS */
  	unsigned int started:1;
  	unsigned int disabled:1;
-@@ -689,7 +690,7 @@ struct hostapd_iface {
+@@ -696,7 +697,9 @@ struct hostapd_iface {
  int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
  			       int (*cb)(struct hostapd_iface *iface,
  					 void *ctx), void *ctx);
 -int hostapd_reload_config(struct hostapd_iface *iface);
 +int hostapd_reload_config(struct hostapd_iface *iface, int reconf);
++void hostapd_reload_bss(struct hostapd_data *hapd);
++void hostapd_bss_deinit(struct hostapd_data *hapd);
  void hostapd_reconfig_encryption(struct hostapd_data *hapd);
  struct hostapd_data *
  hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+@@ -713,6 +716,7 @@ struct hostapd_iface * hostapd_init(stru
+ struct hostapd_iface *
+ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ 			   const char *config_fname, int debug);
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon);
+ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ 			   int reassoc);
+ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
 --- a/src/drivers/driver_nl80211.c
 +++ b/src/drivers/driver_nl80211.c
 @@ -5322,6 +5322,9 @@ static int wpa_driver_nl80211_set_ap(voi
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/701-reload_config_inline.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/701-reload_config_inline.patch
new file mode 100644
index 0000000..071281e
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/701-reload_config_inline.patch
@@ -0,0 +1,33 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -4814,7 +4814,12 @@ struct hostapd_config * hostapd_config_r
+ 	int errors = 0;
+ 	size_t i;
+ 
+-	f = fopen(fname, "r");
++	if (!strncmp(fname, "data:", 5)) {
++		f = fmemopen((void *)(fname + 5), strlen(fname + 5), "r");
++		fname = "<inline>";
++	} else {
++		f = fopen(fname, "r");
++	}
+ 	if (f == NULL) {
+ 		wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+ 			   "for reading.", fname);
+--- a/wpa_supplicant/config_file.c
++++ b/wpa_supplicant/config_file.c
+@@ -326,8 +326,13 @@ struct wpa_config * wpa_config_read(cons
+ 	while (cred_tail && cred_tail->next)
+ 		cred_tail = cred_tail->next;
+ 
++	if (!strncmp(name, "data:", 5)) {
++		f = fmemopen((void *)(name + 5), strlen(name + 5), "r");
++		name = "<inline>";
++	} else {
++		f = fopen(name, "r");
++	}
+ 	wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
+-	f = fopen(name, "r");
+ 	if (f == NULL) {
+ 		wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ 			   "error: %s", name, strerror(errno));
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch
index 0bb00f9..5f40aab 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch
@@ -17,7 +17,7 @@
  	} else if (os_strcmp(buf, "extended_key_id") == 0) {
 --- a/src/ap/hostapd.h
 +++ b/src/ap/hostapd.h
-@@ -734,6 +734,7 @@ void hostapd_cleanup_cs_params(struct ho
+@@ -744,6 +744,7 @@ void hostapd_cleanup_cs_params(struct ho
  void hostapd_periodic_iface(struct hostapd_iface *iface);
  int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
  void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
index 124f5ea..3e282b4 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
@@ -32,7 +32,7 @@
  		os_free(bss->dump_msk_file);
 --- a/src/ap/hostapd.c
 +++ b/src/ap/hostapd.c
-@@ -1534,6 +1534,7 @@ static int hostapd_setup_bss(struct host
+@@ -1538,6 +1538,7 @@ int hostapd_setup_bss(struct hostapd_dat
  		wpa_printf(MSG_ERROR, "GAS server initialization failed");
  		return -1;
  	}
@@ -40,7 +40,7 @@
  
  	if (conf->qos_map_set_len &&
  	    hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
-@@ -1541,7 +1542,6 @@ static int hostapd_setup_bss(struct host
+@@ -1545,7 +1546,6 @@ int hostapd_setup_bss(struct hostapd_dat
  		wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
  		return -1;
  	}
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch
index dad7afd..d60764a 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch
@@ -10,7 +10,7 @@
  	unsigned int time_window;
 --- a/src/ap/hostapd.c
 +++ b/src/ap/hostapd.c
-@@ -1471,6 +1471,7 @@ static int hostapd_setup_bss(struct host
+@@ -1475,6 +1475,7 @@ int hostapd_setup_bss(struct hostapd_dat
  
  			os_memset(&das_conf, 0, sizeof(das_conf));
  			das_conf.port = conf->radius_das_port;
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/770-radius_server.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/770-radius_server.patch
new file mode 100644
index 0000000..6fca86d
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/770-radius_server.patch
@@ -0,0 +1,154 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -63,6 +63,10 @@ endif
+ OBJS += main.o
+ OBJS += config_file.o
+ 
++ifdef CONFIG_RADIUS_SERVER
++OBJS += radius.o
++endif
++
+ OBJS += ../src/ap/hostapd.o
+ OBJS += ../src/ap/wpa_auth_glue.o
+ OBJS += ../src/ap/drv_callbacks.o
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -42,6 +42,7 @@ static struct hapd_global global;
+ static int daemonize = 0;
+ static char *pid_file = NULL;
+ 
++extern int radius_main(int argc, char **argv);
+ 
+ #ifndef CONFIG_NO_HOSTAPD_LOGGER
+ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+@@ -755,6 +756,11 @@ int main(int argc, char *argv[])
+ 	if (os_program_init())
+ 		return -1;
+ 
++#ifdef RADIUS_SERVER
++	if (strstr(argv[0], "radius"))
++		return radius_main(argc, argv);
++#endif
++
+ 	os_memset(&interfaces, 0, sizeof(interfaces));
+ 	interfaces.reload_config = hostapd_reload_config;
+ 	interfaces.config_read_cb = hostapd_config_read;
+--- a/src/radius/radius_server.c
++++ b/src/radius/radius_server.c
+@@ -63,6 +63,12 @@ struct radius_server_counters {
+ 	u32 unknown_acct_types;
+ };
+ 
++struct radius_accept_attr {
++	u8 type;
++	u16 len;
++	void *data;
++};
++
+ /**
+  * struct radius_session - Internal RADIUS server data for a session
+  */
+@@ -90,7 +96,7 @@ struct radius_session {
+ 	unsigned int macacl:1;
+ 	unsigned int t_c_filtering:1;
+ 
+-	struct hostapd_radius_attr *accept_attr;
++	struct radius_accept_attr *accept_attr;
+ 
+ 	u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
+ };
+@@ -394,6 +400,7 @@ static void radius_server_session_free(s
+ 	radius_msg_free(sess->last_reply);
+ 	os_free(sess->username);
+ 	os_free(sess->nas_ip);
++	os_free(sess->accept_attr);
+ 	os_free(sess);
+ 	data->num_sess--;
+ }
+@@ -554,6 +561,36 @@ radius_server_erp_find_key(struct radius
+ }
+ #endif /* CONFIG_ERP */
+ 
++static struct radius_accept_attr *
++radius_server_copy_attr(const struct hostapd_radius_attr *data)
++{
++	const struct hostapd_radius_attr *attr;
++	struct radius_accept_attr *attr_new;
++	size_t data_size = 0;
++	void *data_buf;
++	int n_attr = 1;
++
++	for (attr = data; attr; attr = attr->next) {
++		n_attr++;
++		data_size += wpabuf_len(attr->val);
++	}
++
++	attr_new = os_zalloc(n_attr * sizeof(*attr) + data_size);
++	if (!attr_new)
++		return NULL;
++
++	data_buf = &attr_new[n_attr];
++	for (n_attr = 0, attr = data; attr; attr = attr->next) {
++		struct radius_accept_attr *cur = &attr_new[n_attr++];
++
++		cur->type = attr->type;
++		cur->len = wpabuf_len(attr->val);
++		cur->data = memcpy(data_buf, wpabuf_head(attr->val), cur->len);
++		data_buf += cur->len;
++	}
++
++	return attr_new;
++}
+ 
+ static struct radius_session *
+ radius_server_get_new_session(struct radius_server_data *data,
+@@ -607,7 +644,7 @@ radius_server_get_new_session(struct rad
+ 		eap_user_free(tmp);
+ 		return NULL;
+ 	}
+-	sess->accept_attr = tmp->accept_attr;
++	sess->accept_attr = radius_server_copy_attr(tmp->accept_attr);
+ 	sess->macacl = tmp->macacl;
+ 	eap_user_free(tmp);
+ 
+@@ -1118,11 +1155,10 @@ radius_server_encapsulate_eap(struct rad
+ 	}
+ 
+ 	if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+-		struct hostapd_radius_attr *attr;
+-		for (attr = sess->accept_attr; attr; attr = attr->next) {
+-			if (!radius_msg_add_attr(msg, attr->type,
+-						 wpabuf_head(attr->val),
+-						 wpabuf_len(attr->val))) {
++		struct radius_accept_attr *attr;
++		for (attr = sess->accept_attr; attr->data; attr++) {
++			if (!radius_msg_add_attr(msg, attr->type, attr->data,
++						 attr->len)) {
+ 				wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ 				radius_msg_free(msg);
+ 				return NULL;
+@@ -1211,11 +1247,10 @@ radius_server_macacl(struct radius_serve
+ 	}
+ 
+ 	if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+-		struct hostapd_radius_attr *attr;
+-		for (attr = sess->accept_attr; attr; attr = attr->next) {
+-			if (!radius_msg_add_attr(msg, attr->type,
+-						 wpabuf_head(attr->val),
+-						 wpabuf_len(attr->val))) {
++		struct radius_accept_attr *attr;
++		for (attr = sess->accept_attr; attr->data; attr++) {
++			if (!radius_msg_add_attr(msg, attr->type, attr->data,
++						 attr->len)) {
+ 				wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ 				radius_msg_free(msg);
+ 				return NULL;
+@@ -2512,7 +2547,7 @@ static int radius_server_get_eap_user(vo
+ 	ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
+ 				 phase2, user);
+ 	if (ret == 0 && user) {
+-		sess->accept_attr = user->accept_attr;
++		sess->accept_attr = radius_server_copy_attr(user->accept_attr);
+ 		sess->remediation = user->remediation;
+ 		sess->macacl = user->macacl;
+ 		sess->t_c_timestamp = user->t_c_timestamp;
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
index 4e51a1c..4fa2dfb 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
@@ -1,8 +1,8 @@
-From df9a616286f2d33e5c580517238b93ee22359f95 Mon Sep 17 00:00:00 2001
+From bfca3c43597bf827e4d5faec91ac8f420d33c921 Mon Sep 17 00:00:00 2001
 From: "howard.hsu" <howard-yh.hsu@mediatek.com>
 Date: Wed, 19 Jan 2022 19:18:07 +0800
-Subject: [PATCH 01/32] hostapd: mtk: Add neighbor report and BSS Termination
- for MBO certification
+Subject: [PATCH] hostapd: mtk: Add neighbor report and BSS Termination for MBO
+ certification
 
 1. Add hostapd_neighbor_count() and hostapd_neighbor_insert_buffer ()
 The first function can count the number of neighbor report in neighbore report
@@ -13,12 +13,11 @@
 3. Support including neignbor report elements in BTM response
 4. Support configuring BSS Termination TSF by using hostapd_cli command
 5. Disable interface if BSS Termination TSF is set
-6. Add set_send_disassoc_frame_timer() to send disassociate frame
-Function set_disassoc_timer() may fail if key was deleted first. This new
-function will not ask to delete key as set_disassoc_timer() did.
-7. Support including neighbor report elements in BTM request
-8. Add hostapd_neighbor_set_own_report_pref()
-9. Add hostapd_neighbor_set_pref_by_non_pref_chan()
+6. Support including neighbor report elements in BTM request
+7. Add hostapd_neighbor_set_own_report_pref()
+8. Add hostapd_neighbor_set_pref_by_non_pref_chan()
+
+Revert set_send_disassoc_frame_timer
 ---
  hostapd/ctrl_iface.c   |   5 ++
  src/ap/ap_config.c     |   1 +
@@ -28,11 +27,11 @@
  src/ap/gas_serv.h      |   2 +
  src/ap/neighbor_db.c   | 119 +++++++++++++++++++++++++++++++++++++++++
  src/ap/neighbor_db.h   |   9 ++++
- src/ap/wnm_ap.c        |  72 +++++++++++++++++++++++--
- 9 files changed, 252 insertions(+), 5 deletions(-)
+ src/ap/wnm_ap.c        |  42 ++++++++++++++-
+ 9 files changed, 223 insertions(+), 4 deletions(-)
 
 diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
-index 55711ab10..fab1287cd 100644
+index 55711ab..fab1287 100644
 --- a/hostapd/ctrl_iface.c
 +++ b/hostapd/ctrl_iface.c
 @@ -1347,6 +1347,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
@@ -48,7 +47,7 @@
  		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
  		if (ret)
 diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
-index 41c70708d..7d0de122d 100644
+index 41c7070..7d0de12 100644
 --- a/src/ap/ap_config.c
 +++ b/src/ap/ap_config.c
 @@ -171,6 +171,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
@@ -60,7 +59,7 @@
  
  
 diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
-index 02fd4940c..dc6025279 100644
+index 02fd494..dc60252 100644
 --- a/src/ap/ap_config.h
 +++ b/src/ap/ap_config.h
 @@ -558,6 +558,7 @@ struct hostapd_bss_config {
@@ -72,7 +71,7 @@
  	/* IEEE 802.11u - Interworking */
  	int interworking;
 diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
-index 50a4dc4d6..cf1cff447 100644
+index 50a4dc4..cf1cff4 100644
 --- a/src/ap/ctrl_iface_ap.c
 +++ b/src/ap/ctrl_iface_ap.c
 @@ -1280,6 +1280,10 @@ int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
@@ -115,7 +114,7 @@
  	if (pos) {
  		unsigned int mbo_reason, cell_pref, reassoc_delay;
 diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
-index 4642e4927..cce6df41c 100644
+index 4642e49..cce6df4 100644
 --- a/src/ap/gas_serv.c
 +++ b/src/ap/gas_serv.c
 @@ -19,6 +19,7 @@
@@ -183,7 +182,7 @@
  #ifdef CONFIG_FILS
  		if (info_id == ANQP_FILS_REALM_INFO &&
 diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
-index 7646a98a4..ce492b53f 100644
+index 7646a98..ce492b5 100644
 --- a/src/ap/gas_serv.h
 +++ b/src/ap/gas_serv.h
 @@ -40,6 +40,8 @@
@@ -196,7 +195,7 @@
   * First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
   * optimized bitmap.
 diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
-index 5b276e8da..1c14b3201 100644
+index 5b276e8..1c14b32 100644
 --- a/src/ap/neighbor_db.c
 +++ b/src/ap/neighbor_db.c
 @@ -89,6 +89,38 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
@@ -330,7 +329,7 @@
 +}
 +#endif
 diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
-index 992671b62..a1ddc075b 100644
+index 992671b..a1ddc07 100644
 --- a/src/ap/neighbor_db.h
 +++ b/src/ap/neighbor_db.h
 @@ -24,4 +24,13 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
@@ -348,7 +347,7 @@
 +#endif
  #endif /* NEIGHBOR_DB_H */
 diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
-index ba1dd2ed1..32ccf14ae 100644
+index ba1dd2e..939d447 100644
 --- a/src/ap/wnm_ap.c
 +++ b/src/ap/wnm_ap.c
 @@ -20,6 +20,7 @@
@@ -402,38 +401,10 @@
  	hapd->openwrt_stats.wnm.bss_transition_request_tx++;
  	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
  		   MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
-@@ -890,6 +911,50 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+@@ -890,6 +911,22 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
  }
  
  
-+static void set_send_disassoc_frame_timer(struct hostapd_data *hapd, struct sta_info *sta,
-+			       int disassoc_timer)
-+{
-+	int timeout, beacon_int;
-+
-+	/*
-+	 * Prevent STA from reconnecting using cached PMKSA to force
-+	 * full authentication with the authentication server (which may
-+	 * decide to reject the connection),
-+	 */
-+	wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
-+
-+	beacon_int = hapd->iconf->beacon_int;
-+	if (beacon_int < 1)
-+		beacon_int = 100; /* best guess */
-+	/* Calculate timeout in ms based on beacon_int in TU */
-+	timeout = disassoc_timer * beacon_int * 128 / 125;
-+	wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
-+		   " set to %d ms", MAC2STR(sta->addr), timeout);
-+
-+	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
-+
-+	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
-+	if (sta)
-+		ap_sta_disassociate(hapd, sta, reason);
-+}
-+
-+
 +void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
 +{
 +	struct hostapd_data *hapd = eloop_ctx;
@@ -453,16 +424,7 @@
  int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
  				   struct sta_info *sta, const char *url,
  				   int disassoc_timer)
-@@ -934,7 +999,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
- 	hapd->openwrt_stats.wnm.bss_transition_request_tx++;
- 	if (disassoc_timer) {
- 		/* send disassociation frame after time-out */
--		set_disassoc_timer(hapd, sta, disassoc_timer);
-+		set_send_disassoc_frame_timer(hapd, sta, disassoc_timer);
- 	}
- 
- 	return 0;
-@@ -979,6 +1044,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
+@@ -979,6 +1016,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
  	    bss_term_dur) {
  		os_memcpy(pos, bss_term_dur, 12);
  		pos += 12;
@@ -471,5 +433,5 @@
  
  	if (url) {
 -- 
-2.39.2
+2.18.0
 
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
similarity index 89%
rename from recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch
rename to recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
index af79b24..dbd7163 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
@@ -1,4 +1,4 @@
-From ff273381d463d82898df70cb7b43341405e3d943 Mon Sep 17 00:00:00 2001
+From 67e2363c4875dd918418dd84b43f86041db690c7 Mon Sep 17 00:00:00 2001
 From: Evelyn Tsai <evelyn.tsai@mediatek.com>
 Date: Fri, 12 May 2023 05:21:28 +0800
 Subject: [PATCH] hostapd: mtk: Avoid setting beacon after wpa_supplicant stop
@@ -19,7 +19,7 @@
  6 files changed, 22 insertions(+), 6 deletions(-)
 
 diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
-index 9989a04..4952bef 100644
+index e575c37d1..0e352c5c7 100644
 --- a/hostapd/ctrl_iface.c
 +++ b/hostapd/ctrl_iface.c
 @@ -194,11 +194,15 @@ static int hostapd_ctrl_iface_update(struct hostapd_data *hapd, char *txt)
@@ -39,7 +39,7 @@
  
  	iface->interfaces->config_read_cb = config_read_cb;
 diff --git a/src/ap/beacon.c b/src/ap/beacon.c
-index f26e525..1aaeaa8 100644
+index f26e5254c..1aaeaa8e4 100644
 --- a/src/ap/beacon.c
 +++ b/src/ap/beacon.c
 @@ -2246,7 +2246,8 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
@@ -69,7 +69,7 @@
  			ret = -1;
  	}
 diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c
-index 725d3cd..f2a1a10 100644
+index 725d3cd34..78fd9d8ec 100644
 --- a/src/ap/bss_load.c
 +++ b/src/ap/bss_load.c
 @@ -49,6 +49,9 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
@@ -104,7 +104,7 @@
  			       NULL);
  }
 diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
-index aab8a46..d52188b 100644
+index aab8a4665..d52188bb7 100644
 --- a/src/ap/ctrl_iface_ap.c
 +++ b/src/ap/ctrl_iface_ap.c
 @@ -1028,8 +1028,10 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
@@ -120,18 +120,18 @@
  	return 0;
  }
 diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
-index abadd1a..afe0611 100644
+index 28e549b61..be75613c8 100644
 --- a/src/ap/hostapd.c
 +++ b/src/ap/hostapd.c
-@@ -508,6 +508,7 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
+@@ -510,6 +510,7 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
  	}
  	hapd->started = 0;
  	hapd->beacon_set_done = 0;
 +	hapd->stopped_by_supplicant = 0;
  
  	wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
- 	hostapd_ubus_free_bss(hapd);
-@@ -1316,6 +1317,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+ 	hostapd_ucode_free_bss(hapd);
+@@ -1320,6 +1321,7 @@ int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
  		return -1;
  	}
  	hapd->started = 1;
@@ -139,7 +139,7 @@
  
  	if (!first || first == -1) {
  		u8 *addr = hapd->own_addr;
-@@ -4285,7 +4287,7 @@ void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
+@@ -4289,7 +4291,7 @@ void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
  {
  	struct os_reltime now;
  
@@ -149,10 +149,10 @@
  
  	if (os_get_reltime(&now))
 diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
-index 072205c..4f1f988 100644
+index 5bd1537fe..435dbd027 100644
 --- a/src/ap/hostapd.h
 +++ b/src/ap/hostapd.h
-@@ -191,6 +191,7 @@ struct hostapd_data {
+@@ -197,6 +197,7 @@ struct hostapd_data {
  	unsigned int started:1;
  	unsigned int disabled:1;
  	unsigned int reenable_beacon:1;
@@ -161,5 +161,5 @@
  	u8 own_addr[ETH_ALEN];
  	u8 mld_addr[ETH_ALEN];
 -- 
-2.25.1
+2.39.2
 
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch
new file mode 100644
index 0000000..dd121ca
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch
@@ -0,0 +1,64 @@
+From 76e54b095fdd8ab65a562c28fba330afcfb519ec Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Wed, 5 Jul 2023 10:44:15 +0800
+Subject: [PATCH] hostapd: mtk: Fix background channel overlapping operating
+ channel issue
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/dfs.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/src/ap/dfs.c b/src/ap/dfs.c
+index 2f5c86e..c9a9c6c 100644
+--- a/src/ap/dfs.c
++++ b/src/ap/dfs.c
+@@ -807,6 +807,20 @@ static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
+ }
+ 
+ 
++static void dfs_check_background_overlapped(struct hostapd_iface *iface)
++{
++	int width = hostapd_get_oper_chwidth(iface->conf);
++
++	if (!dfs_use_radar_background(iface))
++		return;
++
++	if (dfs_are_channels_overlapped(iface, iface->radar_background.freq,
++					width, iface->radar_background.centr_freq_seg0_idx,
++					iface->radar_background.centr_freq_seg1_idx))
++		iface->radar_background.channel = -1;
++}
++
++
+ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
+ 				     int start_chan_idx, int n_chans)
+ {
+@@ -1127,6 +1141,8 @@ static void hostpad_dfs_update_background_chain(struct hostapd_iface *iface)
+ 						  &oper_centr_freq_seg1_idx,
+ 						  &channel_type);
+ 	if (!channel ||
++	    channel->chan == iface->conf->channel ||
++	    channel->chan == iface->radar_background.channel ||
+ 	    hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ 				  channel->freq, channel->chan,
+ 				  iface->conf->ieee80211n,
+@@ -1361,6 +1377,7 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
+ 	hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ 					     oper_centr_freq_seg1_idx);
+ 	err = 0;
++	dfs_check_background_overlapped(iface);
+ 
+ 	hostapd_setup_interface_complete(iface, err);
+ 	return err;
+@@ -1488,6 +1505,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+ 			hostapd_set_oper_centr_freq_seg1_idx(
+ 				iface->conf, oper_centr_freq_seg1_idx);
+ 
++			dfs_check_background_overlapped(iface);
+ 			hostapd_disable_iface(iface);
+ 			hostapd_enable_iface(iface);
+ 			return 0;
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
new file mode 100644
index 0000000..7cd34cd
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
@@ -0,0 +1,30 @@
+From 1671a37b5990929bd11823158d496e7877d83d92 Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Wed, 2 Aug 2023 18:33:31 +0800
+Subject: [PATCH 38/38] hostapd: mtk: Fix 11vmbss aid using wrong pool
+
+Fix 11vmbss aid using wrong pool.
+All STAs use the aid pool in transmitted bss.
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index d36798e..f20073c 100755
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -3307,6 +3307,9 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ {
+ 	int i, j = 32, aid;
+ 
++	if (hapd->iconf->mbssid)
++		hapd = hostapd_mbssid_get_tx_bss(hapd);
++
+ 	/* get a unique AID */
+ 	if (sta->aid > 0) {
+ 		wpa_printf(MSG_DEBUG, "  old AID %d", sta->aid);
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
new file mode 100644
index 0000000..9218f9b
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
@@ -0,0 +1,34 @@
+From ea3e20d6cc8d11750e509a701131297da81ef35d Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Mon, 7 Aug 2023 15:27:27 +0800
+Subject: [PATCH 39/39] hostapd: mtk: Fix rnr ie length when no need to report
+ bss
+
+Fix rnr ie length when no need to report bss. If we don't have content in
+TBTT then don't change the length of the ie (*size_offset).
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index f20073c..ef520c8 100755
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -7494,8 +7494,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
+ 		}
+ 
+ 		start = i;
+-		*tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+-		*size_offset = (eid - size_offset) - 1;
++		if (tbtt_count != 0) {
++			*tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
++			*size_offset = (eid - size_offset) - 1;
++		}
+ 	}
+ 
+ 	if (tbtt_count == 0)
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
new file mode 100644
index 0000000..0a27496
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
@@ -0,0 +1,44 @@
+From 2ea36366ea036e3063ff553a2939c9cac17c6ac8 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 8 Aug 2023 19:21:41 +0800
+Subject: [PATCH] hostapd: mtk: add back ht vht cap missing field before dfs
+ channel fallback
+
+hostapd_event_ch_switch would set / clear ht_capab and vht_capab, based
+on the bandwidth of switched channel.
+For example, vht bw 160 support field would be cleared if we switch to
+non bw 160 channel.
+This design works fine with NON-DFS channel switch.
+However, for those DFS channels who require CAC, channel switch command
+calls hostapd_switch_channel_fallback instead of hostapd_switch_channel.
+This is simply restarting the interface not CHANNEL SWITCHING, so
+hostapd will not receive any ch_switch event from kernel.
+Therefore, the cleared field in vht_capab will not be set back to 1,
+even if we channel switch to dfs channel bw 160.
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/hostapd.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index c2e0b13..4b7ebc5 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -4161,6 +4161,13 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ 		break;
+ 	}
+ 
++	if ((iface->current_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
++	    freq_params->bandwidth > 20)
++		iface->conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
++	if ((iface->current_mode->vht_capab & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) &&
++	    freq_params->bandwidth == 160)
++		iface->conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++
+ 	iface->freq = freq_params->freq;
+ 	iface->conf->channel = freq_params->channel;
+ 	iface->conf->secondary_channel = freq_params->sec_channel_offset;
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
index 78dae59..89585bc 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
@@ -17,6 +17,7 @@
     file://150-add-NULL-checks-encountered-during-tests-hwsim.patch \
     file://160-dpp_pkex-EC-point-mul-w-value-prime.patch \
     file://170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch \
+    file://180-BSS-coloring-fix-CCA-with-multiple-BSS.patch \
     file://200-multicall.patch \
     file://300-noscan.patch \
     file://301-mesh-noscan.patch \
@@ -46,8 +47,10 @@
     file://590-rrm-wnm-statistics.patch \
     file://599-wpa_supplicant-fix-warnings.patch \
     file://600-ubus_support.patch \
+    file://601-ucode_support.patch \
     file://610-hostapd_cli_ujail_permission.patch \
     file://700-wifi-reload.patch \
+    file://701-reload_config_inline.patch \
     file://710-vlan_no_bridge.patch \
     file://711-wds_bridge_force.patch \
     file://720-iface_max_num_sta.patch \
@@ -57,6 +60,7 @@
     file://751-qos_map_ignore_when_unsupported.patch \
     file://760-dynamic_own_ip.patch \
     file://761-shared_das_port.patch \
+    file://770-radius_server.patch \
     file://990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch \
     file://mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch \
     file://mtk-0002-hostapd-mtk-print-sae-groups-by-hostapd-ctrl.patch \
@@ -83,17 +87,20 @@
     file://mtk-0023-hostapd-mtk-Add-vendor-for-CAPI-certification-comman.patch \
     file://mtk-0024-hostapd-mtk-Air-Monitor-support-in-hostapd-by-vendor.patch \
     file://mtk-0025-hostapd-mtk-Fix-scan-result-updating-issue.patch \
-    file://mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch \
+    file://mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch \
     file://mtk-0027-hostapd-mtk-Fix-setting-wrong-seg0-index-for-5G-cent.patch \
     file://mtk-0028-hostapd-mtk-Add-muru-user-number-debug-command.patch \
-    file://mtk-0029-hostapd-mtk-Fix-CCA-issue.patch \
     file://mtk-0030-hostapd-mtk-Fix-unexpected-AP-beacon-state-transitio.patch \
     file://mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch \
     file://mtk-0032-hostapd-mtk-Add-HE-capabilities-check.patch \
+    file://mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch \
     file://mtk-0034-hostapd-mtk-Fix-hostapd_dfs_start_cac-log.patch \
     file://mtk-0035-hostapd-mtk-Check-the-bridge-after-ioctl-SIOCBRADDIF.patch \
     file://mtk-0036-hostapd-mtk-Update-parameter_set_count-in-MU-EDCA-IE.patch \
     file://mtk-0037-hostapd-mtk-Add-extension-IE-list-for-non-inherit-IE.patch \
+    file://mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch \
+    file://mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch \
+    file://mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch \
     file://mtk-1000-hostapd-mtk-update-eht-operation-element.patch \
     file://mtk-1001-hostapd-mtk-Add-support-for-gtk-rekeying-in-hostapd-.patch \
     "
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
index f51b42f..b3f4138 100644
--- a/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
@@ -1,7 +1,7 @@
-From e063e89785d74506976e34a0a3cbb14836d6b8e3 Mon Sep 17 00:00:00 2001
+From 53a7b7af61b75ea0e3f9d12d3d6302cf40941a8a Mon Sep 17 00:00:00 2001
 From: TomLiu <tomml.liu@mediatek.com>
 Date: Tue, 9 Aug 2022 10:23:44 -0700
-Subject: [PATCH 06/35] hostapd: mtk: Add hostapd MU SET/GET control
+Subject: [PATCH 06/37] hostapd: mtk: Add hostapd MU SET/GET control
 
 ---
  hostapd/config_file.c             |   9 +++
@@ -156,14 +156,14 @@
  	{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
  	  "report a scanned DPP URI from a QR Code" },
 diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
-index 344585a..d4fc191 100644
+index 344585a..1b0e990 100644
 --- a/src/ap/ap_config.c
 +++ b/src/ap/ap_config.c
 @@ -280,6 +280,7 @@ struct hostapd_config * hostapd_config_defaults(void)
  	conf->he_6ghz_max_ampdu_len_exp = 7;
  	conf->he_6ghz_rx_ant_pat = 1;
  	conf->he_6ghz_tx_ant_pat = 1;
-+	conf->mu_onoff = 13;
++	conf->mu_onoff = 0xf;
  #endif /* CONFIG_IEEE80211AX */
  
  	/* The third octet of the country string uses an ASCII space character
@@ -446,5 +446,5 @@
  			}
  
 -- 
-2.18.0
+2.39.0
 
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
new file mode 100644
index 0000000..aff2234
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
@@ -0,0 +1,30 @@
+From 845f192fe55b4774425752ecba8cb8f5c4e24c69 Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Wed, 2 Aug 2023 18:33:31 +0800
+Subject: [PATCH 37/38] hostapd: mtk: Fix 11vmbss aid using wrong pool
+
+Fix 11vmbss aid using wrong pool.
+All STAs use the aid pool in transmitted bss.
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index f866b8a..b73b821 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -4002,6 +4002,9 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ {
+ 	int i, j = 32, aid;
+ 
++	if (hapd->iconf->mbssid)
++		hapd = hostapd_mbssid_get_tx_bss(hapd);
++
+ 	/* get a unique AID */
+ 	if (sta->aid > 0) {
+ 		wpa_printf(MSG_DEBUG, "  old AID %d", sta->aid);
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
new file mode 100644
index 0000000..ec82302
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
@@ -0,0 +1,44 @@
+From 87ed81b81030cb5567c04227d0fe65c6a15148f3 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 8 Aug 2023 19:21:41 +0800
+Subject: [PATCH] hostapd: mtk: add back ht vht cap missing field before dfs
+ channel fallback
+
+hostapd_event_ch_switch would set / clear ht_capab and vht_capab, based
+on the bandwidth of switched channel.
+For example, vht bw 160 support field would be cleared if we switch to
+non bw 160 channel.
+This design works fine with NON-DFS channel switch.
+However, for those DFS channels who require CAC, channel switch command
+calls hostapd_switch_channel_fallback instead of hostapd_switch_channel.
+This is simply restarting the interface not CHANNEL SWITCHING, so
+hostapd will not receive any ch_switch event from kernel.
+Therefore, the cleared field in vht_capab will not be set back to 1,
+even if we channel switch to dfs channel bw 160.
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/hostapd.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 707e7d5..5d17cf8 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -3888,6 +3888,13 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ 		break;
+ 	}
+ 
++	if ((iface->current_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
++	    freq_params->bandwidth > 20)
++		iface->conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
++	if ((iface->current_mode->vht_capab & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) &&
++	    freq_params->bandwidth == 160)
++		iface->conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++
+ 	iface->freq = freq_params->freq;
+ 	iface->conf->channel = freq_params->channel;
+ 	iface->conf->secondary_channel = freq_params->sec_channel_offset;
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
new file mode 100644
index 0000000..d6fa8b6
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
@@ -0,0 +1,34 @@
+From 70c8f9355c4df3c083965ce652d33e01f8fe7e7c Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Mon, 7 Aug 2023 15:27:27 +0800
+Subject: [PATCH 38/38] hostapd: mtk: Fix rnr ie length when no need to report
+ bss
+
+Fix rnr ie length when no need to report bss. If we don't have content in
+TBTT then don't change the length of the ie (*size_offset).
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index b73b821..ff39fad 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -7530,8 +7530,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
+ 		}
+ 
+ 		start = i;
+-		*tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+-		*size_offset = (eid - size_offset) - 1;
++		if (tbtt_count != 0) {
++			*tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
++			*size_offset = (eid - size_offset) - 1;
++		}
+ 	}
+ 
+ 	if (tbtt_count == 0)
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/patches.inc b/recipes-wifi/wpa-supplicant/files/patches/patches.inc
index 3e8cc14..f783c48 100644
--- a/recipes-wifi/wpa-supplicant/files/patches/patches.inc
+++ b/recipes-wifi/wpa-supplicant/files/patches/patches.inc
@@ -99,4 +99,7 @@
     file://mtk-0035-hostapd-mtk-add-extension-IE-list-for-non-inherit-IE.patch \
     file://mtk-0036-hostapd-mtk-Fix-background-channel-overlapping-opera.patch \
     file://mtk-0036-hostapd-mtk-Fix-wpa_supplicant-configuration-parsing.patch \
+    file://mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch \
+    file://mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch \
+    file://mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch \
     "
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/hostapd/radius.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/hostapd/radius.c
new file mode 100644
index 0000000..362a22c
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/hostapd/radius.c
@@ -0,0 +1,715 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/tls.h"
+
+#include "ap/ap_config.h"
+#include "eap_server/eap.h"
+#include "radius/radius.h"
+#include "radius/radius_server.h"
+#include "eap_register.h"
+
+#include <libubox/blobmsg_json.h>
+#include <libubox/blobmsg.h>
+#include <libubox/avl.h>
+#include <libubox/avl-cmp.h>
+#include <libubox/kvlist.h>
+
+#include <sys/stat.h>
+#include <fnmatch.h>
+
+#define VENDOR_ID_WISPR 14122
+#define VENDOR_ATTR_SIZE 6
+
+struct radius_parse_attr_data {
+	unsigned int vendor;
+	u8 type;
+	int size;
+	char format;
+	const char *data;
+};
+
+struct radius_parse_attr_state {
+	struct hostapd_radius_attr *prev;
+	struct hostapd_radius_attr *attr;
+	struct wpabuf *buf;
+	void *attrdata;
+};
+
+struct radius_user_state {
+	struct avl_node node;
+	struct eap_user data;
+};
+
+struct radius_user_data {
+	struct kvlist users;
+	struct avl_tree user_state;
+	struct blob_attr *wildcard;
+};
+
+struct radius_state {
+	struct radius_server_data *radius;
+	struct eap_config eap;
+
+	struct radius_user_data phase1, phase2;
+	const char *user_file;
+	time_t user_file_ts;
+
+	int n_attrs;
+	struct hostapd_radius_attr *attrs;
+};
+
+struct radius_config {
+	struct tls_connection_params tls;
+	struct radius_server_conf radius;
+};
+
+enum {
+	USER_ATTR_PASSWORD,
+	USER_ATTR_HASH,
+	USER_ATTR_SALT,
+	USER_ATTR_METHODS,
+	USER_ATTR_RADIUS,
+	USER_ATTR_VLAN,
+	USER_ATTR_MAX_RATE_UP,
+	USER_ATTR_MAX_RATE_DOWN,
+	__USER_ATTR_MAX
+};
+
+static void radius_tls_event(void *ctx, enum tls_event ev,
+			      union tls_event_data *data)
+{
+	switch (ev) {
+	case TLS_CERT_CHAIN_SUCCESS:
+		wpa_printf(MSG_DEBUG, "radius: remote certificate verification success");
+		break;
+	case TLS_CERT_CHAIN_FAILURE:
+		wpa_printf(MSG_INFO, "radius: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
+			   data->cert_fail.reason,
+			   data->cert_fail.depth,
+			   data->cert_fail.subject,
+			   data->cert_fail.reason_txt);
+		break;
+	case TLS_PEER_CERTIFICATE:
+		wpa_printf(MSG_DEBUG, "radius: peer certificate: depth=%d serial_num=%s subject=%s",
+			   data->peer_cert.depth,
+			   data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
+			   data->peer_cert.subject);
+		break;
+	case TLS_ALERT:
+		if (data->alert.is_local)
+			wpa_printf(MSG_DEBUG, "radius: local TLS alert: %s",
+				   data->alert.description);
+		else
+			wpa_printf(MSG_DEBUG, "radius: remote TLS alert: %s",
+				   data->alert.description);
+		break;
+	case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+		/* Not applicable to TLS server */
+		break;
+	}
+}
+
+static void radius_userdata_init(struct radius_user_data *u)
+{
+	kvlist_init(&u->users, kvlist_blob_len);
+	avl_init(&u->user_state, avl_strcmp, false, NULL);
+}
+
+static void radius_userdata_free(struct radius_user_data *u)
+{
+	struct radius_user_state *s, *tmp;
+
+	kvlist_free(&u->users);
+	free(u->wildcard);
+	u->wildcard = NULL;
+	avl_remove_all_elements(&u->user_state, s, node, tmp)
+		free(s);
+}
+
+static void
+radius_userdata_load(struct radius_user_data *u, struct blob_attr *data)
+{
+	enum {
+		USERSTATE_USERS,
+		USERSTATE_WILDCARD,
+		__USERSTATE_MAX,
+	};
+	static const struct blobmsg_policy policy[__USERSTATE_MAX] = {
+		[USERSTATE_USERS] = { "users", BLOBMSG_TYPE_TABLE },
+		[USERSTATE_WILDCARD] = { "wildcard", BLOBMSG_TYPE_ARRAY },
+	};
+	struct blob_attr *tb[__USERSTATE_MAX], *cur;
+	int rem;
+
+	if (!data)
+		return;
+
+	blobmsg_parse(policy, __USERSTATE_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+	blobmsg_for_each_attr(cur, tb[USERSTATE_USERS], rem)
+		kvlist_set(&u->users, blobmsg_name(cur), cur);
+
+	if (tb[USERSTATE_WILDCARD])
+		u->wildcard = blob_memdup(tb[USERSTATE_WILDCARD]);
+}
+
+static void
+load_userfile(struct radius_state *s)
+{
+	enum {
+		USERDATA_PHASE1,
+		USERDATA_PHASE2,
+		__USERDATA_MAX
+	};
+	static const struct blobmsg_policy policy[__USERDATA_MAX] = {
+		[USERDATA_PHASE1] = { "phase1", BLOBMSG_TYPE_TABLE },
+		[USERDATA_PHASE2] = { "phase2", BLOBMSG_TYPE_TABLE },
+	};
+	struct blob_attr *tb[__USERDATA_MAX], *cur;
+	static struct blob_buf b;
+	struct stat st;
+	int rem;
+
+	if (stat(s->user_file, &st))
+		return;
+
+	if (s->user_file_ts == st.st_mtime)
+		return;
+
+	s->user_file_ts = st.st_mtime;
+	radius_userdata_free(&s->phase1);
+	radius_userdata_free(&s->phase2);
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_json_from_file(&b, s->user_file);
+	blobmsg_parse(policy, __USERDATA_MAX, tb, blob_data(b.head), blob_len(b.head));
+	radius_userdata_load(&s->phase1, tb[USERDATA_PHASE1]);
+	radius_userdata_load(&s->phase2, tb[USERDATA_PHASE2]);
+
+	blob_buf_free(&b);
+}
+
+static struct blob_attr *
+radius_user_get(struct radius_user_data *s, const char *name)
+{
+	struct blob_attr *cur;
+	int rem;
+
+	cur = kvlist_get(&s->users, name);
+	if (cur)
+		return cur;
+
+	blobmsg_for_each_attr(cur, s->wildcard, rem) {
+		static const struct blobmsg_policy policy = {
+			"name", BLOBMSG_TYPE_STRING
+		};
+		struct blob_attr *pattern;
+
+		if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
+			continue;
+
+		blobmsg_parse(&policy, 1, &pattern, blobmsg_data(cur), blobmsg_len(cur));
+		if (!name)
+			continue;
+
+		if (!fnmatch(blobmsg_get_string(pattern), name, 0))
+			return cur;
+	}
+
+	return NULL;
+}
+
+static struct radius_parse_attr_data *
+radius_parse_attr(struct blob_attr *attr)
+{
+	static const struct blobmsg_policy policy[4] = {
+		{ .type = BLOBMSG_TYPE_INT32 },
+		{ .type = BLOBMSG_TYPE_INT32 },
+		{ .type = BLOBMSG_TYPE_STRING },
+		{ .type = BLOBMSG_TYPE_STRING },
+	};
+	static struct radius_parse_attr_data data;
+	struct blob_attr *tb[4];
+	const char *format;
+
+	blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(attr), blobmsg_len(attr));
+
+	if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
+		return NULL;
+
+	format = blobmsg_get_string(tb[2]);
+	if (strlen(format) != 1)
+		return NULL;
+
+	data.vendor = blobmsg_get_u32(tb[0]);
+	data.type = blobmsg_get_u32(tb[1]);
+	data.format = format[0];
+	data.data = blobmsg_get_string(tb[3]);
+	data.size = strlen(data.data);
+
+	switch (data.format) {
+	case 's':
+		break;
+	case 'x':
+		if (data.size & 1)
+			return NULL;
+		data.size /= 2;
+		break;
+	case 'd':
+		data.size = 4;
+		break;
+	default:
+		return NULL;
+	}
+
+	return &data;
+}
+
+static void
+radius_count_attrs(struct blob_attr **tb, int *n_attr, size_t *attr_size)
+{
+	struct blob_attr *data = tb[USER_ATTR_RADIUS];
+	struct blob_attr *cur;
+	int rem;
+
+	blobmsg_for_each_attr(cur, data, rem) {
+		struct radius_parse_attr_data *data;
+		size_t prev = *attr_size;
+
+		data = radius_parse_attr(cur);
+		if (!data)
+			continue;
+
+		*attr_size += data->size;
+		if (data->vendor)
+			*attr_size += VENDOR_ATTR_SIZE;
+
+		(*n_attr)++;
+	}
+
+	*n_attr += !!tb[USER_ATTR_VLAN] * 3 +
+		   !!tb[USER_ATTR_MAX_RATE_UP] +
+		   !!tb[USER_ATTR_MAX_RATE_DOWN];
+	*attr_size += !!tb[USER_ATTR_VLAN] * (4 + 4 + 5) +
+		      !!tb[USER_ATTR_MAX_RATE_UP] * (4 + VENDOR_ATTR_SIZE) +
+		      !!tb[USER_ATTR_MAX_RATE_DOWN] * (4 + VENDOR_ATTR_SIZE);
+}
+
+static void *
+radius_add_attr(struct radius_parse_attr_state *state,
+		u32 vendor, u8 type, u8 len)
+{
+	struct hostapd_radius_attr *attr;
+	struct wpabuf *buf;
+	void *val;
+
+	val = state->attrdata;
+
+	buf = state->buf++;
+	buf->buf = val;
+
+	attr = state->attr++;
+	attr->val = buf;
+	attr->type = type;
+
+	if (state->prev)
+		state->prev->next = attr;
+	state->prev = attr;
+
+	if (vendor) {
+		u8 *vendor_hdr = val + 4;
+
+		WPA_PUT_BE32(val, vendor);
+		vendor_hdr[0] = type;
+		vendor_hdr[1] = len + 2;
+
+		len += VENDOR_ATTR_SIZE;
+		val += VENDOR_ATTR_SIZE;
+		attr->type = RADIUS_ATTR_VENDOR_SPECIFIC;
+	}
+
+	buf->size = buf->used = len;
+	state->attrdata += len;
+
+	return val;
+}
+
+static void
+radius_parse_attrs(struct blob_attr **tb, struct radius_parse_attr_state *state)
+{
+	struct blob_attr *data = tb[USER_ATTR_RADIUS];
+	struct hostapd_radius_attr *prev = NULL;
+	struct blob_attr *cur;
+	int len, rem;
+	void *val;
+
+	if ((cur = tb[USER_ATTR_VLAN]) != NULL && blobmsg_get_u32(cur) < 4096) {
+		char buf[5];
+
+		val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_TYPE, 4);
+		WPA_PUT_BE32(val, RADIUS_TUNNEL_TYPE_VLAN);
+
+		val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, 4);
+		WPA_PUT_BE32(val, RADIUS_TUNNEL_MEDIUM_TYPE_802);
+
+		len = snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(cur));
+		val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, len);
+		memcpy(val, buf, len);
+	}
+
+	if ((cur = tb[USER_ATTR_MAX_RATE_UP]) != NULL) {
+		val = radius_add_attr(state, VENDOR_ID_WISPR, 7, 4);
+		WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+	}
+
+	if ((cur = tb[USER_ATTR_MAX_RATE_DOWN]) != NULL) {
+		val = radius_add_attr(state, VENDOR_ID_WISPR, 8, 4);
+		WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+	}
+
+	blobmsg_for_each_attr(cur, data, rem) {
+		struct radius_parse_attr_data *data;
+		void *val;
+		int size;
+
+		data = radius_parse_attr(cur);
+		if (!data)
+			continue;
+
+		val = radius_add_attr(state, data->vendor, data->type, data->size);
+		switch (data->format) {
+		case 's':
+			memcpy(val, data->data, data->size);
+			break;
+		case 'x':
+			hexstr2bin(data->data, val, data->size);
+			break;
+		case 'd':
+			WPA_PUT_BE32(val, atoi(data->data));
+			break;
+		}
+	}
+}
+
+static void
+radius_user_parse_methods(struct eap_user *eap, struct blob_attr *data)
+{
+	struct blob_attr *cur;
+	int rem, n = 0;
+
+	if (!data)
+		return;
+
+	blobmsg_for_each_attr(cur, data, rem) {
+		const char *method;
+
+		if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+			continue;
+
+		if (n == EAP_MAX_METHODS)
+			break;
+
+		method = blobmsg_get_string(cur);
+		eap->methods[n].method = eap_server_get_type(method, &eap->methods[n].vendor);
+		if (eap->methods[n].vendor == EAP_VENDOR_IETF &&
+		    eap->methods[n].method == EAP_TYPE_NONE) {
+			if (!strcmp(method, "TTLS-PAP")) {
+				eap->ttls_auth |= EAP_TTLS_AUTH_PAP;
+				continue;
+			}
+			if (!strcmp(method, "TTLS-CHAP")) {
+				eap->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+				continue;
+			}
+			if (!strcmp(method, "TTLS-MSCHAP")) {
+				eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+				continue;
+			}
+			if (!strcmp(method, "TTLS-MSCHAPV2")) {
+				eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+				continue;
+			}
+		}
+		n++;
+	}
+}
+
+static struct eap_user *
+radius_user_get_state(struct radius_user_data *u, struct blob_attr *data,
+		      const char *id)
+{
+	static const struct blobmsg_policy policy[__USER_ATTR_MAX] = {
+		[USER_ATTR_PASSWORD] = { "password", BLOBMSG_TYPE_STRING },
+		[USER_ATTR_HASH] = { "hash", BLOBMSG_TYPE_STRING },
+		[USER_ATTR_SALT] = { "salt", BLOBMSG_TYPE_STRING },
+		[USER_ATTR_METHODS] = { "methods", BLOBMSG_TYPE_ARRAY },
+		[USER_ATTR_RADIUS] = { "radius", BLOBMSG_TYPE_ARRAY },
+		[USER_ATTR_VLAN] = { "vlan-id", BLOBMSG_TYPE_INT32 },
+		[USER_ATTR_MAX_RATE_UP] = { "max-rate-up", BLOBMSG_TYPE_INT32 },
+		[USER_ATTR_MAX_RATE_DOWN] = { "max-rate-down", BLOBMSG_TYPE_INT32 },
+	};
+	struct blob_attr *tb[__USER_ATTR_MAX], *cur;
+	char *password_buf, *salt_buf, *name_buf;
+	struct radius_parse_attr_state astate = {};
+	struct hostapd_radius_attr *attr;
+	struct radius_user_state *state;
+	int pw_len = 0, salt_len = 0;
+	struct eap_user *eap;
+	struct wpabuf *val;
+	size_t attrsize = 0;
+	void *attrdata;
+	int n_attr = 0;
+
+	state = avl_find_element(&u->user_state, id, state, node);
+	if (state)
+		return &state->data;
+
+	blobmsg_parse(policy, __USER_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+	if ((cur = tb[USER_ATTR_SALT]) != NULL)
+		salt_len = strlen(blobmsg_get_string(cur)) / 2;
+	if ((cur = tb[USER_ATTR_HASH]) != NULL)
+		pw_len = strlen(blobmsg_get_string(cur)) / 2;
+	else if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+		pw_len = blobmsg_len(cur) - 1;
+	radius_count_attrs(tb, &n_attr, &attrsize);
+
+	state = calloc_a(sizeof(*state), &name_buf, strlen(id) + 1,
+			 &password_buf, pw_len,
+			 &salt_buf, salt_len,
+			 &astate.attr, n_attr * sizeof(*astate.attr),
+			 &astate.buf, n_attr * sizeof(*astate.buf),
+			 &astate.attrdata, attrsize);
+	eap = &state->data;
+	eap->salt = salt_len ? salt_buf : NULL;
+	eap->salt_len = salt_len;
+	eap->password = pw_len ? password_buf : NULL;
+	eap->password_len = pw_len;
+	eap->force_version = -1;
+
+	if ((cur = tb[USER_ATTR_SALT]) != NULL)
+		hexstr2bin(blobmsg_get_string(cur), salt_buf, salt_len);
+	if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+		memcpy(password_buf, blobmsg_get_string(cur), pw_len);
+	else if ((cur = tb[USER_ATTR_HASH]) != NULL) {
+		hexstr2bin(blobmsg_get_string(cur), password_buf, pw_len);
+		eap->password_hash = 1;
+	}
+	radius_user_parse_methods(eap, tb[USER_ATTR_METHODS]);
+
+	if (n_attr > 0) {
+		cur = tb[USER_ATTR_RADIUS];
+		eap->accept_attr = astate.attr;
+		radius_parse_attrs(tb, &astate);
+	}
+
+	state->node.key = strcpy(name_buf, id);
+	avl_insert(&u->user_state, &state->node);
+
+	return &state->data;
+
+free:
+	free(state);
+	return NULL;
+}
+
+static int radius_get_eap_user(void *ctx, const u8 *identity,
+			       size_t identity_len, int phase2,
+			       struct eap_user *user)
+{
+	struct radius_state *s = ctx;
+	struct radius_user_data *u = phase2 ? &s->phase2 : &s->phase1;
+	struct blob_attr *entry;
+	struct eap_user *data;
+	char *id;
+
+	if (identity_len > 512)
+		return -1;
+
+	load_userfile(s);
+
+	id = alloca(identity_len + 1);
+	memcpy(id, identity, identity_len);
+	id[identity_len] = 0;
+
+	entry = radius_user_get(u, id);
+	if (!entry)
+		return -1;
+
+	if (!user)
+		return 0;
+
+	data = radius_user_get_state(u, entry, id);
+	if (!data)
+		return -1;
+
+	*user = *data;
+	if (user->password_len > 0)
+		user->password = os_memdup(user->password, user->password_len);
+	if (user->salt_len > 0)
+		user->salt = os_memdup(user->salt, user->salt_len);
+	user->phase2 = phase2;
+
+	return 0;
+}
+
+static int radius_setup(struct radius_state *s, struct radius_config *c)
+{
+	struct eap_config *eap = &s->eap;
+	struct tls_config conf = {
+		.event_cb = radius_tls_event,
+		.tls_flags = TLS_CONN_DISABLE_TLSv1_3,
+		.cb_ctx = s,
+	};
+
+	eap->eap_server = 1;
+	eap->max_auth_rounds = 100;
+	eap->max_auth_rounds_short = 50;
+	eap->ssl_ctx = tls_init(&conf);
+	if (!eap->ssl_ctx) {
+		wpa_printf(MSG_INFO, "TLS init failed\n");
+		return 1;
+	}
+
+	if (tls_global_set_params(eap->ssl_ctx, &c->tls)) {
+		wpa_printf(MSG_INFO, "failed to set TLS parameters\n");
+		return 1;
+	}
+
+	c->radius.eap_cfg = eap;
+	c->radius.conf_ctx = s;
+	c->radius.get_eap_user = radius_get_eap_user;
+	s->radius = radius_server_init(&c->radius);
+	if (!s->radius) {
+		wpa_printf(MSG_INFO, "failed to initialize radius server\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int radius_init(struct radius_state *s)
+{
+	memset(s, 0, sizeof(*s));
+	radius_userdata_init(&s->phase1);
+	radius_userdata_init(&s->phase2);
+}
+
+static void radius_deinit(struct radius_state *s)
+{
+	if (s->radius)
+		radius_server_deinit(s->radius);
+
+	if (s->eap.ssl_ctx)
+		tls_deinit(s->eap.ssl_ctx);
+
+	radius_userdata_free(&s->phase1);
+	radius_userdata_free(&s->phase2);
+}
+
+static int usage(const char *progname)
+{
+	fprintf(stderr, "Usage: %s <options>\n",
+		progname);
+}
+
+int radius_main(int argc, char **argv)
+{
+	static struct radius_state state = {};
+	static struct radius_config config = {};
+	const char *progname = argv[0];
+	int ret = 0;
+	int ch;
+
+	wpa_debug_setup_stdout();
+	wpa_debug_level = 0;
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return 1;
+	}
+
+	eap_server_register_methods();
+	radius_init(&state);
+
+	while ((ch = getopt(argc, argv, "6C:c:d:i:k:K:p:P:s:u:")) != -1) {
+		switch (ch) {
+		case '6':
+			config.radius.ipv6 = 1;
+			break;
+		case 'C':
+			config.tls.ca_cert = optarg;
+			break;
+		case 'c':
+			if (config.tls.client_cert2)
+				return usage(progname);
+
+			if (config.tls.client_cert)
+				config.tls.client_cert2 = optarg;
+			else
+				config.tls.client_cert = optarg;
+			break;
+		case 'd':
+			config.tls.dh_file = optarg;
+			break;
+		case 'i':
+			state.eap.server_id = optarg;
+			state.eap.server_id_len = strlen(optarg);
+			break;
+		case 'k':
+			if (config.tls.private_key2)
+				return usage(progname);
+
+			if (config.tls.private_key)
+				config.tls.private_key2 = optarg;
+			else
+				config.tls.private_key = optarg;
+			break;
+		case 'K':
+			if (config.tls.private_key_passwd2)
+				return usage(progname);
+
+			if (config.tls.private_key_passwd)
+				config.tls.private_key_passwd2 = optarg;
+			else
+				config.tls.private_key_passwd = optarg;
+			break;
+		case 'p':
+			config.radius.auth_port = atoi(optarg);
+			break;
+		case 'P':
+			config.radius.acct_port = atoi(optarg);
+			break;
+		case 's':
+			config.radius.client_file = optarg;
+			break;
+		case 'u':
+			state.user_file = optarg;
+			break;
+		default:
+			return usage(progname);
+		}
+	}
+
+	if (!config.tls.client_cert || !config.tls.private_key ||
+	    !config.radius.client_file || !state.eap.server_id ||
+	    !state.user_file) {
+		wpa_printf(MSG_INFO, "missing options\n");
+		goto out;
+	}
+
+	ret = radius_setup(&state, &config);
+	if (ret)
+		goto out;
+
+	load_userfile(&state);
+	eloop_run();
+
+out:
+	radius_deinit(&state);
+	os_program_deinit();
+
+	return ret;
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.c
new file mode 100644
index 0000000..a609eb1
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.c
@@ -0,0 +1,2002 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/wpabuf.h"
+#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
+#include "hostapd.h"
+#include "neighbor_db.h"
+#include "wps_hostapd.h"
+#include "sta_info.h"
+#include "ubus.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+#include "rrm.h"
+#include "wnm_ap.h"
+#include "taxonomy.h"
+#include "airtime_policy.h"
+#include "hw_features.h"
+
+static struct ubus_context *ctx;
+static struct blob_buf b;
+static int ctx_ref;
+
+static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
+{
+	return container_of(obj, struct hostapd_data, ubus.obj);
+}
+
+struct ubus_banned_client {
+	struct avl_node avl;
+	u8 addr[ETH_ALEN];
+};
+
+static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
+{
+	if (ubus_reconnect(ctx, NULL)) {
+		eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+		return;
+	}
+
+	ubus_add_uloop(ctx);
+}
+
+static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
+{
+	uloop_fd_delete(&ctx->sock);
+	eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+}
+
+static bool hostapd_ubus_init(void)
+{
+	if (ctx)
+		return true;
+
+	eloop_add_uloop();
+	ctx = ubus_connect(NULL);
+	if (!ctx)
+		return false;
+
+	ctx->connection_lost = hostapd_ubus_connection_lost;
+	ubus_add_uloop(ctx);
+
+	return true;
+}
+
+static void hostapd_ubus_ref_inc(void)
+{
+	ctx_ref++;
+}
+
+static void hostapd_ubus_ref_dec(void)
+{
+	ctx_ref--;
+	if (!ctx)
+		return;
+
+	if (ctx_ref)
+		return;
+
+	uloop_fd_delete(&ctx->sock);
+	ubus_free(ctx);
+	ctx = NULL;
+}
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+	if (!hostapd_ubus_init())
+		return;
+}
+
+void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+	if (!ctx)
+		return;
+}
+
+static void hostapd_notify_ubus(struct ubus_object *obj, char *bssname, char *event)
+{
+	char *event_type;
+
+	if (!ctx || !obj)
+		return;
+
+	if (asprintf(&event_type, "bss.%s", event) < 0)
+		return;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_string(&b, "name", bssname);
+	ubus_notify(ctx, obj, event_type, b.head, -1);
+	free(event_type);
+}
+
+static void
+hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
+{
+	struct ubus_banned_client *ban = eloop_data;
+	struct hostapd_data *hapd = user_ctx;
+
+	avl_delete(&hapd->ubus.banned, &ban->avl);
+	free(ban);
+}
+
+static void
+hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time)
+{
+	struct ubus_banned_client *ban;
+
+	if (time < 0)
+		time = 0;
+
+	ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+	if (!ban) {
+		if (!time)
+			return;
+
+		ban = os_zalloc(sizeof(*ban));
+		memcpy(ban->addr, addr, sizeof(ban->addr));
+		ban->avl.key = ban->addr;
+		avl_insert(&hapd->ubus.banned, &ban->avl);
+	} else {
+		eloop_cancel_timeout(hostapd_bss_del_ban, ban, hapd);
+		if (!time) {
+			hostapd_bss_del_ban(ban, hapd);
+			return;
+		}
+	}
+
+	eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd);
+}
+
+static int
+hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
+		   struct ubus_request_data *req, const char *method,
+		   struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	return hostapd_reload_config(hapd->iface, 1);
+}
+
+
+static void
+hostapd_parse_vht_map_blobmsg(uint16_t map)
+{
+	char label[4];
+	int16_t val;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		snprintf(label, 4, "%dss", i + 1);
+
+		val = (map & (BIT(1) | BIT(0))) + 7;
+		blobmsg_add_u16(&b, label, val == 10 ? -1 : val);
+		map = map >> 2;
+	}
+}
+
+static void
+hostapd_parse_vht_capab_blobmsg(struct ieee80211_vht_capabilities *vhtc)
+{
+	void *supported_mcs;
+	void *map;
+	int i;
+
+	static const struct {
+		const char *name;
+		uint32_t flag;
+	} vht_capas[] = {
+		{ "su_beamformee", VHT_CAP_SU_BEAMFORMEE_CAPABLE },
+		{ "mu_beamformee", VHT_CAP_MU_BEAMFORMEE_CAPABLE },
+	};
+
+	for (i = 0; i < ARRAY_SIZE(vht_capas); i++)
+		blobmsg_add_u8(&b, vht_capas[i].name,
+				!!(vhtc->vht_capabilities_info & vht_capas[i].flag));
+
+	supported_mcs = blobmsg_open_table(&b, "mcs_map");
+
+	/* RX map */
+	map = blobmsg_open_table(&b, "rx");
+	hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.rx_map));
+	blobmsg_close_table(&b, map);
+
+	/* TX map */
+	map = blobmsg_open_table(&b, "tx");
+	hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.tx_map));
+	blobmsg_close_table(&b, map);
+
+	blobmsg_close_table(&b, supported_mcs);
+}
+
+static void
+hostapd_parse_capab_blobmsg(struct sta_info *sta)
+{
+	void *r, *v;
+
+	v = blobmsg_open_table(&b, "capabilities");
+
+	if (sta->vht_capabilities) {
+		r = blobmsg_open_table(&b, "vht");
+		hostapd_parse_vht_capab_blobmsg(sta->vht_capabilities);
+		blobmsg_close_table(&b, r);
+	}
+
+	/* ToDo: Add HT / HE capability parsing */
+
+	blobmsg_close_table(&b, v);
+}
+
+static int
+hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct hostap_sta_driver_data sta_driver_data;
+	struct sta_info *sta;
+	void *list, *c;
+	char mac_buf[20];
+	static const struct {
+		const char *name;
+		uint32_t flag;
+	} sta_flags[] = {
+		{ "auth", WLAN_STA_AUTH },
+		{ "assoc", WLAN_STA_ASSOC },
+		{ "authorized", WLAN_STA_AUTHORIZED },
+		{ "preauth", WLAN_STA_PREAUTH },
+		{ "wds", WLAN_STA_WDS },
+		{ "wmm", WLAN_STA_WMM },
+		{ "ht", WLAN_STA_HT },
+		{ "vht", WLAN_STA_VHT },
+		{ "he", WLAN_STA_HE },
+		{ "wps", WLAN_STA_WPS },
+		{ "mfp", WLAN_STA_MFP },
+	};
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+	list = blobmsg_open_table(&b, "clients");
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		void *r;
+		int i;
+
+		sprintf(mac_buf, MACSTR, MAC2STR(sta->addr));
+		c = blobmsg_open_table(&b, mac_buf);
+		for (i = 0; i < ARRAY_SIZE(sta_flags); i++)
+			blobmsg_add_u8(&b, sta_flags[i].name,
+				       !!(sta->flags & sta_flags[i].flag));
+
+#ifdef CONFIG_MBO
+		blobmsg_add_u8(&b, "mbo", !!(sta->cell_capa));
+#endif
+
+		r = blobmsg_open_array(&b, "rrm");
+		for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
+			blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
+		blobmsg_close_array(&b, r);
+
+		r = blobmsg_open_array(&b, "extended_capabilities");
+		/* Check if client advertises extended capabilities */
+		if (sta->ext_capability && sta->ext_capability[0] > 0) {
+			for (i = 0; i < sta->ext_capability[0]; i++) {
+				blobmsg_add_u32(&b, "", sta->ext_capability[1 + i]);
+			}
+		}
+		blobmsg_close_array(&b, r);
+
+		blobmsg_add_u32(&b, "aid", sta->aid);
+#ifdef CONFIG_TAXONOMY
+		r = blobmsg_alloc_string_buffer(&b, "signature", 1024);
+		if (retrieve_sta_taxonomy(hapd, sta, r, 1024) > 0)
+			blobmsg_add_string_buffer(&b);
+#endif
+
+		/* Driver information */
+		if (hostapd_drv_read_sta_data(hapd, &sta_driver_data, sta->addr) >= 0) {
+			r = blobmsg_open_table(&b, "bytes");
+			blobmsg_add_u64(&b, "rx", sta_driver_data.rx_bytes);
+			blobmsg_add_u64(&b, "tx", sta_driver_data.tx_bytes);
+			blobmsg_close_table(&b, r);
+			r = blobmsg_open_table(&b, "airtime");
+			blobmsg_add_u64(&b, "rx", sta_driver_data.rx_airtime);
+			blobmsg_add_u64(&b, "tx", sta_driver_data.tx_airtime);
+			blobmsg_close_table(&b, r);
+			r = blobmsg_open_table(&b, "packets");
+			blobmsg_add_u32(&b, "rx", sta_driver_data.rx_packets);
+			blobmsg_add_u32(&b, "tx", sta_driver_data.tx_packets);
+			blobmsg_close_table(&b, r);
+			r = blobmsg_open_table(&b, "rate");
+			/* Rate in kbits */
+			blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100);
+			blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
+			blobmsg_close_table(&b, r);
+			blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
+		}
+
+		hostapd_parse_capab_blobmsg(sta);
+
+		blobmsg_close_table(&b, c);
+	}
+	blobmsg_close_array(&b, list);
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+static int
+hostapd_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_u8(&b, "ht_supported", ht_supported(hapd->iface->hw_features));
+	blobmsg_add_u8(&b, "vht_supported", vht_supported(hapd->iface->hw_features));
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+static int
+hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
+		       struct ubus_request_data *req, const char *method,
+		       struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	void *airtime_table, *dfs_table, *rrm_table, *wnm_table;
+	struct os_reltime now;
+	char ssid[SSID_MAX_LEN + 1];
+	char phy_name[17];
+	size_t ssid_len = SSID_MAX_LEN;
+	u8 channel = 0, op_class = 0;
+
+	if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN)
+		ssid_len = hapd->conf->ssid.ssid_len;
+	
+	ieee80211_freq_to_channel_ext(hapd->iface->freq,
+				      hapd->iconf->secondary_channel,
+				      hostapd_get_oper_chwidth(hapd->iconf),
+				      &op_class, &channel);
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state));
+	blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
+
+	memset(ssid, 0, SSID_MAX_LEN + 1);
+	memcpy(ssid, hapd->conf->ssid.ssid, ssid_len);
+	blobmsg_add_string(&b, "ssid", ssid);
+
+	blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+	blobmsg_add_u32(&b, "channel", channel);
+	blobmsg_add_u32(&b, "op_class", op_class);
+	blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
+#ifdef CONFIG_IEEE80211AX
+	blobmsg_add_u32(&b, "bss_color", hapd->iface->conf->he_op.he_bss_color_disabled ? -1 :
+					 hapd->iface->conf->he_op.he_bss_color);
+#else
+	blobmsg_add_u32(&b, "bss_color", -1);
+#endif
+
+	snprintf(phy_name, 17, "%s", hapd->iface->phy);
+	blobmsg_add_string(&b, "phy", phy_name);
+
+	/* RRM */
+	rrm_table = blobmsg_open_table(&b, "rrm");
+	blobmsg_add_u64(&b, "neighbor_report_tx", hapd->openwrt_stats.rrm.neighbor_report_tx);
+	blobmsg_close_table(&b, rrm_table);
+
+	/* WNM */
+	wnm_table = blobmsg_open_table(&b, "wnm");
+	blobmsg_add_u64(&b, "bss_transition_query_rx", hapd->openwrt_stats.wnm.bss_transition_query_rx);
+	blobmsg_add_u64(&b, "bss_transition_request_tx", hapd->openwrt_stats.wnm.bss_transition_request_tx);
+	blobmsg_add_u64(&b, "bss_transition_response_rx", hapd->openwrt_stats.wnm.bss_transition_response_rx);
+	blobmsg_close_table(&b, wnm_table);
+
+	/* Airtime */
+	airtime_table = blobmsg_open_table(&b, "airtime");
+	blobmsg_add_u64(&b, "time", hapd->iface->last_channel_time);
+	blobmsg_add_u64(&b, "time_busy", hapd->iface->last_channel_time_busy);
+	blobmsg_add_u16(&b, "utilization", hapd->iface->channel_utilization);
+	blobmsg_close_table(&b, airtime_table);
+
+	/* DFS */
+	dfs_table = blobmsg_open_table(&b, "dfs");
+	blobmsg_add_u32(&b, "cac_seconds", hapd->iface->dfs_cac_ms / 1000);
+	blobmsg_add_u8(&b, "cac_active", !!(hapd->iface->cac_started));
+	os_reltime_age(&hapd->iface->dfs_cac_start, &now);
+	blobmsg_add_u32(&b, "cac_seconds_left",
+			hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
+	blobmsg_close_table(&b, dfs_table);
+
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+enum {
+	NOTIFY_RESPONSE,
+	__NOTIFY_MAX
+};
+
+static const struct blobmsg_policy notify_policy[__NOTIFY_MAX] = {
+	[NOTIFY_RESPONSE] = { "notify_response", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_notify_response(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__NOTIFY_MAX];
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct wpabuf *elems;
+	const char *pos;
+	size_t len;
+
+	blobmsg_parse(notify_policy, __NOTIFY_MAX, tb,
+		      blob_data(msg), blob_len(msg));
+
+	if (!tb[NOTIFY_RESPONSE])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	hapd->ubus.notify_response = blobmsg_get_u32(tb[NOTIFY_RESPONSE]);
+
+	return UBUS_STATUS_OK;
+}
+
+enum {
+	DEL_CLIENT_ADDR,
+	DEL_CLIENT_REASON,
+	DEL_CLIENT_DEAUTH,
+	DEL_CLIENT_BAN_TIME,
+	__DEL_CLIENT_MAX
+};
+
+static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = {
+	[DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+	[DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 },
+	[DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 },
+	[DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__DEL_CLIENT_MAX];
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct sta_info *sta;
+	bool deauth = false;
+	int reason;
+	u8 addr[ETH_ALEN];
+
+	blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[DEL_CLIENT_ADDR])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (tb[DEL_CLIENT_REASON])
+		reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]);
+
+	if (tb[DEL_CLIENT_DEAUTH])
+		deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]);
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta) {
+		if (deauth) {
+			hostapd_drv_sta_deauth(hapd, addr, reason);
+			ap_sta_deauthenticate(hapd, sta, reason);
+		} else {
+			hostapd_drv_sta_disassoc(hapd, addr, reason);
+			ap_sta_disassociate(hapd, sta, reason);
+		}
+	}
+
+	if (tb[DEL_CLIENT_BAN_TIME])
+		hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME]));
+
+	return 0;
+}
+
+static void
+blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr)
+{
+	char *s;
+
+	s = blobmsg_alloc_string_buffer(buf, name, 20);
+	sprintf(s, MACSTR, MAC2STR(addr));
+	blobmsg_add_string_buffer(buf);
+}
+
+static int
+hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct ubus_banned_client *ban;
+	void *c;
+
+	blob_buf_init(&b, 0);
+	c = blobmsg_open_array(&b, "clients");
+	avl_for_each_element(&hapd->ubus.banned, ban, avl)
+		blobmsg_add_macaddr(&b, NULL, ban->addr);
+	blobmsg_close_array(&b, c);
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+#ifdef CONFIG_WPS
+static int
+hostapd_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	rc = hostapd_wps_button_pushed(hapd, NULL);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+
+
+static const char * pbc_status_enum_str(enum pbc_status status)
+{
+	switch (status) {
+	case WPS_PBC_STATUS_DISABLE:
+		return "Disabled";
+	case WPS_PBC_STATUS_ACTIVE:
+		return "Active";
+	case WPS_PBC_STATUS_TIMEOUT:
+		return "Timed-out";
+	case WPS_PBC_STATUS_OVERLAP:
+		return "Overlap";
+	default:
+		return "Unknown";
+	}
+}
+
+static int
+hostapd_bss_wps_status(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	blob_buf_init(&b, 0);
+
+	blobmsg_add_string(&b, "pbc_status", pbc_status_enum_str(hapd->wps_stats.pbc_status));
+	blobmsg_add_string(&b, "last_wps_result",
+			   (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
+			    "Success":
+			    (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
+			     "Failed" : "None")));
+
+	/* If status == Failure - Add possible Reasons */
+	if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
+	   hapd->wps_stats.failure_reason > 0)
+		blobmsg_add_string(&b, "reason", wps_ei_str(hapd->wps_stats.failure_reason));
+
+	if (hapd->wps_stats.status)
+		blobmsg_printf(&b, "peer_address", MACSTR, MAC2STR(hapd->wps_stats.peer_addr));
+
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+static int
+hostapd_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	rc = hostapd_wps_cancel(hapd);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+#endif /* CONFIG_WPS */
+
+static int
+hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+	rc = ieee802_11_set_beacon(hapd);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+
+enum {
+	CONFIG_IFACE,
+	CONFIG_FILE,
+	__CONFIG_MAX
+};
+
+enum {
+	CSA_FREQ,
+	CSA_BCN_COUNT,
+	CSA_CENTER_FREQ1,
+	CSA_CENTER_FREQ2,
+	CSA_BANDWIDTH,
+	CSA_SEC_CHANNEL_OFFSET,
+	CSA_HT,
+	CSA_VHT,
+	CSA_HE,
+	CSA_BLOCK_TX,
+	CSA_FORCE,
+	__CSA_MAX
+};
+
+static const struct blobmsg_policy csa_policy[__CSA_MAX] = {
+	[CSA_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
+	[CSA_BCN_COUNT] = { "bcn_count", BLOBMSG_TYPE_INT32 },
+	[CSA_CENTER_FREQ1] = { "center_freq1", BLOBMSG_TYPE_INT32 },
+	[CSA_CENTER_FREQ2] = { "center_freq2", BLOBMSG_TYPE_INT32 },
+	[CSA_BANDWIDTH] = { "bandwidth", BLOBMSG_TYPE_INT32 },
+	[CSA_SEC_CHANNEL_OFFSET] = { "sec_channel_offset", BLOBMSG_TYPE_INT32 },
+	[CSA_HT] = { "ht", BLOBMSG_TYPE_BOOL },
+	[CSA_VHT] = { "vht", BLOBMSG_TYPE_BOOL },
+	[CSA_HE] = { "he", BLOBMSG_TYPE_BOOL },
+	[CSA_BLOCK_TX] = { "block_tx", BLOBMSG_TYPE_BOOL },
+	[CSA_FORCE] = { "force", BLOBMSG_TYPE_BOOL },
+};
+
+
+static void switch_chan_fallback_cb(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_iface *iface = eloop_data;
+	struct hostapd_freq_params *freq_params = user_ctx;
+
+	hostapd_switch_channel_fallback(iface, freq_params);
+}
+
+#ifdef NEED_AP_MLME
+static int
+hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
+		    struct ubus_request_data *req, const char *method,
+		    struct blob_attr *msg)
+{
+	struct blob_attr *tb[__CSA_MAX];
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct hostapd_config *iconf = hapd->iface->conf;
+	struct hostapd_freq_params *freq_params;
+	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+	struct csa_settings css = {
+		.freq_params = {
+			.ht_enabled = iconf->ieee80211n,
+			.vht_enabled = iconf->ieee80211ac,
+			.he_enabled = iconf->ieee80211ax,
+			.sec_channel_offset = iconf->secondary_channel,
+		}
+	};
+	u8 chwidth = hostapd_get_oper_chwidth(iconf);
+	u8 seg0 = 0, seg1 = 0;
+	int ret = UBUS_STATUS_OK;
+	int i;
+
+	blobmsg_parse(csa_policy, __CSA_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[CSA_FREQ])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	switch (iconf->vht_oper_chwidth) {
+	case CHANWIDTH_USE_HT:
+		if (iconf->secondary_channel)
+			css.freq_params.bandwidth = 40;
+		else
+			css.freq_params.bandwidth = 20;
+		break;
+	case CHANWIDTH_160MHZ:
+		css.freq_params.bandwidth = 160;
+		break;
+	default:
+		css.freq_params.bandwidth = 80;
+		break;
+	}
+
+	css.freq_params.freq = blobmsg_get_u32(tb[CSA_FREQ]);
+
+#define SET_CSA_SETTING(name, field, type) \
+	do { \
+		if (tb[name]) \
+			css.field = blobmsg_get_ ## type(tb[name]); \
+	} while(0)
+
+	SET_CSA_SETTING(CSA_BCN_COUNT, cs_count, u32);
+	SET_CSA_SETTING(CSA_CENTER_FREQ1, freq_params.center_freq1, u32);
+	SET_CSA_SETTING(CSA_CENTER_FREQ2, freq_params.center_freq2, u32);
+	SET_CSA_SETTING(CSA_BANDWIDTH, freq_params.bandwidth, u32);
+	SET_CSA_SETTING(CSA_SEC_CHANNEL_OFFSET, freq_params.sec_channel_offset, u32);
+	SET_CSA_SETTING(CSA_HT, freq_params.ht_enabled, bool);
+	SET_CSA_SETTING(CSA_VHT, freq_params.vht_enabled, bool);
+	SET_CSA_SETTING(CSA_HE, freq_params.he_enabled, bool);
+	SET_CSA_SETTING(CSA_BLOCK_TX, block_tx, bool);
+
+	css.freq_params.channel = hostapd_hw_get_channel(hapd, css.freq_params.freq);
+	if (!css.freq_params.channel)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	switch (css.freq_params.bandwidth) {
+	case 160:
+		chwidth = CHANWIDTH_160MHZ;
+		break;
+	case 80:
+		chwidth = css.freq_params.center_freq2 ? CHANWIDTH_80P80MHZ : CHANWIDTH_80MHZ;
+		break;
+	default:
+		chwidth = CHANWIDTH_USE_HT;
+		break;
+	}
+
+	hostapd_set_freq_params(&css.freq_params, iconf->hw_mode,
+				css.freq_params.freq,
+				css.freq_params.channel, iconf->enable_edmg,
+				iconf->edmg_channel,
+				css.freq_params.ht_enabled,
+				css.freq_params.vht_enabled,
+				css.freq_params.he_enabled,
+				css.freq_params.eht_enabled,
+				css.freq_params.sec_channel_offset,
+				chwidth, seg0, seg1,
+				iconf->vht_capab,
+				mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+				NULL,
+				mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
+				NULL);
+
+	for (i = 0; i < hapd->iface->num_bss; i++) {
+		struct hostapd_data *bss = hapd->iface->bss[i];
+
+		if (hostapd_switch_channel(bss, &css) != 0)
+			ret = UBUS_STATUS_NOT_SUPPORTED;
+	}
+
+	if (!ret || !tb[CSA_FORCE] || !blobmsg_get_bool(tb[CSA_FORCE]))
+		return ret;
+
+	freq_params = malloc(sizeof(*freq_params));
+	memcpy(freq_params, &css.freq_params, sizeof(*freq_params));
+	eloop_register_timeout(0, 1, switch_chan_fallback_cb,
+			       hapd->iface, freq_params);
+
+	return 0;
+#undef SET_CSA_SETTING
+}
+#endif
+
+enum {
+	VENDOR_ELEMENTS,
+	__VENDOR_ELEMENTS_MAX
+};
+
+static const struct blobmsg_policy ve_policy[__VENDOR_ELEMENTS_MAX] = {
+	/* vendor elements are provided as hex-string */
+	[VENDOR_ELEMENTS] = { "vendor_elements", BLOBMSG_TYPE_STRING },
+};
+
+static int
+hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__VENDOR_ELEMENTS_MAX];
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct hostapd_bss_config *bss = hapd->conf;
+	struct wpabuf *elems;
+	const char *pos;
+	size_t len;
+
+	blobmsg_parse(ve_policy, __VENDOR_ELEMENTS_MAX, tb,
+		      blob_data(msg), blob_len(msg));
+
+	if (!tb[VENDOR_ELEMENTS])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	pos = blobmsg_data(tb[VENDOR_ELEMENTS]);
+	len = os_strlen(pos);
+	if (len & 0x01)
+			return UBUS_STATUS_INVALID_ARGUMENT;
+
+	len /= 2;
+	if (len == 0) {
+		wpabuf_free(bss->vendor_elements);
+		bss->vendor_elements = NULL;
+		return 0;
+	}
+
+	elems = wpabuf_alloc(len);
+	if (elems == NULL)
+		return 1;
+
+	if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+		wpabuf_free(elems);
+		return UBUS_STATUS_INVALID_ARGUMENT;
+	}
+
+	wpabuf_free(bss->vendor_elements);
+	bss->vendor_elements = elems;
+
+	/* update beacons if vendor elements were set successfully */
+	if (ieee802_11_update_beacons(hapd->iface) != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+	return UBUS_STATUS_OK;
+}
+
+static void
+hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
+{
+	const u8 *data;
+	char *str;
+	int len;
+
+	blobmsg_printf(&b, "", MACSTR, MAC2STR(nr->bssid));
+
+	str = blobmsg_alloc_string_buffer(&b, "", nr->ssid.ssid_len + 1);
+	memcpy(str, nr->ssid.ssid, nr->ssid.ssid_len);
+	str[nr->ssid.ssid_len] = 0;
+	blobmsg_add_string_buffer(&b);
+
+	len = wpabuf_len(nr->nr);
+	str = blobmsg_alloc_string_buffer(&b, "", 2 * len + 1);
+	wpa_snprintf_hex(str, 2 * len + 1, wpabuf_head_u8(nr->nr), len);
+	blobmsg_add_string_buffer(&b);
+}
+
+enum {
+	BSS_MGMT_EN_NEIGHBOR,
+	BSS_MGMT_EN_BEACON,
+	BSS_MGMT_EN_LINK_MEASUREMENT,
+#ifdef CONFIG_WNM_AP
+	BSS_MGMT_EN_BSS_TRANSITION,
+#endif
+	__BSS_MGMT_EN_MAX
+};
+
+static bool
+__hostapd_bss_mgmt_enable_f(struct hostapd_data *hapd, int flag)
+{
+	struct hostapd_bss_config *bss = hapd->conf;
+	uint32_t flags;
+
+	switch (flag) {
+	case BSS_MGMT_EN_NEIGHBOR:
+		if (bss->radio_measurements[0] &
+		    WLAN_RRM_CAPS_NEIGHBOR_REPORT)
+			return false;
+
+		bss->radio_measurements[0] |=
+			WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+		hostapd_neighbor_set_own_report(hapd);
+		return true;
+	case BSS_MGMT_EN_BEACON:
+		flags = WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+			WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+			WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+
+		if (bss->radio_measurements[0] & flags == flags)
+			return false;
+
+		bss->radio_measurements[0] |= (u8) flags;
+		return true;
+	case BSS_MGMT_EN_LINK_MEASUREMENT:
+		flags = WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+		if (bss->radio_measurements[0] & flags == flags)
+			return false;
+
+		bss->radio_measurements[0] |= (u8) flags;
+		return true;
+#ifdef CONFIG_WNM_AP
+	case BSS_MGMT_EN_BSS_TRANSITION:
+		if (bss->bss_transition)
+			return false;
+
+		bss->bss_transition = 1;
+		return true;
+#endif
+	}
+}
+
+static void
+__hostapd_bss_mgmt_enable(struct hostapd_data *hapd, uint32_t flags)
+{
+	bool update = false;
+	int i;
+
+	for (i = 0; i < __BSS_MGMT_EN_MAX; i++) {
+		if (!(flags & (1 << i)))
+			continue;
+
+		update |= __hostapd_bss_mgmt_enable_f(hapd, i);
+	}
+
+	if (update)
+		ieee802_11_update_beacons(hapd->iface);
+}
+
+
+static const struct blobmsg_policy bss_mgmt_enable_policy[__BSS_MGMT_EN_MAX] = {
+	[BSS_MGMT_EN_NEIGHBOR] = { "neighbor_report", BLOBMSG_TYPE_BOOL },
+	[BSS_MGMT_EN_BEACON] = { "beacon_report", BLOBMSG_TYPE_BOOL },
+	[BSS_MGMT_EN_LINK_MEASUREMENT] = { "link_measurement", BLOBMSG_TYPE_BOOL },
+#ifdef CONFIG_WNM_AP
+	[BSS_MGMT_EN_BSS_TRANSITION] = { "bss_transition", BLOBMSG_TYPE_BOOL },
+#endif
+};
+
+static int
+hostapd_bss_mgmt_enable(struct ubus_context *ctx, struct ubus_object *obj,
+		   struct ubus_request_data *req, const char *method,
+		   struct blob_attr *msg)
+
+{
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct blob_attr *tb[__BSS_MGMT_EN_MAX];
+	struct blob_attr *cur;
+	uint32_t flags = 0;
+	int i;
+	bool neigh = false, beacon = false;
+
+	blobmsg_parse(bss_mgmt_enable_policy, __BSS_MGMT_EN_MAX, tb, blob_data(msg), blob_len(msg));
+
+	for (i = 0; i < ARRAY_SIZE(tb); i++) {
+		if (!tb[i] || !blobmsg_get_bool(tb[i]))
+			continue;
+
+		flags |= (1 << i);
+	}
+
+	__hostapd_bss_mgmt_enable(hapd, flags);
+
+	return 0;
+}
+
+
+static void
+hostapd_rrm_nr_enable(struct hostapd_data *hapd)
+{
+	__hostapd_bss_mgmt_enable(hapd, 1 << BSS_MGMT_EN_NEIGHBOR);
+}
+
+static int
+hostapd_rrm_nr_get_own(struct ubus_context *ctx, struct ubus_object *obj,
+		       struct ubus_request_data *req, const char *method,
+		       struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct hostapd_neighbor_entry *nr;
+	void *c;
+
+	hostapd_rrm_nr_enable(hapd);
+
+	nr = hostapd_neighbor_get(hapd, hapd->own_addr, NULL);
+	if (!nr)
+		return UBUS_STATUS_NOT_FOUND;
+
+	blob_buf_init(&b, 0);
+
+	c = blobmsg_open_array(&b, "value");
+	hostapd_rrm_print_nr(nr);
+	blobmsg_close_array(&b, c);
+
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+static int
+hostapd_rrm_nr_list(struct ubus_context *ctx, struct ubus_object *obj,
+		    struct ubus_request_data *req, const char *method,
+		    struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct hostapd_neighbor_entry *nr;
+	void *c;
+
+	hostapd_rrm_nr_enable(hapd);
+	blob_buf_init(&b, 0);
+
+	c = blobmsg_open_array(&b, "list");
+	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
+		void *cur;
+
+		if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
+			continue;
+
+		cur = blobmsg_open_array(&b, NULL);
+		hostapd_rrm_print_nr(nr);
+		blobmsg_close_array(&b, cur);
+	}
+	blobmsg_close_array(&b, c);
+
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+enum {
+	NR_SET_LIST,
+	__NR_SET_LIST_MAX
+};
+
+static const struct blobmsg_policy nr_set_policy[__NR_SET_LIST_MAX] = {
+	[NR_SET_LIST] = { "list", BLOBMSG_TYPE_ARRAY },
+};
+
+
+static void
+hostapd_rrm_nr_clear(struct hostapd_data *hapd)
+{
+	struct hostapd_neighbor_entry *nr;
+
+restart:
+	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
+		if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
+			continue;
+
+		hostapd_neighbor_remove(hapd, nr->bssid, &nr->ssid);
+		goto restart;
+	}
+}
+
+static int
+hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
+		   struct ubus_request_data *req, const char *method,
+		   struct blob_attr *msg)
+{
+	static const struct blobmsg_policy nr_e_policy[] = {
+		{ .type = BLOBMSG_TYPE_STRING },
+		{ .type = BLOBMSG_TYPE_STRING },
+		{ .type = BLOBMSG_TYPE_STRING },
+	};
+	struct hostapd_data *hapd = get_hapd_from_object(obj);
+	struct blob_attr *tb_l[__NR_SET_LIST_MAX];
+	struct blob_attr *tb[ARRAY_SIZE(nr_e_policy)];
+	struct blob_attr *cur;
+	int rem;
+
+	hostapd_rrm_nr_enable(hapd);
+
+	blobmsg_parse(nr_set_policy, __NR_SET_LIST_MAX, tb_l, blob_data(msg), blob_len(msg));
+	if (!tb_l[NR_SET_LIST])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	hostapd_rrm_nr_clear(hapd);
+	blobmsg_for_each_attr(cur, tb_l[NR_SET_LIST], rem) {
+		struct wpa_ssid_value ssid;
+		struct wpabuf *data;
+		u8 bssid[ETH_ALEN];
+		char *s, *nr_s;
+
+		blobmsg_parse_array(nr_e_policy, ARRAY_SIZE(nr_e_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur));
+		if (!tb[0] || !tb[1] || !tb[2])
+			goto invalid;
+
+		/* Neighbor Report binary */
+		nr_s = blobmsg_get_string(tb[2]);
+		data = wpabuf_parse_bin(nr_s);
+		if (!data)
+			goto invalid;
+
+		/* BSSID */
+		s = blobmsg_get_string(tb[0]);
+		if (strlen(s) == 0) {
+			/* Copy BSSID from neighbor report */
+			if (hwaddr_compact_aton(nr_s, bssid))
+				goto invalid;
+		} else if (hwaddr_aton(s, bssid)) {
+			goto invalid;
+		}
+
+		/* SSID */
+		s = blobmsg_get_string(tb[1]);
+		if (strlen(s) == 0) {
+			/* Copy SSID from hostapd BSS conf */
+			memcpy(&ssid, &hapd->conf->ssid, sizeof(ssid));
+		} else {
+			ssid.ssid_len = strlen(s);
+			if (ssid.ssid_len > sizeof(ssid.ssid))
+				goto invalid;
+
+			memcpy(&ssid, s, ssid.ssid_len);
+		}
+
+		hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0, 0);
+		wpabuf_free(data);
+		continue;
+
+invalid:
+		return UBUS_STATUS_INVALID_ARGUMENT;
+	}
+
+	return 0;
+}
+
+enum {
+	BEACON_REQ_ADDR,
+	BEACON_REQ_MODE,
+	BEACON_REQ_OP_CLASS,
+	BEACON_REQ_CHANNEL,
+	BEACON_REQ_DURATION,
+	BEACON_REQ_BSSID,
+	BEACON_REQ_SSID,
+	__BEACON_REQ_MAX,
+};
+
+static const struct blobmsg_policy beacon_req_policy[__BEACON_REQ_MAX] = {
+	[BEACON_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+	[BEACON_REQ_OP_CLASS] { "op_class", BLOBMSG_TYPE_INT32 },
+	[BEACON_REQ_CHANNEL] { "channel", BLOBMSG_TYPE_INT32 },
+	[BEACON_REQ_DURATION] { "duration", BLOBMSG_TYPE_INT32 },
+	[BEACON_REQ_MODE] { "mode", BLOBMSG_TYPE_INT32 },
+	[BEACON_REQ_BSSID] { "bssid", BLOBMSG_TYPE_STRING },
+	[BEACON_REQ_SSID] { "ssid", BLOBMSG_TYPE_STRING },
+};
+
+static int
+hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
+		       struct ubus_request_data *ureq, const char *method,
+		       struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct blob_attr *tb[__BEACON_REQ_MAX];
+	struct blob_attr *cur;
+	struct wpabuf *req;
+	u8 bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	u8 addr[ETH_ALEN];
+	int mode, rem, ret;
+	int buf_len = 13;
+
+	blobmsg_parse(beacon_req_policy, __BEACON_REQ_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[BEACON_REQ_ADDR] || !tb[BEACON_REQ_MODE] || !tb[BEACON_REQ_DURATION] ||
+	    !tb[BEACON_REQ_OP_CLASS] || !tb[BEACON_REQ_CHANNEL])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (tb[BEACON_REQ_SSID])
+		buf_len += blobmsg_data_len(tb[BEACON_REQ_SSID]) + 2 - 1;
+
+	mode = blobmsg_get_u32(tb[BEACON_REQ_MODE]);
+	if (hwaddr_aton(blobmsg_data(tb[BEACON_REQ_ADDR]), addr))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (tb[BEACON_REQ_BSSID] &&
+	    hwaddr_aton(blobmsg_data(tb[BEACON_REQ_BSSID]), bssid))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	req = wpabuf_alloc(buf_len);
+	if (!req)
+		return UBUS_STATUS_UNKNOWN_ERROR;
+
+	/* 1: regulatory class */
+	wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_OP_CLASS]));
+
+	/* 2: channel number */
+	wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_CHANNEL]));
+
+	/* 3-4: randomization interval */
+	wpabuf_put_le16(req, 0);
+
+	/* 5-6: duration */
+	wpabuf_put_le16(req, blobmsg_get_u32(tb[BEACON_REQ_DURATION]));
+
+	/* 7: mode */
+	wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_MODE]));
+
+	/* 8-13: BSSID */
+	wpabuf_put_data(req, bssid, ETH_ALEN);
+
+	if ((cur = tb[BEACON_REQ_SSID]) != NULL) {
+		wpabuf_put_u8(req, WLAN_EID_SSID);
+		wpabuf_put_u8(req, blobmsg_data_len(cur) - 1);
+		wpabuf_put_data(req, blobmsg_data(cur), blobmsg_data_len(cur) - 1);
+	}
+
+	ret = hostapd_send_beacon_req(hapd, addr, 0, req);
+	if (ret < 0)
+		return -ret;
+
+	return 0;
+}
+
+enum {
+	LM_REQ_ADDR,
+	LM_REQ_TX_POWER_USED,
+	LM_REQ_TX_POWER_MAX,
+	__LM_REQ_MAX,
+};
+
+static const struct blobmsg_policy lm_req_policy[__LM_REQ_MAX] = {
+	[LM_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+	[LM_REQ_TX_POWER_USED] = { "tx-power-used", BLOBMSG_TYPE_INT32 },
+	[LM_REQ_TX_POWER_MAX] = { "tx-power-max", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_rrm_lm_req(struct ubus_context *ctx, struct ubus_object *obj,
+		   struct ubus_request_data *ureq, const char *method,
+		   struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct blob_attr *tb[__LM_REQ_MAX];
+	struct wpabuf *buf;
+	u8 addr[ETH_ALEN];
+	int ret;
+	int8_t txp_used, txp_max;
+
+	txp_used = 0;
+	txp_max = 0;
+
+	blobmsg_parse(lm_req_policy, __LM_REQ_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[LM_REQ_ADDR])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (tb[LM_REQ_TX_POWER_USED])
+		txp_used = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_USED]);
+
+	if (tb[LM_REQ_TX_POWER_MAX])
+		txp_max = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_MAX]);
+
+	if (hwaddr_aton(blobmsg_data(tb[LM_REQ_ADDR]), addr))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	buf = wpabuf_alloc(5);
+	if (!buf)
+		return UBUS_STATUS_UNKNOWN_ERROR;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
+	wpabuf_put_u8(buf, 1);
+	/* TX-Power used */
+	wpabuf_put_u8(buf, txp_used);
+	/* Max TX Power */
+	wpabuf_put_u8(buf, txp_max);
+
+	ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+				      wpabuf_head(buf), wpabuf_len(buf));
+
+	wpabuf_free(buf);
+	if (ret < 0)
+		return -ret;
+
+	return 0;
+}
+
+
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) data;
+	const u8 *pos, *end;
+	u8 token;
+
+	end = data + len;
+	token = mgmt->u.action.u.rrm.dialog_token;
+	pos = mgmt->u.action.u.rrm.variable;
+
+	if (end - pos < 8)
+		return;
+
+	if (!hapd->ubus.obj.has_subscribers)
+		return;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", mgmt->sa);
+	blobmsg_add_u16(&b, "dialog-token", token);
+	blobmsg_add_u16(&b, "rx-antenna-id", pos[4]);
+	blobmsg_add_u16(&b, "tx-antenna-id", pos[5]);
+	blobmsg_add_u16(&b, "rcpi", pos[6]);
+	blobmsg_add_u16(&b, "rsni", pos[7]);
+
+	ubus_notify(ctx, &hapd->ubus.obj, "link-measurement-report", b.head, -1);
+}
+
+
+#ifdef CONFIG_WNM_AP
+
+static int
+hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
+		    u16 disassoc_timer, u8 validity_period, u8 dialog_token,
+		    struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
+{
+	struct blob_attr *cur;
+	struct sta_info *sta;
+	int nr_len = 0;
+	int rem;
+	u8 *nr = NULL;
+	u8 req_mode = 0;
+	u8 mbo[10];
+	size_t mbo_len = 0;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta)
+		return UBUS_STATUS_NOT_FOUND;
+
+	if (neighbors) {
+		u8 *nr_cur;
+
+		if (blobmsg_check_array(neighbors,
+					BLOBMSG_TYPE_STRING) < 0)
+			return UBUS_STATUS_INVALID_ARGUMENT;
+
+		blobmsg_for_each_attr(cur, neighbors, rem) {
+			int len = strlen(blobmsg_get_string(cur));
+
+			if (len % 2)
+				return UBUS_STATUS_INVALID_ARGUMENT;
+
+			nr_len += (len / 2) + 2;
+		}
+
+		if (nr_len) {
+			nr = os_zalloc(nr_len);
+			if (!nr)
+				return UBUS_STATUS_UNKNOWN_ERROR;
+		}
+
+		nr_cur = nr;
+		blobmsg_for_each_attr(cur, neighbors, rem) {
+			int len = strlen(blobmsg_get_string(cur)) / 2;
+
+			*nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
+			*nr_cur++ = (u8) len;
+			if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
+				free(nr);
+				return UBUS_STATUS_INVALID_ARGUMENT;
+			}
+
+			nr_cur += len;
+		}
+	}
+
+	if (nr)
+		req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+
+	if (abridged)
+		req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+
+	if (disassoc_imminent)
+		req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+#ifdef CONFIG_MBO
+	u8 *mbo_pos = mbo;
+
+	if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+	*mbo_pos++ = 1;
+	*mbo_pos++ = mbo_reason;
+	*mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+	*mbo_pos++ = 1;
+	*mbo_pos++ = cell_pref;
+
+	if (reassoc_delay) {
+		*mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+		*mbo_pos++ = 2;
+		WPA_PUT_LE16(mbo_pos, reassoc_delay);
+		mbo_pos += 2;
+	}
+
+	mbo_len = mbo_pos - mbo;
+#endif
+
+	if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
+				dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
+		return UBUS_STATUS_UNKNOWN_ERROR;
+
+	return 0;
+}
+
+enum {
+	BSS_TR_ADDR,
+	BSS_TR_DA_IMMINENT,
+	BSS_TR_DA_TIMER,
+	BSS_TR_VALID_PERIOD,
+	BSS_TR_NEIGHBORS,
+	BSS_TR_ABRIDGED,
+	BSS_TR_DIALOG_TOKEN,
+#ifdef CONFIG_MBO
+	BSS_TR_MBO_REASON,
+	BSS_TR_CELL_PREF,
+	BSS_TR_REASSOC_DELAY,
+#endif
+	__BSS_TR_DISASSOC_MAX
+};
+
+static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
+	[BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+	[BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
+	[BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
+	[BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
+	[BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
+	[BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
+	[BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
+#ifdef CONFIG_MBO
+	[BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
+	[BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
+	[BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
+#endif
+};
+
+static int
+hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj,
+			       struct ubus_request_data *ureq, const char *method,
+			       struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct blob_attr *tb[__BSS_TR_DISASSOC_MAX];
+	struct sta_info *sta;
+	u32 da_timer = 0;
+	u32 valid_period = 0;
+	u8 addr[ETH_ALEN];
+	u32 dialog_token = 1;
+	bool abridged;
+	bool da_imminent;
+	u8 mbo_reason;
+	u8 cell_pref;
+	u8 reassoc_delay;
+
+	blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[BSS_TR_ADDR])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (tb[BSS_TR_DA_TIMER])
+		da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
+
+	if (tb[BSS_TR_VALID_PERIOD])
+		valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
+
+	if (tb[BSS_TR_DIALOG_TOKEN])
+		dialog_token = blobmsg_get_u32(tb[BSS_TR_DIALOG_TOKEN]);
+
+	da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
+	abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
+
+#ifdef CONFIG_MBO
+	if (tb[BSS_TR_MBO_REASON])
+		mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
+
+	if (tb[BSS_TR_CELL_PREF])
+		cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
+
+	if (tb[BSS_TR_REASSOC_DELAY])
+		reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
+#endif
+
+	return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
+				   dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
+}
+#endif
+
+#ifdef CONFIG_AIRTIME_POLICY
+enum {
+	UPDATE_AIRTIME_STA,
+	UPDATE_AIRTIME_WEIGHT,
+	__UPDATE_AIRTIME_MAX,
+};
+
+
+static const struct blobmsg_policy airtime_policy[__UPDATE_AIRTIME_MAX] = {
+	[UPDATE_AIRTIME_STA] = { "sta", BLOBMSG_TYPE_STRING },
+	[UPDATE_AIRTIME_WEIGHT] = { "weight", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_bss_update_airtime(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *ureq, const char *method,
+			   struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct blob_attr *tb[__UPDATE_AIRTIME_MAX];
+	struct sta_info *sta = NULL;
+	u8 addr[ETH_ALEN];
+	int weight;
+
+	blobmsg_parse(airtime_policy, __UPDATE_AIRTIME_MAX, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[UPDATE_AIRTIME_WEIGHT])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	weight = blobmsg_get_u32(tb[UPDATE_AIRTIME_WEIGHT]);
+
+	if (!tb[UPDATE_AIRTIME_STA]) {
+		if (!weight)
+			return UBUS_STATUS_INVALID_ARGUMENT;
+
+		hapd->conf->airtime_weight = weight;
+		return 0;
+	}
+
+	if (hwaddr_aton(blobmsg_data(tb[UPDATE_AIRTIME_STA]), addr))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta)
+		return UBUS_STATUS_NOT_FOUND;
+
+	sta->dyn_airtime_weight = weight;
+	airtime_policy_new_sta(hapd, sta);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_TAXONOMY
+static const struct blobmsg_policy addr_policy[] = {
+	{ "address", BLOBMSG_TYPE_STRING }
+};
+
+static bool
+hostapd_add_b64_data(const char *name, const struct wpabuf *buf)
+{
+	char *str;
+
+	if (!buf)
+		return false;
+
+	str = blobmsg_alloc_string_buffer(&b, name, B64_ENCODE_LEN(wpabuf_len(buf)));
+	b64_encode(wpabuf_head(buf), wpabuf_len(buf), str, B64_ENCODE_LEN(wpabuf_len(buf)));
+	blobmsg_add_string_buffer(&b);
+
+	return true;
+}
+
+static int
+hostapd_bss_get_sta_ies(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+	struct blob_attr *tb;
+	struct sta_info *sta;
+	u8 addr[ETH_ALEN];
+
+	blobmsg_parse(addr_policy, 1, &tb, blobmsg_data(msg), blobmsg_len(msg));
+
+	if (!tb || hwaddr_aton(blobmsg_data(tb), addr))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta || (!sta->probe_ie_taxonomy && !sta->assoc_ie_taxonomy))
+		return UBUS_STATUS_NOT_FOUND;
+
+	blob_buf_init(&b, 0);
+	hostapd_add_b64_data("probe_ie", sta->probe_ie_taxonomy);
+	hostapd_add_b64_data("assoc_ie", sta->assoc_ie_taxonomy);
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+#endif
+
+
+static const struct ubus_method bss_methods[] = {
+	UBUS_METHOD_NOARG("reload", hostapd_bss_reload),
+	UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
+#ifdef CONFIG_TAXONOMY
+	UBUS_METHOD("get_sta_ies", hostapd_bss_get_sta_ies, addr_policy),
+#endif
+	UBUS_METHOD_NOARG("get_status", hostapd_bss_get_status),
+	UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
+#ifdef CONFIG_AIRTIME_POLICY
+	UBUS_METHOD("update_airtime", hostapd_bss_update_airtime, airtime_policy),
+#endif
+	UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans),
+#ifdef CONFIG_WPS
+	UBUS_METHOD_NOARG("wps_start", hostapd_bss_wps_start),
+	UBUS_METHOD_NOARG("wps_status", hostapd_bss_wps_status),
+	UBUS_METHOD_NOARG("wps_cancel", hostapd_bss_wps_cancel),
+#endif
+	UBUS_METHOD_NOARG("update_beacon", hostapd_bss_update_beacon),
+	UBUS_METHOD_NOARG("get_features", hostapd_bss_get_features),
+#ifdef NEED_AP_MLME
+	UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy),
+#endif
+	UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
+	UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
+	UBUS_METHOD("bss_mgmt_enable", hostapd_bss_mgmt_enable, bss_mgmt_enable_policy),
+	UBUS_METHOD_NOARG("rrm_nr_get_own", hostapd_rrm_nr_get_own),
+	UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
+	UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
+	UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
+	UBUS_METHOD("link_measurement_req", hostapd_rrm_lm_req, lm_req_policy),
+#ifdef CONFIG_WNM_AP
+	UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
+#endif
+};
+
+static struct ubus_object_type bss_object_type =
+	UBUS_OBJECT_TYPE("hostapd_bss", bss_methods);
+
+static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr)
+{
+	return memcmp(k1, k2, ETH_ALEN);
+}
+
+void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+	struct ubus_object *obj = &hapd->ubus.obj;
+	char *name;
+	int ret;
+
+#ifdef CONFIG_MESH
+	if (hapd->conf->mesh & MESH_ENABLED)
+		return;
+#endif
+
+	if (!hostapd_ubus_init())
+		return;
+
+	if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0)
+		return;
+
+	avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL);
+	obj->name = name;
+	obj->type = &bss_object_type;
+	obj->methods = bss_object_type.methods;
+	obj->n_methods = bss_object_type.n_methods;
+	ret = ubus_add_object(ctx, obj);
+	hostapd_ubus_ref_inc();
+}
+
+void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+	struct ubus_object *obj = &hapd->ubus.obj;
+	char *name = (char *) obj->name;
+
+#ifdef CONFIG_MESH
+	if (hapd->conf->mesh & MESH_ENABLED)
+		return;
+#endif
+
+	if (!ctx)
+		return;
+
+	if (obj->id) {
+		ubus_remove_object(ctx, obj);
+		hostapd_ubus_ref_dec();
+	}
+
+	free(name);
+}
+
+static void
+hostapd_ubus_vlan_action(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+			 const char *action)
+{
+	struct vlan_description *desc = &vlan->vlan_desc;
+	void *c;
+	int i;
+
+	if (!hapd->ubus.obj.has_subscribers)
+		return;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_string(&b, "ifname", vlan->ifname);
+	blobmsg_add_string(&b, "bridge", vlan->bridge);
+	blobmsg_add_u32(&b, "vlan_id", vlan->vlan_id);
+
+	if (desc->notempty) {
+		blobmsg_add_u32(&b, "untagged", desc->untagged);
+		c = blobmsg_open_array(&b, "tagged");
+		for (i = 0; i < ARRAY_SIZE(desc->tagged) && desc->tagged[i]; i++)
+			blobmsg_add_u32(&b, "", desc->tagged[i]);
+		blobmsg_close_array(&b, c);
+	}
+
+	ubus_notify(ctx, &hapd->ubus.obj, action, b.head, -1);
+}
+
+void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+	hostapd_ubus_vlan_action(hapd, vlan, "vlan_add");
+}
+
+void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+	hostapd_ubus_vlan_action(hapd, vlan, "vlan_remove");
+}
+
+struct ubus_event_req {
+	struct ubus_notify_request nreq;
+	int resp;
+};
+
+static void
+ubus_event_cb(struct ubus_notify_request *req, int idx, int ret)
+{
+	struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq);
+
+	ureq->resp = ret;
+}
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+	struct ubus_banned_client *ban;
+	const char *types[HOSTAPD_UBUS_TYPE_MAX] = {
+		[HOSTAPD_UBUS_PROBE_REQ] = "probe",
+		[HOSTAPD_UBUS_AUTH_REQ] = "auth",
+		[HOSTAPD_UBUS_ASSOC_REQ] = "assoc",
+	};
+	const char *type = "mgmt";
+	struct ubus_event_req ureq = {};
+	const u8 *addr;
+
+	if (req->mgmt_frame)
+		addr = req->mgmt_frame->sa;
+	else
+		addr = req->addr;
+
+	ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+	if (ban)
+		return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+	if (!hapd->ubus.obj.has_subscribers)
+		return WLAN_STATUS_SUCCESS;
+
+	if (req->type < ARRAY_SIZE(types))
+		type = types[req->type];
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", addr);
+	if (req->mgmt_frame)
+		blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da);
+	if (req->ssi_signal)
+		blobmsg_add_u32(&b, "signal", req->ssi_signal);
+	blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+
+	if (req->elems) {
+		if(req->elems->ht_capabilities)
+		{
+			struct ieee80211_ht_capabilities *ht_capabilities;
+			void *ht_cap, *ht_cap_mcs_set, *mcs_set;
+
+
+			ht_capabilities = (struct ieee80211_ht_capabilities*) req->elems->ht_capabilities;
+			ht_cap = blobmsg_open_table(&b, "ht_capabilities");
+			blobmsg_add_u16(&b, "ht_capabilities_info", ht_capabilities->ht_capabilities_info);
+			ht_cap_mcs_set = blobmsg_open_table(&b, "supported_mcs_set");
+			blobmsg_add_u16(&b, "a_mpdu_params", ht_capabilities->a_mpdu_params);
+			blobmsg_add_u16(&b, "ht_extended_capabilities", ht_capabilities->ht_extended_capabilities);
+			blobmsg_add_u32(&b, "tx_bf_capability_info", ht_capabilities->tx_bf_capability_info);
+			blobmsg_add_u16(&b, "asel_capabilities", ht_capabilities->asel_capabilities);
+			mcs_set = blobmsg_open_array(&b, "supported_mcs_set");
+			for (int i = 0; i < 16; i++) {
+				blobmsg_add_u16(&b, NULL, (u16) ht_capabilities->supported_mcs_set[i]);
+			}
+			blobmsg_close_array(&b, mcs_set);
+			blobmsg_close_table(&b, ht_cap_mcs_set);
+			blobmsg_close_table(&b, ht_cap);
+		}
+		if(req->elems->vht_capabilities)
+		{
+			struct ieee80211_vht_capabilities *vht_capabilities;
+			void *vht_cap, *vht_cap_mcs_set;
+
+			vht_capabilities = (struct ieee80211_vht_capabilities*) req->elems->vht_capabilities;
+			vht_cap = blobmsg_open_table(&b, "vht_capabilities");
+			blobmsg_add_u32(&b, "vht_capabilities_info", vht_capabilities->vht_capabilities_info);
+			vht_cap_mcs_set = blobmsg_open_table(&b, "vht_supported_mcs_set");
+			blobmsg_add_u16(&b, "rx_map", vht_capabilities->vht_supported_mcs_set.rx_map);
+			blobmsg_add_u16(&b, "rx_highest", vht_capabilities->vht_supported_mcs_set.rx_highest);
+			blobmsg_add_u16(&b, "tx_map", vht_capabilities->vht_supported_mcs_set.tx_map);
+			blobmsg_add_u16(&b, "tx_highest", vht_capabilities->vht_supported_mcs_set.tx_highest);
+			blobmsg_close_table(&b, vht_cap_mcs_set);
+			blobmsg_close_table(&b, vht_cap);
+		}
+	}
+
+	if (!hapd->ubus.notify_response) {
+		ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq))
+		return WLAN_STATUS_SUCCESS;
+
+	ureq.nreq.status_cb = ubus_event_cb;
+	ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+	if (ureq.resp)
+		return ureq.resp;
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *addr)
+{
+	if (!hapd->ubus.obj.has_subscribers)
+		return;
+
+	if (!addr)
+		return;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", addr);
+
+	ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
+}
+
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+				    const char *auth_alg)
+{
+	if (!hapd->ubus.obj.has_subscribers)
+		return;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", sta->addr);
+	if (auth_alg)
+		blobmsg_add_string(&b, "auth-alg", auth_alg);
+
+	ubus_notify(ctx, &hapd->ubus.obj, "sta-authorized", b.head, -1);
+}
+
+void hostapd_ubus_notify_beacon_report(
+	struct hostapd_data *hapd, const u8 *addr, u8 token, u8 rep_mode,
+	struct rrm_measurement_beacon_report *rep, size_t len)
+{
+	if (!hapd->ubus.obj.has_subscribers)
+		return;
+
+	if (!addr || !rep)
+		return;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", addr);
+	blobmsg_add_u16(&b, "op-class", rep->op_class);
+	blobmsg_add_u16(&b, "channel", rep->channel);
+	blobmsg_add_u64(&b, "start-time", rep->start_time);
+	blobmsg_add_u16(&b, "duration", rep->duration);
+	blobmsg_add_u16(&b, "report-info", rep->report_info);
+	blobmsg_add_u16(&b, "rcpi", rep->rcpi);
+	blobmsg_add_u16(&b, "rsni", rep->rsni);
+	blobmsg_add_macaddr(&b, "bssid", rep->bssid);
+	blobmsg_add_u16(&b, "antenna-id", rep->antenna_id);
+	blobmsg_add_u16(&b, "parent-tsf", rep->parent_tsf);
+	blobmsg_add_u16(&b, "rep-mode", rep_mode);
+
+	ubus_notify(ctx, &hapd->ubus.obj, "beacon-report", b.head, -1);
+}
+
+void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+					int chan_width, int cf1, int cf2)
+{
+	struct hostapd_data *hapd;
+	int i;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_u16(&b, "frequency", frequency);
+	blobmsg_add_u16(&b, "width", chan_width);
+	blobmsg_add_u16(&b, "center1", cf1);
+	blobmsg_add_u16(&b, "center2", cf2);
+
+	for (i = 0; i < iface->num_bss; i++) {
+		hapd = iface->bss[i];
+		ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1);
+	}
+}
+
+#ifdef CONFIG_WNM_AP
+static void hostapd_ubus_notify_bss_transition_add_candidate_list(
+	const u8 *candidate_list, u16 candidate_list_len)
+{
+	char *cl_str;
+	int i;
+
+	if (candidate_list_len == 0)
+		return;
+
+	cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1);
+	for (i = 0; i < candidate_list_len; i++)
+		snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]);
+	blobmsg_add_string_buffer(&b);
+
+}
+#endif
+
+void hostapd_ubus_notify_bss_transition_response(
+	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+	u8 bss_termination_delay, const u8 *target_bssid,
+	const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+	u16 i;
+
+	if (!hapd->ubus.obj.has_subscribers)
+		return;
+
+	if (!addr)
+		return;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", addr);
+	blobmsg_add_u8(&b, "dialog-token", dialog_token);
+	blobmsg_add_u8(&b, "status-code", status_code);
+	blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay);
+	if (target_bssid)
+		blobmsg_add_macaddr(&b, "target-bssid", target_bssid);
+	
+	hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+	ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
+#endif
+}
+
+int hostapd_ubus_notify_bss_transition_query(
+	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+	const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+	struct ubus_event_req ureq = {};
+	char *cl_str;
+	u16 i;
+
+	if (!hapd->ubus.obj.has_subscribers)
+		return 0;
+
+	if (!addr)
+		return 0;
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_macaddr(&b, "address", addr);
+	blobmsg_add_u8(&b, "dialog-token", dialog_token);
+	blobmsg_add_u8(&b, "reason", reason);
+	hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+	if (!hapd->ubus.notify_response) {
+		ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, -1);
+		return 0;
+	}
+
+	if (ubus_notify_async(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, &ureq.nreq))
+		return 0;
+
+	ureq.nreq.status_cb = ubus_event_cb;
+	ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+	return ureq.resp;
+#endif
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.h
new file mode 100644
index 0000000..b0f7c44
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.h
@@ -0,0 +1,154 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef __HOSTAPD_UBUS_H
+#define __HOSTAPD_UBUS_H
+
+enum hostapd_ubus_event_type {
+	HOSTAPD_UBUS_PROBE_REQ,
+	HOSTAPD_UBUS_AUTH_REQ,
+	HOSTAPD_UBUS_ASSOC_REQ,
+	HOSTAPD_UBUS_TYPE_MAX
+};
+
+struct hostapd_ubus_request {
+	enum hostapd_ubus_event_type type;
+	const struct ieee80211_mgmt *mgmt_frame;
+	const struct ieee802_11_elems *elems;
+	int ssi_signal; /* dBm */
+	const u8 *addr;
+};
+
+struct hostapd_iface;
+struct hostapd_data;
+struct hapd_interfaces;
+struct rrm_measurement_beacon_report;
+
+#ifdef UBUS_SUPPORT
+
+#include <libubox/avl.h>
+#include <libubus.h>
+
+struct hostapd_ubus_bss {
+	struct ubus_object obj;
+	struct avl_tree banned;
+	int notify_response;
+};
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface);
+void hostapd_ubus_free_iface(struct hostapd_iface *iface);
+void hostapd_ubus_add_bss(struct hostapd_data *hapd);
+void hostapd_ubus_free_bss(struct hostapd_data *hapd);
+void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req);
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len);
+void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac);
+void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
+				       const u8 *addr, u8 token, u8 rep_mode,
+				       struct rrm_measurement_beacon_report *rep,
+				       size_t len);
+void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+					int chan_width, int cf1, int cf2);
+
+void hostapd_ubus_notify_bss_transition_response(
+	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+	u8 bss_termination_delay, const u8 *target_bssid,
+	const u8 *candidate_list, u16 candidate_list_len);
+void hostapd_ubus_add(struct hapd_interfaces *interfaces);
+void hostapd_ubus_free(struct hapd_interfaces *interfaces);
+int hostapd_ubus_notify_bss_transition_query(
+	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+	const u8 *candidate_list, u16 candidate_list_len);
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+				    const char *auth_alg);
+
+#else
+
+struct hostapd_ubus_bss {};
+
+static inline void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+}
+
+static inline void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+}
+
+static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+	return 0;
+}
+
+static inline void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+}
+
+static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac)
+{
+}
+
+static inline void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
+						     const u8 *addr, u8 token,
+						     u8 rep_mode,
+						     struct rrm_measurement_beacon_report *rep,
+						     size_t len)
+{
+}
+static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+						      int chan_width, int cf1, int cf2)
+{
+}
+
+static inline void hostapd_ubus_notify_bss_transition_response(
+	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+	u8 bss_termination_delay, const u8 *target_bssid,
+	const u8 *candidate_list, u16 candidate_list_len)
+{
+}
+
+static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
+{
+}
+
+static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces)
+{
+}
+
+static inline int hostapd_ubus_notify_bss_transition_query(
+	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+	const u8 *candidate_list, u16 candidate_list_len)
+{
+	return 0;
+}
+
+static inline void
+hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+			       const char *auth_alg)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.c
new file mode 100644
index 0000000..137cb81
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.c
@@ -0,0 +1,394 @@
+#include <sys/un.h>
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include <libubox/uloop.h>
+
+static uc_resource_type_t *global_type, *bss_type, *iface_type;
+static struct hapd_interfaces *interfaces;
+static uc_value_t *global, *bss_registry, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+hostapd_ucode_bss_get_uval(struct hostapd_data *hapd)
+{
+	uc_value_t *val;
+
+	if (hapd->ucode.idx)
+		return wpa_ucode_registry_get(bss_registry, hapd->ucode.idx);
+
+	val = uc_resource_new(bss_type, hapd);
+	wpa_ucode_registry_add(bss_registry, val, &hapd->ucode.idx);
+
+	return val;
+}
+
+static uc_value_t *
+hostapd_ucode_iface_get_uval(struct hostapd_iface *hapd)
+{
+	uc_value_t *val;
+
+	if (hapd->ucode.idx)
+		return wpa_ucode_registry_get(iface_registry, hapd->ucode.idx);
+
+	val = uc_resource_new(iface_type, hapd);
+	wpa_ucode_registry_add(iface_registry, val, &hapd->ucode.idx);
+
+	return val;
+}
+
+static void
+hostapd_ucode_update_bss_list(struct hostapd_iface *iface)
+{
+	uc_value_t *ifval, *list;
+	int i;
+
+	list = ucv_array_new(vm);
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *hapd = iface->bss[i];
+		uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
+		uc_value_t *proto = ucv_prototype_get(val);
+
+		ucv_object_add(proto, "name", ucv_get(ucv_string_new(hapd->conf->iface)));
+		ucv_object_add(proto, "index", ucv_int64_new(i));
+		ucv_array_set(list, i, ucv_get(val));
+	}
+
+	ifval = hostapd_ucode_iface_get_uval(iface);
+	ucv_object_add(ucv_prototype_get(ifval), "bss", ucv_get(list));
+}
+
+static void
+hostapd_ucode_update_interfaces(void)
+{
+	uc_value_t *ifs = ucv_object_new(vm);
+	int i;
+
+	for (i = 0; i < interfaces->count; i++) {
+		struct hostapd_iface *iface = interfaces->iface[i];
+
+		ucv_object_add(ifs, iface->phy, ucv_get(hostapd_ucode_iface_get_uval(iface)));
+		hostapd_ucode_update_bss_list(iface);
+	}
+
+	ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+	ucv_gc(vm);
+}
+
+static uc_value_t *
+uc_hostapd_add_iface(uc_vm_t *vm, size_t nargs)
+{
+	uc_value_t *iface = uc_fn_arg(0);
+	int ret;
+
+	if (ucv_type(iface) != UC_STRING)
+		return ucv_int64_new(-1);
+
+	ret = hostapd_add_iface(interfaces, ucv_string_get(iface));
+	hostapd_ucode_update_interfaces();
+
+	return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+	uc_value_t *iface = uc_fn_arg(0);
+
+	if (ucv_type(iface) != UC_STRING)
+		return NULL;
+
+	hostapd_remove_iface(interfaces, ucv_string_get(iface));
+	hostapd_ucode_update_interfaces();
+
+	return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
+{
+	struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+	struct hostapd_bss_config *old_bss;
+	struct hostapd_iface *iface;
+	struct hostapd_config *conf;
+	uc_value_t *file = uc_fn_arg(0);
+	uc_value_t *index = uc_fn_arg(1);
+	unsigned int i, idx = 0;
+	int ret = -1;
+
+	if (!hapd || ucv_type(file) != UC_STRING)
+		goto out;
+
+	if (ucv_type(index) == UC_INTEGER)
+		idx = ucv_int64_get(index);
+
+	iface = hapd->iface;
+	conf = interfaces->config_read_cb(ucv_string_get(file));
+	if (!conf || idx > conf->num_bss || !conf->bss[idx])
+		goto out;
+
+	hostapd_bss_deinit_no_free(hapd);
+	hostapd_drv_stop_ap(hapd);
+	hostapd_free_hapd_data(hapd);
+
+	old_bss = hapd->conf;
+	for (i = 0; i < iface->conf->num_bss; i++)
+		if (iface->conf->bss[i] == hapd->conf)
+			iface->conf->bss[i] = conf->bss[idx];
+	hapd->conf = conf->bss[idx];
+	conf->bss[idx] = old_bss;
+	hostapd_config_free(conf);
+
+	hostapd_setup_bss(hapd, hapd == iface->bss[0], !iface->conf->mbssid);
+
+	ret = 0;
+
+out:
+	return ucv_int64_new(ret);
+}
+
+static void
+hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
+			      struct hostapd_bss_config *conf)
+{
+	int i;
+
+	for (i = 0; i < iconf->num_bss; i++)
+		if (iconf->bss[i] == conf)
+			break;
+
+	if (i == iconf->num_bss)
+		return;
+
+	for (i++; i < iconf->num_bss; i++)
+		iconf->bss[i - 1] = iconf->bss[i];
+	iconf->num_bss--;
+}
+
+
+static uc_value_t *
+uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
+{
+	struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+	struct hostapd_iface *iface;
+	int i, idx;
+
+	if (!hapd || hapd == hapd->iface->bss[0])
+		return NULL;
+
+	iface = hapd->iface;
+	for (idx = 0; idx < iface->num_bss; idx++)
+		if (iface->bss[idx] == hapd)
+			break;
+
+	if (idx == iface->num_bss)
+		return NULL;
+
+	for (i = idx + 1; i < iface->num_bss; i++)
+		iface->bss[i - 1] = iface->bss[i];
+	iface->num_bss--;
+
+	hostapd_drv_stop_ap(hapd);
+	hostapd_bss_deinit(hapd);
+	hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
+	hostapd_config_free_bss(hapd->conf);
+	os_free(hapd);
+
+	hostapd_ucode_update_bss_list(iface);
+	ucv_gc(vm);
+
+	return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
+{
+	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+	struct hostapd_bss_config *bss;
+	struct hostapd_config *conf;
+	struct hostapd_data *hapd;
+	uc_value_t *file = uc_fn_arg(0);
+	uc_value_t *index = uc_fn_arg(1);
+	unsigned int idx = 0;
+	uc_value_t *ret = NULL;
+
+	if (!iface || ucv_type(file) != UC_STRING)
+		goto out;
+
+	if (ucv_type(index) == UC_INTEGER)
+		idx = ucv_int64_get(index);
+
+	conf = interfaces->config_read_cb(ucv_string_get(file));
+	if (!conf || idx > conf->num_bss || !conf->bss[idx])
+		goto out;
+
+	bss = conf->bss[idx];
+	hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+	if (!hapd)
+		goto out;
+
+	hapd->driver = iface->bss[0]->driver;
+	hapd->drv_priv = iface->bss[0]->drv_priv;
+	if (interfaces->ctrl_iface_init &&
+	    interfaces->ctrl_iface_init(hapd) < 0)
+		goto free_hapd;
+
+	if (iface->state == HAPD_IFACE_ENABLED &&
+	    hostapd_setup_bss(hapd, -1, true))
+		goto deinit_ctrl;
+
+	iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+				      sizeof(*iface->bss));
+	iface->bss[iface->num_bss++] = hapd;
+
+	iface->conf->bss = os_realloc_array(iface->conf->bss,
+					    iface->conf->num_bss + 1,
+					    sizeof(*iface->conf->bss));
+	iface->conf->bss[iface->conf->num_bss] = bss;
+	conf->bss[idx] = NULL;
+	ret = hostapd_ucode_bss_get_uval(hapd);
+	hostapd_ucode_update_bss_list(iface);
+	goto out;
+
+deinit_ctrl:
+	if (interfaces->ctrl_iface_deinit)
+		interfaces->ctrl_iface_deinit(hapd);
+free_hapd:
+	hostapd_free_hapd_data(hapd);
+	os_free(hapd);
+out:
+	hostapd_config_free(conf);
+	return ret;
+}
+
+static uc_value_t *
+uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
+{
+	struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+	uc_value_t *arg = uc_fn_arg(0);
+	struct sockaddr_storage from = {};
+	static char reply[4096];
+	int reply_len;
+
+	if (!hapd || !interfaces->ctrl_iface_recv ||
+	    ucv_type(arg) != UC_STRING)
+		return NULL;
+
+	reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
+						reply, sizeof(reply),
+						&from, sizeof(from));
+	if (reply_len < 0)
+		return NULL;
+
+	if (reply_len && reply[reply_len - 1] == '\n')
+		reply_len--;
+
+	return ucv_string_new_length(reply, reply_len);
+}
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+	static const uc_function_list_t global_fns[] = {
+		{ "printf",	uc_wpa_printf },
+		{ "getpid", uc_wpa_getpid },
+		{ "sha1", uc_wpa_sha1 },
+		{ "add_iface", uc_hostapd_add_iface },
+		{ "remove_iface", uc_hostapd_remove_iface },
+	};
+	static const uc_function_list_t bss_fns[] = {
+		{ "ctrl", uc_hostapd_bss_ctrl },
+		{ "set_config", uc_hostapd_bss_set_config },
+		{ "delete", uc_hostapd_bss_delete },
+	};
+	static const uc_function_list_t iface_fns[] = {
+		{ "add_bss", uc_hostapd_iface_add_bss }
+	};
+	uc_value_t *data, *proto;
+
+	interfaces = ifaces;
+	vm = wpa_ucode_create_vm();
+
+	global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
+	bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
+	iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
+
+	bss_registry = ucv_array_new(vm);
+	uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
+
+	iface_registry = ucv_array_new(vm);
+	uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
+
+	global = wpa_ucode_global_init("hostapd", global_type);
+
+	if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
+		goto free_vm;
+	ucv_gc(vm);
+
+	return 0;
+
+free_vm:
+	wpa_ucode_free_vm();
+	return -1;
+}
+
+void hostapd_ucode_free(void)
+{
+	if (wpa_ucode_call_prepare("shutdown") == 0)
+		ucv_put(wpa_ucode_call(0));
+	wpa_ucode_free_vm();
+}
+
+void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+	wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
+}
+
+void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+	uc_value_t *val;
+
+	if (wpa_ucode_call_prepare("bss_add"))
+		return;
+
+	val = hostapd_ucode_bss_get_uval(hapd);
+	uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+	uc_value_push(ucv_get(val));
+	ucv_put(wpa_ucode_call(2));
+	ucv_gc(vm);
+}
+
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
+{
+	uc_value_t *val;
+
+	if (wpa_ucode_call_prepare("bss_reload"))
+		return;
+
+	val = hostapd_ucode_bss_get_uval(hapd);
+	uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+	uc_value_push(ucv_get(val));
+	uc_value_push(ucv_int64_new(reconf));
+	ucv_put(wpa_ucode_call(3));
+	ucv_gc(vm);
+}
+
+void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+	uc_value_t *val;
+
+	val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
+	if (!val)
+		return;
+
+	hapd->ucode.idx = 0;
+	if (wpa_ucode_call_prepare("bss_remove"))
+		return;
+
+	uc_value_push(ucv_string_new(hapd->conf->iface));
+	uc_value_push(ucv_get(val));
+	ucv_put(wpa_ucode_call(2));
+	ucv_gc(vm);
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.h
new file mode 100644
index 0000000..dbc49e6
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.h
@@ -0,0 +1,54 @@
+#ifndef __HOSTAPD_AP_UCODE_H
+#define __HOSTAPD_AP_UCODE_H
+
+#include "utils/ucode.h"
+
+struct hostapd_data;
+
+struct hostapd_ucode_bss {
+#ifdef UCODE_SUPPORT
+	int idx;
+#endif
+};
+
+struct hostapd_ucode_iface {
+#ifdef UCODE_SUPPORT
+	int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces);
+
+void hostapd_ucode_free(void);
+void hostapd_ucode_free_iface(struct hostapd_iface *iface);
+void hostapd_ucode_add_bss(struct hostapd_data *hapd);
+void hostapd_ucode_free_bss(struct hostapd_data *hapd);
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf);
+
+#else
+
+static inline int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+	return -EINVAL;
+}
+static inline void hostapd_ucode_free(void)
+{
+}
+static inline void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+}
+static inline void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
+{
+}
+static inline void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+}
+static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/build_features.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/build_features.h
new file mode 100644
index 0000000..553769e
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/build_features.h
@@ -0,0 +1,65 @@
+#ifndef BUILD_FEATURES_H
+#define BUILD_FEATURES_H
+
+static inline int has_feature(const char *feat)
+{
+#if defined(IEEE8021X_EAPOL) || (defined(HOSTAPD) && !defined(CONFIG_NO_RADIUS))
+	if (!strcmp(feat, "eap"))
+		return 1;
+#endif
+#ifdef CONFIG_IEEE80211AC
+	if (!strcmp(feat, "11ac"))
+		return 1;
+#endif
+#ifdef CONFIG_IEEE80211AX
+	if (!strcmp(feat, "11ax"))
+		return 1;
+#endif
+#ifdef CONFIG_IEEE80211R
+	if (!strcmp(feat, "11r"))
+		return 1;
+#endif
+#ifdef CONFIG_ACS
+	if (!strcmp(feat, "acs"))
+		return 1;
+#endif
+#ifdef CONFIG_SAE
+	if (!strcmp(feat, "sae"))
+		return 1;
+#endif
+#ifdef CONFIG_OWE
+	if (!strcmp(feat, "owe"))
+		return 1;
+#endif
+#ifdef CONFIG_SUITEB192
+	if (!strcmp(feat, "suiteb192"))
+		return 1;
+#endif
+#ifdef CONFIG_WEP
+	if (!strcmp(feat, "wep"))
+		return 1;
+#endif
+#ifdef CONFIG_HS20
+	if (!strcmp(feat, "hs20"))
+		return 1;
+#endif
+#ifdef CONFIG_WPS
+	if (!strcmp(feat, "wps"))
+		return 1;
+#endif
+#ifdef CONFIG_FILS
+	if (!strcmp(feat, "fils"))
+		return 1;
+#endif
+#ifdef CONFIG_OCV
+	if (!strcmp(feat, "ocv"))
+		return 1;
+#endif
+#ifdef CONFIG_MESH
+	if (!strcmp(feat, "mesh"))
+		return 1;
+#endif
+	return 0;
+}
+
+#endif /* BUILD_FEATURES_H */
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.c
new file mode 100644
index 0000000..a92913a
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.c
@@ -0,0 +1,251 @@
+#include <unistd.h>
+#include "ucode.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include <libubox/uloop.h>
+#include <ucode/compiler.h>
+
+static uc_value_t *registry;
+static uc_vm_t vm;
+static struct uloop_timeout gc_timer;
+
+static void uc_gc_timer(struct uloop_timeout *timeout)
+{
+	ucv_gc(&vm);
+}
+
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs)
+{
+	uc_value_t *level = uc_fn_arg(0);
+	uc_value_t *ret, **args;
+	uc_cfn_ptr_t _sprintf;
+	int l = MSG_INFO;
+	int i, start = 0;
+
+	_sprintf = uc_stdlib_function("sprintf");
+	if (!sprintf)
+		return NULL;
+
+	if (ucv_type(level) == UC_INTEGER) {
+		l = ucv_int64_get(level);
+		start++;
+	}
+
+	if (nargs <= start)
+		return NULL;
+
+	ret = _sprintf(vm, nargs - start);
+	if (ucv_type(ret) != UC_STRING)
+		return NULL;
+
+	wpa_printf(l, "%s", ucv_string_get(ret));
+	ucv_put(ret);
+
+	return NULL;
+}
+
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs)
+{
+	return ucv_int64_new(getpid());
+}
+
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs)
+{
+	u8 hash[SHA1_MAC_LEN];
+	char hash_hex[2 * ARRAY_SIZE(hash) + 1];
+	uc_value_t *val;
+	size_t *lens;
+	const u8 **args;
+	int i;
+
+	if (!nargs)
+		return NULL;
+
+	args = alloca(nargs * sizeof(*args));
+	lens = alloca(nargs * sizeof(*lens));
+	for (i = 0; i < nargs; i++) {
+		val = uc_fn_arg(i);
+		if (ucv_type(val) != UC_STRING)
+			return NULL;
+
+		args[i] = ucv_string_get(val);
+		lens[i] = ucv_string_length(val);
+	}
+
+	if (sha1_vector(nargs, args, lens, hash))
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(hash); i++)
+		sprintf(hash_hex + 2 * i, "%02x", hash[i]);
+
+	return ucv_string_new_length(hash_hex, 2 * ARRAY_SIZE(hash));
+}
+
+uc_vm_t *wpa_ucode_create_vm(void)
+{
+	static uc_parse_config_t config = {
+		.strict_declarations = true,
+		.lstrip_blocks = true,
+		.trim_blocks = true,
+		.raw_mode = true
+	};
+
+	uc_search_path_init(&config.module_search_path);
+	uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.so");
+	uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.uc");
+
+	uc_vm_init(&vm, &config);
+
+	uc_stdlib_load(uc_vm_scope_get(&vm));
+	eloop_add_uloop();
+	gc_timer.cb = uc_gc_timer;
+
+	return &vm;
+}
+
+int wpa_ucode_run(const char *script)
+{
+	uc_source_t *source;
+	uc_program_t *prog;
+	uc_value_t *ops;
+	char *err;
+	int ret;
+
+	source = uc_source_new_file(script);
+	if (!source)
+		return -1;
+
+	prog = uc_compile(vm.config, source, &err);
+	uc_source_put(source);
+	if (!prog) {
+		wpa_printf(MSG_ERROR, "Error loading ucode: %s\n", err);
+		return -1;
+	}
+
+	ret = uc_vm_execute(&vm, prog, &ops);
+	uc_program_put(prog);
+	if (ret || !ops)
+		return -1;
+
+	registry = ucv_array_new(&vm);
+	uc_vm_registry_set(&vm, "hostap.registry", registry);
+	ucv_array_set(registry, 0, ucv_get(ops));
+
+	return 0;
+}
+
+int wpa_ucode_call_prepare(const char *fname)
+{
+	uc_value_t *obj, *func;
+
+	if (!registry)
+		return -1;
+
+	obj = ucv_array_get(registry, 0);
+	if (!obj)
+		return -1;
+
+	func = ucv_object_get(obj, fname, NULL);
+	if (!ucv_is_callable(func))
+		return -1;
+
+	uc_vm_stack_push(&vm, ucv_get(obj));
+	uc_vm_stack_push(&vm, ucv_get(func));
+
+	return 0;
+}
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type)
+{
+	uc_value_t *global = uc_resource_new(global_type, NULL);
+	uc_value_t *proto;
+
+	uc_vm_registry_set(&vm, "hostap.global", global);
+	proto = ucv_prototype_get(global);
+	ucv_object_add(proto, "data", ucv_get(ucv_object_new(&vm)));
+
+#define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
+	ADD_CONST(MSG_EXCESSIVE);
+	ADD_CONST(MSG_MSGDUMP);
+	ADD_CONST(MSG_DEBUG);
+	ADD_CONST(MSG_INFO);
+	ADD_CONST(MSG_WARNING);
+	ADD_CONST(MSG_ERROR);
+#undef ADD_CONST
+
+	ucv_object_add(uc_vm_scope_get(&vm), name, ucv_get(global));
+
+	return global;
+}
+
+static uc_value_t *wpa_ucode_prototype_clone(uc_value_t *uval)
+{
+	uc_value_t *proto, *proto_new;
+
+	proto = ucv_prototype_get(uval);
+	proto_new = ucv_object_new(&vm);
+
+	ucv_object_foreach(proto, key, val)
+		ucv_object_add(proto_new, key, ucv_get(val));
+	ucv_prototype_set(uval, ucv_get(proto));
+
+	return proto;
+}
+
+void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx)
+{
+	uc_value_t *data;
+	int i = 0;
+
+	while (ucv_array_get(reg, i))
+		i++;
+
+	ucv_array_set(reg, i, ucv_get(val));
+
+	data = ucv_object_new(&vm);
+	ucv_object_add(wpa_ucode_prototype_clone(val), "data", ucv_get(data));
+
+	*idx = i + 1;
+}
+
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx)
+{
+	if (!idx)
+		return NULL;
+
+	return ucv_array_get(reg, idx - 1);
+}
+
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx)
+{
+	uc_value_t *val = wpa_ucode_registry_get(reg, idx);
+
+	if (val)
+		ucv_array_set(reg, idx - 1, NULL);
+
+	return val;
+}
+
+
+uc_value_t *wpa_ucode_call(size_t nargs)
+{
+	if (uc_vm_call(&vm, true, nargs) != EXCEPTION_NONE)
+		return NULL;
+
+	if (!gc_timer.pending)
+		uloop_timeout_set(&gc_timer, 10);
+
+	return uc_vm_stack_pop(&vm);
+}
+
+void wpa_ucode_free_vm(void)
+{
+	if (!vm.config)
+		return;
+
+	uc_search_path_free(&vm.config->module_search_path);
+	uc_vm_free(&vm);
+	registry = NULL;
+	vm = (uc_vm_t){};
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.h
new file mode 100644
index 0000000..4caf8ad
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.h
@@ -0,0 +1,28 @@
+#ifndef __HOSTAPD_UTILS_UCODE_H
+#define __HOSTAPD_UTILS_UCODE_H
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include <ucode/lib.h>
+#include <ucode/vm.h>
+
+#define HOSTAPD_UC_PATH	"/usr/share/hostap/"
+
+extern uc_value_t *uc_registry;
+uc_vm_t *wpa_ucode_create_vm(void);
+int wpa_ucode_run(const char *script);
+int wpa_ucode_call_prepare(const char *fname);
+uc_value_t *wpa_ucode_call(size_t nargs);
+void wpa_ucode_free_vm(void);
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type);
+
+void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx);
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx);
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx);
+
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs);
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.c
new file mode 100644
index 0000000..1c477f0
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.c
@@ -0,0 +1,280 @@
+/*
+ * wpa_supplicant / ubus support
+ * Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/wpabuf.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "ubus.h"
+
+static struct ubus_context *ctx;
+static struct blob_buf b;
+static int ctx_ref;
+
+static inline struct wpa_global *get_wpa_global_from_object(struct ubus_object *obj)
+{
+	return container_of(obj, struct wpa_global, ubus_global);
+}
+
+static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj)
+{
+	return container_of(obj, struct wpa_supplicant, ubus.obj);
+}
+
+static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
+{
+	if (ubus_reconnect(ctx, NULL)) {
+		eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+		return;
+	}
+
+	ubus_add_uloop(ctx);
+}
+
+static void wpas_ubus_connection_lost(struct ubus_context *ctx)
+{
+	uloop_fd_delete(&ctx->sock);
+	eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+}
+
+static bool wpas_ubus_init(void)
+{
+	if (ctx)
+		return true;
+
+	eloop_add_uloop();
+	ctx = ubus_connect(NULL);
+	if (!ctx)
+		return false;
+
+	ctx->connection_lost = wpas_ubus_connection_lost;
+	ubus_add_uloop(ctx);
+
+	return true;
+}
+
+static void wpas_ubus_ref_inc(void)
+{
+	ctx_ref++;
+}
+
+static void wpas_ubus_ref_dec(void)
+{
+	ctx_ref--;
+	if (!ctx)
+		return;
+
+	if (ctx_ref)
+		return;
+
+	uloop_fd_delete(&ctx->sock);
+	ubus_free(ctx);
+	ctx = NULL;
+}
+
+static int
+wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+	blob_buf_init(&b, 0);
+	blobmsg_add_u8(&b, "ht_supported", ht_supported(wpa_s->hw.modes));
+	blobmsg_add_u8(&b, "vht_supported", vht_supported(wpa_s->hw.modes));
+	ubus_send_reply(ctx, req, b.head);
+
+	return 0;
+}
+
+static int
+wpas_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
+{
+	struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+	if (wpa_supplicant_reload_configuration(wpa_s))
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	else
+		return 0;
+}
+
+#ifdef CONFIG_WPS
+enum {
+	WPS_START_MULTI_AP,
+	__WPS_START_MAX
+};
+
+static const struct blobmsg_policy wps_start_policy[] = {
+	[WPS_START_MULTI_AP] = { "multi_ap", BLOBMSG_TYPE_BOOL },
+};
+
+static int
+wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+	struct blob_attr *tb[__WPS_START_MAX], *cur;
+	int multi_ap = 0;
+
+	blobmsg_parse(wps_start_policy, __WPS_START_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
+
+	if (tb[WPS_START_MULTI_AP])
+		multi_ap = blobmsg_get_bool(tb[WPS_START_MULTI_AP]);
+
+	rc = wpas_wps_start_pbc(wpa_s, NULL, 0, multi_ap);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+
+static int
+wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	int rc;
+	struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+	rc = wpas_wps_cancel(wpa_s);
+
+	if (rc != 0)
+		return UBUS_STATUS_NOT_SUPPORTED;
+
+	return 0;
+}
+#endif
+
+static const struct ubus_method bss_methods[] = {
+	UBUS_METHOD_NOARG("reload", wpas_bss_reload),
+	UBUS_METHOD_NOARG("get_features", wpas_bss_get_features),
+#ifdef CONFIG_WPS
+	UBUS_METHOD_NOARG("wps_start", wpas_bss_wps_start),
+	UBUS_METHOD_NOARG("wps_cancel", wpas_bss_wps_cancel),
+#endif
+};
+
+static struct ubus_object_type bss_object_type =
+	UBUS_OBJECT_TYPE("wpas_bss", bss_methods);
+
+void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
+{
+	struct ubus_object *obj = &wpa_s->ubus.obj;
+	char *name;
+	int ret;
+
+	if (!wpas_ubus_init())
+		return;
+
+	if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0)
+		return;
+
+	obj->name = name;
+	obj->type = &bss_object_type;
+	obj->methods = bss_object_type.methods;
+	obj->n_methods = bss_object_type.n_methods;
+	ret = ubus_add_object(ctx, obj);
+	wpas_ubus_ref_inc();
+}
+
+void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
+{
+	struct ubus_object *obj = &wpa_s->ubus.obj;
+	char *name = (char *) obj->name;
+
+	if (!ctx)
+		return;
+
+	if (obj->id) {
+		ubus_remove_object(ctx, obj);
+		wpas_ubus_ref_dec();
+	}
+
+	free(name);
+}
+
+#ifdef CONFIG_WPS
+void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred)
+{
+	u16 auth_type;
+	char *ifname, *encryption, *ssid, *key;
+	size_t ifname_len;
+
+	if (!cred)
+		return;
+
+	auth_type = cred->auth_type;
+
+	if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))
+		auth_type = WPS_AUTH_WPA2PSK;
+
+	if (auth_type != WPS_AUTH_OPEN &&
+	    auth_type != WPS_AUTH_WPAPSK &&
+	    auth_type != WPS_AUTH_WPA2PSK) {
+		wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
+			   "unsupported authentication type 0x%x",
+			   auth_type);
+		return;
+	}
+
+	if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+		if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+			wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+				   "invalid Network Key length %lu",
+				   (unsigned long) cred->key_len);
+			return;
+		}
+	}
+
+	blob_buf_init(&b, 0);
+
+	ifname_len = strlen(wpa_s->ifname);
+	ifname = blobmsg_alloc_string_buffer(&b, "ifname", ifname_len + 1);
+	memcpy(ifname, wpa_s->ifname, ifname_len + 1);
+	ifname[ifname_len] = '\0';
+	blobmsg_add_string_buffer(&b);
+
+	switch (auth_type) {
+		case WPS_AUTH_WPA2PSK:
+			encryption = "psk2";
+			break;
+		case WPS_AUTH_WPAPSK:
+			encryption = "psk";
+			break;
+		default:
+			encryption = "none";
+			break;
+	}
+
+	blobmsg_add_string(&b, "encryption", encryption);
+
+	ssid = blobmsg_alloc_string_buffer(&b, "ssid", cred->ssid_len + 1);
+	memcpy(ssid, cred->ssid, cred->ssid_len);
+	ssid[cred->ssid_len] = '\0';
+	blobmsg_add_string_buffer(&b);
+
+	if (cred->key_len > 0) {
+		key = blobmsg_alloc_string_buffer(&b, "key", cred->key_len + 1);
+		memcpy(key, cred->key, cred->key_len);
+		key[cred->key_len] = '\0';
+		blobmsg_add_string_buffer(&b);
+	}
+
+//	ubus_notify(ctx, &wpa_s->ubus.obj, "wps_credentials", b.head, -1);
+	ubus_send_event(ctx, "wps_credentials", b.head);
+}
+#endif /* CONFIG_WPS */
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.h
new file mode 100644
index 0000000..f6681cb
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.h
@@ -0,0 +1,55 @@
+/*
+ * wpa_supplicant / ubus support
+ * Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef __WPAS_UBUS_H
+#define __WPAS_UBUS_H
+
+struct wpa_supplicant;
+struct wpa_global;
+
+#include "wps_supplicant.h"
+
+#ifdef UBUS_SUPPORT
+#include <libubus.h>
+
+struct wpas_ubus_bss {
+	struct ubus_object obj;
+};
+
+void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s);
+
+#ifdef CONFIG_WPS
+void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred);
+#endif
+
+#else
+struct wpas_ubus_bss {};
+
+static inline void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ubus_notify(struct wpa_supplicant *wpa_s, struct wps_credential *cred)
+{
+}
+
+static inline void wpas_ubus_add(struct wpa_global *global)
+{
+}
+
+static inline void wpas_ubus_free(struct wpa_global *global)
+{
+}
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.c
new file mode 100644
index 0000000..eec3980
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.c
@@ -0,0 +1,177 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "ucode.h"
+
+static struct wpa_global *wpa_global;
+static uc_resource_type_t *global_type, *iface_type;
+static uc_value_t *global, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
+{
+	uc_value_t *val;
+
+	if (wpa_s->ucode.idx)
+		return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+
+	val = uc_resource_new(iface_type, wpa_s);
+	wpa_ucode_registry_add(iface_registry, val, &wpa_s->ucode.idx);
+
+	return val;
+}
+
+static void
+wpas_ucode_update_interfaces(void)
+{
+	uc_value_t *ifs = ucv_object_new(vm);
+	struct wpa_supplicant *wpa_s;
+	int i;
+
+	for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+		ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+
+	ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+	ucv_gc(vm);
+}
+
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+	uc_value_t *val;
+
+	if (wpa_ucode_call_prepare("iface_add"))
+		return;
+
+	uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+	uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+	ucv_put(wpa_ucode_call(2));
+	ucv_gc(vm);
+}
+
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+	uc_value_t *val;
+
+	val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
+	if (!val)
+		return;
+
+	wpa_s->ucode.idx = 0;
+	if (wpa_ucode_call_prepare("iface_remove"))
+		return;
+
+	uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+	uc_value_push(ucv_get(val));
+	ucv_put(wpa_ucode_call(2));
+	ucv_gc(vm);
+}
+
+static const char *obj_stringval(uc_value_t *obj, const char *name)
+{
+	uc_value_t *val = ucv_object_get(obj, name, NULL);
+
+	return ucv_string_get(val);
+}
+
+static uc_value_t *
+uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
+{
+	uc_value_t *info = uc_fn_arg(0);
+	uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
+	uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
+	uc_value_t *config = ucv_object_get(info, "config", NULL);
+	uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
+	uc_value_t *hapd_ctrl = ucv_object_get(info, "hostapd_ctrl", NULL);
+	struct wpa_interface iface;
+	int ret = -1;
+
+	if (ucv_type(info) != UC_OBJECT)
+		goto out;
+
+	iface = (struct wpa_interface){
+		.driver = "nl80211",
+		.ifname = ucv_string_get(ifname),
+		.bridge_ifname = ucv_string_get(bridge),
+		.confname = ucv_string_get(config),
+		.ctrl_interface = ucv_string_get(ctrl),
+		.hostapd_ctrl = ucv_string_get(hapd_ctrl),
+	};
+
+	if (!iface.ifname || !iface.confname)
+		goto out;
+
+	ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
+	wpas_ucode_update_interfaces();
+
+out:
+	return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+	struct wpa_supplicant *wpa_s = NULL;
+	uc_value_t *ifname_arg = uc_fn_arg(0);
+	const char *ifname = ucv_string_get(ifname_arg);
+	int ret = -1;
+
+	if (!ifname)
+		goto out;
+
+	for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+		if (!strcmp(wpa_s->ifname, ifname))
+			break;
+
+	if (!wpa_s)
+		goto out;
+
+	ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
+	wpas_ucode_update_interfaces();
+
+out:
+	return ucv_int64_new(ret);
+}
+
+int wpas_ucode_init(struct wpa_global *gl)
+{
+	static const uc_function_list_t global_fns[] = {
+		{ "printf",	uc_wpa_printf },
+		{ "getpid", uc_wpa_getpid },
+		{ "add_iface", uc_wpas_add_iface },
+		{ "remove_iface", uc_wpas_remove_iface },
+	};
+	static const uc_function_list_t iface_fns[] = {
+	};
+	uc_value_t *data, *proto;
+
+	wpa_global = gl;
+	vm = wpa_ucode_create_vm();
+
+	global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
+	iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
+
+	iface_registry = ucv_array_new(vm);
+	uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
+
+	global = wpa_ucode_global_init("wpas", global_type);
+
+	if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
+		goto free_vm;
+
+	ucv_gc(vm);
+	return 0;
+
+free_vm:
+	wpa_ucode_free_vm();
+	return -1;
+}
+
+void wpas_ucode_free(void)
+{
+	if (wpa_ucode_call_prepare("shutdown") == 0)
+		ucv_put(wpa_ucode_call(0));
+	wpa_ucode_free_vm();
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.h
new file mode 100644
index 0000000..fcd2313
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.h
@@ -0,0 +1,38 @@
+#ifndef __WPAS_UCODE_H
+#define __WPAS_UCODE_H
+
+#include "utils/ucode.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+struct wpas_ucode_bss {
+#ifdef UCODE_SUPPORT
+	unsigned int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+int wpas_ucode_init(struct wpa_global *gl);
+void wpas_ucode_free(void);
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s);
+#else
+static inline int wpas_ucode_init(struct wpa_global *gl)
+{
+	return -EINVAL;
+}
+static inline void wpas_ucode_free(void)
+{
+}
+static inline void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/wpa_supplicant.uc b/recipes-wifi/wpa-supplicant/files/wpa_supplicant.uc
new file mode 100644
index 0000000..22cb130
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/wpa_supplicant.uc
@@ -0,0 +1,161 @@
+let libubus = require("ubus");
+import { open, readfile } from "fs";
+import { wdev_create, wdev_remove, is_equal, vlist_new } from "common";
+
+let ubus = libubus.connect();
+
+wpas.data.config = {};
+
+function iface_stop(iface)
+{
+	let ifname = iface.config.iface;
+
+	wpas.remove_iface(ifname);
+	wdev_remove(ifname);
+	iface.running = false;
+}
+
+function iface_start(phy, iface)
+{
+	if (iface.running)
+		return;
+
+	let ifname = iface.config.iface;
+
+	wdev_remove(ifname);
+	let ret = wdev_create(phy, ifname, iface.config);
+	if (ret)
+		wpas.printf(`Failed to create device ${ifname}: ${ret}`);
+	wpas.add_iface(iface.config);
+	iface.running = true;
+}
+
+function iface_cb(new_if, old_if)
+{
+	if (old_if && new_if && is_equal(old_if.config, new_if.config)) {
+		new_if.running = old_if.running;
+		return;
+	}
+
+	if (old_if && old_if.running)
+		iface_stop(old_if);
+}
+
+function prepare_config(config)
+{
+	config.config_data = readfile(config.config);
+
+	return { config: config };
+}
+
+function set_config(phy_name, config_list)
+{
+	let phy = wpas.data.config[phy_name];
+
+	if (!phy) {
+		phy = vlist_new(iface_cb, false);
+		wpas.data.config[phy_name] = phy;
+	}
+
+	let values = [];
+	for (let config in config_list)
+		push(values, [ config.iface, prepare_config(config) ]);
+
+	phy.update(values);
+}
+
+function start_pending(phy_name)
+{
+	let phy = wpas.data.config[phy_name];
+
+	for (let ifname in phy.data)
+		iface_start(phy_name, phy.data[ifname]);
+}
+
+let main_obj = {
+	config_set: {
+		args: {
+			phy: "",
+			config: [],
+			defer: true,
+		},
+		call: function(req) {
+			if (!req.args.phy)
+				return libubus.STATUS_INVALID_ARGUMENT;
+
+			try {
+				if (req.args.config)
+					set_config(req.args.phy, req.args.config);
+
+				if (!req.args.defer)
+					start_pending(req.args.phy);
+			} catch (e) {
+				wpas.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
+				return libubus.STATUS_INVALID_ARGUMENT;
+			}
+
+			return {
+				pid: wpas.getpid()
+			};
+		}
+	},
+	config_add: {
+		args: {
+			driver: "",
+			iface: "",
+			bridge: "",
+			hostapd_ctrl: "",
+			ctrl: "",
+			config: "",
+		},
+		call: function(req) {
+			if (!req.args.iface || !req.args.config)
+				return libubus.STATUS_INVALID_ARGUMENT;
+
+			if (wpas.add_iface(req.args) < 0)
+				return libubus.STATUS_INVALID_ARGUMENT;
+
+			return {
+				pid: wpas.getpid()
+			};
+		}
+	},
+	config_remove: {
+		args: {
+			iface: ""
+		},
+		call: function(req) {
+			if (!req.args.iface)
+				return libubus.STATUS_INVALID_ARGUMENT;
+
+			wpas.remove_iface(req.args.iface);
+			return 0;
+		}
+	},
+};
+
+wpas.data.ubus = ubus;
+wpas.data.obj = ubus.publish("wpa_supplicant", main_obj);
+
+function iface_event(type, name, data) {
+	let ubus = wpas.data.ubus;
+
+	data ??= {};
+	data.name = name;
+	wpas.data.obj.notify(`iface.${type}`, data, null, null, null, -1);
+	ubus.call("service", "event", { type: `wpa_supplicant.${name}.${type}`, data: {} });
+}
+
+return {
+	shutdown: function() {
+		for (let phy in wpas.data.config)
+			set_config(phy, []);
+		wpas.ubus.disconnect();
+	},
+	iface_add: function(name, obj) {
+		iface_event("add", name);
+	},
+	iface_remove: function(name, obj) {
+		iface_event("remove", name);
+	}
+};
diff --git a/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb b/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb
index 0f446aa..f3bb828 100644
--- a/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb
+++ b/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb
@@ -6,7 +6,7 @@
 LICENSE = "BSD-3-Clause"
 LIC_FILES_CHKSUM = "file://hostapd/README;md5=c905478466c90f1cefc0df987c40e172"
 
-DEPENDS = "dbus libnl ubus"
+DEPENDS = "dbus libnl ubus ucode"
 FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
 FILESEXTRAPATHS_prepend := "${THISDIR}/files/patches-${PV}:"
 
@@ -17,8 +17,9 @@
            file://wpa_supplicant.conf-sane \
            file://99_wpa_supplicant \
            file://wpa_supplicant-full.config \
-           file://src \
-           file://001-rdkb-remove-ubus-support.patch;apply=no \
+	   file://wpa_supplicant.uc \
+           file://src-${PV} \
+           file://002-rdkb-add-ucode-support.patch;apply=no \
            "
 require files/patches-${PV}/patches.inc
 
@@ -38,13 +39,13 @@
 }
 
 do_copy_openwrt_src() {
-    cp -Rfp ${WORKDIR}/src/* ${S}/
+    cp -Rfp ${WORKDIR}/src-${PV}/* ${S}/
 }
 
 do_filogic_patches() {
     cd ${S}
         if [ ! -e patch_applied ]; then
-            patch -p1 < ${WORKDIR}/001-rdkb-remove-ubus-support.patch
+            patch -p1 < ${WORKDIR}/002-rdkb-add-ucode-support.patch
             touch patch_applied
         fi
 }
@@ -83,8 +84,10 @@
 	echo "CONFIG_AP=y" >> wpa_supplicant/.config
 	echo "CONFIG_MESH=y" >> wpa_supplicant/.config
 	echo "CONFIG_IEEE80211BE=y" >> wpa_supplicant/.config
+	echo "CONFIG_IEEE80211AC=y" >> wpa_supplicant/.config
 	echo "CONFIG_HE_OVERRIDES=y" >> wpa_supplicant/.config
 	echo "CONFIG_EHT_OVERRIDES=y" >> wpa_supplicant/.config
+	echo "CONFIG_UCODE=y" >> wpa_supplicant/.config
 }
 
 do_compile () {
@@ -125,6 +128,9 @@
 
 	install -d ${D}${libdir}
 	install -m 0644 ${S}/wpa_supplicant/libwpa_client.so ${D}${libdir}
+
+	install -d ${D}${datadir}/hostap
+	install -m 0755 ${WORKDIR}/wpa_supplicant.uc ${D}${datadir}/hostap
 }
 
 pkg_postinst:${PN} () {
@@ -144,7 +150,7 @@
 
 FILES:${PN}-passphrase = "${sbindir}/wpa_passphrase"
 FILES:${PN}-cli = "${sbindir}/wpa_cli"
-FILES:${PN} += "${datadir}/dbus-1/system-services/* ${systemd_system_unitdir}/*"
+FILES:${PN} += "${datadir}/dbus-1/system-services/* ${systemd_system_unitdir}/* ${datadir}/hostap/*"
 FILES:${PN}-dbg += "${sbindir}/.debug ${libdir}/.debug"
 
 CONFFILES:${PN} += "${sysconfdir}/wpa_supplicant.conf"