/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * bbfdm_plugin.c - provides WiFi Legacy objects
 *
 * Copyright (C) 2023-2024 IOPSYS Software Solutions AB. All rights reserved.
 * Copyright (C) 2025-2026 Genexis AB.
 *
 *
 * See LICENSE file for license related information.
 *
 * Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
 *
 */

#include <libbbfdm-api/dmcommon.h>
#include <libbbfdm-ubus/bbfdm-ubus.h>

#include <easy/easy.h>
#include <wifi.h>
#include <wifidefs.h>

#include "../wifimngr.h"

/*
 * Exported pointer to the live wifimngr instance.
 * TR-181 handler callbacks use this to access radio/interface data
 * without an extra indirection layer.
 * Set by bbfdm_plugin_register(), cleared implicitly on process exit.
 */
static struct wifimngr *bbfdm_wifimngr = NULL;

/*
 * Module-private bbfdm context.
 * Initialised by bbfdm_plugin_init(), bound to ubus by
 * bbfdm_plugin_register(), and released by bbfdm_plugin_free().
 * Lifetime matches the process.
 */
static struct bbfdm_context g_bbfdm_ctx = {0};

/* Symbols defined in wifimngr.c and shared with this plugin. */
extern const char *PROG_NAME;
extern const char *standard_str[];

struct bbfdm_wifi_radio_info {
	struct wifimngr_device *wdev;
	struct wifi_radio radio;
};

struct bbfdm_wifi_radio {
	struct bbfdm_wifi_radio_info supp_radio_info[WIFI_DEV_MAX_NUM];
	struct wifimngr_device *wdev;
	struct wifi_radio radio;
	struct wifi_radio_stats radio_stats;
	char *radio_name;
};

struct bbfdm_wifi_ap {
	struct wifimngr_iface *iface;
	struct wifi_ap ap;
	struct wifi_ap_stats ap_stats;
	char *iface_name;
};

struct bbfdm_wifi_ap_sta {
	struct bbfdm_wifi_ap *wifi_ap;
	struct wifi_mlsta mlsta;
	struct wifi_sta sx;
};

struct wifi_radio_scan {
	int num_radio;
	struct {
		char name[32];
		bool scan_done;
	} radios[WIFI_DEV_MAX_NUM];
};

#define WIFI_DMMAP_PATH "/etc/bbfdm/dmmap/WiFi"

static const struct txpower_percent_map {
	int8_t sup_percent;
	int8_t neg_power;
} txpower_map[] = {
	{ -1,  -1 },
	{ 25,   6 },
	{ 50,   3 },
	{ 75,   1 },
	{ 100,  0 }
};

static char *MFP_Config[] = {"Disabled", "Optional", "Required", NULL};
static const char *supp_multiap_security_modes =
		"None,"
		/* "WEP-64,WEP-128," // No longer supported */
		/* "WPA-Enterprise,WPA2-Enterprise,WPA3-Enterprise,WPA-WPA2-Enterprise," // Enterprise modes are not supported by Multi-AP */
		/* "WPA-Personal,WPA-WPA2-Personal," // No longer supported */
		"WPA2-Personal,WPA3-Personal,WPA3-Personal-Transition";

static const char *supp_slo_security_modes =
		"None,"
		/* "WEP-64,WEP-128," // No longer supported */
		"WPA-Enterprise,WPA2-Enterprise,WPA3-Enterprise,WPA-WPA2-Enterprise,"
		/* "WPA-Personal,WPA-WPA2-Personal," // No longer supported */
		"WPA2-Personal,WPA3-Personal,WPA3-Personal-Transition";

static bool easymesh_enable = false;
static bool mld_capable = false;
DM_MAP_OBJ tDynamicObj[];

enum wifi_cap {
	WIFI_CAP_EMLMR,
	WIFI_CAP_EMLSR,
	WIFI_CAP_STR,
	WIFI_CAP_NSTR,
	WIFI_CAP_TID_LINK_MAPPING
};

/*************************************************************
* Global APIs
**************************************************************/
int bbfdm_plugin_init(int dm_type, int loglevel)
{
	memset(&g_bbfdm_ctx, 0, sizeof(g_bbfdm_ctx));

	bbfdm_ubus_set_service_name(&g_bbfdm_ctx, PROG_NAME);
	bbfdm_ubus_set_log_level(loglevel + 2);
	bbfdm_ubus_load_data_model(tDynamicObj);

	if (dm_type > 0) {
		int res = bbfdm_print_data_model_schema(&g_bbfdm_ctx, dm_type);
		exit(res);
	}

	return 0;
}

int bbfdm_plugin_register(struct wifimngr *w)
{
	int ret;

	if (!w || !w->ubus_ctx)
		return -1;

	/* Make the live wifimngr instance available to TR-181 handlers. */
	bbfdm_wifimngr = w;
	g_bbfdm_ctx.ubus_ctx = w->ubus_ctx;

	ret = bbfdm_ubus_register_init(&g_bbfdm_ctx);
	if (ret) {
		fprintf(stderr, "wifimngr: Failed to register data model.\n");
		return ret;
	}

	return 0;
}

int bbfdm_plugin_free(struct wifimngr *w)
{
	(void)w; /* reserved for future use */

	bbfdm_ubus_register_free(&g_bbfdm_ctx);
	bbfdm_wifimngr = NULL;

	return 0;
}

/*************************************************************
* SHARED APIs FROM WIFIMNGR
**************************************************************/
int init_wifi_legacy_module(void *data);
const char *radio_band_to_band_ghz(enum wifi_band band);
uint32_t bw_value(enum wifi_bw bw);
int is_opclass_chgrp_supported(uint32_t *ctrl_channels, int num, uint32_t *supp_channels);
#ifdef WIFIMNGR_VENDOR_EXTENSIONS
float wifimngr_sta_ratings_calc(const char *ap_ifname, struct wifi_sta *sta);
#endif

/*************************************************************
* COMMON INTERNAL APIs
**************************************************************/
static char *macaddr_to_string(const uint8_t macaddr[6])
{
	char macaddr_str[18] = {0};
	hwaddr_ntoa(macaddr, macaddr_str);
	return dmstrdup(macaddr_str);
}

static char *radio_standards_to_string(uint32_t std)
{
	char buf[32] = {0};
	uint32_t pos = 0;

	for (int i = 0; i < WIFI_NUM_STD; i++) {
		if (std & (1 << i)) {
			pos += snprintf(buf + pos, sizeof(buf) - pos, "%s%s", pos ? "," : "", standard_str[i]);
		}
	}

	return dmstrdup(buf);
}

static int get_sub_band(uint8_t ccfs)
{
	int sub_band = 0;

	switch (ccfs) {
		case 31:
		case 95:
		case 159:
			sub_band = 1;
			break;
		case 63:
		case 127:
		case 191:
			sub_band = 2;
			break;
		default:
			break;
	}

	return sub_band;
}

static char *radio_bandwidth_to_string(uint32_t bandwidth, uint8_t ccfs0, uint8_t ccfs1)
{
	char *bw = NULL;
	int sub_band;

	switch (bandwidth) {
		case 320:
			sub_band = get_sub_band(ccfs0);
			if (!sub_band)
				sub_band = get_sub_band(ccfs1);

			if (sub_band)
				dmasprintf(&bw, "320MHz-%d", sub_band);
			else
				dmasprintf(&bw, "20MHz");
			break;
		case 8080:
			dmasprintf(&bw, "80+80MHz");
			break;
		case 0:
			dmasprintf(&bw, "20MHz");
			break;
		default:
			dmasprintf(&bw, "%uMHz", bandwidth);
			break;
	}

	return bw;
}

static char *security_mode_supported_to_string(uint32_t sec)
{
	char buf[256] = {0};
	uint32_t pos = 0;

	if (!!(sec & BIT(WIFI_SECURITY_NONE)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sNone", pos ? "," : "");

	if (!!(sec & BIT(WIFI_SECURITY_WEP64)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWEP-64", pos ? "," : ""); // No longer supported

	if (!!(sec & BIT(WIFI_SECURITY_WEP128)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWEP-128", pos ? "," : ""); // No longer supported

	if (!!(sec & BIT(WIFI_SECURITY_WPAPSK)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA-Personal", pos ? "," : ""); // No longer supported

	if (!!(sec & BIT(WIFI_SECURITY_WPA2PSK)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA2-Personal", pos ? "," : "");

	if (!!(sec & BIT(WIFI_SECURITY_WPA3PSK)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA3-Personal", pos ? "," : "");

	if (!!(sec & BIT(WIFI_SECURITY_WPAPSK)) && (sec & BIT(WIFI_SECURITY_WPA2PSK)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA-WPA2-Personal", pos ? "," : ""); // No longer supported

	if (!!(sec & BIT(WIFI_SECURITY_WPA2PSK)) && (sec & BIT(WIFI_SECURITY_WPA3PSK)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA3-Personal-Transition", pos ? "," : "");

	if (!!(sec & BIT(WIFI_SECURITY_WPA)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA-Enterprise", pos ? "," : "");

	if (!!(sec & BIT(WIFI_SECURITY_WPA2)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA2-Enterprise", pos ? "," : "");

	if (!!(sec & BIT(WIFI_SECURITY_WPA3)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA3-Enterprise", pos ? "," : "");

	if (!!(sec & BIT(WIFI_SECURITY_WPA)) && (sec & BIT(WIFI_SECURITY_WPA2)))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sWPA-WPA2-Enterprise", pos ? "," : "");

	return dmstrdup(buf);
}

static const char *security_mode_enabled_to_string(uint32_t sec)
{
	if (!!(sec & BIT(WIFI_SECURITY_WPA2PSK)) && !!(sec & BIT(WIFI_SECURITY_WPA3PSK_C)))
		return "WPA2-PSK-WPA3-SAE-RSNO";

	if ((!!(sec & BIT(WIFI_SECURITY_WPA2PSK)) && !!(sec & BIT(WIFI_SECURITY_WPA3PSK))) ||
		 !!(sec & BIT(WIFI_SECURITY_WPA3PSK_T)))
		return "WPA2-PSK-WPA3-SAE";

	if (!!(sec & BIT(WIFI_SECURITY_WPAPSK)) && !!(sec & BIT(WIFI_SECURITY_WPA2PSK)))
		return "WPA-WPA2";

	if (!!(sec & BIT(WIFI_SECURITY_WPA)) && !!(sec & BIT(WIFI_SECURITY_WPA2)))
		return "WPA-WPA2-Enterprise";

	if (!!(sec & BIT(WIFI_SECURITY_WPA3PSK_C)))
		return "WPA2-PSK-WPA3-SAE-RSNO";

	if (!!(sec & BIT(WIFI_SECURITY_FT_WPA3PSK)) || !!(sec & BIT(WIFI_SECURITY_WPA3PSK)))
		return "WPA3-SAE";

	if (!!(sec & BIT(WIFI_SECURITY_FT_WPA2PSK)) || !!(sec & BIT(WIFI_SECURITY_WPA2PSK)))
		return "WPA2";

	if (!!(sec & BIT(WIFI_SECURITY_WPAPSK)))
		return "WPA";

	if (!!(sec & BIT(WIFI_SECURITY_WPA3)))
		return "WPA3-Enterprise";

	if (!!(sec & BIT(WIFI_SECURITY_WPA2)))
		return "WPA2-Enterprise";

	if (!!(sec & BIT(WIFI_SECURITY_WPA)))
		return "WPA-Enterprise";

	if (!!(sec & BIT(WIFI_SECURITY_WEP128)))
		return "WEP";

	if (!!(sec & BIT(WIFI_SECURITY_WEP64)))
		return "WEP";

	return "None";
}

static char *ap_encryption_mode_to_string(uint32_t ciphers)
{
	char buf[16] = {0};
	uint32_t pos = 0;

	/* TKIP */
	if (ciphers & (1 << 2)) { // index of "TKIP"
		pos += snprintf(buf + pos, sizeof(buf) - pos, "TKIP");
	}

	/* AES-based ciphers */
	if (ciphers & (
		(1 << 4)  |  // CCMP
		(1 << 8)  |  // GCMP
		(1 << 9)  |  // GCMP256
		(1 << 10)    // CCMP256
	)) {
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%sAES", pos ? "," : "");
	}

	return dmstrdup(buf);
}

static uint8_t antenna_mask_to_count(uint32_t mask)
{
	uint8_t count = 0;
	int i;

	for (i = 0; i < 8; i++) {
		if (!!(mask & (1 << i)))
			count++;
	}

	return count;
}

static const char *get_wlan_default_value(const char *json_key, const char *fallback)
{
	json_object *json_obj = json_object_from_file(BOARD_JSON_FILE);
	const char *value = NULL;

	if (!json_obj)
		return fallback;

	char *tmp = dmjson_get_value(json_obj, 5,
			"wlan", "defaults", "ssids", "all", json_key);

	value = DM_STRLEN(tmp) ? dmstrdup(tmp) : fallback;

	json_object_put(json_obj);
	return value;
}

static const char *radio_band_to_string(enum wifi_band band)
{
	switch (band) {
	case BAND_2:
		return "2";
	case BAND_5:
		return "5";
	case BAND_6:
		return "6";
	case BAND_ANY:
		return "any";
	default:
		break;
	}

	return "unknown";
}

static const char *bbfdm_wifimngr_lookup_device_from_band(const char *band)
{
	for (int i = 0; i < WIFI_DEV_MAX_NUM; i++) {
		if (!strlen(bbfdm_wifimngr->wdev[i].device))
			continue;

		if (!strcmp(radio_band_to_string(bbfdm_wifimngr->wdev[i].band), band))
			return bbfdm_wifimngr->wdev[i].device;
	}

	return NULL;
}

static const char *bbfdm_wifimngr_lookup_band_from_device(const char *device)
{
	for (int i = 0; i < WIFI_DEV_MAX_NUM; i++) {
		if (!strlen(bbfdm_wifimngr->wdev[i].device))
			continue;

		if (!strcmp(bbfdm_wifimngr->wdev[i].device, device))
			return radio_band_to_string(bbfdm_wifimngr->wdev[i].band);
	}

	return NULL;
}

static void bbfdm_store_supp_radio_info(struct bbfdm_wifi_radio_info *supp_radio_info, int size)
{
	int idx = 0;

	if (!supp_radio_info || !bbfdm_wifimngr || size <= 0)
		return;

	memset(supp_radio_info, 0, size * sizeof(struct bbfdm_wifi_radio_info));

	for (int i = 0; i < WIFI_DEV_MAX_NUM; i++) {
		struct wifimngr_device *wdev = &bbfdm_wifimngr->wdev[i];

		if (idx >= size)
			break;

		if (!strlen(wdev->device))
			continue;

		supp_radio_info[idx].wdev = wdev;
		wifi_radio_info_band(wdev->phy, wdev->band, &supp_radio_info[idx].radio);
		idx++;
	}
}

static struct wifi_radio *bbfdm_lookup_radio_info(struct bbfdm_wifi_radio_info *supp_radio_info, struct wifimngr_device *wdev)
{
	if (!supp_radio_info || !wdev)
		return NULL;

	for (int i = 0; i < WIFI_DEV_MAX_NUM; i++) {

		if (!supp_radio_info[i].wdev)
			break;

		if (supp_radio_info[i].wdev == wdev)
			return &supp_radio_info[i].radio;
	}

	return NULL;
}

static const struct txpower_percent_map *get_curr_txpower_percent(const char *value)
{
	char *endptr = NULL;

	long req_txpower = strtol(value, &endptr, 10);
	if (errno || *endptr != '\0')
		return NULL;

	for (int i = 0; i < ARRAY_SIZE(txpower_map); i++) {
		if (req_txpower == txpower_map[i].sup_percent)
			return &txpower_map[i];
	}

	return NULL;
}

void remove_unused_mld_sections(void)
{
	char *cur_mld = NULL;
	struct uci_section *ssid_s = NULL, *s = NULL, *stmp = NULL;

	if (mld_capable == false)
		return;

	uci_foreach_sections_safe("mapcontroller", "mld", s, stmp) {
		dmuci_get_value_by_section_string(s, "id", &cur_mld);

		ssid_s = get_dup_section_in_dmmap_opt("WiFi", "SSID", "mld_id", cur_mld);
		if (ssid_s != NULL)
			continue;

		// No SSID has assigned this mld unit so delete
		dmuci_delete_by_section(s, NULL, NULL);
	}
}

static void fill_wifi_mesh_capability(void)
{
	char map_enable[10] = {0};
	bool easymesh = false;
	bool mld = false;

	BBFDM_UCI_GET("mapcontroller", "controller", "enabled", "0",
			map_enable, sizeof(map_enable));

	easymesh = dmuci_string_to_boolean(map_enable);

	if (easymesh) {
		for (int i = 0; i < WIFI_DEV_MAX_NUM; i++) {
			if (!strlen(bbfdm_wifimngr->wdev[i].device))
				continue;

			if (bbfdm_wifimngr->wdev[i].mlo_capable) {
				mld = true;
				break;
			}
		}
	}

	easymesh_enable = easymesh;
	mld_capable = mld;
}

static void remove_mld_unit(char *old_mld)
{
	if (DM_STRLEN(old_mld) == 0)
		return;

	struct uci_section *ss = get_dup_section_in_dmmap_opt("WiFi", "SSID", "mld_id", old_mld);
	if (ss != NULL)
		return;

	// No SSID has assigned this mld unit so delete
	struct uci_section *map_mld = get_dup_section_in_config_opt("mapcontroller", "mld", "id", old_mld);
	if (map_mld)
		dmuci_delete_by_section(map_mld, NULL, NULL);
}

static bool check_backhaul_mld(char *mld_unit)
{
	struct uci_section *map_sec = NULL;
	char *type = NULL;

	if (mld_unit == NULL)
		return false;

	map_sec = get_dup_section_in_config_opt("mapcontroller", "mld", "id", mld_unit);
	if (map_sec) {
		dmuci_get_value_by_section_string(map_sec, "type", &type);
		if (DM_STRCMP(type, "backhaul") == 0)
			return true;
	}

	return false;
}

static void create_mld_unit_mapcontroller(char *mld_id, char *ssid, char *key)
{
	struct uci_section *stmp = NULL;

	if (mld_id == NULL || ssid == NULL || key == NULL)
		return;

	// Need to create new mld section in mapcontroller
	dmuci_add_section("mapcontroller", "mld", &stmp);
	dmuci_set_value_by_section(stmp, "id", mld_id);
	dmuci_set_value_by_section(stmp, "ssid", ssid);
	dmuci_set_value_by_section(stmp, "key", key);
	dmuci_set_value_by_section(stmp, "type", "fronthaul");
}

static void configure_mld_section(const char *mld, const char *option, char *value)
{
	if (DM_STRLEN(mld) == 0 || option == NULL || value == NULL)
		return;

	struct uci_section *map_sec = get_dup_section_in_config_opt("mapcontroller", "mld", "id", mld);
	if (map_sec)
		dmuci_set_value_by_section(map_sec, option, value);
}

static bool check_slo_ap(struct uci_section *sec)
{
	char *m_ap = NULL;
	char *type = NULL;

	dmuci_get_value_by_section_string(sec, "type", &type);
	dmuci_get_value_by_section_string(sec, "multi_ap", &m_ap);

	if (DM_STRLEN(type) == 0 &&
	    (DM_STRLEN(m_ap) == 0 || DM_STRCMP(m_ap, "0") == 0))
		return true;

	return false;
}

static char *get_wireless_uci_ap_section_fallback_def(void *data, const char *option, const char *def_val)
{
	struct uci_section *s = NULL, *config_s = NULL, *dmmap_s = NULL;
	char *wireless_sec_name = NULL;
	const char *device = NULL;
	char *ssid = NULL;
	char *band = NULL;
	char *value = NULL;

	config_s = ((struct dm_data *)data)->config_section;
	dmmap_s = ((struct dm_data *)data)->dmmap_section;

	if (config_s == NULL)
		return dmstrdup(def_val);

	if (check_slo_ap(config_s)) {
		value = dmuci_get_value_by_section_fallback_def(config_s, option, def_val);
		return value;
	}

	dmuci_get_value_by_section_string(dmmap_s, "wireless_sec_name", &wireless_sec_name);
	s = get_config_section_from_dmmap_section_name(wireless_sec_name);
	if (s) {
		value = dmuci_get_value_by_section_fallback_def(s, option, def_val);
		dmuci_set_value_by_section(dmmap_s, option, "");
		return value;
	}

	dmuci_get_value_by_section_string(config_s, "ssid", &ssid);
	dmuci_get_value_by_section_string(config_s, "band", &band);
	device = bbfdm_wifimngr_lookup_device_from_band(band);

	if (DM_STRLEN(ssid) == 0 || DM_STRLEN(device) == 0) {
		value = dmuci_get_value_by_section_fallback_def(dmmap_s, option, def_val);
		return value;
	}

	uci_foreach_sections("wireless", "wifi-iface", s) {
		char *curr_ssid = NULL;
		char *curr_dev = NULL;

		dmuci_get_value_by_section_string(s, "ssid", &curr_ssid);
		dmuci_get_value_by_section_string(s, "device", &curr_dev);

		if (DM_STRCMP(curr_ssid, ssid) == 0 && DM_STRCMP(curr_dev, device) == 0) {
			value = dmuci_get_value_by_section_fallback_def(s, option, def_val);
			dmuci_set_value_by_section(dmmap_s, option, "");
			return value;
		}
	}

	value = dmuci_get_value_by_section_fallback_def(dmmap_s, option, def_val);
	return value;
}

static int set_wireless_uci_ap_section(void *data, const char *option, const char *value)
{
	struct uci_section *s = NULL, *config_s = NULL, *dmmap_s = NULL;
	char *wireless_sec_name = NULL;
	const char *device = NULL;
	char *ssid = NULL;
	char *band = NULL;

	config_s = ((struct dm_data *)data)->config_section;
	dmmap_s = ((struct dm_data *)data)->dmmap_section;

	if (config_s == NULL)
		return -1;

	if (check_slo_ap(config_s)) {
		dmuci_set_value_by_section(config_s, option, value);
		return 0;
	}

	dmuci_get_value_by_section_string(dmmap_s, "wireless_sec_name", &wireless_sec_name);
	s = get_config_section_from_dmmap_section_name(wireless_sec_name);
	if (s) {
		dmuci_set_value_by_section(s, option, value);
		return 0;
	}

	dmuci_get_value_by_section_string(config_s, "ssid", &ssid);
	dmuci_get_value_by_section_string(config_s, "band", &band);
	device = bbfdm_wifimngr_lookup_device_from_band(band);

	if (DM_STRLEN(ssid) == 0 || DM_STRLEN(device) == 0)
		return -1;

	uci_foreach_sections("wireless", "wifi-iface", s) {
		char *curr_ssid = NULL;
		char *curr_dev = NULL;

		dmuci_get_value_by_section_string(s, "ssid", &curr_ssid);
		dmuci_get_value_by_section_string(s, "device", &curr_dev);

		if (DM_STRCMP(curr_ssid, ssid) == 0 && DM_STRCMP(curr_dev, device) == 0) {
			dmuci_set_value_by_section(s, option, value);
			return 0;
		}
	}

	return -1;
}

static void set_wireless_uci_ap_section_fallback(void *data, const char *option, const char *value)
{
	if (set_wireless_uci_ap_section(data, option, value) == 0)
		return;

	dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, option, value);
	return;
}

static char *get_security_mode(struct uci_section *section)
{
	char *encryption = NULL;
	char *ptrch = NULL;

	dmuci_get_value_by_section_string(section, "encryption", &encryption);
	if (!encryption || *encryption == '\0')
		return "None";

	/* Here the encryption type and the cipher are separated */
	ptrch  = DM_STRCHR(encryption, '+');
	if (ptrch)
		*ptrch = '\0';

	if (DM_LSTRSTR(encryption, "wep")) { // No longer supported
		char *key_index = NULL, *key = NULL;

		dmuci_get_value_by_section_string(section, "key", &key_index);
		if (key_index && (*key_index) > '0' && (*key_index) < '5' && *(key_index+1) == '\0') {
			char buf[16];

			snprintf(buf, sizeof(buf), "key%s", key_index);
			dmuci_get_value_by_section_string(section, buf, &key);
		}
		return (key && DM_STRLEN(key) == 10) ? "WEP-64" : "WEP-128";
	}
	else if (DM_LSTRNCMP(encryption, "psk-mixed", 9) == 0)
		return "WPA-WPA2-Personal";
	else if (DM_LSTRNCMP(encryption, "psk2", 4) == 0)
		return "WPA2-Personal";
	else if (DM_LSTRNCMP(encryption, "psk", 3) == 0)
		return "WPA-Personal";
	else if (DM_LSTRCMP(encryption, "sae") == 0)
		return "WPA3-Personal";
	else if (DM_LSTRCMP(encryption, "sae-mixed") == 0)
		return "WPA3-Personal-Transition";
	else if (DM_LSTRNCMP(encryption, "wpa-mixed", 9) == 0)
		return "WPA-WPA2-Enterprise";
	else if (DM_LSTRNCMP(encryption, "wpa2", 4) == 0)
		return "WPA2-Enterprise";
	else if (DM_LSTRNCMP(encryption, "wpa3", 4) == 0)
		return "WPA3-Enterprise";
	else if (DM_LSTRNCMP(encryption, "wpa", 3) == 0)
		return "WPA-Enterprise";
	else
		return "None";
}

static bool is_different_security_mode_group(const char *mode1, const char *mode2)
{
	int i, g1 = 0, g2 = 0;
	char *security_modes[] = {
		"None",
		"WEP-64, WEP-128",
		"WPA-Personal, WPA2-Personal, WPA3-Personal, WPA-WPA2-Personal, WPA3-Personal-Transition",
		"WPA-Enterprise, WPA2-Enterprise, WPA3-Enterprise, WPA-WPA2-Enterprise"
	};

	for (i = 0; i < ARRAY_SIZE(security_modes); i++) {
		if (DM_STRSTR(security_modes[i], mode1)) {
			g1 = i;
		}

		if (DM_STRSTR(security_modes[i], mode2)) {
			g2 = i;
		}
	}

	return (g1 != g2);
}

static void set_security_mode(void *data, const char *required_mode)
{
	struct uci_section *config_s = ((struct dm_data *)data)->config_section;
	char *curr_mode = NULL;

	curr_mode = get_security_mode(config_s);

	// Only reset the security options if its belongs to different group
	if (is_different_security_mode_group(required_mode, curr_mode)) {
		// Available in both wireless and mapcontroller configs
		dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", "");

		// Available only in wireless config
		set_wireless_uci_ap_section_fallback(data, "wpa_group_rekey", "");
		set_wireless_uci_ap_section_fallback(data, "key1", "");
		set_wireless_uci_ap_section_fallback(data, "key2", "");
		set_wireless_uci_ap_section_fallback(data, "key3", "");
		set_wireless_uci_ap_section_fallback(data, "key4", "");
		set_wireless_uci_ap_section_fallback(data, "auth_server", "");
		set_wireless_uci_ap_section_fallback(data, "auth_port", "");
		set_wireless_uci_ap_section_fallback(data, "auth_secret", "");
	}

	if (DM_LSTRCMP(required_mode, "None") == 0) { // None
		dmuci_set_value_by_section(config_s, "encryption", "none");
	}

	if (DM_LSTRSTR(required_mode, "Enterprise")) { // WPA-Enterprise, WPA2-Enterprise, WPA3-Enterprise, WPA-WPA2-Enterprise
		if (DM_LSTRNCMP(required_mode, "WPA3", 4) == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "wpa3");
			set_wireless_uci_ap_section_fallback(data, "ieee80211w", "2");
		} else if (DM_LSTRNCMP(required_mode, "WPA2", 4) == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "wpa2");
			set_wireless_uci_ap_section_fallback(data, "ieee80211w", "1");
		} else if (DM_LSTRNCMP(required_mode, "WPA-WPA2", 8) == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "wpa-mixed");
		} else {
			dmuci_set_value_by_section(config_s, "encryption", "wpa");
		}
	}

	if (DM_LSTRSTR(required_mode, "Personal")) { // WPA-Personal, WPA2-Personal, WPA-WPA2-Personal, WPA3-Personal, WPA3-Personal-Transition
		char *key = NULL;

		dmuci_get_value_by_section_string(config_s, "key", &key);
		if (DM_STRLEN(key) == 0) {
			struct uci_section *dmmap_s = ((struct dm_data *)data)->dmmap_section;

			dmuci_get_value_by_section_string(dmmap_s, "key", &key);

			dmuci_set_value_by_section(config_s, "key",
					DM_STRLEN(key) ? key : get_wlan_default_value("key", "1234567890"));
		}

		if (DM_LSTRCMP(required_mode, "WPA-Personal") == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "psk");
		} else if (DM_LSTRCMP(required_mode, "WPA2-Personal") == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "psk2");
			set_wireless_uci_ap_section_fallback(data, "ieee80211w", "1");
		} else if (DM_LSTRCMP(required_mode, "WPA-WPA2-Personal") == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "psk-mixed");
		} else if (DM_LSTRCMP(required_mode, "WPA3-Personal") == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "sae");
			set_wireless_uci_ap_section_fallback(data, "ieee80211w", "2");
		} else if (DM_LSTRCMP(required_mode, "WPA3-Personal-Transition") == 0) {
			dmuci_set_value_by_section(config_s, "encryption", "sae-mixed");
			set_wireless_uci_ap_section_fallback(data, "ieee80211w", "1");
		}
	}

	if (DM_LSTRNCMP(required_mode, "WEP", 3) == 0) { // WEP-64, WEP-128
		// No longer supported
	}
}

static int get_bandwidth_from_config(struct uci_section *config_sec)
{
	char *htmode = NULL;
	int bw = 20; // default

	dmuci_get_value_by_section_string(config_sec, "htmode", &htmode);
	if (DM_STRLEN(htmode)) {
		int parsed_bw = 0;

		if (sscanf(htmode, "%*[^0-9]%d", &parsed_bw) == 1 && parsed_bw > 0)
			bw = parsed_bw;
	}

	return bw;
}

static void configure_map_sections(const char *mld_id, const char *option, const char *value, bool sync_dmmap)
{
	struct uci_section *s = NULL, *s_map = NULL;
	char *ap_sec_name = NULL;

	if (DM_STRLEN(mld_id) == 0)
		return;

	uci_path_foreach_option_eq(bbfdm, "WiFi", "SSID", "mld_id", mld_id, s){
		if (sync_dmmap == true)
			dmuci_set_value_by_section(s, option, value);

		dmuci_get_value_by_section_string(s, "__section_name__", &ap_sec_name);
		s_map = get_config_section_from_dmmap_section_name(ap_sec_name);
		if (s_map != NULL) {
			dmuci_set_value_by_section(s_map, option, value);
		}
	}
}

static bool multi_ap_type_backhaul(struct uci_section *config_section)
{
	char *multi_ap = NULL;
	char *type = NULL;

	 /* multi_ap              type
	  * 1                     Backhaul
	  * 2                     Fronthaul
	  * 3                     Combined
	  * Others                None
	  */
	dmuci_get_value_by_section_string(config_section, "multi_ap", &multi_ap);
	dmuci_get_value_by_section_string(config_section, "type", &type);
	if (DM_STRCMP(multi_ap, "1") == 0 || DM_STRCMP(type, "backhaul") == 0)
		return true;

	return false;
}

static bool duplicate_ssid_exists(const char *ssid, const char *device)
{
	if (DM_STRLEN(ssid) == 0 || DM_STRLEN(device) == 0)
		return false;

	struct uci_section *s = NULL;
	uci_path_foreach_option_eq(bbfdm, "WiFi", "SSID", "ssid", ssid, s) {
		char *dev = NULL;

		dmuci_get_value_by_section_string(s, "device", &dev);
		if (DM_STRCMP(device, dev) == 0) {
			return true;
		}
	}

	return false;
}

static bool backhaul_ssid_exist(const char *ssid)
{
	struct uci_section *s = NULL;

	if (DM_STRLEN(ssid) == 0)
		return false;

	if (easymesh_enable == true)
		s = get_dup_section_in_config_opt("mapcontroller", "ap", "ssid", ssid);
	else
		s = get_dup_section_in_config_opt("wireless", "wifi-iface", "ssid", ssid);

	if (s != NULL && multi_ap_type_backhaul(s))
		return true;

	return false;
}

static bool easymesh_ssid_exist(const char *ssid)
{
	if (DM_STRLEN(ssid) == 0)
		return false;

	if (easymesh_enable == true) {
		struct uci_section *s = get_dup_section_in_config_opt("mapcontroller", "ap", "ssid", ssid);
		if (s != NULL)
			return true;
	} else {
		struct uci_section *s = get_dup_section_in_config_opt("wireless", "wifi-iface", "ssid", ssid);
		if (s != NULL && !check_slo_ap(s))
			return true;
	}

	return false;
}

static bool slo_ssid_exist(const char *ssid)
{
	if (DM_STRLEN(ssid) == 0)
		return false;

	struct uci_section *s = NULL;
	uci_foreach_option_eq("wireless", "wifi-iface", "ssid", ssid, s) {
		char *multi_ap = NULL;

		dmuci_get_value_by_section_string(s, "multi_ap", &multi_ap);
		if (DM_STRLEN(multi_ap) == 0 || DM_STRCMP(multi_ap, "0") == 0) {
			return true;
		}
	}

	return false;
}

static void dmmap_synchronize_WiFi_Radio(struct dmctx *dmctx)
{
	struct uci_section *config_s = NULL;
	char *instance = NULL;

	uci_foreach_sections("wireless", "wifi-device", config_s) {
		create_dmmap_obj(dmctx, 0, "WiFi", "Radio", config_s, &instance);
	}
}

static void dmmap_synchronize_WiFi_SSID(struct dmctx *dmctx)
{
	struct uci_section *config_s = NULL, *ssid_s = NULL;
	char *instance = NULL;

	uci_foreach_sections("wireless", "wifi-iface", config_s) {
		char *disabled = NULL, *ssid = NULL, *device = NULL;

		dmuci_get_value_by_section_string(config_s, "disabled", &disabled);
		dmuci_get_value_by_section_string(config_s, "ssid", &ssid);
		dmuci_get_value_by_section_string(config_s, "device", &device);

		if ((easymesh_enable == true && check_slo_ap(config_s) == false) ||
				DM_STRLEN(ssid) == 0 ||
				multi_ap_type_backhaul(config_s))
			continue;

		ssid_s = create_dmmap_obj(dmctx, 0, "WiFi", "SSID", config_s, &instance);
		if (ssid_s && DM_STRLEN(instance)) {
			dmuci_set_value_by_section(ssid_s, "enabled", DM_STRLEN(disabled) ? ((*disabled == '1') ? "0" : "1") : "1");
			dmuci_set_value_by_section(ssid_s, "ssid", ssid);
			dmuci_set_value_by_section(ssid_s, "device", device);
			dmuci_set_value_by_section(ssid_s, "Name", section_name(config_s));
		}
	}

	// If easymesh is disabled => No need to sync with mapcontroller
	if (easymesh_enable == false)
		return;

	uci_foreach_sections("mapcontroller", "ap", config_s) {
		char *enabled = NULL, *ssid = NULL, *band = NULL, *mld_id = NULL;
		const char *device = NULL;

		dmuci_get_value_by_section_string(config_s, "enabled", &enabled);
		dmuci_get_value_by_section_string(config_s, "ssid", &ssid);
		dmuci_get_value_by_section_string(config_s, "band", &band);
		dmuci_get_value_by_section_string(config_s, "mld_id", &mld_id);

		if (DM_STRLEN(ssid) == 0 || multi_ap_type_backhaul(config_s))
			continue;

		device = bbfdm_wifimngr_lookup_device_from_band(band);

		ssid_s = create_dmmap_obj(dmctx, 0, "WiFi", "SSID", config_s, &instance);
		if (ssid_s && DM_STRLEN(instance)) {
			dmuci_set_value_by_section(ssid_s, "enabled", DM_STRLEN(enabled) ? ((*enabled == '1') ? "1" : "0") : "1");
			dmuci_set_value_by_section(ssid_s, "ssid", ssid);
			dmuci_set_value_by_section(ssid_s, "device", device ? device : "");
			dmuci_set_value_by_section(ssid_s, "Name", section_name(config_s));
			dmuci_set_value_by_section(ssid_s, "mld_id", mld_id);
		}
	}
}

static void dmmap_synchronize_WiFi_AccessPoint(struct dmctx *dmctx)
{
	struct uci_section *config_s = NULL;
	char *instance = NULL;

	if (easymesh_enable == true) {
		uci_foreach_sections("mapcontroller", "ap", config_s) {

			if (multi_ap_type_backhaul(config_s))
				continue;

			create_dmmap_obj(dmctx, 0, "WiFi", "AccessPoint", config_s, &instance);
		}
	}

	uci_foreach_sections("wireless", "wifi-iface", config_s) {

		if ((easymesh_enable == true && check_slo_ap(config_s) == false) ||
				multi_ap_type_backhaul(config_s))
			continue;

		char *mode = NULL;
		dmuci_get_value_by_section_string(config_s, "mode", &mode);
		if (DM_LSTRCMP(mode, "ap") != 0)
			continue;

		create_dmmap_obj(dmctx, 0, "WiFi", "AccessPoint", config_s, &instance);
	}
}

static void dmmap_synchronize_WiFi_EndPoint(struct dmctx *dmctx)
{
	struct uci_section *config_s = NULL;
	char *instance = NULL;

	uci_foreach_sections("wireless", "wifi-iface", config_s) {

		char *mode = NULL;
		dmuci_get_value_by_section_string(config_s, "mode", &mode);
		if (DM_LSTRCMP(mode, "sta") != 0)
			continue;

		create_dmmap_obj(dmctx, 0, "WiFi", "EndPoint", config_s, &instance);
	}
}

static void dmmap_synchronize_WiFi_Legacy(struct dmctx *dmctx)
{
	// Device.WiFi.Radio.{i}.
	dmmap_synchronize_WiFi_Radio(dmctx);

	// Device.WiFi.SSID.{i}.
	dmmap_synchronize_WiFi_SSID(dmctx);

	// Device.WiFi.AccessPoint.{i}.
	dmmap_synchronize_WiFi_AccessPoint(dmctx);

	// Device.WiFi.EndPoint.{i}.
	dmmap_synchronize_WiFi_EndPoint(dmctx);
}

static bool radio_caps_supported(enum wifi_cap type, struct wifi_caps *caps)
{
	if (!caps || !(caps->valid & WIFI_CAP_ML_VALID))
		return false;

	switch (type) {
		case WIFI_CAP_EMLMR:
			if (caps->ml.valid & WIFI_CAP_ML_EML_VALID) {
				uint8_t *eml = caps->ml.eml;
				return !!(eml[0] & BIT(7));
			}
			break;

		case WIFI_CAP_EMLSR:
			if (caps->ml.valid & WIFI_CAP_ML_EML_VALID) {
				uint8_t *eml = caps->ml.eml;
				return !!(eml[0] & BIT(0));
			}
			break;

		case WIFI_CAP_STR:
			if (caps->ml.valid & WIFI_CAP_ML_MLD_VALID) {
				uint8_t *mld = caps->ml.mld;
				uint8_t max_simlinks = (mld[0] & 0x0f);
				bool nstr_mobile_ap = !!(mld[0] & 0x80);

				return (max_simlinks > 0 && !nstr_mobile_ap);
			}
			break;

		case WIFI_CAP_NSTR:
			if (caps->ml.valid & WIFI_CAP_ML_MLD_VALID) {
				uint8_t *mld = caps->ml.mld;
				uint8_t max_simlinks = (mld[0] & 0x0f);
				bool nstr_mobile_ap = !!(mld[0] & 0x80);

				return (max_simlinks > 0 && nstr_mobile_ap);
			}
			break;

		case WIFI_CAP_TID_LINK_MAPPING:
			if (caps->ml.valid & WIFI_CAP_ML_MLD_VALID) {
				uint8_t *mld = caps->ml.mld;
				return (((mld[0] >> 1) & 0x3) > 0);
			}
			break;

		default:
			break;
	}

	return false;
}

static int remove_new_lines(const char *src, int src_len, char *out, int out_len)
{
	int i, new_len;

	if (out_len < src_len)
		return 0;

	for (i = 0, new_len = 0; i < src_len; ++i) {
		if (src[i] != '\n') {
			*out = src[i];
			++out;
			++new_len;
		}
	}

	return new_len;
}

static char *to_base64_str(const uint8_t *src, size_t src_len, char *out, size_t out_len)
{
	size_t tmp_len = out_len;
	char *tmp_str;
	int new_out_len;

	if (!out || !src)
		return NULL;

	tmp_str = malloc(tmp_len);
	if (!tmp_str)
		return NULL;

	if (base64_encode(src, src_len, (unsigned char *)tmp_str, &tmp_len)) {
		free(tmp_str);
		return NULL;
	}

	new_out_len = remove_new_lines(tmp_str, tmp_len, out, out_len);
	free(tmp_str);

	if (new_out_len < 1)
		return NULL;

	if (new_out_len < out_len)
		out[new_out_len] = '\0';
	else
		out[new_out_len - 1] = '\0';

	return out;
}

/*************************************************************
* ADD DEL OBJ
**************************************************************/
static int addObjWiFiSSID(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct dm_data *curr_data = (struct dm_data *)ctx->addobj_instance;
	char ssid_name[32] = {0};

	snprintf(ssid_name, sizeof(ssid_name), "ssid_%s", *instance);

	// dmmap is already created by the core, Set default dmmap option if needed
	dmuci_set_value_by_section(curr_data->dmmap_section, "enabled", "0");
	dmuci_set_value_by_section(curr_data->dmmap_section, "ssid", ssid_name);
	dmuci_set_value_by_section(curr_data->dmmap_section, "Name", ssid_name);

	return 0;
}

static int delObjWiFiSSID(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	if (((struct dm_data *)data)->config_section) {
		/* If mapcontroller not enabled then do not allow to delete easymesh nodes */
		if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
			bbfdm_set_fault_message(ctx, "Easy-mesh node deletion not allowed on this device.");
			return FAULT_9001;
		}

		dmuci_delete_by_section(((struct dm_data *)data)->config_section, "device", NULL);
		dmuci_delete_by_section(((struct dm_data *)data)->config_section, "band", NULL);
		dmuci_delete_by_section(((struct dm_data *)data)->config_section, "mld_id", NULL);
		dmuci_delete_by_section(((struct dm_data *)data)->config_section, "ssid", NULL);
	}

	/* If SSID has mld_id and if it is last instance having this mld_id then remove the mld section */
	char *mld_id = NULL;
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "mld_id", &mld_id);
	dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, "mld_id", NULL);
	remove_mld_unit(mld_id);

	dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);

	return 0;
}

static int addObjWiFiAccessPoint(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct dm_data *curr_data = (struct dm_data *)ctx->addobj_instance;
	char sec_name[32] = {0};

	snprintf(sec_name, sizeof(sec_name), "ap_%s", *instance);

	if (easymesh_enable == false) {
		/* Add AP as SLO node */
		dmuci_add_section("wireless", "wifi-iface", &curr_data->config_section);
		dmuci_rename_section_by_section(curr_data->config_section, sec_name);

		dmuci_set_value_by_section(curr_data->config_section, "disabled", "1");
		dmuci_set_value_by_section(curr_data->config_section, "network", "lan");
		dmuci_set_value_by_section(curr_data->config_section, "mode", "ap");
		dmuci_set_value_by_section(curr_data->config_section, "wps_pushbutton", "1");
	} else {
		/* Add AP as easymesh network node */
		dmuci_add_section("mapcontroller", "ap", &curr_data->config_section);
		dmuci_rename_section_by_section(curr_data->config_section, sec_name);

		dmuci_set_value_by_section(curr_data->config_section, "enabled", "0");
		dmuci_set_value_by_section(curr_data->config_section, "type", "fronthaul");
	}

	// dmmap is already created by the core, Set default dmmap option if needed
	dmuci_set_value_by_section(curr_data->dmmap_section, "__is_new__", "1");

	return 0;
}

static int delObjWiFiAccessPoint(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	char *config_sec_name = NULL;

	/* If mapcontroller not enabled then do not allow to delete Easy-mesh AP */
	if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
		bbfdm_set_fault_message(ctx, "Easy-mesh AP node can not be deleted on this device");
		return FAULT_9001;
	}

	// If any SSID is refenced to this AP, remove the reference
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "__section_name__", &config_sec_name);
	if (DM_STRLEN(config_sec_name) != 0) {
		struct uci_section *ssid_s = get_dup_section_in_dmmap_opt("WiFi", "SSID", "__section_name__", config_sec_name);
		if (ssid_s) dmuci_delete_by_section(ssid_s, "__section_name__", NULL);
	}

	dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
	dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);

	return 0;
}

static int addObjWiFiEndPoint(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct dm_data *curr_data = (struct dm_data *)ctx->addobj_instance;
	char sec_name[32] = {0};

	snprintf(sec_name, sizeof(sec_name), "sta_%s", *instance);

	dmuci_add_section("wireless", "wifi-iface", &curr_data->config_section);
	dmuci_rename_section_by_section(curr_data->config_section, sec_name);

	dmuci_set_value_by_section(curr_data->config_section, "disabled", "1");
	dmuci_set_value_by_section(curr_data->config_section, "network", "lan");
	dmuci_set_value_by_section(curr_data->config_section, "mode", "sta");

	return 0;
}

static int delObjWiFiEndPoint(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
	dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);
	return 0;
}

/*************************************************************
* ENTRY METHOD
**************************************************************/
static int browseWiFiRadioInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct bbfdm_wifi_radio_info supp_radio_info[WIFI_DEV_MAX_NUM];
	struct dm_data curr_data = {0};
	char *inst = NULL;

	/* Pre-fetch all radio info once before the browse loop */
	bbfdm_store_supp_radio_info(supp_radio_info, ARRAY_SIZE(supp_radio_info));

	uci_path_foreach_sections(bbfdm, "WiFi", "Radio", curr_data.dmmap_section) {
		struct bbfdm_wifi_radio *w_radio = NULL;
		struct wifi_radio *supp_radio = NULL;
		char *config_sec_name = NULL;
		bool multiband = false;

		dmuci_get_value_by_section_string(curr_data.dmmap_section, "__section_name__", &config_sec_name);

		curr_data.config_section = get_config_section_from_dmmap_section_name(config_sec_name);
		if (curr_data.config_section == NULL)
			continue;

		w_radio = (struct bbfdm_wifi_radio *)dmcalloc(1, sizeof(struct bbfdm_wifi_radio));
		if (!w_radio)
			continue;

		w_radio->radio_name = section_name(curr_data.config_section);
		if (!bbfdm_wifimngr || !strlen(w_radio->radio_name))
			continue;

		w_radio->wdev = wifimngr_lookup_wifi_device(bbfdm_wifimngr, w_radio->radio_name);
		if (!w_radio->wdev)
			continue;

		supp_radio = bbfdm_lookup_radio_info(supp_radio_info, w_radio->wdev);
		if (supp_radio)
			w_radio->radio = *supp_radio;
		else
			wifi_radio_info_band(w_radio->wdev->phy, w_radio->wdev->band, &w_radio->radio);

		/* Copy pre-fetched supp_radio_info into per-instance w_radio so it's available at next level */
		memcpy(w_radio->supp_radio_info, supp_radio_info, sizeof(w_radio->supp_radio_info));

		wifi_radio_is_multiband(w_radio->wdev->phy, &multiband);
		if (multiband) {
			if (wifi_radio_get_band_stats(w_radio->wdev->phy, w_radio->wdev->band, &w_radio->radio_stats))
				continue;
		} else {
			if (wifi_radio_get_stats(w_radio->wdev->phy, &w_radio->radio_stats))
				continue;
		}

		curr_data.additional_data = (void *)w_radio;

		inst = uci_handle_instance(dmctx, parent_node, &curr_data);
		if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
			break;
	}
	return 0;
}

static struct uci_section *find_wireless_section(const char *ssid, const char *device)
{
	struct uci_section *s = NULL;

	if (DM_STRLEN(ssid) == 0 || DM_STRLEN(device) == 0)
		return NULL;

	uci_foreach_option_eq("wireless", "wifi-iface", "ssid", ssid, s) {
		char *curr_device = NULL;

		dmuci_get_value_by_section_string(s, "device", &curr_device);
		if (DM_STRCMP(curr_device, device) == 0)
			return s;
	}

	return NULL;
}

static char *get_ap_iface_name(struct dm_data *data)
{
	struct uci_section *ap_s = data->config_section;
	char *ifname = NULL;

	if (check_slo_ap(ap_s) == true || easymesh_enable == false) {
		dmuci_get_value_by_section_string(ap_s, "ifname", &ifname);
		return ifname;
	} else {
		struct uci_section *wireless_s = NULL;
		char *ssid = NULL, *band = NULL;
		const char *device = NULL;

		dmuci_get_value_by_section_string(ap_s, "ssid", &ssid);
		dmuci_get_value_by_section_string(ap_s, "band", &band);
		device = bbfdm_wifimngr_lookup_device_from_band(band);

		// Map SSID and device to find wireless interface section
		wireless_s = find_wireless_section(ssid, device);
		if (wireless_s) {
			struct uci_section *dmmap_s = data->dmmap_section;
			char buf[64] = {0};

			snprintf(buf, sizeof(buf), "wireless.%s", section_name(wireless_s));
			dmuci_set_value_by_section(dmmap_s, "wireless_sec_name", buf);

			dmuci_get_value_by_section_string(wireless_s, "ifname", &ifname);
			return ifname;
		}
	}

	return NULL;
}

static int browseWiFiAccessPointSSIDInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data curr_data = {0};
	char *inst = NULL;

	uci_path_foreach_sections(bbfdm, parent_node->current_object_file, parent_node->obj->obj, curr_data.dmmap_section) {
		char *config_sec_name = NULL;

		dmuci_get_value_by_section_string(curr_data.dmmap_section, "__section_name__", &config_sec_name);
		curr_data.config_section = get_config_section_from_dmmap_section_name(config_sec_name);

		if (curr_data.config_section) {
			struct bbfdm_wifi_ap *w_ap = NULL;

			w_ap = (struct bbfdm_wifi_ap *)dmcalloc(1, sizeof(struct bbfdm_wifi_ap));
			if (w_ap) {
				w_ap->iface_name = get_ap_iface_name(&curr_data);

				if (bbfdm_wifimngr && DM_STRLEN(w_ap->iface_name)) {
					w_ap->iface = wifimngr_lookup_wifi_iface(bbfdm_wifimngr, w_ap->iface_name);
					if (w_ap->iface) {
						char *ifname = NULL;

						if (strlen(w_ap->iface->mld_netdev) && if_nametoindex(w_ap->iface->mld_netdev) != 0)
							ifname = w_ap->iface->mld_netdev;
						else
							ifname = w_ap->iface_name;

						wifi_ap_info_band(ifname, w_ap->iface->band, &w_ap->ap);
					}

					wifi_ap_get_stats(w_ap->iface_name, &w_ap->ap_stats);
				}
			}

			curr_data.additional_data = (void *)w_ap;
		} else {
			curr_data.additional_data = NULL;
		}

		inst = uci_handle_instance(dmctx, parent_node, &curr_data);
		if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
			break;
	}

	return 0;
}

static int browseWiFiSSIDInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiAccessPointSSIDInst(dmctx, parent_node, prev_data, prev_instance);
}

static int browseWiFiAccessPointInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiAccessPointSSIDInst(dmctx, parent_node, prev_data, prev_instance);
}

static int browseWiFiEndPointInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data curr_data = {0};
	char *inst = NULL;

	uci_path_foreach_sections(bbfdm, "WiFi", "EndPoint", curr_data.dmmap_section) {
		char *config_sec_name = NULL;
		struct wifi_sta sta = {0};
		char *ifname = NULL;

		dmuci_get_value_by_section_string(curr_data.dmmap_section, "__section_name__", &config_sec_name);
		curr_data.config_section = get_config_section_from_dmmap_section_name(config_sec_name);
		if (curr_data.config_section == NULL)
			continue;

		dmuci_get_value_by_section_string(curr_data.config_section, "ifname", &ifname);

		if (DM_STRLEN(ifname) && !wifi_sta_info(ifname, &sta))
			curr_data.additional_data = (void *)&sta;
		else
			curr_data.additional_data = NULL;

		inst = uci_handle_instance(dmctx, parent_node, &curr_data);
		if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
			break;
	}
	return 0;
}

static int browseWiFiEndPointProfileInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	DM_LINK_INST_OBJ(dmctx, parent_node, prev_data, "1");
	return 0;
}

static int browseWifiNeighboringWiFiDiagnosticResultInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data curr_data = {0};
	char *inst = NULL;
	int id = 0;

	uci_path_foreach_sections(bbfdm, "WiFiDiagnostic", "Result", curr_data.config_section) {
		inst = handle_instance_without_section(dmctx, parent_node, ++id);
		if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
			break;
	}

	return 0;
}

static int browse_wifi_associated_device(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)prev_data)->additional_data;
	struct dm_data curr_data = {0};
	unsigned char stas[768] = {0};
	char *inst = NULL;
	int nr = 128, id = 0;

	if (!w_ap ||
			DM_STRLEN(w_ap->iface_name) == 0 ||
			hwaddr_is_zero(w_ap->ap.bss.bssid))
		return 0;

	if (strlen(w_ap->iface->mld_netdev) && if_nametoindex(w_ap->iface->mld_netdev) != 0) {

		if (wifi_get_assoclist(w_ap->iface->mld_netdev, stas, &nr) != 0)
			return 0;

		for (int i = 0; i < nr; i++) {
			struct bbfdm_wifi_ap_sta w_ap_sta = {0};
			unsigned char *sta = &stas[i*6];

			memset(&w_ap_sta.mlsta, 0, sizeof(w_ap_sta.mlsta));

			// Only standard (non-MLO) STAs appear under AccessPoint{i}.AssociatedDevice.{i}.
			// MLO STAs use a separate data model and are listed under DataElements.Network.Device.{i}.APMLD.{i}.STAMLD.{i}.
			if (wifi_get_mlsta_info(w_ap->iface->mld_netdev, sta, &w_ap_sta.mlsta) ||
					w_ap_sta.mlsta.mlo_capable)
				continue;

			if (!hwaddr_is_zero(w_ap_sta.mlsta.sta[0].bssid)
					&& memcmp(w_ap_sta.mlsta.sta[0].bssid, w_ap->ap.bss.bssid, 6))
				continue;

			w_ap_sta.wifi_ap = w_ap;

			curr_data.additional_data = (void *)&w_ap_sta;

			inst = handle_instance_without_section(dmctx, parent_node, ++id);
			if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
				return 0;

		}
	} else {

		if (wifi_get_assoclist_band(w_ap->iface_name, w_ap->iface->band, stas, &nr) != 0)
			return 0;

		for (int i = 0; i < nr; i++) {
			struct bbfdm_wifi_ap_sta w_ap_sta = {0};
			unsigned char *sta = &stas[i*6];

			memset(&w_ap_sta.sx, 0, sizeof(w_ap_sta.sx));

			if (wifi_get_sta_info_band(w_ap->iface_name, w_ap->iface->band, sta, &w_ap_sta.sx))
				continue;

			if (!hwaddr_is_zero(w_ap_sta.sx.bssid)
					&& memcmp(w_ap_sta.sx.bssid, w_ap->ap.bss.bssid, 6))
				continue;

			w_ap_sta.wifi_ap = w_ap;

			curr_data.additional_data = (void *)&w_ap_sta;

			inst = handle_instance_without_section(dmctx, parent_node, ++id);
			if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
				return 0;
		}
	}

	return 0;
}

static int browseWiFiRadioCapabilitiesWiFi7Inst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, enum wifi_cap type, enum wifi_mode m)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)prev_data)->additional_data;
	struct dm_data curr_data = {0};
	char *inst = NULL;
	int id = 0;

	for (int i = 0; i < WIFI_DEV_MAX_NUM; i++) {
		struct wifimngr_device *wdev = &bbfdm_wifimngr->wdev[i];
		struct wifi_radio *info = NULL;
		uint8_t hwaddr[6] = {0};
		char ruid[32] = {0};

		if (!strlen(wdev->device))
			continue;

		// Self Radio => Skip it
		if (!strcmp(wdev->device, w_radio->radio_name))
			continue;

		info = bbfdm_lookup_radio_info(w_radio->supp_radio_info, wdev);
		if (!info)
			continue;

		if (!radio_caps_supported(type, (m == WIFI_MODE_AP) ? &info->ap_caps : &info->sta_caps))
			continue;

		if (wifi_radio_get_hwaddr(wdev->phy, hwaddr) != 0)
			if_gethwaddr(wdev->phy, hwaddr);

		if (hwaddr_is_zero(hwaddr) && !hwaddr_is_zero(wdev->macaddr))
			memcpy(hwaddr, wdev->macaddr, 6);

		to_base64_str(hwaddr, 6, ruid, sizeof(ruid));

		curr_data.additional_data = (void *)dmstrdup(ruid);

		inst = handle_instance_without_section(dmctx, parent_node, ++id);
		if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&curr_data, inst) == DM_STOP)
			return 0;
	}

	return 0;
}

static int browseWiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_EMLMR, WIFI_MODE_AP);
}

static int browseWiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_EMLSR, WIFI_MODE_AP);
}

static int browseWiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_STR, WIFI_MODE_AP);
}

static int browseWiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_NSTR, WIFI_MODE_AP);
}

static int browseWiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_EMLMR, WIFI_MODE_STA);
}

static int browseWiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_EMLSR, WIFI_MODE_STA);
}

static int browseWiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_STR, WIFI_MODE_STA);
}

static int browseWiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparationInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return browseWiFiRadioCapabilitiesWiFi7Inst(dmctx, parent_node, prev_data, WIFI_CAP_NSTR, WIFI_MODE_STA);
}

/**************************************************************************
* SET & GET VALUE
***************************************************************************/
static int get_WiFi_RadioNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, NULL);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFi_SSIDNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, NULL);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFi_AccessPointNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, NULL);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFi_EndPointNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, NULL);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiEndPoint_ProfileNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("1");
	return 0;
}

static int get_WiFi_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "Alias", instance, value);
}

static int set_WiFi_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "Alias", instance, value);
}

static int get_WiFiRadio_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", value);
	*value = ((*value)[0] == '1') ? "0" : "1";
	return 0;
}

static int set_WiFiRadio_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			return 0;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1");
			return 0;
	}
	return 0;
}

static int get_WiFiRadio_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	*value = dmstrdup(!w_radio->wdev->disabled ? "Up" : "Down");
	return 0;
}

static int get_WiFiRadio_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("");
	return 0;
}

static int set_WiFiRadio_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string_list(ctx, value, -1, -1, 1024, -1, -1, NULL, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			break;
	}
	return 0;
}

static int get_WiFiRadio_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	*value = dmstrdup(w_radio->radio_name);
	return 0;
}

static int get_WiFiRadio_MaxBitRate(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio.maxrate);
	return 0;
}

static int get_WiFiRadio_SupportedFrequencyBands(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	uint32_t supp_band = w_radio->radio.supp_band;
	char buf[32] = {0};
	uint32_t pos = 0;

	if (supp_band & BAND_2)
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s2.4GHz", pos ? "," : "");
	if (supp_band & BAND_5)
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s5GHz", pos ? "," : "");
	if (supp_band & BAND_6)
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s6GHz", pos ? "," : "");
	if (supp_band & BAND_60)
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s60GHz", pos ? "," : "");

	*value = dmstrdup(buf);
	return 0;
}

static int get_WiFiRadio_OperatingFrequencyBand(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	*value = dmstrdup(radio_band_to_band_ghz(w_radio->wdev->band));
	return 0;
}

static int set_WiFiRadio_OperatingFrequencyBand(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *Supported_Frequency_Bands[] = {"2.4GHz", "5GHz", "6GHz", NULL};
	char *supported_frequency_bands = NULL;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, Supported_Frequency_Bands, NULL))
				return FAULT_9007;

			// Get the list of all supported frequency bands
			get_WiFiRadio_SupportedFrequencyBands(refparam, ctx, data, instance, &supported_frequency_bands);

			// Check if the input value is a supported band value
			if (!value_exits_in_str_list(supported_frequency_bands, ",", value)) {
				bbfdm_set_fault_message(ctx, "'%s' band is not supported by this radio. Possible bands are [%s].", value, supported_frequency_bands);
				return FAULT_9007;
			}

			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "band", (value[0] == '6') ? "6g" : (value[0] == '5') ? "5g" : "2g");
			break;
	}
	return 0;
}

static int get_WiFiRadio_SupportedStandards(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	*value = radio_standards_to_string(w_radio->radio.supp_std);
	return 0;
}

static int get_WiFiRadio_OperatingStandards(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	*value = radio_standards_to_string(w_radio->radio.oper_std);
	return 0;
}

static int set_WiFiRadio_OperatingStandards(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *Supported_Standards[] = {"a", "b", "g", "n", "ac", "ax", "be", NULL};
	char *supported_standards = NULL;
	char buf[16], htmode[8];
	char *pch, *spch;
	int bandwidth;

	switch (action) {
			case VALUECHECK:
				if (bbfdm_validate_string_list(ctx, value, -1, -1, -1, -1, -1, Supported_Standards, NULL))
					return FAULT_9007;

				// Get the list of all supported standards
				get_WiFiRadio_SupportedStandards(refparam, ctx, data, instance, &supported_standards);

				// Check if the input value is a valid standard value
				snprintf(buf, sizeof(buf), "%s", value);
				for (pch = strtok_r(buf, ",", &spch); pch != NULL; pch = strtok_r(NULL, ",", &spch)) {
					if (!value_exits_in_str_list(supported_standards, ",", pch)) {
						bbfdm_set_fault_message(ctx, "'%s' standard is not supported by this radio. Possible standards are [%s].", pch, supported_standards);
						return FAULT_9007;
					}
				}

				break;
			case VALUESET:
				bandwidth = get_bandwidth_from_config(((struct dm_data *)data)->config_section);

				if (DM_LSTRSTR(value, "be"))
					snprintf(htmode, sizeof(htmode), "EHT%d", bandwidth);
				else if (DM_LSTRSTR(value, "ax"))
					snprintf(htmode, sizeof(htmode), "HE%d", bandwidth);
				else if (DM_LSTRSTR(value, "ac"))
					snprintf(htmode, sizeof(htmode), "VHT%d", bandwidth);
				else if (DM_LSTRSTR(value, "n"))
					snprintf(htmode, sizeof(htmode), "HT%d", bandwidth);
				else
					snprintf(htmode, sizeof(htmode), "NOHT");

				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "htmode", htmode);
				break;
		}
		return 0;
}

static int get_WiFiRadio_AutoChannelEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "channel", value);
	if (DM_LSTRCMP(*value, "auto") == 0 || (*value)[0] == '\0')
		*value = dmstrdup("1");
	else
		*value = dmstrdup("0");
	return 0;
}

static int set_WiFiRadio_AutoChannelEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *channel = NULL;
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			return 0;
		case VALUESET:
			string_to_bool(value, &b);
			if (b) {
				channel = "auto";
			} else {
				struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
				dmasprintf(&channel, "%u", w_radio->radio.channel);
			}

			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "channel", channel);
			return 0;
	}
	return 0;
}

static int get_WiFiRadio_PossibleChannels(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	struct wifi_opclass supp_opclass[64] = {0};
	size_t num_opclass = ARRAY_SIZE(supp_opclass);
	uint32_t supp_channels[64] = {0}, pos = 0;
	int num_supp_channels = sizeof(supp_channels);
	uint8_t channels[256] = {0};
	char buf[256] = {0};
	enum wifi_bw bw;

	/* in case of no nedev use BW20 */
	bw = w_radio->radio.curr_bw;
	if (bw == BW_UNKNOWN)
		bw = BW20;

	wifi_get_opclass_e4table(w_radio->wdev->band, (1 << bw), &num_opclass, supp_opclass);
	wifi_get_supp_channels(w_radio->wdev->phy, supp_channels, &num_supp_channels, "", w_radio->wdev->band, bw);

	for (int i = 0; i < num_opclass; i++) {
		for (int j = 0; j < supp_opclass[i].opchannel.num; j++) {
			if (is_opclass_chgrp_supported(supp_opclass[i].opchannel.ch[j].ctrl_channels,
							num_supp_channels, supp_channels)) {
				for (int k = 0; k < 32 && supp_opclass[i].opchannel.ch[j].ctrl_channels[k] != 0; k++) {
					channels[supp_opclass[i].opchannel.ch[j].ctrl_channels[k]] = 1;
				}
			}
		}
	}

	for (int i = 0; i < sizeof(channels); i++) {
		if (channels[i] == 1) {
			pos += snprintf(buf + pos, sizeof(buf) - pos, "%s%d", pos ? "," : "", i);
		}
	}

	*value = dmstrdup(buf);
	return 0;
}

static int get_WiFiRadio_ChannelsInUse(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio.channel);
	return 0;
}

static int get_WiFiRadio_Channel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *channel = NULL;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "channel", &channel);

	if (DM_LSTRCMP(channel, "auto") == 0 || DM_STRLEN(channel) == 0) {
		struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
		dmasprintf(&channel, "%u", w_radio->radio.channel);
	}

	*value = channel;
	return 0;
}

static int set_WiFiRadio_Channel(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *supported_channels = NULL;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"1","255"}}, 1))
				return FAULT_9007;

			// Get the list of all supported channels
			get_WiFiRadio_PossibleChannels(refparam, ctx, data, instance, &supported_channels);

			// Check if the input value is a valid channel
			if (!value_exits_in_str_list(supported_channels, ",", value))
				return FAULT_9007;

			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "channel", value);
			return 0;
	}
	return 0;
}

static int get_WiFiRadio_AutoChannelSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("true");
	return 0;
}

static int get_WiFiRadio_AutoChannelRefreshPeriod(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "acs_refresh_period", "0");
	return 0;
}

static int set_WiFiRadio_AutoChannelRefreshPeriod(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "acs_refresh_period", value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_MaxSupportedSSIDs(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio.max_iface_ap);
	return 0;
}

static int get_WiFiRadio_MaxSupportedAssociations(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	char *max_assoc = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "maxassoc", "32");

	uint8_t max_iface_sta = w_radio->radio.max_iface_sta;
	uint8_t assoc_val = (uint8_t)DM_STRTOUL(max_assoc);

	if (max_iface_sta > 0 && assoc_val > max_iface_sta)
		dmasprintf(value, "%u", max_iface_sta);
	else
		*value = max_assoc;

	return 0;
}

static int get_WiFiRadio_FragmentationThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "frag_threshold", "2346");
	return 0;
}

static int set_WiFiRadio_FragmentationThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "frag_threshold", value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_RTSThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "rts_threshold", "2347");
	return 0;
}

static int set_WiFiRadio_RTSThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "rts_threshold", value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_BeaconPeriod(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "beacon_int", "100");
	return 0;
}

static int set_WiFiRadio_BeaconPeriod(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "beacon_int", value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_DTIMPeriod(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "dtim_period", "2");
	return 0;
}

static int set_WiFiRadio_DTIMPeriod(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct uci_section *s = NULL;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;
			break;
		case VALUESET:
			//Here need to loop the iface and match the section name then add the dtim_period on each section
			//as this param is read by mac80211.sh script and is overwriten as 2 if not written in all section
			//of radio
			uci_foreach_option_eq("wireless", "wifi-iface", "device", section_name(((struct dm_data *)data)->config_section), s) {
				char *mode;

				dmuci_get_value_by_section_string(s, "mode", &mode);

				if (DM_LSTRCMP(mode, "ap") != 0)
					continue;

				dmuci_set_value_by_section(s, "dtim_period", value);
			}

			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "dtim_period", value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_OperatingChannelBandwidth(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int bw = get_bandwidth_from_config(((struct dm_data *)data)->config_section);
	dmasprintf(value, "%dMHz", bw);
	return 0;
}

static int get_WiFiRadio_SupportedOperatingChannelBandwidths(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	uint32_t supp_bw = w_radio->radio.supp_bw;
	char buf[64] = {0};
	uint32_t pos = 0;

	if (supp_bw & BIT(BW20))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s20MHz", pos ? "," : "");
	if (supp_bw & BIT(BW40))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s40MHz", pos ? "," : "");
	if (supp_bw & BIT(BW80))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s80MHz", pos ? "," : "");
	if (supp_bw & BIT(BW160))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s160MHz", pos ? "," : "");
	if (supp_bw & BIT(BW8080))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s80+80MHz", pos ? "," : "");
	if (supp_bw & BIT(BW320))
		pos += snprintf(buf + pos, sizeof(buf) - pos, "%s320MHz-1,320MHz-2", pos ? "," : "");

	*value = dmstrdup(buf);
	return 0;
}

static int set_WiFiRadio_OperatingChannelBandwidth(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *Supported_Operating_Channel_Bandwidth[] = {"20MHz", "40MHz", "80MHz", "160MHz", "320MHz", "80+80MHz", "Auto", NULL};
	char *supported_bandwidths = NULL;
	char *curr_htmode = NULL;
	char htmode[32];
	int freq;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, Supported_Operating_Channel_Bandwidth, NULL))
				return FAULT_9007;

			// Get the list of all supported operating channel bandwidths
			get_WiFiRadio_SupportedOperatingChannelBandwidths(refparam, ctx, data, instance, &supported_bandwidths);

			// Check if the input value is a valid channel bandwidth value
			if (!value_exits_in_str_list(supported_bandwidths, ",", value)) {
				bbfdm_set_fault_message(ctx, "'%s' bandwidth is not supported by this radio. Possible bandwidths are [%s].", value, supported_bandwidths);
				return FAULT_9007;
			}

			break;
		case VALUESET:
			sscanf(value, "%d", &freq);

			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "htmode", &curr_htmode);

			if (DM_LSTRNCMP(curr_htmode, "EHT", 3) == 0)
				snprintf(htmode, sizeof(htmode), "EHT%d", freq);
			else if (DM_LSTRNCMP(curr_htmode, "VHT", 3) == 0)
				snprintf(htmode, sizeof(htmode), "VHT%d", freq);
			else if (DM_LSTRNCMP(curr_htmode, "HT", 2) == 0)
				snprintf(htmode, sizeof(htmode), "HT%d", freq);
			else
				snprintf(htmode, sizeof(htmode), "HE%d", freq);

			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "htmode", htmode);
			break;
	}
	return 0;
}

static int get_WiFiRadio_CurrentOperatingChannelBandwidth(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	uint32_t bw = bw_value(w_radio->radio.curr_bw);
	uint8_t ccfs0 = w_radio->radio.ccfs0;
	uint8_t ccfs1 = w_radio->radio.ccfs1;

	*value = radio_bandwidth_to_string(bw, ccfs0, ccfs1);
	return 0;
}

static int get_WiFiRadio_PreambleType(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "short_preamble", value);
	*value = ((*value)[0] == '1') ? "short" : "long";
	return 0;
}

static int set_WiFiRadio_PreambleType(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *Preamble_Type[] = {"short", "long", "auto", NULL};

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, Preamble_Type, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "short_preamble", (DM_LSTRCMP(value, "short") == 0) ? "1" : "0");
			break;
	}
	return 0;
}

static int get_WiFiRadio_IEEE80211hSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", w_radio->radio.dot11h_capable);
	return 0;
}

static int get_WiFiRadio_IEEE80211hEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "doth", "0");
	return 0;
}

static int set_WiFiRadio_IEEE80211hEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			break;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "doth", b ? "1" : "0");
			break;
	}
	return 0;
}

static int get_WiFiRadio_TransmitPowerSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char power_list[64] = {0};
	uint32_t pos = 0;

	for (int i = 0; i < ARRAY_SIZE(txpower_map); i++)
		pos += snprintf(power_list + pos, sizeof(power_list) - pos, "%s%d", pos ? "," : "", txpower_map[i].sup_percent);

	*value = dmstrdup(power_list);
	return 0;
}

static int get_WiFiRadio_TransmitPower(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *txpower_config = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "txpower", "-1");
	if (DM_STRCMP(txpower_config, "-1") == 0) {
		*value = txpower_config;
	} else {
		struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
		dmasprintf(value, "%d", w_radio->radio.txpower);
	}

	return 0;
}

static int set_WiFiRadio_TransmitPower(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	const struct txpower_percent_map *curr_power = get_curr_txpower_percent(value);

	switch (action)	{
		case VALUECHECK:
			if (!curr_power) {
				bbfdm_set_fault_message(ctx, "Transit Power percentage is not supported");
				return FAULT_9007;
			}
			break;
		case VALUESET:
			if (curr_power->sup_percent == -1) {
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "txpower", "");
				return 0;
			}

			{
				struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
				struct wifi_opclass supp_opclass[64] = {0};
				int num_opclass = ARRAY_SIZE(supp_opclass);

				wifi_get_band_supp_opclass(w_radio->wdev->phy, w_radio->wdev->band, &num_opclass, supp_opclass);

				if (w_radio->radio.curr_opclass == 0 || !num_opclass) {
					bbfdm_set_fault_message(ctx,
							"Failed to identify current operating class");
					return FAULT_9002;
				}

				for (int i = 0; i < num_opclass; i++) {
					char str_val[16] = {0};

					if (supp_opclass[i].g_opclass != w_radio->radio.curr_opclass)
						continue;

					if (supp_opclass[i].opchannel.txpower == 0) {
						bbfdm_set_fault_message(ctx,
								"Failed to identify maximum transmit power");
						break;
					}

					snprintf(str_val, sizeof(str_val), "%d",
							supp_opclass[i].opchannel.txpower -
							curr_power->neg_power);
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "txpower", str_val);
					return 0;
				}

				bbfdm_set_fault_message(ctx,
						"Current operating class not supported");
				return FAULT_9002;
			}
			break;
	}

	return 0;
}

static int get_WiFiRadio_RegulatoryDomain(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *conf_country, *dmmap_contry = NULL;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "country", &conf_country);
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "country", &dmmap_contry);

	dmasprintf(value, "%s%c", conf_country, (dmmap_contry && *dmmap_contry) ? dmmap_contry[2] : ' ');
	return 0;
}

static int set_WiFiRadio_RegulatoryDomain(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *Regulatory_Domain[] = {"^[A-Z][A-Z]$", "^[A-Z][A-Z][ OI]$", NULL};

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, 2, 3, NULL, Regulatory_Domain))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "country", value);

			// uci only support country code, so strip I/O from value before setting
			if (DM_STRLEN(value) == 3)
				value[2] = '\0';

			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "country", value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_CenterFrequencySegment0(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio.ccfs0);
	return 0;
}

static int get_WiFiRadio_CenterFrequencySegment1(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio.ccfs1);
	return 0;
}

static int get_WiFiRadio_ConfiguredReceiveAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "rxantenna", "-1");
	return 0;
}

static int set_WiFiRadio_ConfiguredReceiveAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1","-1"},{"0","255"}}, 2))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "rxantenna", !DM_STRCMP(value, "-1") ? "" : value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_ConfiguredTransmitAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "txantenna", "-1");
	return 0;
}

static int set_WiFiRadio_ConfiguredTransmitAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1","-1"},{"0","255"}}, 2))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "txantenna", !DM_STRCMP(value, "-1") ? "" : value);
			break;
	}
	return 0;
}

static int get_WiFiRadio_SupportedReceiveAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", antenna_mask_to_count(w_radio->radio.supp_rx_antenna));
	return 0;
}

static int get_WiFiRadio_SupportedTransmitAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", antenna_mask_to_count(w_radio->radio.supp_tx_antenna));
	return 0;
}

static int get_WiFiRadio_ActiveReceiveAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio.rx_antenna);
	return 0;
}

static int get_WiFiRadio_ActiveTransmitAntennas(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio.tx_antenna);
	return 0;
}

static int get_WiFiRadioStats_Noise(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", w_radio->radio_stats.noise);
	return 0;
}

static int get_WiFiRadioStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%lu", w_radio->radio_stats.tx_bytes);
	return 0;
}

static int get_WiFiRadioStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%lu", w_radio->radio_stats.rx_bytes);
	return 0;
}

static int get_WiFiRadioStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%lu", w_radio->radio_stats.tx_pkts);
	return 0;
}

static int get_WiFiRadioStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%lu", w_radio->radio_stats.rx_pkts);
	return 0;
}

static int get_WiFiRadioStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio_stats.tx_err_pkts);
	return 0;
}

static int get_WiFiRadioStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio_stats.rx_err_pkts);
	return 0;
}

static int get_WiFiRadioStats_DiscardPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio_stats.tx_dropped_pkts);
	return 0;
}

static int get_WiFiRadioStats_DiscardPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio_stats.rx_dropped_pkts);
	return 0;
}

static int get_WiFiRadioStats_FCSErrorCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", w_radio->radio_stats.rx_fcs_err_pkts);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_EMLMRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_EMLMR, &w_radio->radio.ap_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_EMLSRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_EMLSR, &w_radio->radio.ap_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_STRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_STR, &w_radio->radio.ap_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_NSTRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_NSTR, &w_radio->radio.ap_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_TIDLinkMapNegotiation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_TID_LINK_MAPPING, &w_radio->radio.ap_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_EMLMRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_EMLSRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_STRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRole_NSTRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_EMLMRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_EMLMR, &w_radio->radio.sta_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_EMLSRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_EMLSR, &w_radio->radio.sta_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_STRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_STR, &w_radio->radio.sta_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_NSTRSupport(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_NSTR, &w_radio->radio.sta_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_TIDLinkMapNegotiation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_radio *w_radio = (struct bbfdm_wifi_radio *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", radio_caps_supported(WIFI_CAP_TID_LINK_MAPPING, &w_radio->radio.sta_caps));
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_EMLMRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_EMLSRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_STRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARole_NSTRFreqSeparationNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparationInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparation_RUID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)((struct dm_data *)data)->additional_data;
	return 0;
}

static int get_WiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparation_FreqSeparation(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("0");
	return 0;
}

static int get_WiFiSSID_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "enabled", value);
	return 0;
}

static int set_WiFiSSID_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			if (((struct dm_data *)data)->config_section) {
				/* If mapcontroller not enabled then do not allow config change on easymesh nodes */
				if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
					bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node not allowed on this device");
					return FAULT_9001;
				}
			}

			return 0;
		case VALUESET:
			string_to_bool(value, &b);

			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "enabled", b ? "1" : "0");

			if (((struct dm_data *)data)->config_section == NULL)
				return 0;

			if (check_slo_ap(((struct dm_data *)data)->config_section)) {
				// wireless config: Update disabled option
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1");
			} else {
				// mapcontroller config: Update enabled option
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "enabled", b ? "1" : "0");
			}

			return 0;
	}
	return 0;
}

static int get_WiFiSSID_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	char *enable = NULL;

	get_WiFiSSID_Enable(refparam, ctx, data, instance, &enable);
	if (DM_LSTRCMP(enable, "0") == 0) {
		*value = dmstrdup("Down");
		return 0;
	}

	if (!w_ap || DM_STRLEN(w_ap->iface_name) == 0) {
		*value = dmstrdup("Error");
		return 0;
	}

	if (w_ap->iface == NULL) {
		 *value = dmstrdup("Unknown");
	} else {
		ifstatus_t ifs = 0;

		wifi_get_ifstatus(w_ap->iface_name, &ifs);

		if ((ifs & IFF_UP) || (ifs & IFF_RUNNING)) {
			*value = dmstrdup("Up");
		} else {
			*value = dmstrdup("Unknown");
		}
	}

	return 0;
}

static int get_WiFiSSID_SSID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ssid", value);
	return 0;
}

static int set_WiFiSSID_SSID(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *device = NULL, *mld = NULL, *id = NULL, *key = NULL;
	struct uci_section *mld_sec = NULL, *ssid_sec = NULL;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, 1, 32, NULL, NULL))
				return FAULT_9007;

			if (((struct dm_data *)data)->config_section) {
				/* If mapcontroller not enabled then do not allow config change on easymesh nodes */
				if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
					bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node not allowed on this device");
					return FAULT_9001;
				}
			}

			/* There should not be any backhaul AP assigned this SSID value */
			if (backhaul_ssid_exist(value)) {
				bbfdm_set_fault_message(ctx, "An instance with ssid (%s) is configured as backhaul AP.", value);
				return FAULT_9001;
			}

			/* Check if any instance with same SSID and Radio is already exist
			 * then reject the request to avoid multiple SSID instance with same SSID and Radio */
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "device", &device);
			if (duplicate_ssid_exists(value, device)) {
				char *ll = NULL;

				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "LowerLayers", &ll);
				bbfdm_set_fault_message(ctx, "An instance with ssid (%s) and LowerLayer (%s) already present.", value, ll);
				return FAULT_9001;
			}

			if (easymesh_enable && mld_capable) {
				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "mld_id", &mld);

				/* if current SSID has mld unit configured and if SSID instance with new SSID is present,
				 * then the new SSID should not have other MLD id, otherwise multiple MLD sections can
				 * have same SSID */
				ssid_sec = get_dup_section_in_dmmap_opt("WiFi", "SSID", "ssid", value);
				if (ssid_sec != NULL && DM_STRLEN(mld) != 0) {
					mld_sec = get_dup_section_in_config_opt("mapcontroller", "mld", "ssid", value);
					if (mld_sec != NULL) {
						dmuci_get_value_by_section_string(mld_sec, "id", &id);
					}

					if (DM_STRCMP(id, mld) != 0) {
						bbfdm_set_fault_message(ctx, "SSID (%s) already configured with MLD (%s)."
									"Can not be configured with MLD (%s)", value, id ? id : "-1", mld);
						return FAULT_9001;
					}
				}
			}

			if (((struct dm_data *)data)->config_section == NULL)
				return 0;

			/* If AP is assigned then check:
			 * 1. If SLO AP then there should not be any easymesh node with this SSID value
			 * 2. If easymesh AP then there should not be any SLO AP with this SSID value
			 */
			if (check_slo_ap(((struct dm_data *)data)->config_section)) {
				if (easymesh_ssid_exist(value)) {
					bbfdm_set_fault_message(ctx, "Can't assign because an easymesh node is present with SSID (%s)", value);
					return FAULT_9001;
				}
			} else {
				if (slo_ssid_exist(value)) {
					bbfdm_set_fault_message(ctx, "Can't assign because an standalone AP is present with SSID (%s)", value);
					return FAULT_9001;
				}
			}

			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "ssid", value);
			if (easymesh_enable && mld_capable) {
				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "mld_id", &mld);
				if (DM_STRLEN(mld) != 0) {
					// if mld unit is configured then update ssid in MLD section
					configure_mld_section(mld, "ssid", value);
					configure_map_sections(mld, "ssid", value, true);
				} else {
					// if new ssid has assigned mld then change MLDunit of this instance
					mld_sec = get_dup_section_in_config_opt("mapcontroller", "mld", "ssid", value);
					if (mld_sec != NULL) {
						dmuci_get_value_by_section_string(mld_sec, "id", &id);
						dmuci_get_value_by_section_string(mld_sec, "key", &key);
					}

					if (DM_STRLEN(id) != 0)
						dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "mld_id", id);
				}
			}

			if (((struct dm_data *)data)->config_section == NULL)
				return 0;

			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ssid", value);
			if (easymesh_enable && mld_capable) {
				if (DM_STRLEN(id) != 0)
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "mld_id", id);
				if (DM_STRLEN(key) != 0)
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", key);
			}

			return 0;
	}
	return 0;
}

static int get_WiFiSSID_MLDUnit(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *mld_id = NULL;

	if (mld_capable == false)
		goto none;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "mld_id", &mld_id);
	if (DM_STRLEN(mld_id) == 0)
		goto none;

	if (!get_dup_section_in_config_opt("mapcontroller", "mld", "id", mld_id)) {
		struct uci_section *ssid_sec = NULL;

		uci_path_foreach_option_eq(bbfdm, "WiFi", "SSID", "mld_id", mld_id, ssid_sec) {
			dmuci_set_value_by_section(ssid_sec, "mld_id", "");
		}
		goto none;
	}

	*value = dmstrdup(mld_id);
	return 0;

none:
	*value = dmstrdup("-1");
	return 0;
}

static int set_WiFiSSID_MLDUnit(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *old_mld = NULL, *ssid = NULL, *device = NULL, *key = NULL;
	struct uci_section *s = NULL;

	/* Remove unused MLD sections if any */
	remove_unused_mld_sections();

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1", "24"}}, 1))
				return FAULT_9007;

			if (DM_STRCMP(value, "-1") == 0)
				break;

			/* Reject if device has no support of MLD */
			if (mld_capable == false || easymesh_enable == false) {
				bbfdm_set_fault_message(ctx, "Device can not support MLD configuration");
				return FAULT_9001;
			}

			if (DM_STRCMP(value, "0") == 0) {
				bbfdm_set_fault_message(ctx, "MLDUnit 0 is not supported");
				return FAULT_9007;
			}

			/* Reject if MLD is requested for an SLO AP */
			if (((struct dm_data *)data)->config_section != NULL && check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "SSID is referred by standalone AP. MLDUnit is only allowed to easymesh nodes.");
				return FAULT_9001;
			}

			/* Reject if MLD is configured as backhaul */
			if (check_backhaul_mld(value)) {
				bbfdm_set_fault_message(ctx, "MLDUnit %s is of backhaul type and can't be configured", value);
				return FAULT_9001;
			}

			/* Check if any instance with mld unit's SSID and current radio is already exist then reject the request
			 * to avoid multiple SSID instance with same SSID and Radio */
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "device", &device);
			struct uci_section *map_mld = get_dup_section_in_config_opt("mapcontroller", "mld", "id", value);
			dmuci_get_value_by_section_string(map_mld, "ssid", &ssid);

			if (duplicate_ssid_exists(ssid, device)) {
				bbfdm_set_fault_message(ctx, "Another SSID instance with same radio and MLDUnit is present");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "mld_id", &old_mld);
			if (DM_STRCMP(value, "-1") == 0) {
				/* MLDUnit removal scenario */
				if (DM_STRLEN(old_mld) == 0)
					break;

				/* remove mld from all ssid which are allocated with same mld_id as the current ssid instance */
				uci_foreach_option_eq("mapcontroller", "ap", "mld_id", old_mld, s) {
					dmuci_set_value_by_section(s, "mld_id", "");
				}

				uci_path_foreach_option_eq(bbfdm, "WiFi", "SSID", "mld_id", old_mld, s) {
					dmuci_set_value_by_section(s, "mld_id", "");
				}

				/* Remove the MLD section from mapcontroller */
				remove_mld_unit(old_mld);
				break;
			}

			/* MLDUnit assignment scenarion, either MLD section with this ID can exist or need to be created newly */
			struct uci_section *mld_sec = get_dup_section_in_config_opt("mapcontroller", "mld", "id", value);
			if (mld_sec == NULL) {
				/* MLD section for requested id not exists */
				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ssid", &ssid);
				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", &key);

				if (DM_STRLEN(old_mld) == 0) {
					/* MLD changing from -1 to N, create new MLD section */
					create_mld_unit_mapcontroller(value, ssid, key);
				} else {
					/* MLD changing from M to N, update existing MLD section with mld id N */
					configure_mld_section(old_mld, "id", value);
				}

				/* reset the MLDUnit with new value to all instances having same ssid and old_mld */
				uci_foreach_option_eq("mapcontroller", "ap", "mld_id", old_mld, s) {
					char *cur_ssid = NULL;

					dmuci_get_value_by_section_string(s, "ssid", &cur_ssid);
					if (DM_STRCMP(ssid, cur_ssid) != 0) {
						continue;
					}

					dmuci_set_value_by_section(s, "mld_id", value);
				}

				uci_path_foreach_option_eq(bbfdm, "WiFi", "SSID", "mld_id", old_mld, s){
					char *cur_ssid = NULL;

					dmuci_get_value_by_section_string(s, "ssid", &cur_ssid);
					if (DM_STRCMP(ssid, cur_ssid) != 0) {
						continue;
					}

					dmuci_set_value_by_section(s, "mld_id", value);
				}
			} else {
				// MLD section exist, change the SSID with MLD section's SSID and set mld_id, key */
				dmuci_get_value_by_section_string(mld_sec, "ssid", &ssid);
				dmuci_get_value_by_section_string(mld_sec, "key", &key);
				dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "ssid", ssid);
				dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "mld_id", value);

				if (((struct dm_data *)data)->config_section != NULL) {
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ssid", ssid);
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", key);
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "mld_id", value);
				}
			}

			break;
	}
	return 0;
}

static int get_WiFiSSID_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "Name", value);
	return 0;
}

static int get_WiFiSSID_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "LowerLayers", value);

	if ((*value)[0] == '\0') {
		char *device = NULL;

		dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "device", &device);

		_bbfdm_get_references(ctx, "Device.WiFi.Radio.", "Name", device, value);

		// Store LowerLayers value
		dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", *value);
	}

	return 0;
}

static int set_WiFiSSID_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *allowed_objects[] = {"Device.WiFi.Radio.", NULL};
	struct dm_reference reference = {0};
	char *ssid = NULL;

	bbfdm_get_reference_linker(ctx, value, &reference);

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string_list(ctx, reference.path, -1, -1, 1024, -1, -1, NULL, NULL))
				return FAULT_9007;

			if (dm_validate_allowed_objects(ctx, &reference, allowed_objects))
				return FAULT_9007;

			if (((struct dm_data *)data)->config_section) {
				/* If mapcontroller not enabled then do not allow config change on easymesh nodes */
				if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
					bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node not allowed on this device");
					return FAULT_9001;
				}
			}

			/* Check if any instance with same SSID and Radio is already exist
			 * then reject the request to avoid multiple SSID instance with
			 * same SSID and Radio */
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ssid", &ssid);
			if (duplicate_ssid_exists(ssid, reference.value)) {
				bbfdm_set_fault_message(ctx, "An instance with ssid (%s) and LowerLayer (%s) already present.", ssid, value);
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			// Store LowerLayers value under dmmap section
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", reference.path);
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "device", reference.value);

			if (((struct dm_data *)data)->config_section == NULL)
				return 0;

			if (check_slo_ap(((struct dm_data *)data)->config_section)) {
				/* wireless config: change device */
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "device", reference.value);
			} else {
				/* mapcontroller config: change band */
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "band", bbfdm_wifimngr_lookup_band_from_device(reference.value));
			}

			return 0;
	}
	return 0;
}

static int get_WiFiSSID_BSSID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	*value = (w_ap && DM_STRLEN(w_ap->iface_name)) ? macaddr_to_string(w_ap->ap.bss.bssid) : "";
	return 0;
}

static int get_WiFiSSID_MACAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	*value = (w_ap && DM_STRLEN(w_ap->iface_name)) ? macaddr_to_string(w_ap->ap.bss.bssid) : "";
	return 0;
}

static int get_WiFiSSIDStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_bytes : 0);
	return 0;
}

static int get_WiFiSSIDStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_bytes : 0);
	return 0;
}

static int get_WiFiSSIDStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_err_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_err_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_DiscardPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_dropped_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_DiscardPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_dropped_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_UnicastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_ucast_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_UnicastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_ucast_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_MulticastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_mcast_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_MulticastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_mcast_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_BroadcastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_bcast_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_BroadcastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_bcast_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_RetransCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_rtx_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_FailedRetransCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_rtx_fail_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_RetryCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_retry_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_MultipleRetryCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.tx_mretry_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_ACKFailureCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.ack_fail_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_AggregatedPacketCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.aggr_pkts : 0);
	return 0;
}

static int get_WiFiSSIDStats_UnknownProtoPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%"PRIu64, w_ap ? w_ap->ap_stats.rx_unknown_pkts : 0);
	return 0;
}

static int get_WiFiAccessPoint_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	if (check_slo_ap(((struct dm_data *)data)->config_section)) {
		dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", value);
		*value = ((*value)[0] == '1') ? dmstrdup("0") : dmstrdup("1");
	} else {
		*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "enabled", "1");
	}

	return 0;
}

static int set_WiFiAccessPoint_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char sec_name[64] = {0};
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			string_to_bool(value, &b);

			if (check_slo_ap(((struct dm_data *)data)->config_section)) {
				// wireless config: Update disabled option
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1");
			} else {
				// mapcontroller config: Update enabled option
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "enabled", b ? "1" : "0");
			}

			snprintf(sec_name, sizeof(sec_name), "%s.%s",
					section_config(((struct dm_data *)data)->config_section),
					section_name(((struct dm_data *)data)->config_section));

			struct uci_section *ssid_s = get_dup_section_in_dmmap_opt("WiFi", "SSID", "__section_name__", sec_name);
			if (ssid_s != NULL) {
				dmuci_set_value_by_section(ssid_s, "enabled", b ? "1" : "0");
			}

			return 0;
	}
	return 0;
}

static int get_WiFiAccessPoint_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	char *enable = NULL;

	get_WiFiAccessPoint_Enable(refparam, ctx, data, instance, &enable);
	if (DM_LSTRCMP(enable, "0") == 0) {
		*value = dmstrdup("Disabled");
		return 0;
	}

	if (!w_ap || DM_STRLEN(w_ap->iface_name) == 0) {
		*value = dmstrdup("Error");
		return 0;
	}

	if (w_ap->iface == NULL) {
		 *value = dmstrdup("Error");
	} else {
		ifstatus_t ifs = 0;

		wifi_get_ifstatus(w_ap->iface_name, &ifs);

		if ((ifs & IFF_UP) || (ifs & IFF_RUNNING)) {
			*value = dmstrdup("Enabled");
		} else {
			*value = dmstrdup("Error");
		}
	}

	return 0;
}

static int get_WiFiAccessPoint_SSIDReference(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "LowerLayers", value);

	if ((*value)[0] == '\0') {
		struct uci_section *ssid_s = NULL;
		char sec_name[64] = {0};

		snprintf(sec_name, sizeof(sec_name), "%s.%s",
				section_config(((struct dm_data *)data)->config_section),
				section_name(((struct dm_data *)data)->config_section));

		ssid_s = get_dup_section_in_dmmap_opt("WiFi", "SSID", "__section_name__", sec_name);
		if (ssid_s != NULL) {
			char *ssid_instance = NULL;

			dmuci_get_value_by_section_string(ssid_s, "__instance__", &ssid_instance);
			if (DM_STRLEN(ssid_instance) == 0)
				return 0;

			dmasprintf(value, "Device.WiFi.SSID.%s", ssid_instance);

			// Store LowerLayers value
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", *value);
		}
	}

	return 0;
}

static int set_WiFiAccessPoint_SSIDReference(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *allowed_objects[] = {"Device.WiFi.SSID.", NULL};
	struct uci_section *ss = NULL;
	char *device = NULL, *ssid = NULL, *enabled = NULL, *ap_sec = NULL, *mld = NULL;
	struct dm_reference reference = {0};
	char sec_name[64] = {0};

	bbfdm_get_reference_linker(ctx, value, &reference);

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, reference.path, -1, 256, NULL, NULL))
				return FAULT_9007;

			if (dm_validate_allowed_objects(ctx, &reference, allowed_objects))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			if (DM_STRLEN(reference.path) == 0)
				return 0;

			/* If this SSID instance is already referred by other AP then reject */
			ss = get_dup_section_in_dmmap_opt("WiFi", "SSID", "Name", reference.value);
			dmuci_get_value_by_section_string(ss, "__section_name__", &ap_sec);
			if (DM_STRLEN(ap_sec) != 0) {
				bbfdm_set_fault_message(ctx, "SSID (%s) already referenced by other AP", reference.path);
				return FAULT_9001;
			}

			if (check_slo_ap(((struct dm_data *)data)->config_section)) {
				/* This is a SLO ap so SSID instance should not be assigned MLDUnit */
				if (mld_capable) {
					dmuci_get_value_by_section_string(ss, "mld_id", &mld);
					if (DM_STRLEN(mld) != 0) {
						bbfdm_set_fault_message(ctx, "SSID has MLDUnit (%s), so can not be "
									"referenced by standalone AP", mld);
						return FAULT_9001;
					}
				}

				/* Easymesh network should not have AP with same SSID */
				dmuci_get_value_by_section_string(ss, "ssid", &ssid);
				if (easymesh_ssid_exist(ssid)) {
					bbfdm_set_fault_message(ctx, "Easymesh AP is configured with SSID (%s),"
								" so can not be referenced by standalone AP", ssid);
					return FAULT_9001;
				}
			} else {
				/* SSID should not be part of SLO AP */
				dmuci_get_value_by_section_string(ss, "ssid", &ssid);
				if (slo_ssid_exist(ssid)) {
					bbfdm_set_fault_message(ctx, "Standalone AP is configured with SSID (%s),"
								" so can not be referenced by easymesh node", ssid);
					return FAULT_9001;
				}
			}

			break;
		case VALUESET:
			// Store LowerLayers value under dmmap_wireless section
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", reference.path);

			snprintf(sec_name, sizeof(sec_name), "%s.%s",
					section_config(((struct dm_data *)data)->config_section),
					section_name(((struct dm_data *)data)->config_section));

			/* If AP is already referenced to a SSID instance then remove the references from existing SSID */
			ss = get_dup_section_in_dmmap_opt("WiFi", "SSID", "__section_name__", sec_name);
			if (ss != NULL) {
				dmuci_set_value_by_section(ss, "__section_name__", "");
			}

			if (DM_STRLEN(reference.value)) {
				/* Find the new SSID section and add the configurations */
				ss = get_dup_section_in_dmmap_opt("WiFi", "SSID", "Name", reference.value);

				/* Add reference to new SSID */
				dmuci_set_value_by_section(ss, "__section_name__", sec_name);

				/* Read ssid, device, mld, enabled from SSID section to set in AP section */
				dmuci_get_value_by_section_string(ss, "device", &device);
				dmuci_get_value_by_section_string(ss, "ssid", &ssid);
				dmuci_get_value_by_section_string(ss, "enabled", &enabled);
				dmuci_get_value_by_section_string(ss, "mld_id", &mld);

				bool b = dmuci_string_to_boolean(enabled);

				if (check_slo_ap(((struct dm_data *)data)->config_section)) {
					/* wireless config */
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ssid", ssid);
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "device", device);
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1");
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ifname", "");
				} else {
					/* mapcontroller config */
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ssid", ssid);
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "band", bbfdm_wifimngr_lookup_band_from_device(device));
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "enabled", b ? "1" : "0");

					if (!mld_capable || DM_STRLEN(mld) == 0) {
						break;
					}

					/* Set the MLDUnit in the AP section */
					dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "mld_id", mld);

					/* Sync the key of MLD section and AP section */
					char *ap_key = NULL, *mld_key = NULL;

					dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", &ap_key);

					struct uci_section *mld_sec = get_dup_section_in_config_opt("mapcontroller", "mld", "id", mld);
					if (mld_sec == NULL) {
						break;
					}

					dmuci_get_value_by_section_string(mld_sec, "key", &mld_key);

					if (DM_STRLEN(mld_key) == 0 && DM_STRLEN(ap_key) != 0) {
						configure_mld_section(mld, "key", ap_key);
						configure_map_sections(mld, "key", ap_key, false);
					} else if (DM_STRCMP(mld_key, ap_key) != 0) {
						dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", mld_key);
						dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "SAEPassphrase", "");
						dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "KeyPassphrase", "");
						dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Key", "");
					}
				}
			} else {
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ssid", "");
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ifname", "");
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "device", "");
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "band", "");
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "mld_id", "");
			}
			break;
	}
	return 0;
}

static int get_WiFiAccessPoint_SSIDAdvertisementEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "hidden", value);
	*value = ((*value)[0] == '1') ? "0" : "1";
	return 0;
}

static int set_WiFiAccessPoint_SSIDAdvertisementEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "SSIDAdvertisementEnabled not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "hidden", b ? "0" : "1");
			return 0;

	}
	return 0;
}

static int get_WiFiAccessPoint_WMMEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "wmm", "1");
	return 0;
}

static int set_WiFiAccessPoint_WMMEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "WMMEnable not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "wmm", value);
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPoint_UAPSDCapability(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("true");
	return 0;
}

static int get_WiFiAccessPoint_UAPSDEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "wmm_apsd", "1");
	return 0;
}

static int set_WiFiAccessPoint_UAPSDEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "UAPSDEnable not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "wmm_apsd", b ? "1" : "0");
			break;
	}
	return 0;
}

static int get_WiFiAccessPoint_MACAddressControlEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *macfilter;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "macfilter", &macfilter);
	if (macfilter[0] == 0 || DM_LSTRCMP(macfilter, "deny") == 0 || DM_LSTRCMP(macfilter, "disable") == 0)
		*value = dmstrdup("false");
	else
		*value = dmstrdup("true");
	return 0;
}

static int set_WiFiAccessPoint_MACAddressControlEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "MACAddressControlEnabled not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "macfilter", b ? "allow" : "disable");
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPoint_WMMCapability(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("true");
	return 0;
}

static int get_WiFiAccessPoint_MaxAllowedAssociations(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "maxassoc", "32");
	return 0;
}

static int set_WiFiAccessPoint_MaxAllowedAssociations(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "MaxAllowedAssociations not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "maxassoc", value);
			break;
	}
	return 0;
}

static int get_WiFiAccessPoint_IsolationEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "isolate", "0");
	return 0;
}

static int set_WiFiAccessPoint_IsolationEnable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "IsolationEnable not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "isolate", b ? "1" : "0");
			break;
	}
	return 0;
}

static int get_WiFiAccessPoint_AllowedMACAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct uci_list *val = NULL;
	dmuci_get_value_by_section_list(((struct dm_data *)data)->config_section, "maclist", &val);
	*value = dmuci_list_to_string(val, ",");
	return 0;
}

static int set_WiFiAccessPoint_AllowedMACAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char **arr = NULL;
	size_t length, idx;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string_list(ctx, value, -1, -1, -1, -1, 17, NULL, MACAddress))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "AllowedMACAddress not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			arr = strsplit(value, ",", &length);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "maclist", "");
			for (idx = 0; idx < length; idx++)
				dmuci_add_list_value_by_section(((struct dm_data *)data)->config_section, "maclist", arr[idx]);
			break;
	}
	return 0;
}

#ifdef WIFIMNGR_VENDOR_EXTENSIONS
static int get_WiFiAccessPoint_MultiAPMode(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = check_slo_ap(((struct dm_data *)data)->config_section) ? dmstrdup("0") : dmstrdup("2");
	return 0;
}

static int set_WiFiAccessPoint_MultiAPMode(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct uci_section *uci_s = NULL;
	char sec_name[64] = {0};
	char *is_new_obj = NULL;

	switch (action)	{
		case VALUECHECK:
			/*
			 * Multi-AP mode can only be set at the time of Access Point creation.
			 * If the object is already created (__is_new__ != "1"), disallow changes.
			 */
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "__is_new__", &is_new_obj);
			if (DM_STRCMP(is_new_obj, "1") != 0) {
				bbfdm_set_fault_message(ctx,
						"Multi-AP mode cannot be modified after the Access Point instance is created and applied");
				return FAULT_9007;
			}

			/* Only value "0" is currently supported for Multi-AP mode */
			if (DM_STRCMP(value, "0") != 0) {
				bbfdm_set_fault_message(ctx, "Only '0' is a supported Multi-AP mode value");
				return FAULT_9007;
			}

			break;
		case VALUESET:
			/* Create new section in wireless config */
			{
				char *ssid = NULL, *band = NULL, *encr = NULL, *key = NULL, *enabled = NULL, *ieee80211w = NULL;
				const char *device = NULL;
				bool enable;

				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ssid", &ssid);
				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "band", &band);
				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "encryption", &encr);
				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", &key);
				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "enabled", &enabled);
				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "ieee80211w", &ieee80211w);

				device = bbfdm_wifimngr_lookup_device_from_band(band);

				if (DM_STRLEN(enabled) != 0)
					enable = dmuci_string_to_boolean(enabled);
				else
					enable = true;

				snprintf(sec_name, sizeof(sec_name), "wifi_%s", section_name(((struct dm_data *)data)->config_section));

				dmuci_add_section("wireless", "wifi-iface", &uci_s);
				dmuci_rename_section_by_section(uci_s, sec_name);

				dmuci_set_value_by_section(uci_s, "disabled", enable ? "0" : "1");
				dmuci_set_value_by_section(uci_s, "network", "lan");
				dmuci_set_value_by_section(uci_s, "mode", "ap");
				dmuci_set_value_by_section(uci_s, "ssid", ssid);
				dmuci_set_value_by_section(uci_s, "device", device ? device : "");
				dmuci_set_value_by_section(uci_s, "encryption", encr);
				dmuci_set_value_by_section(uci_s, "key", key);
				dmuci_set_value_by_section(uci_s, "wps_pushbutton", "1");

				if (DM_STRLEN(ieee80211w) != 0) { // MFPConfig is automatically defined by ModeEnabled
					dmuci_set_value_by_section(uci_s, "ieee80211w", ieee80211w);
					dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "ieee80211w", "");
				}
			}

			/* Update the AP's dmmap section to keep the instance information intact */
			{
				snprintf(sec_name, sizeof(sec_name), "wireless.wifi_%s", section_name(((struct dm_data *)data)->config_section));

				dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "__section_name__", sec_name);
			}

			/* Update SSID dmmap section if AP was referenced to an SSID, to keep the references intact */
			{
				char old_sec_name[64] = {0};

				snprintf(old_sec_name, sizeof(old_sec_name), "%s.%s",
						section_config(((struct dm_data *)data)->config_section),
						section_name(((struct dm_data *)data)->config_section));

				uci_s = get_dup_section_in_dmmap_opt("WiFi", "SSID", "__section_name__", old_sec_name);
				if (uci_s != NULL) {
					dmuci_set_value_by_section(uci_s, "__section_name__", sec_name);
					dmuci_set_value_by_section(uci_s, "mld_id", "");
				}
			}

			/* Remove the AP section from mapcontroller */
			{
				dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
			}

			break;
	}
	return 0;
}
#endif

static int get_WiFiAccessPoint_AssociatedDeviceNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browse_wifi_associated_device);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiAccessPointSecurity_ModesSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	const char *supp_modes = check_slo_ap(((struct dm_data *)data)->config_section) ?
			supp_slo_security_modes : supp_multiap_security_modes;

	/* No interface -> return full supported list */
	if (!w_ap || DM_STRLEN(w_ap->iface_name) == 0) {
		*value = dmstrdup(supp_modes);
		return 0;
	}

	char *curr_supp_modes = security_mode_supported_to_string(w_ap->ap.sec.supp_modes);

	/* Interface has no modes -> fall back to full supported list */
	if (DM_STRLEN(curr_supp_modes) == 0) {
		*value = dmstrdup(supp_modes);
	} else {
		char buf[256] = {0};
		uint32_t pos = 0;
		char *pch, *spch;

		for (pch = strtok_r(curr_supp_modes, ",", &spch); pch != NULL; pch = strtok_r(NULL, ",", &spch)) {
			if (value_exits_in_str_list(supp_modes, ",", pch))
				pos += snprintf(buf + pos, sizeof(buf) - pos, "%s%s", pos ? "," : "", pch);
		}

		*value = dmstrdup(pos ? buf: supp_modes);
	}

	return 0;
}

static int get_WiFiAccessPointSecurity_ModeEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_security_mode(((struct dm_data *)data)->config_section);
	return 0;
}

static int set_WiFiAccessPointSecurity_ModeEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *supported_modes = NULL;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow config change on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			// Get the list of all supported security modes
			get_WiFiAccessPointSecurity_ModesSupported(refparam, ctx, data, instance, &supported_modes);

			// Check if the input value is a valid security mode
			if (!value_exits_in_str_list(supported_modes, ",", value))
				return FAULT_9007;

			return 0;
		case VALUESET:
			set_security_mode(data, value);
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_EncryptionMode(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;

	if (!w_ap || DM_STRLEN(w_ap->iface_name) == 0)
		*value = dmstrdup("");
	else
		*value = ap_encryption_mode_to_string(w_ap->ap.bss.rsn.pair_ciphers);

	return 0;
}

static int get_WiFiAccessPointSecurity_WEPKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	/* WEP is deprecated and not supported in current Wi-Fi configurations */
	return 0;
}

static int set_WiFiAccessPointSecurity_WEPKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			bbfdm_set_fault_message(ctx, "WEP security mode is deprecated and no longer supported for EasyMesh or Standalone AP");
			return FAULT_9007;
		case VALUESET:
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_PreSharedKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *key = NULL;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", &key);

	/* Must be exactly 64 characters */
	if (DM_STRLEN(key) != 64) {
		*value = dmstrdup("");
	} else {
		int i;

		/* Validate all 64 chars are hex */
	    for (i = 0; i < 64; i++) {
	        if (!isxdigit((unsigned char)key[i]))
	            break;
	    }

	    *value = dmstrdup((i == 64) ? key : "");
	}

	return 0;
}

static int set_WiFiAccessPointSecurity_PreSharedKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_hexBinary(ctx, value, RANGE_ARGS{{"32","32"}}, 1))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "PreSharedKey not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", value);
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_KeyPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *key = NULL;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", &key);

	if (DM_STRLEN(key) >= 8 && DM_STRLEN(key) <= 63)
		*value = dmstrdup(key);
	else
		*value = dmstrdup("");

	return 0;
}

static int set_WiFiAccessPointSecurity_KeyPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, 8, 63, NULL, NULL))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", value);

			// Store a copy of key in dmmap. It may be required later when setting the ModeEnabled parameter
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "key", value);

			if (check_slo_ap(((struct dm_data *)data)->config_section)) {
				/* This is a SLO AP so no need to check MLD section config */
				return 0;
			}

			if (mld_capable) {
				/* This is an easymesh AP node, check if AP is referenced to a mld configured SSID */
				struct uci_section *ssid_s = NULL;
				char sec_name[64] = {0};
				char *mld_id = NULL;

				snprintf(sec_name, sizeof(sec_name), "%s.%s",
						section_config(((struct dm_data *)data)->config_section),
						section_name(((struct dm_data *)data)->config_section));

				ssid_s = get_dup_section_in_dmmap_opt("WiFi", "SSID", "__section_name__", sec_name);
				dmuci_get_value_by_section_string(ssid_s, "mld_id", &mld_id);

				if (DM_STRLEN(mld_id) == 0)
					return 0;

				/* MLDUnit configured so need to change the key in MLD section */
				configure_mld_section(mld_id, "key", value);
				configure_map_sections(mld_id, "key", value, false);
			}
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_RekeyingInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_wireless_uci_ap_section_fallback_def(data, "wpa_group_rekey", "0");
	return 0;
}

static int set_WiFiAccessPointSecurity_RekeyingInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			set_wireless_uci_ap_section_fallback(data, "wpa_group_rekey", value);
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_SAEPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", value);
	return 0;
}

static int set_WiFiAccessPointSecurity_SAEPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, 8, 63, NULL, NULL))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", value);

			// Store a copy of key in dmmap. It may be required later when setting the ModeEnabled parameter
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "key", value);

			if (check_slo_ap(((struct dm_data *)data)->config_section)) {
				/* This is a SLO AP so no need to check MLD section config */
				return 0;
			}

			if (mld_capable) {
				/* This is an easymesh AP node, check if AP is referenced to a mld configured SSID */
				struct uci_section *ssid_s = NULL;
				char sec_name[64] = {0};
				char *mld_id = NULL;

				snprintf(sec_name, sizeof(sec_name), "%s.%s",
						section_config(((struct dm_data *)data)->config_section),
						section_name(((struct dm_data *)data)->config_section));

				ssid_s = get_dup_section_in_dmmap_opt("WiFi", "SSID", "__section_name__", sec_name);
				dmuci_get_value_by_section_string(ssid_s, "mld_id", &mld_id);

				if (DM_STRLEN(mld_id) == 0)
					return 0;

				/* MLDUnit configured so need to change the key in MLD section */
				configure_mld_section(mld_id, "key", value);
				configure_map_sections(mld_id, "key", value, false);
			}
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_RadiusServerIPAddr(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_wireless_uci_ap_section_fallback_def(data, "auth_server", "");
	return 0;
}

static int set_WiFiAccessPointSecurity_RadiusServerIPAddr(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, 45, NULL, IPAddress))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			set_wireless_uci_ap_section_fallback(data, "auth_server", value);
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_RadiusServerPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_wireless_uci_ap_section_fallback_def(data, "auth_port", "1812");
	return 0;
}

static int set_WiFiAccessPointSecurity_RadiusServerPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			set_wireless_uci_ap_section_fallback(data, "auth_port", value);
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_RadiusSecret(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_wireless_uci_ap_section_fallback_def(data, "auth_secret", "");
	return 0;
}

static int set_WiFiAccessPointSecurity_RadiusSecret(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			return 0;
		case VALUESET:
			set_wireless_uci_ap_section_fallback(data, "auth_secret", value);
			return 0;
	}
	return 0;
}

static int get_WiFiAccessPointSecurity_MFPConfig(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_wireless_uci_ap_section_fallback_def(data, "ieee80211w", "0");

	if (*value[0] == '1')
		*value = dmstrdup("Optional");
	else if (*value[0] == '2')
		*value = dmstrdup("Required");
	else
		*value = dmstrdup("Disabled");
	return 0;
}

static int set_WiFiAccessPointSecurity_MFPConfig(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char buf[2];

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, MFP_Config, NULL))
				return FAULT_9007;

			/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
			if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
				bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			if (DM_LSTRCMP(value, "Disabled") == 0)
				buf[0] = '0';
			else if (DM_LSTRCMP(value, "Optional") == 0)
				buf[0] = '1';
			else if (DM_LSTRCMP(value, "Required") == 0)
				buf[0] = '2';
			buf[1] = 0;
			set_wireless_uci_ap_section_fallback(data, "ieee80211w", buf);
			break;
	}
	return 0;
}

static int get_WiFiAccessPointWPS_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	/* This is a restricted parameter for easymesh node and set to enabled always */
	if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
		*value = dmstrdup("1");
		return 0;
	}

	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "wps_pushbutton", "0");
	return 0;
}

static int set_WiFiAccessPointWPS_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;

			/* This is a restricted parameter for easymesh node and set to enabled always */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "WPS Enable not configurable for EasyMesh network node");
				return FAULT_9007;
			}

			break;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "wps_pushbutton", b ? "1" : "0");
			break;
	}
	return 0;
}

static int get_WiFiAccessPointWPS_ConfigMethodsSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("PushButton");
	return 0;
}

static int get_WiFiAccessPointWPS_ConfigMethodsEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("PushButton");
	return 0;
}

static int set_WiFiAccessPointWPS_ConfigMethodsEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string_list(ctx, value, -1, -1, -1, -1, -1, NULL, NULL))
				return FAULT_9007;

			if (DM_STRCMP(value, "PushButton") != 0)
				return FAULT_9007;

			break;
		case VALUESET:
			// Don't do anything since we only support 'PushButton'
			break;
	}
	return 0;
}

static int get_WiFiAccessPointWPS_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *wps_status;

	/* This is a restricted parameter for easymesh node and set to enabled always */
	if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
		*value = dmstrdup("Configured");
		return 0;
	}

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "wps_pushbutton", &wps_status);
	*value = (wps_status[0] == '1') ? dmstrdup("Configured") : dmstrdup("Disabled");
	return 0;
}

static operation_args WiFiAccessPointWPSInitiateWPSPBC_args = {
	.out = (const char *[]) {
		"Status",
		NULL
	}
};

static int get_WiFiAccessPointAssociatedDevice_Active(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("true");
	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_Noise(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		//TODO
	} else {
		int noise;

		if (!w_ap_sta->sx.noise_avg)
			wifi_get_band_noise(w_ap_sta->wifi_ap->iface_name, w_ap_sta->wifi_ap->iface->band, &noise);
		else
			noise = w_ap_sta->sx.noise_avg;

		dmasprintf(value, "%d", noise);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_SNR(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		//TODO
	} else {
		int noise;

		if (!w_ap_sta->sx.noise_avg)
			wifi_get_band_noise(w_ap_sta->wifi_ap->iface_name, w_ap_sta->wifi_ap->iface->band, &noise);
		else
			noise = w_ap_sta->sx.noise_avg;

		dmasprintf(value, "%d", w_ap_sta->sx.rssi_avg - noise);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_MACAddress(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		*value = macaddr_to_string(w_ap_sta->mlsta.sta[0].mld_macaddr);
	} else {
		*value = macaddr_to_string(w_ap_sta->sx.macaddr);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_OperatingStandard(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		*value = radio_standards_to_string(w_ap_sta->mlsta.sta[0].oper_std);
	} else {
		*value = radio_standards_to_string(w_ap_sta->sx.oper_std);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_LastDataDownlinkRate(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%u", w_ap_sta->mlsta.sta[0].tx_rate.rate * 1000);
	} else {
		dmasprintf(value, "%u", w_ap_sta->sx.tx_rate.rate * 1000);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_LastDataUplinkRate(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%u", w_ap_sta->mlsta.sta[0].rx_rate.rate * 1000);
	} else {
		dmasprintf(value, "%u", w_ap_sta->sx.rx_rate.rate * 1000);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_SignalStrength(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%d", w_ap_sta->mlsta.sta[0].rssi_avg);
	} else {
		dmasprintf(value, "%d", w_ap_sta->sx.rssi_avg);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDevice_AssociationTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;
	char utc_time[32] = {0};
	uint32_t conn_time;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		conn_time = w_ap_sta->mlsta.sta[0].conn_time;
	} else {
		conn_time = w_ap_sta->sx.conn_time;
	}

	time_t t_time = time(NULL) - conn_time;
	if (gmtime(&t_time) == NULL)
		return -1;

	if (strftime(utc_time, sizeof(utc_time), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t_time)) == 0)
		return -1;

	*value = dmstrdup(utc_time);
	return 0;
}

#ifdef WIFIMNGR_VENDOR_EXTENSIONS
static int get_WiFiAccessPointAssociatedDevice_QoERating(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;
	float rating;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		rating = wifimngr_sta_ratings_calc(w_ap_sta->wifi_ap->iface->mld_netdev, &w_ap_sta->mlsta.sta[0]);
	} else {
		rating = wifimngr_sta_ratings_calc(w_ap_sta->wifi_ap->iface_name, &w_ap_sta->sx);
	}

	dmasprintf(value, "%.2f", rating);
	return 0;
}
#endif

static int get_WiFiAccessPointAssociatedDeviceStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%"PRIu64, w_ap_sta->mlsta.stats.tx_bytes);
	} else {
		dmasprintf(value, "%"PRIu64, w_ap_sta->sx.stats.tx_bytes);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDeviceStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%"PRIu64, w_ap_sta->mlsta.stats.rx_bytes);
	} else {
		dmasprintf(value, "%"PRIu64, w_ap_sta->sx.stats.rx_bytes);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDeviceStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%u", w_ap_sta->mlsta.stats.tx_pkts);
	} else {
		dmasprintf(value, "%u", w_ap_sta->sx.stats.tx_pkts);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDeviceStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%u", w_ap_sta->mlsta.stats.rx_pkts);
	} else {
		dmasprintf(value, "%u", w_ap_sta->sx.stats.rx_pkts);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDeviceStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%u", w_ap_sta->mlsta.stats.tx_fail_pkts);
	} else {
		dmasprintf(value, "%u", w_ap_sta->sx.stats.tx_fail_pkts);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDeviceStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%u", w_ap_sta->mlsta.stats.rx_fail_pkts);
	} else {
		dmasprintf(value, "%u", w_ap_sta->sx.stats.rx_fail_pkts);
	}

	return 0;
}

static int get_WiFiAccessPointAssociatedDeviceStats_RetransCount(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct bbfdm_wifi_ap_sta *w_ap_sta = (struct bbfdm_wifi_ap_sta *)((struct dm_data *)data)->additional_data;

	if (strlen(w_ap_sta->wifi_ap->iface->mld_netdev)
			&& if_nametoindex(w_ap_sta->wifi_ap->iface->mld_netdev) != 0) {
		dmasprintf(value, "%u", w_ap_sta->mlsta.stats.tx_retry_pkts);
	} else {
		dmasprintf(value, "%u", w_ap_sta->sx.stats.tx_retry_pkts);
	}

	return 0;
}

static int get_WiFiAccessPointAccounting_ServerIPAddr(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "acct_server", value);
	return 0;
}

static int set_WiFiAccessPointAccounting_ServerIPAddr(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, 45, NULL, IPAddress))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "Accounting ServerIPAddr not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "acct_server", value);
			break;
	}
	return 0;
}

static int get_WiFiAccessPointAccounting_ServerPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "acct_port", "1813");
	return 0;
}

static int set_WiFiAccessPointAccounting_ServerPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "Accounting ServerPort not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "acct_port", value);
			break;
	}
	return 0;
}

static int get_WiFiAccessPointAccounting_Secret(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "acct_secret", value);
	return 0;
}

static int set_WiFiAccessPointAccounting_Secret(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL))
				return FAULT_9007;

			/* Only allowed for standalone AP */
			if (!check_slo_ap(((struct dm_data *)data)->config_section)) {
				bbfdm_set_fault_message(ctx, "Accounting Secret not configurable for EasyMesh network node");
				return FAULT_9001;
			}

			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "acct_secret", value);
			break;
	}
	return 0;
}

static int get_WiFiEndPoint_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", value);
	*value = ((*value)[0] == '1') ? "0" : "1";
	return 0;
}

static int set_WiFiEndPoint_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			break;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "disabled", b ? "0" : "1");
			break;
	}
	return 0;
}

static int get_WiFiEndPoint_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "disabled", value);
	*value = ((*value)[0] == '1') ? "Disabled" : "Enabled";
	return 0;
}

static int get_WiFiEndPointStats_LastDataDownlinkRate(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct wifi_sta *sta = (struct wifi_sta *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", sta ? sta->rx_rate.rate * 1000 : 0);
	return 0;
}

static int get_WiFiEndPointStats_LastDataUplinkRate(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct wifi_sta *sta = (struct wifi_sta *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", sta ? sta->tx_rate.rate * 1000 : 0);
	return 0;
}

static int get_WiFiEndPointStats_SignalStrength(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct wifi_sta *sta = (struct wifi_sta *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%d", sta ? sta->rssi_avg : 0);
	return 0;
}

static int get_WiFiEndPointStats_Retransmissions(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct wifi_sta *sta = (struct wifi_sta *)((struct dm_data *)data)->additional_data;
	dmasprintf(value, "%u", sta ? sta->stats.tx_retry_pkts : 0);
	return 0;
}

static int get_WiFiEndPointSecurity_ModesSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct wifi_sta *sta = (struct wifi_sta *)((struct dm_data *)data)->additional_data;
	const char *supp_modes = check_slo_ap(((struct dm_data *)data)->config_section) ?
			supp_slo_security_modes : supp_multiap_security_modes;

	/* No interface -> return full supported list */
	if (!sta) {
		*value = dmstrdup(supp_modes);
		return 0;
	}

	char *curr_supp_modes = security_mode_supported_to_string(sta->sec.supp_modes);

	/* Interface has no modes -> fall back to full supported list */
	if (DM_STRLEN(curr_supp_modes) == 0) {
		*value = dmstrdup(supp_modes);
	} else {
		char buf[256] = {0};
		uint32_t pos = 0;
		char *pch, *spch;

		for (pch = strtok_r(curr_supp_modes, ",", &spch); pch != NULL; pch = strtok_r(NULL, ",", &spch)) {
			if (value_exits_in_str_list(supp_modes, ",", pch))
				pos += snprintf(buf + pos, sizeof(buf) - pos, "%s%s", pos ? "," : "", pch);
		}

		*value = dmstrdup(pos ? buf: supp_modes);
	}

	return 0;
}

static int get_WiFiEndPointProfile_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("1");
	return 0;
}

static int set_WiFiEndPointProfile_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			break;
		case VALUESET:
			break;
	}
	return 0;
}

static int get_WiFiEndPointProfile_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("Active");
	return 0;
}

static int get_WiFiEndPointProfile_SSID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ssid", value);
	return 0;
}

static int set_WiFiEndPointProfile_SSID(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, 32, NULL, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ssid", value);
			break;
	}
	return 0;
}

static int get_WiFiEndPointProfileSecurity_ModeEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_security_mode(((struct dm_data *)data)->config_section);
	return 0;
}

static int set_WiFiEndPointProfileSecurity_ModeEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *supported_modes = NULL;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL))
				return FAULT_9007;

			// Get the list of all supported security modes
			get_WiFiEndPointSecurity_ModesSupported(refparam, ctx, data, instance, &supported_modes);

			// Check if the input value is a valid security mode
			if (!value_exits_in_str_list(supported_modes, ",", value))
				return FAULT_9007;

			return 0;
		case VALUESET:
			set_security_mode(data, value);
			return 0;
	}
	return 0;
}

static int get_WiFiEndPointProfileSecurity_WEPKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	/* WEP is deprecated and not supported in current Wi-Fi configurations */
	return 0;
}

static int set_WiFiEndPointProfileSecurity_WEPKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			bbfdm_set_fault_message(ctx, "WEP security mode is deprecated and no longer supported");
			return FAULT_9007;
		case VALUESET:
			return 0;
	}
	return 0;
}

static int get_WiFiEndPointProfileSecurity_PreSharedKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", value);
	return 0;
}

static int set_WiFiEndPointProfileSecurity_PreSharedKey(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_hexBinary(ctx, value, RANGE_ARGS{{NULL,"32"}}, 1))
				return FAULT_9007;
			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", value);
			return 0;
	}
	return 0;
}

static int get_WiFiEndPointProfileSecurity_KeyPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", value);
	return 0;
}

static int set_WiFiEndPointProfileSecurity_KeyPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, 8, 63, NULL, NULL))
				return FAULT_9007;
			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", value);
			return 0;
	}
	return 0;
}

static int get_WiFiEndPointProfileSecurity_SAEPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "key", value);
	return 0;
}

static int set_WiFiEndPointProfileSecurity_SAEPassphrase(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, 8, 63, NULL, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key", value);
			break;
	}
	return 0;
}

static int get_WiFiEndPointProfileSecurity_MFPConfig(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ieee80211w", value);
	if(*value[0] == 0 || *value[0] == '0')
		*value = dmstrdup("Disabled");
	else if (DM_LSTRCMP(*value, "1") == 0)
		*value = dmstrdup("Optional");
	else if (DM_LSTRCMP(*value, "2") == 0)
		*value = dmstrdup("Required");
	return 0;
}

static int set_WiFiEndPointProfileSecurity_MFPConfig(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, MFP_Config, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			if (DM_LSTRCMP(value, "Disabled") == 0)
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ieee80211w", "0");
			else if (DM_LSTRCMP(value, "Optional") == 0)
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ieee80211w", "1");
			else if (DM_LSTRCMP(value, "Required") == 0)
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ieee80211w", "2");
			break;
	}
	return 0;
}

static int get_WiFiEndPointWPS_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "wps_pushbutton", "0");
	return 0;
}

static int set_WiFiEndPointWPS_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bool b;

	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_boolean(ctx, value))
				return FAULT_9007;
			break;
		case VALUESET:
			string_to_bool(value, &b);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "wps_pushbutton", b ? "1" : "0");
			break;
	}
	return 0;
}

static int get_WiFiEndPointWPS_ConfigMethodsSupported(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("PushButton");
	return 0;
}

static int get_WiFiEndPointWPS_ConfigMethodsEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("PushButton");
	return 0;
}

static int set_WiFiEndPointWPS_ConfigMethodsEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
		case VALUECHECK:
			if (bbfdm_validate_string_list(ctx, value, -1, -1, -1, -1, -1, NULL, NULL))
				return FAULT_9007;

			if (DM_STRCMP(value, "PushButton") != 0)
				return FAULT_9007;

			break;
		case VALUESET:
			// Don't do anything since we only support 'PushButton'
			break;
	}
	return 0;
}

static int get_WiFiEndPointWPS_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *wps_status;
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "wps_pushbutton", &wps_status);
	*value = (wps_status[0] == '1') ? "Configured" : "Disabled";
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnostic_DiagnosticsState(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_option_value_string_bbfdm("WiFiDiagnostic", "@diagnostic_status[0]", "DiagnosticsState", value);
	if ((*value)[0] == '\0')
		*value = dmstrdup("None");
	return 0;
}

static int set_WiFiNeighboringWiFiDiagnostic_DiagnosticsState(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, DiagnosticsState, NULL))
				return FAULT_9007;
			return 0;
		case VALUESET:
			{
				const char *dmmap_diag_path = "/etc/bbfdm/dmmap/WiFiDiagnostic";
				struct uci_section *s = NULL;

				if (file_exists(dmmap_diag_path))
					remove(dmmap_diag_path);

				dmuci_add_section_bbfdm("WiFiDiagnostic", "diagnostic_status", &s);
				dmuci_set_value_by_section(s, "DiagnosticsState", value);
			}
			return 0;
	}
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnostic_ResultNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseWifiNeighboringWiFiDiagnosticResultInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_Radio(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "radio", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_SSID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ssid", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_BSSID(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "bssid", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_Channel(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "channel", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_SignalStrength(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "rssi", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_OperatingFrequencyBand(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "band", value);
	return 0;
}

/*static int get_WiFiNeighboringWiFiDiagnosticResult_Noise(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "noise", value);
	return 0;
}*/

static int get_WiFiNeighboringWiFiDiagnosticResult_OperatingChannelBandwidth(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "bandwidth", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_OperatingStandards(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "standard", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_SecurityModeEnabled(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "encryption", value);
	return 0;
}

static int get_WiFiNeighboringWiFiDiagnosticResult_EncryptionMode(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ciphers", value);
	return 0;
}

/*************************************************************
 * OPERATE COMMANDS
 *************************************************************/
static int operate_WiFi_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	if (easymesh_enable) {
		struct timespec ts = {25, 0};

		int err = dmubus_call_set("map.agent", "reset", UBUS_ARGS{0}, 0);
		if (err)
			return err;

		// Wait 25sec to reset everything from the backend, then generate the new WiFi dmmap file
		while (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts) == EINTR);

		err = remove(WIFI_DMMAP_PATH);
		if (err) {
			BBF_ERR("Failed to delete WiFi dmmap file");
			return err;
		}

		// Create WiFi dmmap
		init_wifi_legacy_module(NULL);
		return 0;
	} else {
		return !dmcmd_no_wait("/sbin/wifi", 1, "reload") ? 0 : USP_FAULT_COMMAND_FAILURE;
	}
}

static operation_args neighboring_wifi_diagnostic_args = {
	.out = (const char *[]) {
		"Status",
		"Result.{i}.Radio",
		"Result.{i}.SSID",
		"Result.{i}.BSSID",
		"Result.{i}.Channel",
		"Result.{i}.SignalStrength",
		"Result.{i}.SecurityModeEnabled",
		"Result.{i}.EncryptionMode",
		"Result.{i}.OperatingFrequencyBand",
		"Result.{i}.OperatingStandards",
		"Result.{i}.OperatingChannelBandwidth",
		//"Result.{i}.Noise",
		NULL
	}
};

static int get_operate_args_WiFi_NeighboringWiFiDiagnostic(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)&neighboring_wifi_diagnostic_args;
	return 0;
}

static void parse_received_wifi_radio_event(struct ubus_context *ctx, struct ubus_event_handler *ev,
				const char *type, struct blob_attr *msg)
{
	struct wifi_radio_scan *scan_ctx;
	struct dmubus_event_data *data;
	struct wifimngr_device *wdev;

	if (!msg || !ev)
		return;

	data = container_of(ev, struct dmubus_event_data, ev);
	if (!data)
		return;

	scan_ctx = (struct wifi_radio_scan *)data->ev_data;
	if (!scan_ctx)
		return;

	const struct blobmsg_policy p_event[2] = {
		{ "ifname", BLOBMSG_TYPE_STRING },
		{ "event", BLOBMSG_TYPE_STRING }
	};

	struct blob_attr *tb[2] = { 0, 0 };
	blobmsg_parse(p_event, 2, tb, blobmsg_data(msg), blobmsg_len(msg));
	if (!tb[0] || !tb[1])
		return;

	const char *ifname = blobmsg_get_string(tb[0]);
	const char *action = blobmsg_get_string(tb[1]);

	if (strcmp(action, "scan_finished") != 0)
		return;

	wdev = wifimngr_ifname_to_device(bbfdm_wifimngr, ifname);
	if (!wdev)
		return;

	/* Mark scan done */
	for (int i = 0; i < scan_ctx->num_radio; i++) {
		if (strcmp(scan_ctx->radios[i].name, wdev->phy) == 0) {
			scan_ctx->radios[i].scan_done = true;
			break;
		}
	}

	/* Check if all scans finished */
	for (int i = 0; i < scan_ctx->num_radio; i++) {
		if (!scan_ctx->radios[i].scan_done)
			return;
	}

	uloop_end();
}

static void start_wifi_radio_scan(struct uloop_timeout *timeout)
{
	struct wifi_radio_scan *scan_ctx;
	struct dmubus_ev_subtask *data;

	data = container_of(timeout, struct dmubus_ev_subtask, sub_tm);
	if (data == NULL)
		return;

	scan_ctx = (struct wifi_radio_scan *)(data->subtask_data);
	if (!scan_ctx)
		return;

	for (int i = 0; i < scan_ctx->num_radio; i++) {
		struct scan_param p = {0};
		scan_ctx->radios[i].scan_done = false;
		wifi_scan(scan_ctx->radios[i].name, &p);
	}
}


static int operate_WiFi_NeighboringWiFiDiagnostic(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct wifi_radio_scan *scan_ctx;
	uint32_t inst_idx = 1;

	scan_ctx = (struct wifi_radio_scan *)calloc(1, sizeof(*scan_ctx));
	if (!scan_ctx) {
		fill_blob_param(&ctx->bb, "Status", "Error", DMT_TYPE[DMT_STRING], 0);
		goto end;
	}

	for (int i = 0; i < bbfdm_wifimngr->num_wifi_device; i++) {
		struct wifimngr_device *wdev = &bbfdm_wifimngr->wdev[i];

		if (!strlen(wdev->device) || wdev->disabled)
			continue;

		snprintf(scan_ctx->radios[scan_ctx->num_radio].name,
				sizeof(scan_ctx->radios[0].name),
				"%s", wdev->phy);

		scan_ctx->num_radio++;
	}

	if (!scan_ctx->num_radio)
		goto cleanup;

	struct dmubus_ev_subtask subtask = {
		.sub_tm.cb = start_wifi_radio_scan,
		.subtask_data = (void *)scan_ctx,
		.timeout = 1
	};

	dmubus_wait_for_event("wifi.radio", 30, (void *)scan_ctx, parse_received_wifi_radio_event, &subtask);

	/* Collect results */
	for (int i = 0; i < scan_ctx->num_radio; i++) {
		struct wifi_bss bsss[NUM_SCANRES] = {0};
		int num = NUM_SCANRES;
		char *radio_ref = NULL;

		if (wifi_get_scan_results(scan_ctx->radios[i].name, bsss, &num))
			continue;

		adm_entry_get_reference_param(ctx,
				"Device.WiFi.Radio.*.Name",
				scan_ctx->radios[i].name,
				&radio_ref);

		for (int j = 0; j < num; j++) {
			char path[64];
			char channel[8];
			char rssi[8];

			snprintf(channel, sizeof(channel), "%u", bsss[j].channel);
			snprintf(rssi, sizeof(rssi), "%d", bsss[j].rssi);

			snprintf(path, sizeof(path), "Result.%u.Radio", inst_idx);
			fill_blob_param(&ctx->bb, path,
					radio_ref,
					DMT_TYPE[DMT_STRING], 0);

			snprintf(path, sizeof(path), "Result.%u.SSID", inst_idx);
			fill_blob_param(&ctx->bb, path,
					(char *)bsss[j].ssid,
					DMT_TYPE[DMT_STRING], 0);

			char *bssid = macaddr_to_string(bsss[j].bssid);
			snprintf(path, sizeof(path), "Result.%u.BSSID", inst_idx);
			fill_blob_param(&ctx->bb, path,
					bssid,
					DMT_TYPE[DMT_STRING], 0);

			snprintf(path, sizeof(path), "Result.%u.Channel", inst_idx);
			fill_blob_param(&ctx->bb, path,
					channel,
					DMT_TYPE[DMT_UNINT], 0);

			snprintf(path, sizeof(path), "Result.%u.OperatingFrequencyBand", inst_idx);
			fill_blob_param(&ctx->bb, path,
					radio_band_to_band_ghz(bsss[j].band),
					DMT_TYPE[DMT_STRING], 0);

			snprintf(path, sizeof(path), "Result.%u.SignalStrength", inst_idx);
			fill_blob_param(&ctx->bb, path,
					rssi,
					DMT_TYPE[DMT_INT], 0);

			snprintf(path, sizeof(path), "Result.%u.OperatingChannelBandwidth", inst_idx);
			fill_blob_param(&ctx->bb, path,
					radio_bandwidth_to_string(bw_value(bsss[j].curr_bw), bsss[j].ccfs0, bsss[j].ccfs1),
					DMT_TYPE[DMT_STRING], 0);

			snprintf(path, sizeof(path), "Result.%u.OperatingStandards", inst_idx);
			fill_blob_param(&ctx->bb, path,
					radio_standards_to_string(bsss[j].oper_std),
					DMT_TYPE[DMT_STRING], 0);

			snprintf(path, sizeof(path), "Result.%u.SecurityModeEnabled", inst_idx);
			fill_blob_param(&ctx->bb, path,
					security_mode_enabled_to_string(bsss[j].security),
					DMT_TYPE[DMT_STRING], 0);

			snprintf(path, sizeof(path), "Result.%u.EncryptionMode", inst_idx);
			fill_blob_param(&ctx->bb, path,
					ap_encryption_mode_to_string(bsss[j].rsn.pair_ciphers),
					DMT_TYPE[DMT_STRING], 0);

			if (ctx->dm_type != BBFDM_USP) {
				struct uci_section *dmmap_s = NULL;
				dmuci_add_section_bbfdm("WiFiDiagnostic", "Result", &dmmap_s);
				dmuci_set_value_by_section(dmmap_s, "radio",
						radio_ref);
				dmuci_set_value_by_section(dmmap_s, "ssid",
						(char *)bsss[j].ssid);
				dmuci_set_value_by_section(dmmap_s, "bssid",
						bssid);
				dmuci_set_value_by_section(dmmap_s, "channel",
						channel);
				dmuci_set_value_by_section(dmmap_s, "band",
						radio_band_to_band_ghz(bsss[j].band));
				dmuci_set_value_by_section(dmmap_s, "rssi", rssi);
				dmuci_set_value_by_section(dmmap_s, "bandwidth",
						radio_bandwidth_to_string(bw_value(bsss[j].curr_bw), bsss[j].ccfs0, bsss[j].ccfs1));
				dmuci_set_value_by_section(dmmap_s, "standard",
						radio_standards_to_string(bsss[j].oper_std));
				dmuci_set_value_by_section(dmmap_s, "encryption",
						security_mode_enabled_to_string(bsss[j].security));
				dmuci_set_value_by_section(dmmap_s, "ciphers",
						ap_encryption_mode_to_string(bsss[j].rsn.pair_ciphers));
			}

			inst_idx++;
		}
	}

	fill_blob_param(&ctx->bb, "Status", "Complete", DMT_TYPE[DMT_STRING], 0);

cleanup:
	FREE(scan_ctx);

end:
	if (ctx->dm_type != BBFDM_USP) {
		dmuci_set_value_bbfdm("WiFiDiagnostic", "@diagnostic_status[0]", "DiagnosticsState", "Complete");
		dmuci_commit_package_bbfdm("WiFiDiagnostic");
	}

	return 0;
}

static int operate_WiFiAccessPointSecurity_Reset(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	/* If mapcontroller not enabled then do not allow to change config on easymesh nodes */
	if (easymesh_enable == false && check_slo_ap(((struct dm_data *)data)->config_section) == false) {
		bbfdm_set_fault_message(ctx, "Config change on Easy-mesh node is not allowed on this device.");
		return USP_FAULT_REQUEST_DENIED;
	}

	dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "encryption",
			get_wlan_default_value("encryption", "sae-mixed"));
	dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "key",
			get_wlan_default_value("key", "1234567890"));

	if (check_slo_ap(((struct dm_data *)data)->config_section)) {
		/* WPS configurations are only allowed for standalone AP */
		dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "wps_pushbutton", "1");
	}

	return 0;
}

static int get_operate_args_WiFiAccessPointWPS_InitiateWPSPBC(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)&WiFiAccessPointWPSInitiateWPSPBC_args;
	return 0;
}

static int operate_WiFiAccessPointWPS_InitiateWPSPBC(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct bbfdm_wifi_ap *w_ap = (struct bbfdm_wifi_ap *)((struct dm_data *)data)->additional_data;
	char object[256], status[32];
	int ubus_ret = 0;

	if (!w_ap || DM_STRLEN(w_ap->iface_name) == 0)
		return USP_FAULT_COMMAND_FAILURE;

	snprintf(status, sizeof(status), "%s", "Success");

	snprintf(object, sizeof(object), "hostapd.%s", w_ap->iface_name);
	ubus_ret = dmubus_call_set(object, "wps_start", UBUS_ARGS{0}, 0);
	if (ubus_ret != 0)
		snprintf(status, sizeof(status), "%s", "Error_Not_Ready");

	fill_blob_param(&ctx->bb, "Status", status, DMT_TYPE[DMT_STRING], 0);
	return 0;
}

/*************************************************************
* Init, Clean & Sync Module
**************************************************************/
static void on_map_agent_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
			  const char *type, struct blob_attr *msg)
{
	/* { "map.agent": {"radio":"phy1","event":"ap-autoconfiguration","data":{"status":"success","reason":"completed"}} } */
	static const struct blobmsg_policy ev_attr[] = {
		[0] = { .name = "event", .type = BLOBMSG_TYPE_STRING },
		[1] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
	};
	struct blob_attr *tb[ARRAY_SIZE(ev_attr)];

	if (!msg)
		return;

	blobmsg_parse(ev_attr, ARRAY_SIZE(ev_attr), tb, blob_data(msg), blob_len(msg));
	if (!tb[0] || !tb[1])
		return;

	if (strcmp(blobmsg_data(tb[0]), "ap-autoconfiguration") != 0)
		return;

	static const struct blobmsg_policy data_attr[] = {
		[0] = { .name = "status", .type = BLOBMSG_TYPE_STRING },
	};
	struct blob_attr *data[ARRAY_SIZE(data_attr)];

	blobmsg_parse(data_attr, ARRAY_SIZE(data_attr), data, blobmsg_data(tb[1]), blobmsg_data_len(tb[1]));
	if (!data[0])
		return;

	if (strcmp(blobmsg_data(data[0]), "success") != 0)
		return;

	if (remove(WIFI_DMMAP_PATH))
		return;

	// Create WiFi dmmap
	init_wifi_legacy_module(NULL);
}

static struct ubus_event_handler map_agent_event_handler = { .cb = on_map_agent_event_cb };

int init_wifi_legacy_module(void *data)
{
	struct bbfdm_context *bbfdm_ctx = (struct bbfdm_context *)data;
	struct dmctx bbf_ctx = {0};

	if (!bbfdm_wifimngr)
		return 0;

	if (bbfdm_ctx) {
		ubus_register_event_handler(bbfdm_ctx->ubus_ctx, &map_agent_event_handler, "map.agent");
	}

	fill_wifi_mesh_capability();

	bbfdm_create_empty_file(WIFI_DMMAP_PATH);

	bbf_ctx_init(&bbf_ctx, NULL);

	dmmap_synchronize_WiFi_Legacy(&bbf_ctx);

	dmuci_commit_package_bbfdm("WiFi");

	bbf_ctx_clean(&bbf_ctx);

	return 0;
}

int clean_wifi_legacy_module(void *data)
{
	struct bbfdm_context *bbfdm_ctx = (struct bbfdm_context *)data;

	if (bbfdm_ctx) {
		ubus_unregister_event_handler(bbfdm_ctx->ubus_ctx, &map_agent_event_handler);
	}

	return 0;
}

int sync_wifi_module(void *data)
{
	BBF_INFO("Syncing wifi configurations");

	struct bbfdm_context *bbfdm_ctx = (struct bbfdm_context *)data;
	if (!bbfdm_ctx || !bbfdm_wifimngr)
		return 0;

	// If uci is changed externally and only wireless is modified then
	// just do uci to dmmap sync, otherwise rewrite dmmap with changed UCIs
	if (DM_STRCMP(bbfdm_ctx->uci_change_proto, "external") == 0 && !list_empty(&bbfdm_ctx->changed_uci)) {
		bool mapcont_uci = false;

		struct apply_handler_node *node = NULL;
		list_for_each_entry(node, &bbfdm_ctx->changed_uci, list) {
			if (DM_STRCMP(node->file_path, "/etc/config/mapcontroller") == 0) {
				mapcont_uci = true;
				break;
			}
		}

		if (mapcont_uci == true) {
			// Remove dmmap file WiFi and sync
			FILE *fp = fopen(WIFI_DMMAP_PATH, "w"); // empty file
			if (fp) {
				fclose(fp);
			}

			fill_wifi_mesh_capability();
		}

		// Sync WiFi dmmap
		init_wifi_legacy_module(NULL);
	}

	BBF_DEBUG("mapcontroller: %d, mld: %d", easymesh_enable, mld_capable);
	return 0;
}

/**********************************************************************************************************************************
*                                            OBJ & LEAF DEFINITION
***********************************************************************************************************************************/
/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7APRole.EMLMRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7APRole.EMLSRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7APRole.STRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7APRole.NSTRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7APRole. *** */
DMOBJ tWiFiRadioCapabilitiesWiFi7APRoleObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys */
{"EMLMRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7APRoleEMLMRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{"EMLSRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7APRoleEMLSRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{"STRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7APRoleSTRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{"NSTRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7APRoleNSTRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiRadioCapabilitiesWiFi7APRoleParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"EMLMRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7APRole_EMLMRSupport, NULL, BBFDM_BOTH},
{"EMLSRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7APRole_EMLSRSupport, NULL, BBFDM_BOTH},
{"STRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7APRole_STRSupport, NULL, BBFDM_BOTH},
{"NSTRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7APRole_NSTRSupport, NULL, BBFDM_BOTH},
{"TIDLinkMapNegotiation", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7APRole_TIDLinkMapNegotiation, NULL, BBFDM_BOTH},
{"EMLMRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRole_EMLMRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{"EMLSRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRole_EMLSRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{"STRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRole_STRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{"NSTRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7APRole_NSTRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7STARole.EMLMRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7STARole.EMLSRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7STARole.STRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7STARole.NSTRFreqSeparation.{i}. *** */
DMLEAF tWiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparationParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"RUID", &DMREAD, DMT_BASE64, get_WiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparation_RUID, NULL, BBFDM_BOTH},
{"FreqSeparation", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparation_FreqSeparation, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities.WiFi7STARole. *** */
DMOBJ tWiFiRadioCapabilitiesWiFi7STARoleObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys */
{"EMLMRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7STARoleEMLMRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{"EMLSRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7STARoleEMLSRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{"STRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7STARoleSTRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{"NSTRFreqSeparation", &DMREAD, NULL, NULL, NULL, browseWiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparationInst, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7STARoleNSTRFreqSeparationParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiRadioCapabilitiesWiFi7STARoleParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
{"EMLMRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7STARole_EMLMRSupport, NULL, BBFDM_BOTH},
{"EMLSRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7STARole_EMLSRSupport, NULL, BBFDM_BOTH},
{"STRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7STARole_STRSupport, NULL, BBFDM_BOTH},
{"NSTRSupport", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7STARole_NSTRSupport, NULL, BBFDM_BOTH},
{"TIDLinkMapNegotiation", &DMREAD, DMT_BOOL, get_WiFiRadioCapabilitiesWiFi7STARole_TIDLinkMapNegotiation, NULL, BBFDM_BOTH},
{"EMLMRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARole_EMLMRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{"EMLSRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARole_EMLSRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{"STRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARole_STRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{"NSTRFreqSeparationNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiRadioCapabilitiesWiFi7STARole_NSTRFreqSeparationNumberOfEntries, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}.Capabilities. *** */
DMOBJ tWiFiRadioCapabilitiesObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys */
{"WiFi7APRole", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7APRoleObj, tWiFiRadioCapabilitiesWiFi7APRoleParams, NULL, BBFDM_BOTH, NULL},
{"WiFi7STARole", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiRadioCapabilitiesWiFi7STARoleObj, tWiFiRadioCapabilitiesWiFi7STARoleParams, NULL, BBFDM_BOTH, NULL},
{0}
};

/* *** Device.WiFi.Radio.{i}.Stats. *** */
DMLEAF tWiFiRadioStatsParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Noise", &DMREAD, DMT_INT, get_WiFiRadioStats_Noise, NULL, BBFDM_BOTH},
{"BytesSent", &DMREAD, DMT_UNLONG, get_WiFiRadioStats_BytesSent, NULL, BBFDM_BOTH},
{"BytesReceived", &DMREAD, DMT_UNLONG, get_WiFiRadioStats_BytesReceived, NULL, BBFDM_BOTH},
{"PacketsSent", &DMREAD, DMT_UNLONG, get_WiFiRadioStats_PacketsSent, NULL, BBFDM_BOTH},
{"PacketsReceived", &DMREAD, DMT_UNLONG, get_WiFiRadioStats_PacketsReceived, NULL, BBFDM_BOTH},
{"ErrorsSent", &DMREAD, DMT_UNINT, get_WiFiRadioStats_ErrorsSent, NULL, BBFDM_BOTH},
{"ErrorsReceived", &DMREAD, DMT_UNINT, get_WiFiRadioStats_ErrorsReceived, NULL, BBFDM_BOTH},
{"DiscardPacketsSent", &DMREAD, DMT_UNINT, get_WiFiRadioStats_DiscardPacketsSent, NULL, BBFDM_BOTH},
{"DiscardPacketsReceived", &DMREAD, DMT_UNINT, get_WiFiRadioStats_DiscardPacketsReceived, NULL, BBFDM_BOTH},
{"FCSErrorCount", &DMREAD, DMT_UNINT, get_WiFiRadioStats_FCSErrorCount, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.Radio.{i}. *** */
DMOBJ tWiFiRadioObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiRadioStatsParams, NULL, BBFDM_BOTH, NULL},
{"Capabilities", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiRadioCapabilitiesObj, NULL, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiRadioParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Alias", &DMWRITE, DMT_STRING, get_WiFi_Alias, set_WiFi_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"Enable", &DMWRITE, DMT_BOOL, get_WiFiRadio_Enable, set_WiFiRadio_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_WiFiRadio_Status, NULL, BBFDM_BOTH},
{"LowerLayers", &DMWRITE, DMT_STRING, get_WiFiRadio_LowerLayers, set_WiFiRadio_LowerLayers, BBFDM_BOTH},
{"Name", &DMREAD, DMT_STRING, get_WiFiRadio_Name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER},
{"MaxBitRate", &DMREAD, DMT_UNINT, get_WiFiRadio_MaxBitRate, NULL, BBFDM_BOTH},
{"SupportedFrequencyBands", &DMREAD, DMT_STRING, get_WiFiRadio_SupportedFrequencyBands, NULL, BBFDM_BOTH},
{"OperatingFrequencyBand", &DMWRITE, DMT_STRING, get_WiFiRadio_OperatingFrequencyBand, set_WiFiRadio_OperatingFrequencyBand, BBFDM_BOTH},
{"SupportedStandards", &DMREAD, DMT_STRING, get_WiFiRadio_SupportedStandards, NULL, BBFDM_BOTH},
{"OperatingStandards", &DMWRITE, DMT_STRING, get_WiFiRadio_OperatingStandards, set_WiFiRadio_OperatingStandards, BBFDM_BOTH},
{"AutoChannelEnable", &DMWRITE, DMT_BOOL, get_WiFiRadio_AutoChannelEnable, set_WiFiRadio_AutoChannelEnable, BBFDM_BOTH},
{"PossibleChannels", &DMREAD, DMT_STRING, get_WiFiRadio_PossibleChannels, NULL, BBFDM_BOTH},
{"ChannelsInUse", &DMREAD, DMT_STRING, get_WiFiRadio_ChannelsInUse, NULL, BBFDM_BOTH},
{"Channel", &DMWRITE, DMT_UNINT, get_WiFiRadio_Channel, set_WiFiRadio_Channel, BBFDM_BOTH},
{"AutoChannelSupported", &DMREAD, DMT_BOOL, get_WiFiRadio_AutoChannelSupported, NULL, BBFDM_BOTH},
{"AutoChannelRefreshPeriod", &DMWRITE, DMT_UNINT, get_WiFiRadio_AutoChannelRefreshPeriod, set_WiFiRadio_AutoChannelRefreshPeriod, BBFDM_BOTH},
{"MaxSupportedSSIDs", &DMREAD, DMT_UNINT, get_WiFiRadio_MaxSupportedSSIDs, NULL, BBFDM_BOTH},
{"MaxSupportedAssociations", &DMREAD, DMT_UNINT, get_WiFiRadio_MaxSupportedAssociations, NULL, BBFDM_BOTH},
{"FragmentationThreshold", &DMWRITE, DMT_UNINT, get_WiFiRadio_FragmentationThreshold, set_WiFiRadio_FragmentationThreshold, BBFDM_BOTH},
{"RTSThreshold", &DMWRITE, DMT_UNINT, get_WiFiRadio_RTSThreshold, set_WiFiRadio_RTSThreshold, BBFDM_BOTH},
{"BeaconPeriod", &DMWRITE, DMT_UNINT, get_WiFiRadio_BeaconPeriod, set_WiFiRadio_BeaconPeriod, BBFDM_BOTH},
{"DTIMPeriod", &DMWRITE, DMT_UNINT, get_WiFiRadio_DTIMPeriod, set_WiFiRadio_DTIMPeriod, BBFDM_BOTH},
{"SupportedOperatingChannelBandwidths", &DMREAD, DMT_STRING, get_WiFiRadio_SupportedOperatingChannelBandwidths, NULL, BBFDM_BOTH},
{"OperatingChannelBandwidth", &DMWRITE, DMT_STRING, get_WiFiRadio_OperatingChannelBandwidth, set_WiFiRadio_OperatingChannelBandwidth, BBFDM_BOTH},
{"CurrentOperatingChannelBandwidth", &DMREAD, DMT_STRING, get_WiFiRadio_CurrentOperatingChannelBandwidth, NULL, BBFDM_BOTH},
{"PreambleType", &DMWRITE, DMT_STRING, get_WiFiRadio_PreambleType, set_WiFiRadio_PreambleType, BBFDM_BOTH},
{"IEEE80211hSupported", &DMREAD, DMT_BOOL, get_WiFiRadio_IEEE80211hSupported, NULL, BBFDM_BOTH},
{"IEEE80211hEnabled", &DMWRITE, DMT_BOOL, get_WiFiRadio_IEEE80211hEnabled, set_WiFiRadio_IEEE80211hEnabled, BBFDM_BOTH},
{"TransmitPowerSupported", &DMREAD, DMT_STRING, get_WiFiRadio_TransmitPowerSupported, NULL, BBFDM_BOTH},
{"TransmitPower", &DMWRITE, DMT_INT, get_WiFiRadio_TransmitPower, set_WiFiRadio_TransmitPower, BBFDM_BOTH},
{"RegulatoryDomain", &DMWRITE, DMT_STRING, get_WiFiRadio_RegulatoryDomain, set_WiFiRadio_RegulatoryDomain, BBFDM_BOTH},
{"CenterFrequencySegment0", &DMREAD, DMT_UNINT, get_WiFiRadio_CenterFrequencySegment0, NULL, BBFDM_BOTH},
{"CenterFrequencySegment1", &DMREAD, DMT_UNINT, get_WiFiRadio_CenterFrequencySegment1, NULL, BBFDM_BOTH},
{"ConfiguredReceiveAntennas", &DMWRITE, DMT_INT, get_WiFiRadio_ConfiguredReceiveAntennas, set_WiFiRadio_ConfiguredReceiveAntennas, BBFDM_BOTH},
{"ConfiguredTransmitAntennas", &DMWRITE, DMT_INT, get_WiFiRadio_ConfiguredTransmitAntennas, set_WiFiRadio_ConfiguredTransmitAntennas, BBFDM_BOTH},
{"SupportedReceiveAntennas", &DMREAD, DMT_INT, get_WiFiRadio_SupportedReceiveAntennas, NULL, BBFDM_BOTH},
{"SupportedTransmitAntennas", &DMREAD, DMT_INT, get_WiFiRadio_SupportedTransmitAntennas, NULL, BBFDM_BOTH},
{"ActiveReceiveAntennas", &DMREAD, DMT_INT, get_WiFiRadio_ActiveReceiveAntennas, NULL, BBFDM_BOTH},
{"ActiveTransmitAntennas", &DMREAD, DMT_INT, get_WiFiRadio_ActiveTransmitAntennas, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.SSID.{i}.Stats. *** */
DMLEAF tWiFiSSIDStatsParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"BytesSent", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_BytesSent, NULL, BBFDM_BOTH},
{"BytesReceived", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_BytesReceived, NULL, BBFDM_BOTH},
{"PacketsSent", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_PacketsSent, NULL, BBFDM_BOTH},
{"PacketsReceived", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_PacketsReceived, NULL, BBFDM_BOTH},
{"ErrorsSent", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_ErrorsSent, NULL, BBFDM_BOTH},
{"RetransCount", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_RetransCount, NULL, BBFDM_BOTH},
{"FailedRetransCount", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_FailedRetransCount, NULL, BBFDM_BOTH},
{"RetryCount", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_RetryCount, NULL, BBFDM_BOTH},
{"MultipleRetryCount", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_MultipleRetryCount, NULL, BBFDM_BOTH},
{"ACKFailureCount", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_ACKFailureCount, NULL, BBFDM_BOTH},
{"AggregatedPacketCount", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_AggregatedPacketCount, NULL, BBFDM_BOTH},
{"ErrorsReceived", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_ErrorsReceived, NULL, BBFDM_BOTH},
{"UnicastPacketsSent", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_UnicastPacketsSent, NULL, BBFDM_BOTH},
{"UnicastPacketsReceived", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_UnicastPacketsReceived, NULL, BBFDM_BOTH},
{"DiscardPacketsSent", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_DiscardPacketsSent, NULL, BBFDM_BOTH},
{"DiscardPacketsReceived", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_DiscardPacketsReceived, NULL, BBFDM_BOTH},
{"MulticastPacketsSent", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_MulticastPacketsSent, NULL, BBFDM_BOTH},
{"MulticastPacketsReceived", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_MulticastPacketsReceived, NULL, BBFDM_BOTH},
{"BroadcastPacketsSent", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_BroadcastPacketsSent, NULL, BBFDM_BOTH},
{"BroadcastPacketsReceived", &DMREAD, DMT_UNLONG, get_WiFiSSIDStats_BroadcastPacketsReceived, NULL, BBFDM_BOTH},
{"UnknownProtoPacketsReceived", &DMREAD, DMT_UNINT, get_WiFiSSIDStats_UnknownProtoPacketsReceived, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.SSID.{i}. *** */
DMOBJ tWiFiSSIDObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiSSIDStatsParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiSSIDParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Alias", &DMWRITE, DMT_STRING, get_WiFi_Alias, set_WiFi_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"Enable", &DMWRITE, DMT_BOOL, get_WiFiSSID_Enable, set_WiFiSSID_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_WiFiSSID_Status, NULL, BBFDM_BOTH},
{"SSID", &DMWRITE, DMT_STRING, get_WiFiSSID_SSID, set_WiFiSSID_SSID, BBFDM_BOTH},
{"MLDUnit", &DMWRITE, DMT_INT, get_WiFiSSID_MLDUnit, set_WiFiSSID_MLDUnit, BBFDM_BOTH},
{"Name", &DMREAD, DMT_STRING,  get_WiFiSSID_Name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER},
{"LowerLayers", &DMWRITE, DMT_STRING, get_WiFiSSID_LowerLayers, set_WiFiSSID_LowerLayers, BBFDM_BOTH, DM_FLAG_REFERENCE},
{"BSSID", &DMREAD, DMT_STRING, get_WiFiSSID_BSSID, NULL, BBFDM_BOTH},
{"MACAddress", &DMREAD, DMT_STRING, get_WiFiSSID_MACAddress, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.AccessPoint.{i}.Security. *** */
DMLEAF tWiFiAccessPointSecurityParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"ModesSupported", &DMREAD, DMT_STRING, get_WiFiAccessPointSecurity_ModesSupported, NULL, BBFDM_BOTH},
{"ModeEnabled", &DMWRITE, DMT_STRING, get_WiFiAccessPointSecurity_ModeEnabled, set_WiFiAccessPointSecurity_ModeEnabled, BBFDM_BOTH},
{"EncryptionMode", &DMREAD, DMT_STRING, get_WiFiAccessPointSecurity_EncryptionMode, NULL, BBFDM_BOTH},
{"WEPKey", &DMWRITE, DMT_HEXBIN, get_WiFiAccessPointSecurity_WEPKey, set_WiFiAccessPointSecurity_WEPKey, BBFDM_BOTH, DM_FLAG_SECURE},
{"PreSharedKey", &DMWRITE, DMT_HEXBIN, get_WiFiAccessPointSecurity_PreSharedKey, set_WiFiAccessPointSecurity_PreSharedKey, BBFDM_BOTH, DM_FLAG_SECURE},
{"KeyPassphrase", &DMWRITE, DMT_STRING, get_WiFiAccessPointSecurity_KeyPassphrase, set_WiFiAccessPointSecurity_KeyPassphrase, BBFDM_BOTH, DM_FLAG_SECURE},
{"RekeyingInterval", &DMWRITE, DMT_UNINT, get_WiFiAccessPointSecurity_RekeyingInterval, set_WiFiAccessPointSecurity_RekeyingInterval, BBFDM_BOTH},
{"SAEPassphrase", &DMWRITE, DMT_STRING, get_WiFiAccessPointSecurity_SAEPassphrase, set_WiFiAccessPointSecurity_SAEPassphrase, BBFDM_BOTH, DM_FLAG_SECURE},
{"RadiusServerIPAddr", &DMWRITE, DMT_STRING, get_WiFiAccessPointSecurity_RadiusServerIPAddr, set_WiFiAccessPointSecurity_RadiusServerIPAddr, BBFDM_BOTH},
{"RadiusServerPort", &DMWRITE, DMT_UNINT, get_WiFiAccessPointSecurity_RadiusServerPort, set_WiFiAccessPointSecurity_RadiusServerPort, BBFDM_BOTH},
{"RadiusSecret", &DMWRITE, DMT_STRING, get_WiFiAccessPointSecurity_RadiusSecret, set_WiFiAccessPointSecurity_RadiusSecret, BBFDM_BOTH, DM_FLAG_SECURE},
{"MFPConfig", &DMWRITE, DMT_STRING, get_WiFiAccessPointSecurity_MFPConfig, set_WiFiAccessPointSecurity_MFPConfig, BBFDM_BOTH},
{"Reset()", &DMSYNC, DMT_COMMAND, NULL, operate_WiFiAccessPointSecurity_Reset, BBFDM_USP},
{0}
};

/* *** Device.WiFi.AccessPoint.{i}.AssociatedDevice.{i}.Stats. *** */
DMLEAF tWiFiAccessPointAssociatedDeviceStatsParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"BytesSent", &DMREAD, DMT_UNLONG, get_WiFiAccessPointAssociatedDeviceStats_BytesSent, NULL, BBFDM_BOTH},
{"BytesReceived", &DMREAD, DMT_UNLONG, get_WiFiAccessPointAssociatedDeviceStats_BytesReceived, NULL, BBFDM_BOTH},
{"PacketsSent", &DMREAD, DMT_UNLONG, get_WiFiAccessPointAssociatedDeviceStats_PacketsSent, NULL, BBFDM_BOTH},
{"PacketsReceived", &DMREAD, DMT_UNLONG, get_WiFiAccessPointAssociatedDeviceStats_PacketsReceived, NULL, BBFDM_BOTH},
{"ErrorsSent", &DMREAD, DMT_UNINT, get_WiFiAccessPointAssociatedDeviceStats_ErrorsSent, NULL, BBFDM_BOTH},
{"ErrorsReceived", &DMREAD, DMT_UNINT, get_WiFiAccessPointAssociatedDeviceStats_ErrorsReceived, NULL, BBFDM_BOTH},
{"RetransCount", &DMREAD, DMT_UNINT, get_WiFiAccessPointAssociatedDeviceStats_RetransCount, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.AccessPoint.{i}.AssociatedDevice.{i}. *** */
DMOBJ tWiFiAccessPointAssociatedDeviceObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiAccessPointAssociatedDeviceStatsParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiAccessPointAssociatedDeviceParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Active", &DMREAD, DMT_BOOL, get_WiFiAccessPointAssociatedDevice_Active, NULL, BBFDM_BOTH},
{"Noise", &DMREAD, DMT_INT, get_WiFiAccessPointAssociatedDevice_Noise, NULL, BBFDM_BOTH},
{"SNR", &DMREAD, DMT_UNINT, get_WiFiAccessPointAssociatedDevice_SNR, NULL, BBFDM_BOTH},
{"MACAddress", &DMREAD, DMT_STRING, get_WiFiAccessPointAssociatedDevice_MACAddress, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER},
{"OperatingStandard", &DMREAD, DMT_STRING, get_WiFiAccessPointAssociatedDevice_OperatingStandard, NULL, BBFDM_BOTH},
{"LastDataDownlinkRate", &DMREAD, DMT_UNINT, get_WiFiAccessPointAssociatedDevice_LastDataDownlinkRate, NULL, BBFDM_BOTH},
{"LastDataUplinkRate", &DMREAD, DMT_UNINT, get_WiFiAccessPointAssociatedDevice_LastDataUplinkRate, NULL, BBFDM_BOTH},
{"SignalStrength", &DMREAD, DMT_INT, get_WiFiAccessPointAssociatedDevice_SignalStrength, NULL, BBFDM_BOTH},
{"AssociationTime", &DMREAD, DMT_TIME, get_WiFiAccessPointAssociatedDevice_AssociationTime, NULL, BBFDM_BOTH},
#ifdef WIFIMNGR_VENDOR_EXTENSIONS
{BBF_VENDOR_PREFIX"QoERating", &DMREAD, DMT_STRING, get_WiFiAccessPointAssociatedDevice_QoERating, NULL, BBFDM_BOTH},
#endif
{0}
};

/* *** Device.WiFi.AccessPoint.{i}.WPS. *** */
DMLEAF tWiFiAccessPointWPSParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_WiFiAccessPointWPS_Enable, set_WiFiAccessPointWPS_Enable, BBFDM_BOTH},
{"ConfigMethodsSupported", &DMREAD, DMT_STRING, get_WiFiAccessPointWPS_ConfigMethodsSupported, NULL, BBFDM_BOTH},
{"ConfigMethodsEnabled", &DMWRITE, DMT_STRING, get_WiFiAccessPointWPS_ConfigMethodsEnabled, set_WiFiAccessPointWPS_ConfigMethodsEnabled, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_WiFiAccessPointWPS_Status, NULL, BBFDM_BOTH},
{"InitiateWPSPBC()", &DMASYNC, DMT_COMMAND, get_operate_args_WiFiAccessPointWPS_InitiateWPSPBC, operate_WiFiAccessPointWPS_InitiateWPSPBC, BBFDM_USP},
{0}
};

/* *** Device.WiFi.AccessPoint.{i}.Accounting. *** */
DMLEAF tWiFiAccessPointAccountingParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"ServerIPAddr", &DMWRITE, DMT_STRING, get_WiFiAccessPointAccounting_ServerIPAddr, set_WiFiAccessPointAccounting_ServerIPAddr, BBFDM_BOTH},
{"ServerPort", &DMWRITE, DMT_UNINT, get_WiFiAccessPointAccounting_ServerPort, set_WiFiAccessPointAccounting_ServerPort, BBFDM_BOTH},
{"Secret", &DMWRITE, DMT_STRING, get_WiFiAccessPointAccounting_Secret, set_WiFiAccessPointAccounting_Secret, BBFDM_BOTH, DM_FLAG_SECURE},
{0}
};

/* *** Device.WiFi.AccessPoint.{i}. *** */
DMOBJ tWiFiAccessPointObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiAccessPointSecurityParams, NULL, BBFDM_BOTH, NULL},
{"AssociatedDevice", &DMREAD, NULL, NULL, NULL, browse_wifi_associated_device, NULL, NULL, tWiFiAccessPointAssociatedDeviceObj, tWiFiAccessPointAssociatedDeviceParams, NULL, BBFDM_BOTH, NULL},
{"WPS", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiAccessPointWPSParams, NULL, BBFDM_BOTH, NULL},
{"Accounting", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiAccessPointAccountingParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiAccessPointParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Alias", &DMWRITE, DMT_STRING, get_WiFi_Alias, set_WiFi_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"Enable", &DMWRITE, DMT_BOOL,  get_WiFiAccessPoint_Enable, set_WiFiAccessPoint_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_WiFiAccessPoint_Status, NULL, BBFDM_BOTH},
{"SSIDReference", &DMWRITE, DMT_STRING, get_WiFiAccessPoint_SSIDReference, set_WiFiAccessPoint_SSIDReference, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_REFERENCE},
{"SSIDAdvertisementEnabled", &DMWRITE, DMT_BOOL, get_WiFiAccessPoint_SSIDAdvertisementEnabled, set_WiFiAccessPoint_SSIDAdvertisementEnabled, BBFDM_BOTH},
{"WMMEnable", &DMWRITE, DMT_BOOL, get_WiFiAccessPoint_WMMEnable, set_WiFiAccessPoint_WMMEnable, BBFDM_BOTH},
{"UAPSDCapability", &DMREAD, DMT_BOOL, get_WiFiAccessPoint_UAPSDCapability, NULL, BBFDM_BOTH},
{"UAPSDEnable", &DMWRITE, DMT_BOOL, get_WiFiAccessPoint_UAPSDEnable, set_WiFiAccessPoint_UAPSDEnable, BBFDM_BOTH},
{"MACAddressControlEnabled", &DMWRITE, DMT_BOOL, get_WiFiAccessPoint_MACAddressControlEnabled, set_WiFiAccessPoint_MACAddressControlEnabled, BBFDM_BOTH},
{"WMMCapability", &DMREAD, DMT_BOOL, get_WiFiAccessPoint_WMMCapability, NULL, BBFDM_BOTH},
{"MaxAllowedAssociations", &DMWRITE, DMT_UNINT, get_WiFiAccessPoint_MaxAllowedAssociations, set_WiFiAccessPoint_MaxAllowedAssociations, BBFDM_BOTH},
{"IsolationEnable", &DMWRITE, DMT_BOOL, get_WiFiAccessPoint_IsolationEnable, set_WiFiAccessPoint_IsolationEnable, BBFDM_BOTH},
{"AllowedMACAddress", &DMWRITE, DMT_STRING, get_WiFiAccessPoint_AllowedMACAddress, set_WiFiAccessPoint_AllowedMACAddress, BBFDM_BOTH},
#ifdef WIFIMNGR_VENDOR_EXTENSIONS
{BBF_VENDOR_PREFIX"MultiAPMode", &DMWRITE, DMT_UNINT, get_WiFiAccessPoint_MultiAPMode, set_WiFiAccessPoint_MultiAPMode, BBFDM_BOTH},
#endif
{"AssociatedDeviceNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiAccessPoint_AssociatedDeviceNumberOfEntries, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.NeighboringWiFiDiagnostic.Result.{i}. *** */
DMLEAF tWiFiNeighboringWiFiDiagnosticResultParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Radio", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_Radio, NULL, BBFDM_CWMP},
{"SSID", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_SSID, NULL, BBFDM_CWMP},
{"BSSID", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_BSSID, NULL, BBFDM_CWMP},
{"Channel", &DMREAD, DMT_UNINT, get_WiFiNeighboringWiFiDiagnosticResult_Channel, NULL, BBFDM_CWMP},
{"SignalStrength", &DMREAD, DMT_INT, get_WiFiNeighboringWiFiDiagnosticResult_SignalStrength, NULL, BBFDM_CWMP},
{"OperatingFrequencyBand", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_OperatingFrequencyBand, NULL, BBFDM_CWMP},
{"OperatingChannelBandwidth", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_OperatingChannelBandwidth, NULL, BBFDM_CWMP},
{"OperatingStandards", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_OperatingStandards, NULL, BBFDM_CWMP},
{"SecurityModeEnabled", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_SecurityModeEnabled, NULL, BBFDM_CWMP},
{"EncryptionMode", &DMREAD, DMT_STRING, get_WiFiNeighboringWiFiDiagnosticResult_EncryptionMode, NULL, BBFDM_CWMP},
{0}
};

/* *** Device.WiFi.NeighboringWiFiDiagnostic. *** */
DMOBJ tWiFiNeighboringWiFiDiagnosticObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Result", &DMREAD, NULL, NULL, NULL, browseWifiNeighboringWiFiDiagnosticResultInst, NULL, NULL, NULL, tWiFiNeighboringWiFiDiagnosticResultParams, NULL, BBFDM_CWMP, NULL},
{0}
};

DMLEAF tWiFiNeighboringWiFiDiagnosticParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"DiagnosticsState", &DMWRITE, DMT_STRING, get_WiFiNeighboringWiFiDiagnostic_DiagnosticsState, set_WiFiNeighboringWiFiDiagnostic_DiagnosticsState, BBFDM_CWMP},
{"ResultNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiNeighboringWiFiDiagnostic_ResultNumberOfEntries, NULL, BBFDM_CWMP},
{0}
};

/* *** Device.WiFi.EndPoint.{i}.Stats. *** */
DMLEAF tWiFiEndPointStatsParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"LastDataDownlinkRate", &DMREAD, DMT_UNINT, get_WiFiEndPointStats_LastDataDownlinkRate, NULL, BBFDM_BOTH},
{"LastDataUplinkRate", &DMREAD, DMT_UNINT, get_WiFiEndPointStats_LastDataUplinkRate, NULL, BBFDM_BOTH},
{"SignalStrength", &DMREAD, DMT_INT, get_WiFiEndPointStats_SignalStrength, NULL, BBFDM_BOTH},
{"Retransmissions", &DMREAD, DMT_UNINT, get_WiFiEndPointStats_Retransmissions, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.EndPoint.{i}.Security. *** */
DMLEAF tWiFiEndPointSecurityParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"ModesSupported", &DMREAD, DMT_STRING, get_WiFiEndPointSecurity_ModesSupported, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.EndPoint.{i}.Profile.{i}.Security. *** */
DMLEAF tWiFiEndPointProfileSecurityParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"ModeEnabled", &DMWRITE, DMT_STRING, get_WiFiEndPointProfileSecurity_ModeEnabled, set_WiFiEndPointProfileSecurity_ModeEnabled, BBFDM_BOTH},
{"WEPKey", &DMWRITE, DMT_HEXBIN, get_WiFiEndPointProfileSecurity_WEPKey, set_WiFiEndPointProfileSecurity_WEPKey, BBFDM_BOTH, DM_FLAG_SECURE},
{"PreSharedKey", &DMWRITE, DMT_HEXBIN, get_WiFiEndPointProfileSecurity_PreSharedKey, set_WiFiEndPointProfileSecurity_PreSharedKey, BBFDM_BOTH, DM_FLAG_SECURE},
{"KeyPassphrase", &DMWRITE, DMT_STRING, get_WiFiEndPointProfileSecurity_KeyPassphrase, set_WiFiEndPointProfileSecurity_KeyPassphrase, BBFDM_BOTH, DM_FLAG_SECURE},
{"SAEPassphrase", &DMWRITE, DMT_STRING, get_WiFiEndPointProfileSecurity_SAEPassphrase, set_WiFiEndPointProfileSecurity_SAEPassphrase, BBFDM_BOTH, DM_FLAG_SECURE},
{"MFPConfig", &DMWRITE, DMT_STRING, get_WiFiEndPointProfileSecurity_MFPConfig, set_WiFiEndPointProfileSecurity_MFPConfig, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.EndPoint.{i}.Profile.{i}. *** */
DMOBJ tWiFiEndPointProfileObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiEndPointProfileSecurityParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiEndPointProfileParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_WiFiEndPointProfile_Enable, set_WiFiEndPointProfile_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_WiFiEndPointProfile_Status, NULL, BBFDM_BOTH},
{"SSID", &DMWRITE, DMT_STRING, get_WiFiEndPointProfile_SSID, set_WiFiEndPointProfile_SSID, BBFDM_BOTH, DM_FLAG_UNIQUE},
{0}
};

/* *** Device.WiFi.EndPoint.{i}.WPS. *** */
DMLEAF tWiFiEndPointWPSParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_WiFiEndPointWPS_Enable, set_WiFiEndPointWPS_Enable, BBFDM_BOTH},
{"ConfigMethodsSupported", &DMREAD, DMT_STRING, get_WiFiEndPointWPS_ConfigMethodsSupported, NULL, BBFDM_BOTH},
{"ConfigMethodsEnabled", &DMWRITE, DMT_STRING, get_WiFiEndPointWPS_ConfigMethodsEnabled, set_WiFiEndPointWPS_ConfigMethodsEnabled, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_WiFiEndPointWPS_Status, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi.EndPoint.{i}. *** */
DMOBJ tWiFiEndPointObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiEndPointStatsParams, NULL, BBFDM_BOTH, NULL},
{"Security", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiEndPointSecurityParams, NULL, BBFDM_BOTH, NULL},
{"Profile", &DMREAD, NULL, NULL, NULL, browseWiFiEndPointProfileInst, NULL, NULL, tWiFiEndPointProfileObj, tWiFiEndPointProfileParams, NULL, BBFDM_BOTH, NULL},
{"WPS", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiEndPointWPSParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiEndPointParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_WiFiEndPoint_Enable, set_WiFiEndPoint_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_WiFiEndPoint_Status, NULL, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_WiFi_Alias, set_WiFi_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"ProfileNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFiEndPoint_ProfileNumberOfEntries, NULL, BBFDM_BOTH},
{0}
};

/* *** Device.WiFi. *** */
DMOBJ tWiFiObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Radio", &DMREAD, NULL, NULL, NULL, browseWiFiRadioInst, NULL, NULL, tWiFiRadioObj, tWiFiRadioParams, NULL, BBFDM_BOTH, NULL},
{"SSID", &DMWRITE, addObjWiFiSSID, delObjWiFiSSID, NULL, browseWiFiSSIDInst, NULL, NULL, tWiFiSSIDObj, tWiFiSSIDParams, NULL, BBFDM_BOTH, NULL},
{"AccessPoint", &DMWRITE, addObjWiFiAccessPoint, delObjWiFiAccessPoint, NULL, browseWiFiAccessPointInst, NULL, NULL, tWiFiAccessPointObj, tWiFiAccessPointParams, NULL, BBFDM_BOTH, NULL},
{"NeighboringWiFiDiagnostic", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tWiFiNeighboringWiFiDiagnosticObj, tWiFiNeighboringWiFiDiagnosticParams, NULL, BBFDM_BOTH, NULL},
{"EndPoint", &DMWRITE, addObjWiFiEndPoint, delObjWiFiEndPoint, NULL, browseWiFiEndPointInst, NULL, NULL, tWiFiEndPointObj, tWiFiEndPointParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tWiFiParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"RadioNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFi_RadioNumberOfEntries, NULL, BBFDM_BOTH},
{"SSIDNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFi_SSIDNumberOfEntries, NULL, BBFDM_BOTH},
{"AccessPointNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFi_AccessPointNumberOfEntries, NULL, BBFDM_BOTH},
{"EndPointNumberOfEntries", &DMREAD, DMT_UNINT, get_WiFi_EndPointNumberOfEntries, NULL, BBFDM_BOTH},
{"Reset()", &DMSYNC, DMT_COMMAND, NULL, operate_WiFi_Reset, BBFDM_USP},
{"NeighboringWiFiDiagnostic()", &DMASYNC, DMT_COMMAND, get_operate_args_WiFi_NeighboringWiFiDiagnostic, operate_WiFi_NeighboringWiFiDiagnostic, BBFDM_USP},
{0}
};

/* *** Device. *** */
DMOBJ tDeviceWiFiObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"WiFi", &DMREAD, NULL, NULL, "dir:/sys/class/ieee80211", NULL, NULL, NULL, tWiFiObj, tWiFiParams, NULL, BBFDM_BOTH, NULL},
{0}
};

/* ********** DynamicObj ********** */
DM_MAP_OBJ tDynamicObj[] = {
/* parentobj, nextobject, parameter */
{"Device.", tDeviceWiFiObj, NULL, init_wifi_legacy_module, clean_wifi_legacy_module, sync_wifi_module},
{0}
};
