/*
 * Copyright (C) 2024 iopsys Software Solutions AB
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 *		Author: Amin Ben Romdhane <amin.benromdhane@iopsys.eu>
 *
 */

#include "libbbfdm-api/dmcommon.h"

#include "../common/common.h"

struct bridge_port_type_map
{
	char *port_type;
	char *dev_type;
} bridge_port_type_map [] = {
	{ "CustomerNetworkPort",  "8021ad" },
	{ "CustomerVLANPort",      "8021q" },
	{ "CustomerVLANPort",   "untagged" },
	{ "CustomerVLANPort",           "" },
	{ "VLANUnawarePort", "transparent" },
	{ NULL,                       NULL }
};

static void ip___update_child_interfaces(const char *device, const char *option_name, const char *option_value)
{
	struct uci_section *s = NULL;

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

	uci_foreach_option_eq("network", "interface", "device", device, s) {
		dmuci_set_value_by_section(s, option_name, option_value);
	}
}

static void ip___Update_IP_Interface_Layer(const char *path, const char *linker)
{
	struct uci_section *dmmap_s = NULL;

	uci_path_foreach_option_eq(bbfdm, "dmmap_network", "interface", "LowerLayers", path, dmmap_s) {
		struct uci_section *iface_s = NULL;
		char *sec_name = NULL;
		char *instance = NULL;
		char *curr_device = NULL;

		dmuci_get_value_by_section_string(dmmap_s, "ip_int_instance", &instance);
		if (!DM_STRLEN(instance))
			continue;

		dmuci_get_value_by_section_string(dmmap_s, "section_name", &sec_name);
		if (!DM_STRLEN(sec_name))
			continue;

		iface_s = get_origin_section_from_config("network", "interface", sec_name);
		if (!iface_s)
			continue;

		dmuci_get_value_by_section_string(iface_s, "device", &curr_device);

		ip___update_child_interfaces(curr_device, "device", DM_STRLEN(linker) ? linker : section_name(iface_s));
	}
}

void ethernet___Update_Link_Layer(const char *path, const char *linker)
{
	struct uci_section *dmmap_s = NULL;

	char *p = DM_STRRCHR(path, '.');
	if (p) *p = 0;

	uci_path_foreach_option_eq(bbfdm, "dmmap_ethernet", "link", "LowerLayers", path, dmmap_s) {
		char *instance = NULL;
		char curr_path[128] = {0};

		dmuci_get_value_by_section_string(dmmap_s, "link_instance", &instance);
		if (!DM_STRLEN(instance))
			continue;

		dmuci_set_value_by_section(dmmap_s, "device", linker);

		if (match(path, "Device.Bridging.Bridge.*.Port.", 0, NULL)) {
			// Remove unused Interface section created by Bridge Object if it exists
			struct uci_section *s = get_dup_section_in_config_opt("network", "interface", "device", linker);
			dmuci_delete_by_section(s, NULL, NULL);
		}

		snprintf(curr_path, sizeof(curr_path), "Device.Ethernet.Link.%s", instance);

		// Update IP Interface instance if exists
		ip___Update_IP_Interface_Layer(curr_path, linker);
	}
}

bool bridging___is_management_port_instance(struct uci_section *device_sec)
{
	char *mng_port = NULL;

	dmuci_get_value_by_section_string(device_sec, "management", &mng_port);

	return (DM_LSTRCMP(mng_port, "1") == 0);
}

void bridging___get_priority_list(struct uci_section *device_sec, const char *uci_opt_name, const void *data, char **value)
{
	struct uci_list *uci_opt_list = NULL;
	struct uci_element *e = NULL;
	char uci_value[256] = {0};
	unsigned pos = 0;

	if (!data || !uci_opt_name)
		return;

	dmuci_get_value_by_section_list(device_sec, uci_opt_name, &uci_opt_list);
	if (uci_opt_list == NULL)
		return;

	uci_value[0] = '\0';
	/* traverse each list value and create comma separated output */
	uci_foreach_element(uci_opt_list, e) {

		//delimiting priority which is in the form of x:y where y is the priority
		char *priority = strchr(e->name, ':');
		if (priority)
			pos += snprintf(&uci_value[pos], sizeof(uci_value) - pos, "%s,", priority + 1);
	}

	if (pos)
		uci_value[pos - 1] = 0;

	dmasprintf(value, "%s", uci_value);
}

void bridging___set_priority_list(struct uci_section *device_sec, const char *uci_opt_name, const void *data, char *value)
{
	char *pch = NULL, *pchr = NULL;
	int idx = 0;

	if (!data || !uci_opt_name || !value)
		return;

	/* delete current list values */
	dmuci_set_value_by_section(device_sec, uci_opt_name, "");

	/* tokenize each value from received comma separated string and add it to uci file in the format x:y
	x being priority and y being priority to be mapped to */
	for (pch = strtok_r(value, ",", &pchr); pch != NULL; pch = strtok_r(NULL, ",", &pchr), idx++) {
		char buf[16] = {0};

		/* convert values to uci format (x:y) and add */
		snprintf(buf, sizeof(buf), "%d%c%s", idx, ':', pch);
		dmuci_add_list_value_by_section(device_sec, uci_opt_name, buf);
	}
}

static char* get_bridge_port_type(char *dev_type)
{
	if (dev_type != NULL) {
		struct bridge_port_type_map *p;

		p = &bridge_port_type_map[0];
		while (p->dev_type != NULL) {
			if (!strcmp(p->dev_type, dev_type))
				return p->port_type;
			++p;
		}
	}

	return NULL;
}

static char* get_bridge_device_type(char *port_type)
{
	if (port_type != NULL) {
		struct bridge_port_type_map *p;

		p = &bridge_port_type_map[0];
		while (p->port_type != NULL) {
			if (!strcmp(p->port_type, port_type))
				return p->dev_type;
			++p;
		}
	}

	return NULL;
}

/**************************************************************************
* COMMON FUNCTIONS
***************************************************************************/
static bool multi_ap_type_backhaul(struct uci_section *config_section)
{
	bool ret = false;
	char *multi_ap = NULL;

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

	return ret;
}

static struct uci_section *ethernet___get_ethernet_interface_section(const char *device_name)
{
	struct uci_section *s = NULL;

	uci_foreach_sections("network", "device", s) {
		char *name = NULL;

		if (!dmuci_is_option_value_empty(s, "type"))
			continue;

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

		if (DM_STRCMP(name, device_name) == 0)
			return s;
	}

	return NULL;
}

static unsigned long bridging_get_new_vid(const char *br_instance)
{
	struct uci_section *s = NULL;
	unsigned long max = 0;
	char *vid = NULL;

	uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_vlan", "bridge_vlan", "br_inst", br_instance, s) {
		dmuci_get_value_by_section_string(s, "vid", &vid);
		unsigned long vid_tol = DM_STRTOL(vid);
		if (vid_tol > max)
			max = vid_tol;
	}

	return max + 1;
}

static void remove_device_from_bridge_interface(struct uci_section *br_sec)
{
	struct uci_section *s = NULL, *stmp = NULL;
	char *device = NULL;

	if (!br_sec)
		return;

	dmuci_get_value_by_section_string(br_sec, "name", &device);
	if (DM_STRLEN(device) == 0 )
		return;

	uci_foreach_option_eq_safe("network", "interface", "device", device, stmp, s) {
		char *proto = NULL;

		dmuci_get_value_by_section_string(s, "proto", &proto);
		dmuci_delete_by_section(s, (proto && *proto == 0) ? NULL : "device", NULL);
		break;
	}
}

static void add_port_to_bridge_sections(struct uci_section *br_sec, struct uci_section *br_dmmap_sec, const char *device_port)
{
	struct uci_list *uci_list = NULL;

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

	if (br_sec) {
		dmuci_get_value_by_section_list(br_sec, "ports", &uci_list);
		if (!value_exists_in_uci_list(uci_list, device_port))
			dmuci_add_list_value_by_section(br_sec, "ports", device_port);
	}

	if (br_dmmap_sec) {
		dmuci_get_value_by_section_list(br_dmmap_sec, "ports", &uci_list);
		if (!value_exists_in_uci_list(uci_list, device_port))
			dmuci_add_list_value_by_section(br_dmmap_sec, "ports", device_port);
	}
}

static void remove_port_from_bridge_sections(struct uci_section *br_sec, struct uci_section *br_dmmap_sec, const char *device_port)
{
	struct uci_list *uci_list = NULL;

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

	if (br_sec) {
		dmuci_get_value_by_section_list(br_sec, "ports", &uci_list);
		if (value_exists_in_uci_list(uci_list, device_port))
			dmuci_del_list_value_by_section(br_sec, "ports", device_port);
	}

	if (br_dmmap_sec) {
		dmuci_get_value_by_section_list(br_dmmap_sec, "ports", &uci_list);
		if (value_exists_in_uci_list(uci_list, device_port))
			dmuci_del_list_value_by_section(br_dmmap_sec, "ports", device_port);
	}
}

#ifdef BRIDGEMNGR_COPY_PBITS
static void set_one_to_one_qos_mapping(struct uci_section *s, const char *mapping_option_name)
{
	if (s && DM_STRLEN(mapping_option_name)) {
		dmuci_set_value_by_section(s, mapping_option_name, "");

		dmuci_add_list_value_by_section(s, mapping_option_name, "0:0");
		dmuci_add_list_value_by_section(s, mapping_option_name, "1:1");
		dmuci_add_list_value_by_section(s, mapping_option_name, "2:2");
		dmuci_add_list_value_by_section(s, mapping_option_name, "3:3");
		dmuci_add_list_value_by_section(s, mapping_option_name, "4:4");
		dmuci_add_list_value_by_section(s, mapping_option_name, "5:5");
		dmuci_add_list_value_by_section(s, mapping_option_name, "6:6");
		dmuci_add_list_value_by_section(s, mapping_option_name, "7:7");
	}
}
#endif

static void set_Provider_bridge_component(char *refparam, struct dmctx *ctx, void *data, const char *instance, const char *linker, const char *component)
{
	/* *value=Device.Bridging.Bridge.{i}.
	 * In file dmmap_provider_bridge set "option svlan_br_inst {i}" or "list cvlan_br_inst {i}" in this(refered "provider_bridge" section)
	 */
	struct uci_section *s = NULL, *svlan_dev = NULL, *dmmap_bridge_section = NULL;
	struct uci_section *network_bridge_sec_from = NULL, *network_bridge_sec_to = NULL;
	char pr_br_sec_name[64] = {0};
	char *br_sec_name = NULL;
	char *dev_name = NULL;
	char *cvlan_id = NULL;

	if (DM_STRLEN(linker) == 0) // Linker should be like "bridge-X"
		return;

	char *br_inst = DM_STRCHR(linker, '-'); // Get bridge instance 'X' which is linker from Name parameter 'bridge-X'
	if (!br_inst)
		return;

	// section name of bridge in network file
	snprintf(pr_br_sec_name, sizeof(pr_br_sec_name), "pr_br_%s", instance);

	/*
	 * check if provider bridge instance of this provider bridge is present in network uci file
	 * if present add candidate bridge to this provider bridge instance.
	 * if not present, create a provider bridge instance in network uci file,
	 * i.e. just update the candidate bridge section name to pr_br_{i} | {i} = instance of provider bridge
	 */
	uci_foreach_option_eq("network", "device", "type", "bridge", s) {
		if (strcmp(pr_br_sec_name, section_name(s)) == 0) {
			network_bridge_sec_to = s;
			break;
		}
	}

	/* Add candidate bridge to this provider bridge instance(network->device->pr_br_{i}) */
	// Get network->device(bridge) section name from dmmap_bridge_port->bridge_port->device_section_name
	dmmap_bridge_section = get_dup_section_in_dmmap_opt("dmmap_bridge", "device", "bridge_instance", br_inst + 1);
	dmuci_get_value_by_section_string(dmmap_bridge_section, "section_name", &br_sec_name);

	if (!dmmap_bridge_section || DM_STRLEN(br_sec_name) == 0)
		return;

	if (DM_LSTRCMP(component, "CVLAN") == 0) {
		// Set svlan_br_inst in dmmap_provider_bridge->provider_bridge section

		struct uci_section *dmmap_bridge_vlan_section = get_dup_section_in_dmmap_opt("dmmap_bridge_vlan", "bridge_vlan", "br_inst", br_inst + 1);
		if (dmmap_bridge_vlan_section) {
			dmuci_get_value_by_section_string(dmmap_bridge_vlan_section, "vid", &cvlan_id);
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "cvlan_id", cvlan_id);
		}

		dmuci_add_list_value_by_section(((struct dm_data *)data)->dmmap_section, "cvlan_br_inst", br_inst + 1);
	} else if (DM_LSTRCMP(component, "SVLAN") == 0) {
		// Set svlan_br_inst in dmmap_provider_bridgei->provider_bridge section

		dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "svlan_br_inst", br_inst + 1);
	}

	// Find the network->device(candidate bridge) section
	network_bridge_sec_from = get_origin_section_from_config("network", "device", br_sec_name);
	if (!network_bridge_sec_from)
		return;

	if (DM_LSTRCMP(component, "SVLAN") == 0) {
		struct uci_list *uci_list = NULL;
		struct uci_element *e = NULL;

		dmuci_get_value_by_section_list(network_bridge_sec_from, "ports", &uci_list);
		if (uci_list != NULL) {
			uci_foreach_element(uci_list, e) {
				char *dev_ifname = NULL;

				svlan_dev = get_dup_section_in_config_opt("network", "device", "name", e->name);
				if (svlan_dev == NULL)
					continue;

				if (dmuci_is_option_value_empty(svlan_dev, "type"))
					continue;

				dmuci_get_value_by_section_string(svlan_dev, "ifname", &dev_ifname);
				dmuci_get_value_by_section_string(svlan_dev, "name", &dev_name);

				if (DM_STRLEN(dev_ifname) == 0)
					continue;

				dmuci_set_value_by_section(svlan_dev, "type", "8021ad");

#ifdef BRIDGEMNGR_COPY_PBITS
				struct uci_list *mapping = NULL;
				dmuci_get_value_by_section_list(svlan_dev, "egress_qos_mapping", &mapping);

				// do not disturb existing mapping, so existing mapping should not be present
				if (!mapping) {
					set_one_to_one_qos_mapping(svlan_dev, "egress_qos_mapping");
				}
#endif
				break;
			}
		}

		// the svlan bridge is not needed anymore
		// delete interface section of svlan bridge
		char *br_dev_name = NULL;
		dmuci_get_value_by_section_string(network_bridge_sec_from, "name", &br_dev_name);

		// delete device section of this bridge
		dmuci_delete_by_section(network_bridge_sec_from, NULL, NULL);

		struct uci_section *if_section = get_dup_section_in_config_opt("network", "interface", "device", br_dev_name);
		if (if_section) {
			dmuci_delete_by_section(if_section, NULL, NULL);
		}
	}

#ifdef BRIDGEMNGR_COPY_PBITS
	// For CVLAN, set ingress QoS mapping 0:0..7:7 on ALL candidate-bridge ports
	if (DM_LSTRCMP(component, "CVLAN") == 0) {
		struct uci_list *uci_list = NULL;
		struct uci_element *e = NULL;

		char *br_dev_name = NULL;
		dmuci_get_value_by_section_string(network_bridge_sec_from, "name", &br_dev_name);

		dmuci_get_value_by_section_list(network_bridge_sec_from, "ports", &uci_list);
		if (uci_list != NULL) {
			uci_foreach_element(uci_list, e) {
				struct uci_section *port_dev = get_dup_section_in_config_opt("network", "device", "name", e->name);
				if (!port_dev)
					continue;

				struct uci_list *mapping = NULL;
				dmuci_get_value_by_section_list(port_dev, "ingress_qos_mapping", &mapping);

				// port should be a vlan port, so type should not be empty
				// do not disturb existing mapping, so existing mapping should not be present
				if (!dmuci_is_option_value_empty(port_dev, "type") && !mapping) {
					set_one_to_one_qos_mapping(port_dev, "ingress_qos_mapping");
				}
			}
		}
	}
#endif

	if (network_bridge_sec_to) {
		/*
		 * The provider bridge secion has already been created(as a result of previous call to this function) in network uci file.
		 * Just need to find config section of candidate bridge and add it to the existing provider bridge configuration.
		 * And delete the candidate bridge section from network uci file.
		 *
		 */
		dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "cvlan_id", &cvlan_id);

		char qinq_name[32] = {0};
		snprintf(qinq_name, sizeof(qinq_name), "%s.%s", dev_name, cvlan_id);

		dmuci_add_list_value_by_section(network_bridge_sec_to, "ports", qinq_name);

		// add a new section of type 8021q
		s = NULL;
		char new_section_name[32] = {0};
		snprintf(new_section_name, sizeof(new_section_name), "pr_%s_%s", instance, cvlan_id);
		dmuci_add_section("network", "device", &s);
		dmuci_rename_section_by_section(s, new_section_name);
		dmuci_set_value_by_section(s, "enabled", "1");
		dmuci_set_value_by_section(s, "type", "8021q");
		dmuci_set_value_by_section(s, "vid", cvlan_id);
		dmuci_set_value_by_section(s, "ifname", dev_name);
		dmuci_set_value_by_section(s, "name", qinq_name);

#ifdef BRIDGEMNGR_COPY_PBITS
		set_one_to_one_qos_mapping(s, "egress_qos_mapping");
#endif

		dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "8021ad_section", section_name(svlan_dev));
		dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "8021q_section", new_section_name);
	} else {
		/*
		 * This is the first vlan component of this provider bridge instance.
		 * Need to create a porvider bridge instance in network uci file.
		 * To create a new provider bridge instance just rename candidate bridge config section name to pr_br_{i}
		 *
		 */
		// Rename network->device(bridge) section as pr_br_{i}
		dmuci_rename_section_by_section(network_bridge_sec_from, pr_br_sec_name);

		// Add option section_name to dmmap provider bridge section
		dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "section_name", pr_br_sec_name);
	}
}

static void synchronize_bridge_config_sections_with_dmmap_bridge_eq(const char *package, const char *section_type, const char *dmmap_package,
		const char *option_name, const char *option_value, struct list_head *dup_list)
{
	struct uci_section *s = NULL, *dmmap_sect = NULL;

	uci_foreach_option_eq(package, section_type, option_name, option_value, s) {

		// Skip Provider Bridge sections
		if (strncmp(section_name(s), "pr_br_", 6) == 0)
			continue;

		if ((dmmap_sect = get_dup_section_in_dmmap_opt(dmmap_package, "device", "section_name", section_name(s))) == NULL) {
			struct uci_list *ports_list = NULL;

			dmuci_add_section_bbfdm(dmmap_package, "device", &dmmap_sect);
			dmuci_set_value_by_section(dmmap_sect, "section_name", section_name(s));

			dmuci_get_value_by_section_list(s, "ports", &ports_list);
			if (ports_list != NULL) {
				struct uci_element *e = NULL;

				uci_foreach_element(ports_list, e) {
					dmuci_add_list_value_by_section(dmmap_sect, "ports", e->name);
				}
			}
		}
	}

	/*
	 * Add system and dmmap sections to the list
	 */
	uci_path_foreach_sections(bbfdm, dmmap_package, "device", dmmap_sect) {
		char *section_name = NULL;

		dmuci_get_value_by_section_string(dmmap_sect, "section_name", &section_name);
		struct uci_section *origin_s = get_origin_section_from_config(package, section_type, section_name);
		add_dmmap_config_dup_list(dup_list, origin_s, dmmap_sect);
	}
}

static bool is_bridge_section_exist(const char *device)
{
	struct uci_section *s = NULL;

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

	uci_path_foreach_sections(bbfdm, "dmmap_bridge", "device", s) {
		struct uci_list *ports_list = NULL;
		struct uci_element *e = NULL;

		dmuci_get_value_by_section_list(s, "ports", &ports_list);
		if (ports_list == NULL)
			continue;

		uci_foreach_element(ports_list, e) {
			if (DM_STRCMP(e->name, device) == 0)
				return true;
		}
	}

	return false;
}

static int get_last_instance_bridge(const char *package, const char *section, const char *opt_inst)
{
	struct uci_section *s;
	int inst = 0;

	uci_path_foreach_sections(bbfdm, package, section, s) {
		char *opt_val = NULL;

		dmuci_get_value_by_section_string(s, opt_inst, &opt_val);
		if (DM_STRLEN(opt_val) != 0 && DM_STRTOL(opt_val) > inst)
			inst = DM_STRTOL(opt_val);
	}

	return inst;
}

static char *create_dmmap_bridge_section(const char *port)
{
	struct uci_section *dmmap_br_sec = NULL;
	char bridge_name[64] = {0};
	char *current_inst = NULL;

	int last_inst_dmmap = get_last_instance_bridge("dmmap_bridge", "device", "bridge_instance");
	dmasprintf(&current_inst, "%d", (last_inst_dmmap == 0) ? 1 : last_inst_dmmap+1);
	snprintf(bridge_name, sizeof(bridge_name), "dev_br%d", (last_inst_dmmap == 0) ? 1 : last_inst_dmmap+1);

	dmuci_add_section_bbfdm("dmmap_bridge", "device", &dmmap_br_sec);
	dmuci_set_value_by_section(dmmap_br_sec, "section_name", bridge_name);
	dmuci_set_value_by_section(dmmap_br_sec, "bridge_instance", current_inst);
	dmuci_add_list_value_by_section(dmmap_br_sec, "ports", port);

	return current_inst;
}

/*
 * Resolve the role of a provider-bridge port entry.
 *
 * Walks the network device section chain for port_name and classifies it:
 *
 *  PLAIN:   No device section, or device section has no type.
 *           => C-VLAN member bridge port (untagged).
 *           out_ifname = port_name itself.
 *
 *  CVLAN_ONLY: Device section type=8021q, but its ifname has NO 8021ad
 *              device section (i.e. the ifname is a plain ethernet).
 *              => This port is a C-VLAN component port directly.
 *              out_cvlan_vid = VID of this 8021q section.
 *              out_cvlan_sec = this 8021q section.
 *              out_ifname    = ifname of this 8021q section (plain eth).
 *              out_svlan_sec = NULL, out_svlan_vid = NULL.
 *
 *  QINQ:    Device section type=8021q, and its ifname HAS an 8021ad
 *           device section (true QinQ stack).
 *           => C-VLAN component is the 8021q section.
 *           => S-VLAN component is the 8021ad section.
 *           out_cvlan_vid = VID of the 8021q section.
 *           out_cvlan_sec = the 8021q section.
 *           out_svlan_vid = VID of the 8021ad section.
 *           out_svlan_sec = the 8021ad section.
 *           out_ifname    = ifname of the 8021ad section (base eth).
 *
 *  SVLAN_ONLY: Device section type=8021ad directly in the bridge ports list.
 *              => S-VLAN component port.
 *              out_svlan_vid = VID of this 8021ad section.
 *              out_svlan_sec = this 8021ad section.
 *              out_ifname    = ifname of this 8021ad section (base eth).
 *              out_cvlan_sec = NULL, out_cvlan_vid = NULL.
 *
 * Returns true if any VLAN device was found, false for PLAIN.
 */
static bool resolve_provider_bridge_port(const char *port_name,
		char **out_ifname,
		char **out_svlan_vid,
		struct uci_section **out_svlan_sec,
		char **out_cvlan_vid,
		struct uci_section **out_cvlan_sec)
{
	struct uci_section *dev_sec = NULL;

	if (out_ifname)    *out_ifname    = (char *)port_name;
	if (out_svlan_vid) *out_svlan_vid = NULL;
	if (out_svlan_sec) *out_svlan_sec = NULL;
	if (out_cvlan_vid) *out_cvlan_vid = NULL;
	if (out_cvlan_sec) *out_cvlan_sec = NULL;

	/* Find the network device section for this port name */
	uci_foreach_option_eq("network", "device", "name", port_name, dev_sec) {
		char *type = NULL;
		dmuci_get_value_by_section_string(dev_sec, "type", &type);

		if (DM_LSTRCMP(type, "8021q") == 0) {
			char *inner_ifname = NULL;
			char *cvlan_vid    = NULL;

			dmuci_get_value_by_section_string(dev_sec, "ifname", &inner_ifname);
			dmuci_get_value_by_section_string(dev_sec, "vid",    &cvlan_vid);

			if (out_cvlan_vid) *out_cvlan_vid = cvlan_vid;
			if (out_cvlan_sec) *out_cvlan_sec = dev_sec;

			/*
			 * Check whether the ifname of this 8021q device is itself
			 * an 8021ad device. If yes => true QinQ stack (QINQ case).
			 * If no => simple C-VLAN port with plain ethernet underneath
			 * (CVLAN_ONLY case).
			 */
			struct uci_section *svlan_sec = NULL;
			uci_foreach_option_eq("network", "device", "name", inner_ifname, svlan_sec) {
				char *svlan_type = NULL;
				dmuci_get_value_by_section_string(svlan_sec, "type", &svlan_type);

				if (DM_LSTRCMP(svlan_type, "8021ad") == 0) {
					/* QINQ: inner_ifname is an 8021ad device */
					char *svlan_vid   = NULL;
					char *base_ifname = NULL;

					dmuci_get_value_by_section_string(svlan_sec, "vid",    &svlan_vid);
					dmuci_get_value_by_section_string(svlan_sec, "ifname", &base_ifname);

					if (out_svlan_vid) *out_svlan_vid = svlan_vid;
					if (out_svlan_sec) *out_svlan_sec = svlan_sec;
					if (out_ifname)    *out_ifname    = base_ifname;
					return true;
				}
				break; /* found the device section but it's not 8021ad */
			}

			/*
			 * CVLAN_ONLY: ifname is a plain ethernet (no 8021ad wrapper).
			 * The port itself is the C-VLAN component port.
			 * out_ifname = inner_ifname (the plain eth, e.g. "eth1").
			 * svlan_sec / svlan_vid remain NULL.
			 */
			if (out_ifname) *out_ifname = inner_ifname;
			return true;

		} else if (DM_LSTRCMP(type, "8021ad") == 0) {
			/* SVLAN_ONLY: direct 8021ad port in the bridge ports list */
			char *svlan_vid   = NULL;
			char *base_ifname = NULL;

			dmuci_get_value_by_section_string(dev_sec, "vid",    &svlan_vid);
			dmuci_get_value_by_section_string(dev_sec, "ifname", &base_ifname);

			if (out_svlan_vid) *out_svlan_vid = svlan_vid;
			if (out_svlan_sec) *out_svlan_sec = dev_sec;
			if (out_ifname)    *out_ifname    = base_ifname;
			/* cvlan_sec / cvlan_vid remain NULL */
			return true;
		}

		/* Device section exists but has no meaningful type => treat as plain */
		return false;
	}

	/* No device section at all => plain port */
	return false;
}

static void dmmap_synchronizeBridgingProviderBridge(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct uci_section *s = NULL;

	uci_foreach_option_eq("network", "device", "type", "bridge", s) {
		struct uci_section *dmmap_pr_br_sec = NULL;
		struct uci_list *ports_list = NULL;
		struct uci_element *e = NULL;
		char current_inst[16] = {0};
		bool svlan_assigned = false;
		char *bridge_name = NULL;

		if (strncmp(section_name(s), "pr_br_", 6) != 0)
			continue;

		if ((dmmap_pr_br_sec = get_dup_section_in_dmmap("dmmap_provider_bridge", "provider_bridge", section_name(s))) != NULL)
			continue;

		int last_inst_dmmap = get_last_instance_bridge("dmmap_provider_bridge", "provider_bridge", "provider_bridge_instance");
		dmuci_add_section_bbfdm("dmmap_provider_bridge", "provider_bridge", &dmmap_pr_br_sec);
		snprintf(current_inst, sizeof(current_inst), "%d", (last_inst_dmmap == 0) ? 1 : last_inst_dmmap + 1);
		dmuci_set_value_by_section(dmmap_pr_br_sec, "provider_bridge_instance", current_inst);
		dmuci_set_value_by_section(dmmap_pr_br_sec, "section_name", section_name(s));
		dmuci_set_value_by_section(dmmap_pr_br_sec, "enable", "1");

		dmuci_get_value_by_section_string(s, "name", &bridge_name);
		if (DM_STRLEN(bridge_name)) {
			dmuci_set_value_by_section(dmmap_pr_br_sec, "name", bridge_name);
		}

		dmuci_get_value_by_section_list(s, "ports", &ports_list);
		if (ports_list == NULL)
			continue;

		uci_foreach_element(ports_list, e) {
			char *base_ifname = NULL;
			char *svlan_vid   = NULL;
			char *cvlan_vid   = NULL;
			struct uci_section *svlan_sec = NULL;
			struct uci_section *cvlan_sec = NULL;

			bool is_vlan = resolve_provider_bridge_port(e->name,
					&base_ifname, &svlan_vid, &svlan_sec, &cvlan_vid, &cvlan_sec);

			if (!is_vlan) {
				/*
				 * PLAIN port — untagged member, e.g. bare eth1.
				 * Becomes a C-VLAN bridge with this port as its member.
				 * No VLAN id is recorded (untagged C-VLAN component).
				 *
				 * Example: pr_br ports = [ eth1, ae_wan.300 ]
				 *   eth1 => plain => C-VLAN bridge (no tag)
				 */
				if (!is_bridge_section_exist(e->name)) {
					char *cvlan_br_inst = create_dmmap_bridge_section(e->name);
					dmuci_add_list_value_by_section(dmmap_pr_br_sec, "cvlan_br_inst", cvlan_br_inst);
				}
				continue;
			}

			if (cvlan_sec && svlan_sec) {
				/*
				 * QINQ topology — e.g. port ae_wan.300.100:
				 *   cvlan_sec   = pr_1_100    (8021q, vid=100, ifname=ae_wan.300)
				 *   svlan_sec   = br_2_port_1 (8021ad, vid=300, ifname=ae_wan)
				 *   svlan_dev_name = ae_wan.300
				 *
				 * Only the S-VLAN bridge is created here, keyed on the 8021ad
				 * device's name (ae_wan.300). Its port in dmmap_bridge will be
				 * ae_wan.300, representing the S-VLAN trunk.
				 *
				 * The C-VLAN bridge was already created by the CVLAN_ONLY branch
				 * (for eth1.100). We only need to record 8021q_section here
				 * since pr_1_100 is the actual QinQ wrapper device that sits as
				 * a port inside the provider bridge.
				 *
				 * svlan_br_inst  => bridge instance whose port is ae_wan.300
				 * 8021ad_section => br_2_port_1
				 * 8021q_section  => pr_1_100
				 */
				char *svlan_dev_name = NULL;
				dmuci_get_value_by_section_string(svlan_sec, "name", &svlan_dev_name);

				if (!svlan_assigned && svlan_dev_name && !is_bridge_section_exist(svlan_dev_name)) {
					char *svlan_br_inst = create_dmmap_bridge_section(svlan_dev_name);
					dmuci_set_value_by_section(dmmap_pr_br_sec, "svlan_br_inst", svlan_br_inst);
					svlan_assigned = true;
					dmuci_set_value_by_section(dmmap_pr_br_sec, "8021ad_section", section_name(svlan_sec));
					/* 8021q_section is the QinQ wrapper sitting in the pr_br ports list */
					dmuci_set_value_by_section(dmmap_pr_br_sec, "8021q_section", section_name(cvlan_sec));
				}

			} else if (cvlan_sec && !svlan_sec) {
				/*
				 * CVLAN_ONLY topology — e.g. port eth1.100:
				 *   cvlan_sec  = br_1_port_1 (8021q, vid=100, ifname=eth1)
				 *   svlan_sec  = NULL (eth1 is plain ethernet, no 8021ad wrapper)
				 *   base_ifname = eth1
				 *
				 * C-VLAN bridge keyed on e->name (eth1.100) — the 8021q device
				 * name is the effective port name for this C-VLAN component.
				 * cvlan_id is recorded here.
				 * 8021q_section is NOT set here — it is set in the QINQ branch
				 * for the actual QinQ wrapper (pr_1_100). br_1_port_1 is the
				 * C-VLAN port device, not the QinQ wrapper.
				 *
				 * cvlan_br_inst => bridge instance whose port is eth1.100
				 * cvlan_id      => 100
				 */
				if (!is_bridge_section_exist(e->name)) {
					char *cvlan_br_inst = create_dmmap_bridge_section(e->name);
					dmuci_add_list_value_by_section(dmmap_pr_br_sec, "cvlan_br_inst", cvlan_br_inst);
					if (cvlan_vid)
						dmuci_set_value_by_section(dmmap_pr_br_sec, "cvlan_id", cvlan_vid);
				}

			} else if (!cvlan_sec && svlan_sec) {
				/*
				 * SVLAN_ONLY topology — e.g. port ae_wan.300 listed directly:
				 *   svlan_sec   = br_2_port_1 (8021ad, vid=300, ifname=ae_wan)
				 *   base_ifname = ae_wan
				 *   cvlan_sec   = NULL
				 *
				 * S-VLAN bridge keyed on svlan_sec->name (ae_wan.300).
				 * The C-VLAN bridge is handled by PLAIN or CVLAN_ONLY branch.
				 *
				 * svlan_br_inst  => bridge instance whose port is ae_wan.300
				 * 8021ad_section => br_2_port_1
				 */
				char *svlan_dev_name = NULL;
				dmuci_get_value_by_section_string(svlan_sec, "name", &svlan_dev_name);

				if (!svlan_assigned && svlan_dev_name && !is_bridge_section_exist(svlan_dev_name)) {
					char *svlan_br_inst = create_dmmap_bridge_section(svlan_dev_name);
					dmuci_set_value_by_section(dmmap_pr_br_sec, "svlan_br_inst", svlan_br_inst);
					svlan_assigned = true;
					dmuci_set_value_by_section(dmmap_pr_br_sec, "8021ad_section", section_name(svlan_sec));
				}
			}
		}
	}
}

static void dmmap_synchronizeBridgingBridgeVLAN(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data *args = (struct dm_data *)prev_data;
	struct uci_section *s = NULL, *stmp = NULL;
	struct uci_list *br_ports_list = NULL;
	struct uci_element *e = NULL;

	if (!args->config_section)
		return;

	dmuci_get_value_by_section_list(args->config_section, "ports", &br_ports_list);
	if (!br_ports_list)
		return;

	uci_path_foreach_option_eq_safe(bbfdm, "dmmap_bridge_vlan", "bridge_vlan", "br_inst", (char *)args->additional_data, stmp, s) {

		// section added by user ==> skip it
		char *s_user = NULL;
		dmuci_get_value_by_section_string(s, "added_by_user", &s_user);
		if (DM_LSTRCMP(s_user, "1") == 0)
			continue;

		/*
		 * Check whether the VID stored in this dmmap section is still
		 * referenced by a port in the bridge's ports list.
		 *
		 * A port references a VID when:
		 *   (a) the port name literally contains the VID string as a dot-
		 *	   separated component (legacy heuristic), OR
		 *   (b) the network device section for that port has a "vid" option
		 *	   that matches.
		 *
		 * We use method (b) as the primary check, falling back to (a).
		 */
		char *vid = NULL;
		bool vid_found = false;

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

		uci_foreach_element(br_ports_list, e) {
			/* Method (b): look up the device section and compare vid */
			struct uci_section *dev_s = NULL;
			uci_foreach_option_eq("network", "device", "name", e->name, dev_s) {
				char *dev_vid = NULL;
				dmuci_get_value_by_section_string(dev_s, "vid", &dev_vid);
				if (DM_STRCMP(dev_vid, vid) == 0) {
					vid_found = true;
					break;
				}
			}
			if (vid_found)
				break;

			/* Method (a): substring match as fallback */
			if (DM_STRSTR(e->name, vid)) {
				vid_found = true;
				break;
			}
		}

		if (vid_found)
			continue;

		// else ==> delete section
		dmuci_delete_by_section(s, NULL, NULL);
	}

	uci_foreach_element(br_ports_list, e) {
		char *lower_layer = NULL;

		s = get_section_in_dmmap_with_options_eq("dmmap_bridge_port", "bridge_port", "br_inst", (char *)args->additional_data, "port", e->name);
		dmuci_get_value_by_section_string(s, "LowerLayers", &lower_layer);

		if (!s || DM_STRNCMP(lower_layer, "Device.Bridging.Bridge.", strlen("Device.Bridging.Bridge.")) == 0)
			continue;

		struct uci_section *dev_s = NULL;
		uci_foreach_option_eq("network", "device", "name", e->name, dev_s) {
			struct uci_section *br_vlan_s = NULL;
			char *vid = NULL;

			if (dmuci_is_option_value_empty(dev_s, "type"))
				continue;

			/* Prefer the explicit "vid" option on the device section */
			dmuci_get_value_by_section_string(dev_s, "vid", &vid);

			if (DM_STRLEN(vid) == 0) {
				/*
				 * Fall back: derive VID from the last dot-separated component
				 * of the port name only when the port is not a plain Ethernet
				 * interface.
				 */
				char *ifname = (!ethernet___get_ethernet_interface_section(e->name)) ? DM_STRRCHR(e->name, '.') : NULL;
				if (ifname)
					vid = dmstrdup(ifname + 1);
			}

			if (DM_STRLEN(vid) == 0)
				break;

			if (get_section_in_dmmap_with_options_eq("dmmap_bridge_vlan", "bridge_vlan", "br_inst", (char *)args->additional_data, "vid", vid))
				break;

			// Create a new VLAN instance
			dmuci_add_section_bbfdm("dmmap_bridge_vlan", "bridge_vlan", &br_vlan_s);
			dmuci_set_value_by_section(br_vlan_s, "vid", vid);
			dmuci_set_value_by_section(br_vlan_s, "br_inst", (char *)args->additional_data);
			break; /* one VLAN entry per port is enough */
		}
	}
}

static void dmmap_synchronizeBridgingBridgeVLANPort(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data *args = (struct dm_data *)prev_data;
	struct uci_section *s = NULL, *stmp = NULL;
	struct uci_list *br_ports_list = NULL;
	struct uci_element *e = NULL;

	if (!args->config_section)
		return;

	dmuci_get_value_by_section_list(args->config_section, "ports", &br_ports_list);
	if (!br_ports_list)
		return;

	uci_path_foreach_option_eq_safe(bbfdm, "dmmap_bridge_vlanport", "bridge_vlanport", "br_inst", (char *)args->additional_data, stmp, s) {

		// section added by user ==> skip it
		char *s_user = NULL;
		dmuci_get_value_by_section_string(s, "added_by_user", &s_user);
		if (s_user && DM_LSTRCMP(s_user, "1") == 0)
			continue;

		/*
		 * The section_name in a bridge_vlanport entry must refer to a
		 * network device section that:
		 *   (a) still exists in the network config, AND
		 *   (b) is still reachable from the current bridge's port list.
		 *
		 * We now additionally verify (b) so that stale vlanport entries
		 * from a previous provider-bridge topology are cleaned up.
		 */
		char *sec_name = NULL;
		dmuci_get_value_by_section_string(s, "section_name", &sec_name);

		struct uci_section *dev_s = get_origin_section_from_config("network", "device", sec_name);
		if (!dev_s) {
			/* Device section gone → remove vlanport entry */
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}

		/* Check reachability from the bridge ports list */
		char *dev_name = NULL;
		dmuci_get_value_by_section_string(dev_s, "name", &dev_name);
		bool reachable = false;

		uci_foreach_element(br_ports_list, e) {
			if (DM_STRCMP(e->name, dev_name) == 0) {
				reachable = true;
				break;
			}
		}

		if (!reachable) {
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}
	}

	uci_foreach_element(br_ports_list, e) {
		char *lower_layer = NULL;

		s = get_section_in_dmmap_with_options_eq("dmmap_bridge_port", "bridge_port", "br_inst", (char *)args->additional_data, "port", e->name);
		dmuci_get_value_by_section_string(s, "LowerLayers", &lower_layer);

		if (!s || DM_STRNCMP(lower_layer, "Device.Bridging.Bridge.", strlen("Device.Bridging.Bridge.")) == 0)
			continue;

		struct uci_section *dev_s = NULL;
		uci_foreach_option_eq("network", "device", "name", e->name, dev_s) {

			if (dmuci_is_option_value_empty(dev_s, "type"))
				continue;

			if (get_section_in_dmmap_with_options_eq("dmmap_bridge_vlanport", "bridge_vlanport", "br_inst", (char *)args->additional_data, "section_name", section_name(dev_s)))
				break;

			struct uci_section *br_vlanport_s = NULL;
			dmuci_add_section_bbfdm("dmmap_bridge_vlanport", "bridge_vlanport", &br_vlanport_s);
			dmuci_set_value_by_section(br_vlanport_s, "br_inst", (char *)args->additional_data);
			dmuci_set_value_by_section(br_vlanport_s, "section_name", section_name(dev_s));
			break;
		}
	}
}

static bool is_wireless_ifname_exist(const char *dev_sec_name, const char *ifname)
{
	if (DM_STRLEN(dev_sec_name) == 0 || DM_STRLEN(ifname) == 0)
		return false;

	struct uci_section *interface_s = get_dup_section_in_config_opt("network", "interface", "device", dev_sec_name);
	if (interface_s == NULL)
		return false;

	struct uci_section *s = NULL;
	uci_foreach_option_eq("wireless", "wifi-iface", "network", section_name(interface_s), s) {
		char *curr_ifname = NULL;

		/* filter out backhaul types. */
		if (multi_ap_type_backhaul(s))
			continue;

		dmuci_get_value_by_section_string(s, "ifname", &curr_ifname);
		if (DM_STRCMP(curr_ifname, ifname) == 0)
			return true;
	}

	return false;
}

static void create_new_bridge_port_section(const char *config, const char *port, const char *br_inst, const char *management_port)
{
	struct uci_section *br_port_s = NULL;

	dmuci_add_section_bbfdm("dmmap_bridge_port", "bridge_port", &br_port_s);

	dmuci_set_value_by_section(br_port_s, "config", config);
	dmuci_set_value_by_section(br_port_s, "port", port);
	dmuci_set_value_by_section(br_port_s, "br_inst", br_inst);
	dmuci_set_value_by_section(br_port_s, "management", management_port);
	dmuci_set_value_by_section(br_port_s, "enabled", "1");
}

static void dmmap_synchronizeBridgingBridgePort(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data *args = (struct dm_data *)prev_data;
	struct uci_section *s = NULL, *stmp = NULL;
	struct uci_element *e = NULL;
	char *s_user = NULL;

	if (!args->config_section)
		return;

	struct uci_list *br_ports_list = NULL;
	dmuci_get_value_by_section_list(args->config_section, "ports", &br_ports_list);

	/*
	 * The "name" option of the network/device (bridge) section gives us the
	 * bridge device name (e.g. "br-dev1"). This is what becomes the management
	 * port's "port" value.
	 */
	char *dev_name = NULL;
	dmuci_get_value_by_section_string(args->config_section, "name", &dev_name);

	/*
	 * For provider bridges the ports list in the dmmap_bridge section
	 * contains the resolved (effective) port names, not the raw names from
	 * the network bridge ports list. Use the dmmap ports list when iterating
	 * for bridge-port membership checks.
	 */
	struct uci_list *dmmap_ports_list = NULL;
	dmuci_get_value_by_section_list(args->dmmap_section, "ports", &dmmap_ports_list);

	uci_path_foreach_option_eq_safe(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", (char *)args->additional_data, stmp, s) {

		// section added by user ==> skip it
		dmuci_get_value_by_section_string(s, "added_by_user", &s_user);
		if (DM_LSTRCMP(s_user, "1") == 0)
			continue;

		// section for management ==> skip it
		char *management = NULL;
		dmuci_get_value_by_section_string(s, "management", &management);
		if (DM_LSTRCMP(management, "1") == 0)
			continue;

		// port is disabled ==> if yes, skip it
		char *enabled = NULL;
		dmuci_get_value_by_section_string(s, "enabled", &enabled);
		if (DM_LSTRCMP(enabled, "0") == 0)
			continue;

		// port device is available in ports list ==> skip it
		char *port_device = NULL;
		dmuci_get_value_by_section_string(s, "port", &port_device);

		/*
		 * Check against the dmmap ports list first (which holds resolved
		 * effective port names). Fall back to the raw network ports list.
		 */
		if (value_exists_in_uci_list(dmmap_ports_list, port_device))
			continue;

		if (value_exists_in_uci_list(br_ports_list, port_device))
			continue;

		// check for wireless ==> skip it
		if (is_wireless_ifname_exist(dev_name, port_device))
			continue;

		// else ==> delete section
		dmuci_delete_by_section(s, NULL, NULL);
	}

	// section added by user ==> skip it
	dmuci_get_value_by_section_string(args->dmmap_section, "added_by_user", &s_user);

	if (DM_LSTRCMP(s_user, "1") != 0 && !get_section_in_dmmap_with_options_eq("dmmap_bridge_port", "bridge_port", "br_inst", (char *)args->additional_data, "management", "1")) {
		create_new_bridge_port_section("network", dev_name, (char *)args->additional_data, "1");
	}

	/*
	 * Add bridge-port entries for each member in the dmmap ports list.
	 * These are the resolved/effective port names (e.g. "ae_wan.300" rather
	 * than "ae_wan.300.100" for a QinQ S-VLAN port).
	 */
	if (dmmap_ports_list) {
		uci_foreach_element(dmmap_ports_list, e) {
			if (get_section_in_dmmap_with_options_eq("dmmap_bridge_port", "bridge_port", "br_inst", (char *)args->additional_data, "port", e->name))
				continue;

			create_new_bridge_port_section("network", e->name, (char *)args->additional_data, "0");
		}
	} else if (br_ports_list) {
		/* Fallback: use raw network ports list when dmmap list is absent */
		uci_foreach_element(br_ports_list, e) {
			if (get_section_in_dmmap_with_options_eq("dmmap_bridge_port", "bridge_port", "br_inst", (char *)args->additional_data, "port", e->name))
				continue;

			create_new_bridge_port_section("network", e->name, (char *)args->additional_data, "0");
		}
	}

	// get interface section mapped to this device name
	struct uci_section *interface_s = get_dup_section_in_config_opt("network", "interface", "device", dev_name);
	if (interface_s == NULL)
		return;

	uci_foreach_option_eq("wireless", "wifi-iface", "network", section_name(interface_s), s) {
		char *ifname = NULL;

		/* filter out backhaul types. */
		if (multi_ap_type_backhaul(s))
			continue;

		// get ifname from wireless/wifi-iface section
		dmuci_get_value_by_section_string(s, "ifname", &ifname);
		if (DM_STRLEN(ifname) == 0)
			continue;

		if (get_section_in_dmmap_with_options_eq("dmmap_bridge_port", "bridge_port", "br_inst", (char *)args->additional_data, "port", ifname))
			continue;

		create_new_bridge_port_section("wireless", ifname, (char *)args->additional_data, "0");
	}
}

static struct uci_section *get_bridge_vlanport_device_section(struct uci_section *bridge_vlanport_dmmap_sec)
{
	char *dev_sec_name = NULL;

	if (!bridge_vlanport_dmmap_sec)
		return NULL;

	/* Get section_name from dmmap section */
	dmuci_get_value_by_section_string(bridge_vlanport_dmmap_sec, "section_name", &dev_sec_name);
	if (DM_STRLEN(dev_sec_name) == 0)
		return NULL;

	/* Find the device network section corresponding to this device_name */
	return get_origin_section_from_config("network", "device", dev_sec_name);
}

static struct uci_section *get_bridge_port_device_section(struct uci_section *bridge_port_dmmap_sec)
{
	struct uci_section *s = NULL;
	char *port = NULL;

	if (!bridge_port_dmmap_sec)
		return NULL;

	/* Getting device from dmmap section */
	dmuci_get_value_by_section_string(bridge_port_dmmap_sec, "port", &port);
	if (DM_STRLEN(port) == 0)
		return NULL;

	/* Find the device port section corresponding to this device */
	if ((s = ethernet___get_ethernet_interface_section(port)))
		return s;

	/* Find the wifi-iface wireless section corresponding to this device */
	uci_foreach_option_eq("wireless", "wifi-iface", "ifname", port, s) {

		/* filter out backhaul types. */
		if (multi_ap_type_backhaul(s))
			continue;

		return s;
	}

	/* Find the device network section corresponding to this device */
	uci_foreach_option_eq("network", "device", "name", port, s) {
		return s;
	}

	return NULL;
}

static void restore_bridge_config(const char *br_inst)
{
	struct uci_section *s = NULL, *dmmap_br_sec = NULL;
	struct uci_list *br_ports_list = NULL;
	struct uci_element *e = NULL;
	char *device_section_name = NULL;
	char iface_s_name[16];
	char device_name[16];

	// Get bridge config section of vlan bridge from dmmap_bridge_port
	dmmap_br_sec = get_dup_section_in_dmmap_opt("dmmap_bridge", "device", "bridge_instance", br_inst);
	if (dmmap_br_sec == NULL)
		return;

	dmuci_get_value_by_section_string(dmmap_br_sec, "section_name", &device_section_name);
	dmuci_get_value_by_section_list(dmmap_br_sec, "ports", &br_ports_list);

	snprintf(iface_s_name, sizeof(iface_s_name), "iface_br%s", br_inst);
	snprintf(device_name, sizeof(device_name), "br-dev%s", br_inst);

	// Restore bridge config
	dmuci_add_section("network", "interface", &s);
	dmuci_rename_section_by_section(s, iface_s_name);
	dmuci_set_value_by_section(s, "device", device_name);

	dmuci_add_section("network", "device", &s);
	dmuci_rename_section_by_section(s, device_section_name);
	dmuci_set_value_by_section(s, "name", device_name);
	dmuci_set_value_by_section(s, "type", "bridge");
	dmuci_set_value_by_section(s, "bridge_empty", "1");
	if (br_ports_list) {
		uci_foreach_element(br_ports_list, e) {
			dmuci_add_list_value_by_section(s, "ports", e->name);
		}
	}
}

static void delete_provider_bridge(struct uci_section *data)
{
	struct uci_list *cvlan_list = NULL;
	struct uci_section *s = NULL;
	char *svlan_br_inst = NULL;
	char pr_br_inst[32] = {0};
	char *br_inst = NULL;
	char *pr_br_section_name = NULL;

	/*
	 * Get cvlan/svlan bridge instance from the provider_bridge config and re-create all member bridge config section in network file.
	 * Delete all bridge_port config from dmmap_bridge_port which are member of this provider bridge.
	 * Delete provider bridge config. from network file corresponding to this provider bridge instance => config pr_br_{i}
	 * Delete this provider bridge section from dmmap_provider_bridge file.
	 *
	 */

	// Get provider bridge instance
	dmuci_get_value_by_section_string(data, "provider_bridge_instance", &br_inst);
	if (!br_inst || *br_inst == '\0')
		return;

	snprintf(pr_br_inst, sizeof(pr_br_inst), "pr_br_%s", br_inst); //name of provider bridge configuration in network file

	// Get svlan component bridge instance from dmmap section
	dmuci_get_value_by_section_string(data, "svlan_br_inst", &svlan_br_inst);

	if (svlan_br_inst && svlan_br_inst[0] != '\0') {

		// Restore bridge section in network uci file
		restore_bridge_config(svlan_br_inst);
	}

	// Get cvlan component bridge instance list from dmmap section
	dmuci_get_value_by_section_list(data, "cvlan_br_inst", &cvlan_list);
	if (cvlan_list != NULL) {
		struct uci_element *e = NULL;

		/* traverse each list value and delete all bridge section */
		uci_foreach_element(cvlan_list, e) {

			// Restore bridge section in network uci file
			restore_bridge_config(e->name);
		}
	}

	// delete extra 8021q section
	struct uci_section *tmp_s = NULL;
	char *sec_name = NULL;

	dmuci_get_value_by_section_string(data, "8021q_section", &sec_name);
	tmp_s = get_origin_section_from_config("network", "device", sec_name);
	if (tmp_s)
		dmuci_delete_by_section(tmp_s, NULL, NULL);

	// set 8021ad type to 8021q type
	tmp_s = NULL;
	dmuci_get_value_by_section_string(data, "8021ad_section", &sec_name);
	tmp_s = get_origin_section_from_config("network", "device", sec_name);
	if (tmp_s)
		dmuci_set_value_by_section(tmp_s, "type", "8021q");

	dmuci_get_value_by_section_string(data, "section_name", &pr_br_section_name);
	if (pr_br_section_name && pr_br_section_name[0] != '\0') {
                /* Get provider bridge device section from network using pr_br_section_name */
                s = get_origin_section_from_config("network", "device", pr_br_section_name);
	} else {
		// Get provider bridge section from network file and delete
		s = get_origin_section_from_config("network", "device", pr_br_inst);
	}

	if (s) {
		char *dev_name = NULL;
		/* Get device name from this section */
		dmuci_get_value_by_section_string(s, "name", &dev_name);

		if (DM_STRLEN(dev_name)) {
			struct uci_section *iface_sec = NULL;
			char *if_dev = NULL;

			uci_foreach_sections("network", "interface", iface_sec) {
				dmuci_get_value_by_section_string(iface_sec, "device", &if_dev);

				if (DM_STRLEN(if_dev) && DM_STRCMP(if_dev, dev_name) == 0) {
					dmuci_delete_by_section(iface_sec, NULL, NULL);
					break;
				}
			}
		}

		/* Delete provider bridge device section */
		dmuci_delete_by_section(s, NULL, NULL);
	}

	// Delete dmmap bridge section.
	dmuci_delete_by_section_bbfdm(data, NULL, NULL);
}

void remove_bridge_from_provider_bridge(const char *bridge_inst)
{
	struct uci_section *pr_br_sec = NULL;

	// Traverse each provider bridge section and remove the passed bridge instance.
	// Also restore bridge in network file.
	uci_path_foreach_sections(bbfdm, "dmmap_provider_bridge", "provider_bridge", pr_br_sec) {
		struct uci_list *cvlan_list = NULL;
		char *svlan = NULL;

		// Check if the passed bridge section is svlan
		dmuci_get_value_by_section_string(pr_br_sec, "svlan_br_inst", &svlan);
		if (DM_STRCMP(svlan, bridge_inst) == 0) {
			dmuci_set_value_by_section(pr_br_sec, "svlan_br_inst", "");
		}

		// Check if the passed bridge section is cvlan
		dmuci_get_value_by_section_list(pr_br_sec, "cvlan_br_inst", &cvlan_list);
		if (cvlan_list != NULL) {
			struct uci_element *e = NULL;

			uci_foreach_element(cvlan_list, e) {
				if (DM_STRCMP(e->name, bridge_inst) == 0) {
					dmuci_del_list_value_by_section(pr_br_sec, "cvlan_br_inst", bridge_inst);
					break;
				}
			}
		}
	}
}

static void Update_BridgePort_Port_Layer(const char *path, struct uci_section *bridge_vlanport_sec, struct uci_section *bridge_sec, struct uci_section *bridge_dmmap_sec,
		const char *bridge_intsance, const char *old_linker, const char *new_linker)
{
	struct uci_section *dmmap_s = NULL;

	char *p = DM_STRRCHR(path, '.');
	if (!p)
		return;

	uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", bridge_intsance, dmmap_s) {
		char *instance = NULL;
		char *enable = NULL;
		char *type = NULL;

		dmuci_get_value_by_section_string(dmmap_s, "bridge_port_instance", &instance);
		if (DM_STRCMP(instance, p + 1) != 0)
			continue;

		dmuci_set_value_by_section(dmmap_s, "port", new_linker);

		dmuci_get_value_by_section_string(dmmap_s, "enabled", &enable);
		if (DM_STRCMP(enable, "1") == 0) {
			/* Update ports list */
			remove_port_from_bridge_sections(bridge_sec, bridge_dmmap_sec, old_linker);
			add_port_to_bridge_sections(bridge_sec, bridge_dmmap_sec, new_linker);
		}

		dmuci_get_value_by_section_string(dmmap_s, "type", &type);
		if (DM_STRLEN(type)) {
			if (DM_LSTRCMP(type, "33024") == 0)
				dmuci_set_value_by_section(bridge_vlanport_sec, "type", "8021q");
			else if (DM_LSTRCMP(type, "34984") == 0)
				dmuci_set_value_by_section(bridge_vlanport_sec, "type", "8021ad");
		}

		break;
	}
}

static void Update_BridgeVLANPort_Port_Layer(const char *path, struct uci_section *bridge_sec, struct uci_section *bridge_dmmap_sec, const char *bridge_intsance, const char *linker)
{
	struct uci_section *dmmap_s = NULL;

	char *p = DM_STRRCHR(path, '.');
	if (p) *p = 0;

	uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_vlanport", "bridge_vlanport", "br_inst", bridge_intsance, dmmap_s) {
		struct uci_section *device_s = NULL;
		char *sec_name = NULL;
		char *port_ref = NULL;
		char *instance = NULL;
		char *vid = NULL;
		char new_name[32] = {0};

		dmuci_get_value_by_section_string(dmmap_s, "Port", &port_ref);
		if (DM_STRCMP(port_ref, path) != 0)
			continue;

		dmuci_get_value_by_section_string(dmmap_s, "bridge_vlanport_instance", &instance);
		if (!DM_STRLEN(instance))
			return;

		dmuci_get_value_by_section_string(dmmap_s, "section_name", &sec_name);
		if (!DM_STRLEN(sec_name))
			return;

		device_s = get_origin_section_from_config("network", "device", sec_name);
		if (!device_s)
			return;

		dmuci_get_value_by_section_string(device_s, "vid", &vid);

		snprintf(new_name, sizeof(new_name), "%s%s%s", DM_STRLEN(linker) ? linker : "",
								(DM_STRLEN(linker) && DM_STRLEN(vid)) ? "." : "",
								(DM_STRLEN(linker) && DM_STRLEN(vid)) ? vid : "");

		// Set ifname and name options
		dmuci_set_value_by_section(device_s, "ifname", linker);
		dmuci_set_value_by_section(device_s, "name", new_name);

		// Update Bridge Port instance if exists
		Update_BridgePort_Port_Layer(port_ref, device_s, bridge_sec, bridge_dmmap_sec, bridge_intsance, linker, new_name);
	}
}

static void Update_BridgeVLANPort_VLAN_Layer(const char *path, struct uci_section *bridge_sec, struct uci_section *bridge_dmmap_sec, const char *bridge_intsance, const char *linker)
{
	struct uci_section *dmmap_s = NULL;

	char *p = DM_STRRCHR(path, '.');
	if (p) *p = 0;

	uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_vlanport", "bridge_vlanport", "br_inst", bridge_intsance, dmmap_s) {
		struct uci_section *device_s = NULL;
		char *sec_name = NULL;
		char *vlan_ref = NULL;
		char *port_ref = NULL;
		char *instance = NULL;
		char *ifname = NULL;

		dmuci_get_value_by_section_string(dmmap_s, "VLAN", &vlan_ref);
		if (DM_STRCMP(vlan_ref, path) != 0)
			continue;

		dmuci_get_value_by_section_string(dmmap_s, "bridge_vlanport_instance", &instance);
		if (!DM_STRLEN(instance))
			continue;

		dmuci_get_value_by_section_string(dmmap_s, "section_name", &sec_name);
		if (!DM_STRLEN(sec_name))
			continue;

		device_s = get_origin_section_from_config("network", "device", sec_name);

		dmuci_set_value_by_section(device_s, "vid", linker);

		dmuci_get_value_by_section_string(dmmap_s, "Port", &port_ref);
		if (!DM_STRLEN(port_ref))
			continue;

		dmuci_get_value_by_section_string(device_s, "ifname", &ifname);
		if (DM_STRLEN(ifname)) {
			char *old_name = NULL;
			char new_name[32] = {0};

			dmuci_get_value_by_section_string(device_s, "name", &old_name);

			snprintf(new_name, sizeof(new_name), "%s%s%s", ifname, DM_STRLEN(linker) ? "." : "", DM_STRLEN(linker) ? linker : "");

			dmuci_set_value_by_section(device_s, "name", new_name);

			Update_BridgePort_Port_Layer(port_ref, device_s, bridge_sec, bridge_dmmap_sec, bridge_intsance, old_name, new_name);
		}
	}
}

/*************************************************************
* ENTRY METHOD
**************************************************************/
/*#Device.Bridging.Bridge.{i}.!UCI:network/device/dmmap_bridge*/
static int browseBridgingBridgeInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	struct dm_data *curr_data = NULL;
	char *inst = NULL;
	LIST_HEAD(dup_list);

	synchronize_bridge_config_sections_with_dmmap_bridge_eq("network", "device", "dmmap_bridge", "type", "bridge", &dup_list);
	list_for_each_entry(curr_data, &dup_list, list) {

		inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "bridge_instance", "bridge_alias");

		if (curr_data->config_section == NULL)
			curr_data->config_section = curr_data->dmmap_section;

		curr_data->additional_data = (void *)inst;

		if (DM_LINK_INST_OBJ(dmctx, parent_node, curr_data, inst) == DM_STOP)
			break;
	}
	free_dmmap_config_dup_list(&dup_list);
	return 0;
}

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

	dmmap_synchronizeBridgingProviderBridge(dmctx, parent_node, prev_data, prev_instance);
	uci_path_foreach_sections(bbfdm, "dmmap_provider_bridge", "provider_bridge", s) {

		curr_data.dmmap_section = s;
		char *br_section = NULL;
		dmuci_get_value_by_section_string(s, "section_name", &br_section);
		struct uci_section *config_s = get_origin_section_from_config("network", "device", br_section);
		if (config_s)
			curr_data.config_section = config_s;

		inst = handle_instance(dmctx, parent_node, s, "provider_bridge_instance", "provider_bridge_alias");

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

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

	dmmap_synchronizeBridgingBridgePort(dmctx, parent_node, prev_data, prev_instance);
	uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", (char *)((struct dm_data *)prev_data)->additional_data, dmmap_s) {

		curr_data.config_section = get_bridge_port_device_section(dmmap_s);
		curr_data.dmmap_section = dmmap_s;
		curr_data.additional_data = prev_data;

		inst = handle_instance(dmctx, parent_node, dmmap_s, "bridge_port_instance", "bridge_port_alias");

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

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

	dmmap_synchronizeBridgingBridgeVLAN(dmctx, parent_node, prev_data, prev_instance);
	uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_vlan", "bridge_vlan", "br_inst", (char *)((struct dm_data *)prev_data)->additional_data, dmmap_s) {

		curr_data.config_section = dmmap_s;
		curr_data.additional_data = prev_data;

		inst = handle_instance(dmctx, parent_node, dmmap_s, "bridge_vlan_instance", "bridge_vlan_alias");

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

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

	dmmap_synchronizeBridgingBridgeVLANPort(dmctx, parent_node, prev_data, prev_instance);
	uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_vlanport", "bridge_vlanport", "br_inst", (char *)((struct dm_data *)prev_data)->additional_data, dmmap_s) {

		curr_data.config_section = get_bridge_vlanport_device_section(dmmap_s);
		curr_data.dmmap_section = dmmap_s;
		curr_data.additional_data = prev_data;

		inst = handle_instance(dmctx, parent_node, dmmap_s, "bridge_vlanport_instance", "bridge_vlanport_alias");

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

/*************************************************************
* ADD DELETE OBJECT
**************************************************************/
static int addObjBridgingBridge(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct uci_section *s = NULL, *dmmap_bridge = NULL;
	char iface_s_name[16];
	char dev_s_name[16];
	char device_name[16];

	snprintf(iface_s_name, sizeof(iface_s_name), "iface_br%s", *instance);
	snprintf(dev_s_name, sizeof(dev_s_name), "dev_br%s", *instance);
	snprintf(device_name, sizeof(device_name), "br-dev%s", *instance);

	// Add network bridge section
	dmuci_add_section("network", "interface", &s);
	dmuci_rename_section_by_section(s, iface_s_name);
	dmuci_set_value_by_section(s, "device", device_name);

	// Add device bridge section
	dmuci_add_section("network", "device", &s);
	dmuci_rename_section_by_section(s, dev_s_name);
	dmuci_set_value_by_section(s, "name", device_name);
	dmuci_set_value_by_section(s, "type", "bridge");
	dmuci_set_value_by_section(s, "bridge_empty", "1");

	// Add dmmap bridge section
	dmuci_add_section_bbfdm("dmmap_bridge", "device", &dmmap_bridge);
	dmuci_set_value_by_section(dmmap_bridge, "section_name", section_name(s));
	dmuci_set_value_by_section(dmmap_bridge, "added_by_user", "1");
	dmuci_set_value_by_section(dmmap_bridge, "bridge_instance", *instance);
	return 0;
}

static int delObjBridgingBridge(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	struct uci_section *s = NULL, *stmp = NULL;

	switch (del_action) {
		case DEL_INST:
			// Remove all bridge port sections related to this device bridge section
			uci_path_foreach_option_eq_safe(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", (char *)((struct dm_data *)data)->additional_data, stmp, s) {
				dmuci_delete_by_section(s, NULL, NULL);
			}

			// Remove all bridge vlan sections related to this device bridge section
			uci_path_foreach_option_eq_safe(bbfdm, "dmmap_bridge_vlan", "bridge_vlan", "br_inst", (char *)((struct dm_data *)data)->additional_data, stmp, s) {
				dmuci_delete_by_section(s, NULL, NULL);
			}

			// Remove all bridge vlanport sections related to this device bridge section
			uci_path_foreach_option_eq_safe(bbfdm, "dmmap_bridge_vlanport", "bridge_vlanport", "br_inst", (char *)((struct dm_data *)data)->additional_data, stmp, s) {
				char *sec_name = NULL;

				dmuci_get_value_by_section_string(s, "section_name", &sec_name);
				if (DM_STRLEN(sec_name)) {
					struct uci_section *device_s = get_origin_section_from_config("network", "device", sec_name);
					dmuci_delete_by_section(device_s, NULL, NULL);
				}

				dmuci_delete_by_section(s, NULL, NULL);
			}

			// Remove cvlan/svaln from dmmap_provider_bridge section if this bridge instance is a part of it
			remove_bridge_from_provider_bridge((char *)((struct dm_data *)data)->additional_data);

			// Remove interface bridge that maps to this device
			remove_device_from_bridge_interface(((struct dm_data *)data)->config_section);

			// Remove device bridge section
			dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);

			// in browse function, we set config_section = dmmap_section if config_section does not exist
			// so check here so that we do not delete the same section twice and get seg fault
			if (((struct dm_data *)data)->dmmap_section != ((struct dm_data *)data)->config_section) {
				// Remove dmmap device bridge section
				dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);
			}
			break;
		case DEL_ALL:
			break;
	}
	return 0;
}

static int addObjBridgingBridgePort(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct uci_section *br_port_s = NULL;
	char buf[32];

	snprintf(buf, sizeof(buf), "br_%s_port_%s", (char *)((struct dm_data *)data)->additional_data, *instance);

	// Add dmmap section for devices
	dmuci_add_section_bbfdm("dmmap_bridge_port", "bridge_port", &br_port_s);
	dmuci_rename_section_by_section(br_port_s, buf);

	dmuci_set_value_by_section(br_port_s, "config", "network");
	dmuci_set_value_by_section(br_port_s, "br_inst", (char *)((struct dm_data *)data)->additional_data);
	dmuci_set_value_by_section(br_port_s, "bridge_port_instance", *instance);
	dmuci_set_value_by_section(br_port_s, "management", "0");
	dmuci_set_value_by_section(br_port_s, "enabled", "0");
	dmuci_set_value_by_section(br_port_s, "added_by_user", "1");
	return 0;
}

static int delObjBridgingBridgePort(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	switch (del_action) {
	case DEL_INST:
		if (!bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section)) {
			struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
			char *enable = NULL, *port = NULL;

			// Get enabled and port options
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "enabled", &enable);
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "port", &port);

			if (DM_STRCMP(enable, "1") == 0) {
				// Remove port from port list interface
				remove_port_from_bridge_sections(bridge_args->config_section, bridge_args->dmmap_section, port);
			}

			// Update Bridge VLANPort instance if exists
			Update_BridgeVLANPort_Port_Layer(refparam, bridge_args->config_section, bridge_args->dmmap_section, (char *)bridge_args->additional_data, "");
		}

		// Remove dmmap section
		dmuci_delete_by_section_bbfdm(((struct dm_data *)data)->dmmap_section, NULL, NULL);
		break;
	case DEL_ALL:
		break;
	}
	return 0;
}

static int addObjBridgingBridgeVLANPort(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct uci_section *s = NULL, *br_vlanport_s = NULL;
	char device_name[32];

	snprintf(device_name, sizeof(device_name), "br_%s_port_%s", (char *)((struct dm_data *)data)->additional_data, *instance);

	// Add device section
	dmuci_add_section("network", "device", &s);
	dmuci_rename_section_by_section(s, device_name);
	dmuci_set_value_by_section(s, "type", "8021q");
	dmuci_set_value_by_section(s, "enabled", "0");

	// Add dmmap section
	dmuci_add_section_bbfdm("dmmap_bridge_vlanport", "bridge_vlanport", &br_vlanport_s);
	dmuci_set_value_by_section(br_vlanport_s, "br_inst", (char *)((struct dm_data *)data)->additional_data);
	dmuci_set_value_by_section(br_vlanport_s, "bridge_vlanport_instance", *instance);
	dmuci_set_value_by_section(br_vlanport_s, "section_name", device_name);
	dmuci_set_value_by_section(br_vlanport_s, "added_by_user", "1");

	return 0;
}

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

	switch (del_action) {
	case DEL_INST:
		dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "Port", &port_ref);
		if (DM_STRLEN(port_ref)) {
			struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
			char *ifname = NULL, *name = NULL;

			// Get ifname and name options
			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ifname", &ifname);
			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &name);

			// Update Bridge Port instance if exists
			Update_BridgePort_Port_Layer(port_ref, ((struct dm_data *)data)->config_section, bridge_args->config_section, bridge_args->dmmap_section, (char *)bridge_args->additional_data, name, ifname);
		}

		// Remove config section
		dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);

		// Remove dmmap section
		dmuci_delete_by_section_bbfdm(((struct dm_data *)data)->dmmap_section, NULL, NULL);
		break;
	case DEL_ALL:
		break;
	}
	return 0;
}

static int addObjBridgingBridgeVLAN(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct uci_section *br_vlan_s = NULL;
	char vlan_name[32]= {0};
	char vid_str[32] = {0};

	unsigned long vid_ul = bridging_get_new_vid((char *)((struct dm_data *)data)->additional_data);
	DM_ULTOSTR(vid_str, vid_ul, sizeof(vid_str));

	snprintf(vlan_name, sizeof(vlan_name), "br_%s_vlan_%s", (char *)((struct dm_data *)data)->additional_data, *instance);

	dmuci_add_section_bbfdm("dmmap_bridge_vlan", "bridge_vlan", &br_vlan_s);
	dmuci_set_value_by_section(br_vlan_s, "name", vlan_name);
	dmuci_set_value_by_section(br_vlan_s, "br_inst", (char *)((struct dm_data *)data)->additional_data);
	dmuci_set_value_by_section(br_vlan_s, "bridge_vlan_instance", *instance);
	dmuci_set_value_by_section(br_vlan_s, "added_by_user", "1");
	dmuci_set_value_by_section(br_vlan_s, "vid", vid_str);
	return 0;
}

static int delObjBridgingBridgeVLAN(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;

	switch (del_action) {
	case DEL_INST:
		// Remove all vid from device sections
		Update_BridgeVLANPort_VLAN_Layer(refparam, bridge_args->config_section, bridge_args->dmmap_section, (char *)bridge_args->additional_data, "");

		// Remove dmmap section
		dmuci_delete_by_section_bbfdm(((struct dm_data *)data)->config_section, NULL, NULL);
		break;
	case DEL_ALL:
		break;
	}
	return 0;
}

static int addObjBridgingProviderBridge(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct uci_section *pr_br_sec = NULL;

	// Add dmmap section
	dmuci_add_section_bbfdm("dmmap_provider_bridge", "provider_bridge", &pr_br_sec);
	dmuci_set_value_by_section(pr_br_sec, "enable", "1");
	dmuci_set_value_by_section(pr_br_sec, "provider_bridge_instance", *instance);
	return 0;
}

static int delObjBridgingProviderBridge(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	switch (del_action) {
	case DEL_INST:
		delete_provider_bridge(((struct dm_data *)data)->dmmap_section);
		break;
	case DEL_ALL:
		break;
	}
	return 0;
}

/**************************************************************************
*SET & GET PARAMETERS
***************************************************************************/
static int get_Bridging_MaxBridgeEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("20");
	return 0;
}

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

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

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

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

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

/*#Device.Bridging.ProviderBridgeNumberOfEntries!UCI:network/device/*/
static int get_Bridging_ProviderBridgeNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseBridgingProviderBridgeInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

/*#Device.Bridging.BridgeNumberOfEntries!UCI:network/device/*/
static int get_Bridging_BridgeNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, browseBridgingBridgeInst);
	dmasprintf(value, "%d", cnt);
	return 0;
}

/*#Device.Bridging.Bridge.{i}.Enable!UCI:network/device,@i-1/enabled*/
static int get_BridgingBridge_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, "enabled", "1");
	return 0;
}

static int set_BridgingBridge_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, "enabled", b ? "1" : "0");
			return 0;
	}
	return 0;
}

/*#Device.Bridging.Bridge.{i}.Status!UCI:network/device,@i-1/enabled*/
static int get_BridgingBridge_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *name = NULL;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &name);
	get_net_device_status(name, value);
	if (DM_STRCMP(*value, "Up") == 0) {
		*value = dmstrdup("Enabled");
	} else {
		*value = dmstrdup("Disabled");
	}
	return 0;
}

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

static int set_BridgingBridge_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, "bridge_alias", instance, value);
}

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

static int get_BridgingBridge_Standard(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = dmstrdup("802.1Q-2011");
	return 0;
}

static int set_BridgingBridge_Standard(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *Bridge_Standard[] = {"802.1D-2004", "802.1Q-2005", "802.1Q-2011", NULL};

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

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

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

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

#ifdef BRIDGE_ENABLE_VENDOR_EXT
/* Get bridge VLAN filtering state from UCI config.
 * If explicitly set, return that value; otherwise derive from whether any
 * VLAN sections exist for this bridge (1 if present, 0 if none). */
static int get_BridgingBridge_VLANFiltering(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct uci_section *s = NULL;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "vlan_filtering", value);
	if (DM_STRLEN(*value) != 0) {
		return 0;
	}

	uci_foreach_option_eq("bridging", "vlan", "bridge", section_name(((struct dm_data *)data)->config_section), s) {
		*value = dmstrdup("1");
		return 0;
	}

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

/* Set bridge VLAN filtering state in UCI config */
static int set_BridgingBridge_VLANFiltering(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, "vlan_filtering", b ? "1" : "0");
			return 0;
	}
	return 0;
}
#endif /* BRIDGE_ENABLE_VENDOR_EXT */

static int get_BridgingBridgeSTP_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, "stp", "0");
	return 0;
}

static int set_BridgingBridgeSTP_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, "stp", b ? "1" : "0");
			return 0;
	}
	return 0;
}

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

	*value = dmstrdup("Disabled");
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &name);
	if (DM_STRLEN(name) == 0) {
		return 0;
	}

	char *enable = NULL;
	get_net_device_sysfs(name, "bridge/stp_state", &enable);
	if (DM_STRCMP(enable, "1") == 0)
		*value = dmstrdup("Enabled");

	return 0;
}

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

static int set_BridgingBridgeSTP_Protocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *Protocol[] = {"STP", NULL};

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

static int get_BridgingBridgeSTP_BridgePriority(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, "priority", "32767");
	return 0;
}

static int set_BridgingBridgeSTP_BridgePriority(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{{"0","61440"}}, 1))
				return FAULT_9007;
			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "priority", value);
			return 0;
	}
	return 0;
}

static int get_BridgingBridgeSTP_HelloTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "hello_time", value);

	// Value defined in system is in seconds but in datamodel this is in centiseconds, convert the value to centiseconds
	int hello_time = DM_STRLEN(*value) ? DM_STRTOL(*value) * 100 : 200;

	dmasprintf(value, "%d", hello_time);
	return 0;
}

static int set_BridgingBridgeSTP_HelloTime(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char buf[16] = {0};

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"100","1000"}}, 1))
				return FAULT_9007;
			return 0;
		case VALUESET:
			// Value defined in system is in seconds but in datamodel this is in centiseconds, convert the value to seconds
			snprintf(buf, sizeof(buf), "%u", (uint32_t)DM_STRTOL(value) / 100);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "hello_time", buf);
			return 0;
	}
	return 0;
}

static int get_BridgingBridgeSTP_MaxAge(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "max_age", value);

	// Value defined in system is in seconds but in datamodel this is in centiseconds, convert the value to centiseconds
	int max_age = DM_STRLEN(*value) ? DM_STRTOL(*value) * 100 : 2000;

	dmasprintf(value, "%d", max_age);
	return 0;
}

static int set_BridgingBridgeSTP_MaxAge(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char buf[16] = {0};

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{"600","4000"}}, 1))
				return FAULT_9007;
			return 0;
		case VALUESET:
			// Value defined in system is in seconds but in datamodel this is in centiseconds, convert the value to seconds
			snprintf(buf, sizeof(buf), "%u", (uint32_t)DM_STRTOL(value) / 100);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "max_age", buf);
			return 0;
	}
	return 0;
}

static int get_BridgingBridgeSTP_ForwardingDelay(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, "forward_delay", "4");
	return 0;
}

static int set_BridgingBridgeSTP_ForwardingDelay(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{{"4","30"}}, 1))
				return FAULT_9007;
			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "forward_delay", value);
			return 0;
	}
	return 0;
}

static int get_BridgingBridgePort_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_BridgingBridgePort_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
	char *config = NULL, *device = 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 (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
				return 0;

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

			dmuci_get_value_by_section_string(bridge_args->config_section, "name", &device);
			if (DM_STRLEN(device) == 0)
				return 0;

			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "config", &config);
			if (DM_LSTRCMP(config, "wireless") == 0) {
				struct uci_section *wifi_iface_s = get_dup_section_in_config_opt("network", "interface", "device", device);
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "network", b ? section_name(wifi_iface_s) : "");
			} else {
				char *port = NULL;

				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "port", &port);
				if (DM_STRLEN(port) == 0)
					return 0;

				if (b)
					add_port_to_bridge_sections(bridge_args->config_section, bridge_args->dmmap_section, port);
				else
					remove_port_from_bridge_sections(bridge_args->config_section, bridge_args->dmmap_section, port);
			}
			return 0;
	}
	return 0;
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "port", &port);
	return get_net_device_status(port, value);
}

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

static int set_BridgingBridgePort_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, "bridge_port_alias", instance, value);
}

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

static int get_BridgingBridgePort_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section)) {
		struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
		struct uci_section *port_s = NULL;
		char buf[1024] = {0};
		char br_port_path[64] = {0};

		snprintf(br_port_path, sizeof(br_port_path), "Device.Bridging.Bridge.%s.Port.", (char *)bridge_args->additional_data);

		uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", (char *)bridge_args->additional_data, port_s) {
			char *mg_port = NULL;
			char *port = NULL;

			dmuci_get_value_by_section_string(port_s, "management", &mg_port);
			if (DM_LSTRCMP(mg_port, "1") == 0)
				continue;

			dmuci_get_value_by_section_string(port_s, "port", &port);

			bbfdm_get_references(ctx, MATCH_ALL, br_port_path, "Name", port, buf, sizeof(buf));
		}

		*value = dmstrdup(buf);
	} else {
		dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "LowerLayers", value);

		if ((*value)[0] == '\0') {
			char *type = NULL, *port = NULL, *config = NULL;

			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "type", &type);
			if (DM_STRCMP(type, "34984") == 0)
				return 0;

			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "port", &port);
			if (DM_STRLEN(port) == 0)
				return 0;

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

			if (DM_LSTRCMP(config, "network") == 0) {
				struct uci_section *eth_iface_s = ethernet___get_ethernet_interface_section(port);
				if (!eth_iface_s) {
					char *tag = DM_STRRCHR(port, '.');
					if (tag) tag[0] = '\0';
				}

				_bbfdm_get_references(ctx, "Device.Ethernet.Interface.", "Name", port, value);
			} else {
				struct uci_section *iface_s = get_dup_section_in_config_opt("wireless", "wifi-iface", "ifname", port);
				if (iface_s != NULL) {
					char *ssid = NULL, *device = NULL, *name = NULL;

					dmuci_get_value_by_section_string(iface_s, "device", &device);
					dmuci_get_value_by_section_string(iface_s, "ssid", &ssid);


					struct uci_section *ssid_s = get_section_in_dmmap_with_options_eq("WiFi", "SSID", "device", device, "ssid", ssid);

					dmuci_get_value_by_section_string(ssid_s, "Name", &name);

					_bbfdm_get_references(ctx, "Device.WiFi.SSID.", "Name", name, value);
				}
			}

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

	}

	return 0;
}

static int set_BridgingBridgePort_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
	char *allowed_objects[] = {
			"Device.Ethernet.Interface.",
			"Device.WiFi.SSID.",
			"Device.Bridging.Bridge.*.Port.",
			NULL
	};
	struct dm_reference reference = {0};
	char *enable = NULL, *port = NULL, *type = NULL;

	bbfdm_get_reference_linker(ctx, value, &reference);

	if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
		return 0;

	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;

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

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

			// Update config section on dmmap_bridge_port if the linker is wirelss port or network port
			if (DM_LSTRNCMP(reference.path, "Device.WiFi.SSID.", 17) == 0) {
				dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "config", "wireless");
			} else {
				dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "config", "network");
			}

			// Get current port and enable options
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "port", &port);
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "enabled", &enable);

			if (DM_STRCMP(enable, "1") == 0) {
				// Remove port from port list interface
				remove_port_from_bridge_sections(bridge_args->config_section, bridge_args->dmmap_section, port);
			}

			// Update port option in dmmap
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "port", reference.value);

			if (DM_STRCMP(enable, "1") == 0) {
				// Add port to ports list
				add_port_to_bridge_sections(bridge_args->config_section, bridge_args->dmmap_section, reference.value);
			}

			// Update Bridge VLANPort instance if exists
			Update_BridgeVLANPort_Port_Layer(refparam, bridge_args->config_section, bridge_args->dmmap_section, (char *)bridge_args->additional_data, reference.value);
			return 0;
		}
	return 0;
}

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

static int set_BridgingBridgePort_ManagementPort(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
	char *bridge_name = NULL;
	bool b;

	string_to_bool(value, &b);

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

			if (b && get_section_in_dmmap_with_options_eq("dmmap_bridge_port", "bridge_port", "br_inst", (char *)bridge_args->additional_data, "management", "1"))
				return FAULT_9007;

			return 0;
		case VALUESET:
			dmuci_get_value_by_section_string(bridge_args->config_section, "name", &bridge_name);

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

			// Update Ethernet Link instance if exists
			if (b) ethernet___Update_Link_Layer(refparam, bridge_name);
			return 0;
	}
	return 0;
}

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

static int set_BridgingBridgePort_PriorityRegeneration(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt_list(ctx, value, 8, 8, -1, RANGE_ARGS{{"0","7"}}, 1))
				return FAULT_9007;

			if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
				return 0;

			if (dmuci_is_option_value_empty(((struct dm_data *)data)->config_section, "type"))
				return FAULT_9007;

			break;
		case VALUESET:
			if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
				return 0;

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

static int get_BridgingBridgePort_PVID(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, "vid", "1");
	return 0;
}

static int set_BridgingBridgePort_PVID(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
	char *ifname = NULL, *name = NULL, *type = NULL, *enable = NULL;
	char new_name[32] = {0};

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

			if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
				return 0;

			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "type", &type);
			if (DM_LSTRCMP(type, "8021q") != 0)
				return FAULT_9007;

			return 0;
		case VALUESET:
			if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
				return 0;

			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "vid", value);

			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ifname", &ifname);
			if (DM_STRLEN(ifname) == 0)
				return 0;

			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "enabled", &enable);
			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &name);

			snprintf(new_name, sizeof(new_name), "%s.%s", ifname, value);

			if (DM_STRCMP(enable, "1") == 0) {
				// Remove port from ports list
				remove_port_from_bridge_sections(bridge_args->config_section, bridge_args->dmmap_section, name);
			}

			/* Update Port dmmap section */
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "port", new_name);

			/* Update name option in network config */
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "name", new_name);

			if (DM_STRCMP(enable, "1") == 0) {
				// Add new port to ports list
				add_port_to_bridge_sections(bridge_args->config_section, bridge_args->dmmap_section, new_name);
			}

			return 0;
	}
	return 0;
}

static int get_BridgingBridgePort_Type(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *dev_type = NULL;
	char *port_type = NULL;

	// Get type from config section and map it
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "type", &dev_type);
	port_type = get_bridge_port_type(dev_type);
	*value = dmstrdup(port_type ? port_type : "VLANUnawarePort");
	return 0;
}

static int set_BridgingBridgePort_Type(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *dev_type = NULL;
	char *bridge_type[] = {"ProviderNetworkPort", "CustomerNetworkPort", "CustomerEdgePort", "CustomerVLANPort", "VLANUnawarePort", NULL};

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, bridge_type, NULL))
				return FAULT_9007;
			return 0;
		case VALUESET:
			if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
				return 0;

			dev_type = get_bridge_device_type(value);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "type", dev_type ? dev_type : "");
			return 0;
	}
	return 0;
}

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

	// Check config section TPID
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "tpid", value);
	if (*value && DM_STRLEN(*value) > 0)
		return 0;

	// Default TPID based on type
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "type", &type);
	if (DM_LSTRCMP(type, "8021ad") == 0)
		*value = dmstrdup("34984");
	else if (DM_LSTRCMP(type, "8021q") == 0)
		*value = dmstrdup("33024");
	else
		*value = dmstrdup("37120");
	return 0;
}

static int set_BridgingBridgePort_TPID(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;
			return 0;
		case VALUESET:
			if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section))
				return 0;

			// Store TPID in config section
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "tpid", value);
			return 0;
	}
	return 0;
}

static int br_get_sysfs(const struct dm_data *bridge_sec, const char *name, char **value)
{
	char *device = NULL;

	dmuci_get_value_by_section_string(bridge_sec->config_section, "ifname", &device);
	return get_net_device_sysfs(device, name, value);
}

static int br_get_ubus_eth(const struct dm_data *bridge_sec, const char *name, char **value)
{
	json_object *res = NULL;
	char *device = NULL, *config = NULL;

	DM_ASSERT(bridge_sec, *value = dmstrdup("0"));
	dmuci_get_value_by_section_string(bridge_sec->config_section, "ifname", &device);
	dmuci_get_value_by_section_string(bridge_sec->dmmap_section, "config", &config);

	if (DM_LSTRCMP(config, "network") == 0) {
		*value = dmstrdup("0");
	} else {
		char *radio = NULL;
		bool radio_disable = true;

		dmuci_get_value_by_section_string(bridge_sec->config_section, "device", &radio);
		if (DM_STRLEN(radio) == 0) {
			*value = dmstrdup("0");
			return 0;
		}

		/* Find the wifi-device is disabled or not */
		char *disable = dmuci_get_option_value_fallback_def("wireless", radio, "disabled", "0");
		string_to_bool(disable, &radio_disable);

		if (!radio_disable) {
			char object[32];

			snprintf(object, sizeof(object), "wifi.ap.%s", device);
			dmubus_call(object, "stats", UBUS_ARGS{0}, 0, &res);
		}
	}

	DM_ASSERT(res, *value = dmstrdup("0"));
	*value = dmjson_get_value(res, 1, name);
	return 0;
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.BytesSent!SYSFS:/sys/class/net/@Name/statistics/tx_bytes*/
static int get_BridgingBridgePortStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/tx_bytes", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.BytesSent!SYSFS:/sys/class/net/@Name/statistics/rx_bytes*/
static int get_BridgingBridgePortStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/rx_bytes", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.PacketsSent!SYSFS:/sys/class/net/@Name/statistics/tx_packets*/
static int get_BridgingBridgePortStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/tx_packets", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.PacketsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_packets*/
static int get_BridgingBridgePortStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/rx_packets", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.ErrorsSent!SYSFS:/sys/class/net/@Name/statistics/tx_errors*/
static int get_BridgingBridgePortStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/tx_errors", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.ErrorsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_errors*/
static int get_BridgingBridgePortStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/rx_errors", value);
}

static int get_BridgingBridgePortStats_UnicastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_ubus_eth(data, "tx_unicast_packets", value);
}

static int get_BridgingBridgePortStats_UnicastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_ubus_eth(data, "rx_unicast_packets", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.DiscardPacketsSent!SYSFS:/sys/class/net/@Name/statistics/tx_dropped*/
static int get_BridgingBridgePortStats_DiscardPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/tx_dropped", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.DiscardPacketsReceived!SYSFS:/sys/class/net/@Name/statistics/rx_dropped*/
static int get_BridgingBridgePortStats_DiscardPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/rx_dropped", value);
}

static int get_BridgingBridgePortStats_MulticastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_ubus_eth(data, "tx_multicast_packets", value);
}

/*#Device.Bridging.Bridge.{i}.Port.{i}.Stats.MulticastPacketsReceived!SYSFS:/sys/class/net/@Name/statistics/multicast*/
static int get_BridgingBridgePortStats_MulticastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_sysfs(data, "statistics/multicast", value);
}

static int get_BridgingBridgePortStats_BroadcastPacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_ubus_eth(data, "tx_broadcast_packets", value);
}

static int get_BridgingBridgePortStats_BroadcastPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_ubus_eth(data, "rx_broadcast_packets", value);
}

static int get_BridgingBridgePortStats_UnknownProtoPacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	return br_get_ubus_eth(data, "rx_unknown_packets", value);
}

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

static int set_BridgingBridgeVLAN_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;
			return 0;
		case VALUESET:
			return 0;
	}
	return 0;
}

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

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

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

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

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

static int set_BridgingBridgeVLAN_VLANID(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"1","4094"}}, 1))
				return FAULT_9007;
			return 0;
		case VALUESET:
			// Update vid option
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "vid", value);

			// Update Bridge VLANPort instance if exists
			Update_BridgeVLANPort_VLAN_Layer(refparam, bridge_args->config_section, bridge_args->dmmap_section, (char *)bridge_args->additional_data, value);
			return 0;
	}
	return 0;
}

static int get_BridgingBridgeVLANPort_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, "enabled", "1");
	return 0;
}

static int set_BridgingBridgeVLANPort_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, "enabled", b ? "1" : "0");
			break;
	}
	return 0;
}

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

static int set_BridgingBridgeVLANPort_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, "bridge_vlanport_alias", instance, value);
}

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

	if ((*value)[0] == '\0') {
		struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
		char br_vlan_path[64] = {0};
		char *vid = NULL;

		snprintf(br_vlan_path, sizeof(br_vlan_path), "Device.Bridging.Bridge.%s.VLAN.", (char *)bridge_args->additional_data);

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

		_bbfdm_get_references(ctx, br_vlan_path, "VLANID", vid, value);

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

	return 0;
}

static int set_BridgingBridgeVLANPort_VLAN(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
	char lower_layer_path[256] = {0};
	char *allowed_objects[] = {
			lower_layer_path,
			NULL
	};
	struct dm_reference reference = {0};
	char *port_ref = NULL;

	bbfdm_get_reference_linker(ctx, value, &reference);

	snprintf(lower_layer_path, sizeof(lower_layer_path), "Device.Bridging.Bridge.%s.VLAN.", (char *)bridge_args->additional_data);

	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;

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

			// Update vid option
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "vid", reference.value);

			// Update Port instance
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "Port", &port_ref);
			if (DM_STRLEN(port_ref)) {
				char *ifname = NULL;
				char *old_name = NULL;
				char new_name[32] = {0};

				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "ifname", &ifname);
				if (!DM_STRLEN(ifname))
					break;

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

				snprintf(new_name, sizeof(new_name), "%s%s%s", ifname, DM_STRLEN(reference.value) ? "." : "", DM_STRLEN(reference.value) ? reference.value : "");

				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "name", new_name);

				// Update Bridge Port instance if exists
				Update_BridgePort_Port_Layer(port_ref, ((struct dm_data *)data)->config_section, bridge_args->config_section, bridge_args->dmmap_section, (char *)bridge_args->additional_data, old_name, new_name);
			}

			return 0;
	}
	return 0;
}

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

	if ((*value)[0] == '\0') {
		struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
		char br_port_path[128] = {0};
		char *name = NULL;

		snprintf(br_port_path, sizeof(br_port_path), "Device.Bridging.Bridge.%s.Port.", (char *)bridge_args->additional_data);

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

		_bbfdm_get_references(ctx, br_port_path, "Name", name, value);

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

	return 0;
}

static int set_BridgingBridgeVLANPort_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	struct dm_data *bridge_args = ((struct dm_data *)data)->additional_data;
	char lower_layer_path[64] = {0};
	char *allowed_objects[] = {
			lower_layer_path,
			NULL
	};
	struct dm_reference reference = {0};
	char *old_name = NULL;
	char new_name[32] = {0};
	char *vid = NULL;

	bbfdm_get_reference_linker(ctx, value, &reference);

	snprintf(lower_layer_path, sizeof(lower_layer_path), "Device.Bridging.Bridge.%s.Port.", (char *)bridge_args->additional_data);

	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;

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

			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "vid", &vid);
			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &old_name);

			snprintf(new_name, sizeof(new_name), "%s%s%s", DM_STRLEN(reference.value) ? reference.value : "",
									(DM_STRLEN(reference.value) && DM_STRLEN(vid)) ? "." : "",
									(DM_STRLEN(reference.value) && DM_STRLEN(vid)) ? vid : "");

			// Set ifname and name options
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "ifname", reference.value);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "name", new_name);

			// Update Bridge Port instance if exists
			Update_BridgePort_Port_Layer(reference.path, ((struct dm_data *)data)->config_section, bridge_args->config_section, bridge_args->dmmap_section, (char *)bridge_args->additional_data, DM_STRLEN(old_name) ? old_name : reference.value, new_name);
			return 0;
	}
	return 0;
}

static int get_BridgingBridgeVLANPort_Untagged(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *type;
	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "type", &type);
	*value = (DM_STRLEN(type) == 0) ? dmstrdup("1") : dmstrdup("0");
	return 0;
}

static int set_BridgingBridgeVLANPort_Untagged(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, "type", (!b) ? "8021q" : "");
			return 0;
	}
	return 0;
}

static int get_BridgingBridgeProviderBridge_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, "enabled", "1");
	return 0;
}

static int set_BridgingBridgeProviderBridge_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, "enabled", b ? "1" : "0");
		break;
	}
	return 0;
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "name", &name);
	get_net_device_status(name, value);
	if (DM_STRCMP(*value, "Up") == 0) {
		*value = dmstrdup("Enabled");
	} else {
		*value = dmstrdup("Disabled");
	}
	return 0;
}

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

static int set_BridgingBridgeProviderBridge_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action)	{
	case VALUECHECK:
		if (bbfdm_validate_string(ctx, value, -1, 64, NULL, NULL))
			return FAULT_9007;
		break;
	case VALUESET:
		dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "provider_bridge_alias", value);
		break;
	}
	return 0;
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "svlan_br_inst", &br_inst);
	if (DM_STRLEN(br_inst))
		dmasprintf(value, "Device.Bridging.Bridge.%s", br_inst);
	return 0;
}

static int set_BridgingBridgeProviderBridge_SVLANcomponent(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *allowed_objects[] = {"Device.Bridging.Bridge.", NULL};
	struct dm_reference reference = {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;

		break;
	case VALUESET:
		set_Provider_bridge_component(refparam, ctx, data, instance, reference.value, "SVLAN");
		break;
	}
	return 0;
}

static int get_BridgingBridgeProviderBridge_CVLANcomponents(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	struct uci_list *cvlan_list = NULL;
	struct uci_element *e = NULL;
	char cvlan_buf[2048] = {0};
	unsigned pos = 0;

	dmuci_get_value_by_section_list(((struct dm_data *)data)->dmmap_section, "cvlan_br_inst", &cvlan_list);
	if (cvlan_list == NULL)
		return 0;

	cvlan_buf[0] = 0;
	/* Traverse each list value and create comma separated bridge path */
	uci_foreach_element(cvlan_list, e) {
		pos += snprintf(&cvlan_buf[pos], sizeof(cvlan_buf) - pos, "Device.Bridging.Bridge.%s,", e->name);
	}

	if (pos)
		cvlan_buf[pos - 1] = 0;

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

static int set_BridgingBridgeProviderBridge_CVLANcomponents(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *allowed_objects[] = {"Device.Bridging.Bridge.", NULL};
	struct dm_reference reference = {0};
	char *pch = NULL, *pchr = NULL;
	char buf[512] = {0};

	DM_STRNCPY(buf, value, sizeof(buf));

	switch (action)	{
		case VALUECHECK:
			// Validate each item in list and Check if bridge is present
			for (pch = strtok_r(buf, ",", &pchr); pch != NULL; pch = strtok_r(NULL, ",", &pchr)) {
				// Parse each Bridge path and validate:

				bbfdm_get_reference_linker(ctx, pch, &reference);

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

			break;
		case VALUESET:
			for (pch = strtok_r(buf, ",", &pchr); pch != NULL; pch = strtok_r(NULL, ",", &pchr)) {

				bbfdm_get_reference_linker(ctx, pch, &reference);

				set_Provider_bridge_component(refparam, ctx, data, instance, reference.value, "CVLAN");
			}
			break;
	}
	return 0;
}

#ifdef BRIDGE_ENABLE_VENDOR_EXT
static int get_BridgingBridgePort_Egress_PriorityRegeneration(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	bridging___get_priority_list(((struct dm_data *)data)->config_section, "egress_qos_mapping", data, value);
	return 0;
}

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

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_unsignedInt_list(ctx, value, 8, 8, -1, RANGE_ARGS{{"0","7"}}, 1))
				return FAULT_9007;

			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "type", &type);
			if (bridging___is_management_port_instance(((struct dm_data *)data)->dmmap_section) || DM_STRLEN(type) == 0)
				return FAULT_9007;

			return 0;
		case VALUESET:
			bridging___set_priority_list(((struct dm_data *)data)->config_section, "egress_qos_mapping", data, value);
			return 0;
	}
	return 0;
}
#endif /* BRIDGE_ENABLE_VENDOR_EXT */

/**********************************************************************************************************************************
*                                            OBJ & PARAM DEFINITION
***********************************************************************************************************************************/
/*** Bridging.Bridge.{i}.STP. ***/
DMLEAF tBridgingBridgeSTPParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_BridgingBridgeSTP_Enable, set_BridgingBridgeSTP_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_BridgingBridgeSTP_Status, NULL, BBFDM_BOTH},
{"Protocol", &DMWRITE, DMT_STRING, get_BridgingBridgeSTP_Protocol, set_BridgingBridgeSTP_Protocol, BBFDM_BOTH},
{"BridgePriority", &DMWRITE, DMT_UNINT, get_BridgingBridgeSTP_BridgePriority, set_BridgingBridgeSTP_BridgePriority, BBFDM_BOTH},
{"HelloTime", &DMWRITE, DMT_UNINT, get_BridgingBridgeSTP_HelloTime, set_BridgingBridgeSTP_HelloTime, BBFDM_BOTH},
{"MaxAge", &DMWRITE, DMT_UNINT, get_BridgingBridgeSTP_MaxAge, set_BridgingBridgeSTP_MaxAge, BBFDM_BOTH},
{"ForwardingDelay", &DMWRITE, DMT_UNINT, get_BridgingBridgeSTP_ForwardingDelay, set_BridgingBridgeSTP_ForwardingDelay, BBFDM_BOTH},
{0}
};

/*** Bridging.Bridge.{i}.VLAN.{i}. ***/
DMLEAF tBridgingBridgeVLANParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_BridgingBridgeVLAN_Enable, set_BridgingBridgeVLAN_Enable, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_BridgingBridgeVLAN_Alias, set_BridgingBridgeVLAN_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"Name", &DMWRITE, DMT_STRING, get_BridgingBridgeVLAN_Name, set_BridgingBridgeVLAN_Name, BBFDM_BOTH},
{"VLANID", &DMWRITE, DMT_INT, get_BridgingBridgeVLAN_VLANID, set_BridgingBridgeVLAN_VLANID, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER},
{0}
};

/*** Bridging.Bridge.{i}.VLANPort.{i}. ***/
DMLEAF tBridgingBridgeVLANPortParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_BridgingBridgeVLANPort_Enable, set_BridgingBridgeVLANPort_Enable, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING,  get_BridgingBridgeVLANPort_Alias, set_BridgingBridgeVLANPort_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"VLAN", &DMWRITE, DMT_STRING,  get_BridgingBridgeVLANPort_VLAN, set_BridgingBridgeVLANPort_VLAN, BBFDM_BOTH, DM_FLAG_REFERENCE|DM_FLAG_UNIQUE},
{"Port", &DMWRITE, DMT_STRING, get_BridgingBridgeVLANPort_Port, set_BridgingBridgeVLANPort_Port, BBFDM_BOTH, DM_FLAG_REFERENCE|DM_FLAG_UNIQUE},
{"Untagged", &DMWRITE, DMT_BOOL, get_BridgingBridgeVLANPort_Untagged, set_BridgingBridgeVLANPort_Untagged, BBFDM_BOTH},
{0}
};

/*** Bridging.ProviderBridge.{i}. ***/
DMLEAF tBridgingProviderBridgeParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_BridgingBridgeProviderBridge_Enable, set_BridgingBridgeProviderBridge_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_BridgingBridgeProviderBridge_Status, NULL, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_BridgingBridgeProviderBridge_Alias, set_BridgingBridgeProviderBridge_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"SVLANcomponent", &DMWRITE, DMT_STRING, get_BridgingBridgeProviderBridge_SVLANcomponent, set_BridgingBridgeProviderBridge_SVLANcomponent, BBFDM_BOTH, DM_FLAG_REFERENCE},
{"CVLANcomponents", &DMWRITE, DMT_STRING, get_BridgingBridgeProviderBridge_CVLANcomponents, set_BridgingBridgeProviderBridge_CVLANcomponents, BBFDM_BOTH, DM_FLAG_REFERENCE},
{0}
};

/*** Bridging.Bridge.{i}.Port.{i}.Stats. ***/
DMLEAF tBridgingBridgePortStatsParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"BytesSent", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_BytesSent, NULL, BBFDM_BOTH},
{"BytesReceived", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_BytesReceived, NULL, BBFDM_BOTH},
{"PacketsSent", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_PacketsSent, NULL, BBFDM_BOTH},
{"PacketsReceived", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_PacketsReceived, NULL, BBFDM_BOTH},
{"ErrorsSent", &DMREAD, DMT_UNINT, get_BridgingBridgePortStats_ErrorsSent, NULL, BBFDM_BOTH},
{"ErrorsReceived", &DMREAD, DMT_UNINT, get_BridgingBridgePortStats_ErrorsReceived, NULL, BBFDM_BOTH},
{"UnicastPacketsSent", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_UnicastPacketsSent, NULL, BBFDM_BOTH},
{"UnicastPacketsReceived", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_UnicastPacketsReceived, NULL, BBFDM_BOTH},
{"DiscardPacketsSent", &DMREAD, DMT_UNINT, get_BridgingBridgePortStats_DiscardPacketsSent, NULL, BBFDM_BOTH},
{"DiscardPacketsReceived", &DMREAD, DMT_UNINT, get_BridgingBridgePortStats_DiscardPacketsReceived, NULL, BBFDM_BOTH},
{"MulticastPacketsSent", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_MulticastPacketsSent, NULL, BBFDM_BOTH},
{"MulticastPacketsReceived", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_MulticastPacketsReceived, NULL, BBFDM_BOTH},
{"BroadcastPacketsSent", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_BroadcastPacketsSent, NULL, BBFDM_BOTH},
{"BroadcastPacketsReceived", &DMREAD, DMT_UNLONG, get_BridgingBridgePortStats_BroadcastPacketsReceived, NULL, BBFDM_BOTH},
{"UnknownProtoPacketsReceived", &DMREAD, DMT_UNINT, get_BridgingBridgePortStats_UnknownProtoPacketsReceived, NULL, BBFDM_BOTH},
{0}
};

/*** Bridging.Bridge.{i}.Port.{i}. ***/
DMOBJ tBridgingBridgePortObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Stats", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tBridgingBridgePortStatsParams, NULL, BBFDM_BOTH, NULL},
#ifdef BRIDGE_ENABLE_FDB_EXT
{BBF_VENDOR_PREFIX"FDBEntry", &DMREAD, NULL, NULL, NULL, browseBridgingBridgePortFDBEntryInst, NULL, NULL, NULL, tBridgingBridgePortFDBEntryParams, NULL, BBFDM_BOTH, NULL},
#endif
{0}
};

DMLEAF tBridgingBridgePortParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_BridgingBridgePort_Enable, set_BridgingBridgePort_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_BridgingBridgePort_Status, NULL, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_BridgingBridgePort_Alias, set_BridgingBridgePort_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"Name", &DMREAD, DMT_STRING, get_BridgingBridgePort_Name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER},
//{"LastChange", &DMREAD, DMT_UNINT, get_BridgingBridgePort_LastChange, NULL, BBFDM_BOTH},
{"LowerLayers", &DMWRITE, DMT_STRING, get_BridgingBridgePort_LowerLayers, set_BridgingBridgePort_LowerLayers, BBFDM_BOTH, DM_FLAG_REFERENCE},
{"ManagementPort", &DMWRITE, DMT_BOOL, get_BridgingBridgePort_ManagementPort, set_BridgingBridgePort_ManagementPort, BBFDM_BOTH},
{"Type", &DMWRITE, DMT_STRING, get_BridgingBridgePort_Type, set_BridgingBridgePort_Type, BBFDM_BOTH},
//{"DefaultUserPriority", &DMWRITE, DMT_UNINT, get_BridgingBridgePort_DefaultUserPriority, set_BridgingBridgePort_DefaultUserPriority, BBFDM_BOTH},
{"PriorityRegeneration", &DMWRITE, DMT_STRING, get_BridgingBridgePort_PriorityRegeneration, set_BridgingBridgePort_PriorityRegeneration, BBFDM_BOTH},
//{"PortState", &DMREAD, DMT_STRING, get_BridgingBridgePort_PortState, NULL, BBFDM_BOTH},
{"PVID", &DMWRITE, DMT_INT, get_BridgingBridgePort_PVID, set_BridgingBridgePort_PVID, BBFDM_BOTH},
{"TPID", &DMWRITE, DMT_UNINT, get_BridgingBridgePort_TPID, set_BridgingBridgePort_TPID, BBFDM_BOTH},
#ifdef BRIDGE_ENABLE_VENDOR_EXT
{BBF_VENDOR_PREFIX"EgressPriorityRegeneration", &DMWRITE, DMT_STRING, get_BridgingBridgePort_Egress_PriorityRegeneration, set_BridgingBridgePort_Egress_PriorityRegeneration, BBFDM_BOTH},
#endif
#ifdef BRIDGE_ENABLE_FDB_EXT
{BBF_VENDOR_PREFIX"FDBEntryNumberOfEntries", &DMREAD, DMT_UNINT, get_BridgingBridgePort_FDBEntryNumberOfEntries, NULL, BBFDM_BOTH},
#endif
{0}
};

/*** Bridging.Bridge.{i}. ***/
DMOBJ tBridgingBridgeObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"STP", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tBridgingBridgeSTPParams, NULL, BBFDM_BOTH},
{"Port", &DMWRITE, addObjBridgingBridgePort, delObjBridgingBridgePort, NULL, browseBridgingBridgePortInst, NULL, NULL, tBridgingBridgePortObj, tBridgingBridgePortParams, NULL, BBFDM_BOTH, NULL},
{"VLAN", &DMWRITE, addObjBridgingBridgeVLAN, delObjBridgingBridgeVLAN, NULL, browseBridgingBridgeVLANInst, NULL, NULL, NULL, tBridgingBridgeVLANParams, NULL, BBFDM_BOTH, NULL},
{"VLANPort", &DMWRITE, addObjBridgingBridgeVLANPort, delObjBridgingBridgeVLANPort, NULL, browseBridgingBridgeVLANPortInst, NULL, NULL, NULL, tBridgingBridgeVLANPortParams, NULL, BBFDM_BOTH, NULL},
{0}
};

DMLEAF tBridgingBridgeParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"Enable", &DMWRITE, DMT_BOOL, get_BridgingBridge_Enable, set_BridgingBridge_Enable, BBFDM_BOTH},
{"Status", &DMREAD, DMT_STRING, get_BridgingBridge_Status, NULL, BBFDM_BOTH},
{"Alias", &DMWRITE, DMT_STRING, get_BridgingBridge_Alias, set_BridgingBridge_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE},
{"Name", &DMREAD, DMT_STRING, get_BridgingBridge_Name, NULL, BBFDM_BOTH, DM_FLAG_LINKER},
{"Standard", &DMWRITE, DMT_STRING, get_BridgingBridge_Standard, set_BridgingBridge_Standard, BBFDM_BOTH},
{"PortNumberOfEntries", &DMREAD, DMT_UNINT, get_BridgingBridge_PortNumberOfEntries, NULL, BBFDM_BOTH},
{"VLANNumberOfEntries", &DMREAD, DMT_UNINT, get_BridgingBridge_VLANNumberOfEntries, NULL, BBFDM_BOTH},
{"VLANPortNumberOfEntries", &DMREAD, DMT_UNINT, get_BridgingBridge_VLANPortNumberOfEntries, NULL, BBFDM_BOTH},
#ifdef BRIDGE_ENABLE_VENDOR_EXT
{BBF_VENDOR_PREFIX"VLANFiltering", &DMWRITE, DMT_BOOL, get_BridgingBridge_VLANFiltering, set_BridgingBridge_VLANFiltering, BBFDM_BOTH},
#endif
{0}
};

/* *** Device.Bridging. *** */
DMLEAF tBridgingParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"MaxBridgeEntries", &DMREAD, DMT_UNINT, get_Bridging_MaxBridgeEntries, NULL, BBFDM_BOTH},
{"MaxDBridgeEntries", &DMREAD, DMT_UNINT, get_Bridging_MaxDBridgeEntries, NULL, BBFDM_BOTH},
{"MaxQBridgeEntries", &DMREAD, DMT_UNINT, get_Bridging_MaxQBridgeEntries, NULL, BBFDM_BOTH},
{"MaxVLANEntries", &DMREAD, DMT_UNINT, get_Bridging_MaxVLANEntries, NULL, BBFDM_BOTH},
{"MaxProviderBridgeEntries", &DMREAD, DMT_UNINT, get_Bridging_MaxProviderBridgeEntries, NULL, BBFDM_BOTH},
{"ProviderBridgeNumberOfEntries", &DMREAD, DMT_UNINT, get_Bridging_ProviderBridgeNumberOfEntries, NULL, BBFDM_BOTH},
{"MaxFilterEntries", &DMREAD, DMT_UNINT, get_Bridging_get_Bridging_MaxFilterEntries, NULL, BBFDM_BOTH},
{"BridgeNumberOfEntries", &DMREAD, DMT_UNINT, get_Bridging_BridgeNumberOfEntries, NULL, BBFDM_BOTH},
{0}
};

DMOBJ tBridgingObj[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys, version*/
{"Bridge", &DMWRITE, addObjBridgingBridge, delObjBridgingBridge, NULL, browseBridgingBridgeInst, NULL, NULL, tBridgingBridgeObj, tBridgingBridgeParams, NULL, BBFDM_BOTH, NULL},
{"ProviderBridge", &DMWRITE, addObjBridgingProviderBridge, delObjBridgingProviderBridge, NULL, browseBridgingProviderBridgeInst, NULL, NULL, NULL, tBridgingProviderBridgeParams, NULL, BBFDM_BOTH, NULL},
{0}
};

/*** Device. ***/
DMOBJ tDeviceObjs[] = {
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/
{"Bridging", &DMREAD, NULL, NULL, "file:/etc/config/network", NULL, NULL, NULL, tBridgingObj, tBridgingParams, NULL, BBFDM_BOTH, NULL},
{0}
};

/* ********** DynamicObj ********** */
DM_MAP_OBJ tDynamicObj[] = {
/* parentobj, nextobject, parameter */
{"Device.", tDeviceObjs, NULL},
{0}
};

