/*
 * bridging.c: Device.Bridging. datamodel implementation for Layer2 device
 *
 * Copyright (C) 2026 IOPSYS Software Solutions AB. All rights reserved.
 *
 * Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
 *
 * See LICENSE file for license related information.
 */

#include "libbbfdm-ubus/bbfdm-ubus.h"
#include "libbbfdm-api/dmcommon.h"
#include "libbbfdm-api/dmapi.h"

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

/* ============================================================================
 * BRIDGE INSTANCE BROWSING
 * Browse Device.Bridging.Bridge.{i} instances from bridging UCI config
 * ============================================================================ */
static int browseBridgingBridgeInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return generic_browse(dmctx, parent_node, prev_data, prev_instance);
}

/* ============================================================================
 * BRIDGE PORT INSTANCE BROWSING
 * Browse Device.Bridging.Bridge.{i}.Port.{i} instances from port config
 * ============================================================================ */
static int browseBridgingBridgePortInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return generic_browse(dmctx, parent_node, prev_data, prev_instance);
}

/* ============================================================================
 * BRIDGE VLAN INSTANCE BROWSING
 * Browse Device.Bridging.Bridge.{i}.VLAN.{i} instances from bridge-vlan config
 * ============================================================================ */
static int browseBridgingBridgeVLANInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return generic_browse(dmctx, parent_node, prev_data, prev_instance);
}

/* ============================================================================
 * BRIDGE VLAN PORT INSTANCE BROWSING
 * Browse Device.Bridging.Bridge.{i}.VLANPort.{i} instances from vlan-port config
 * ============================================================================ */
static int browseBridgingBridgeVLANPortInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance)
{
	return generic_browse(dmctx, parent_node, prev_data, prev_instance);
}

/* ============================================================================
 * ADD / DELETE OBJECT OPERATIONS
 * Manage creation and deletion of bridge, port, VLAN, and VLAN port objects
 * ============================================================================ */

/* Add a new bridge to the bridging configuration */
static int addObjBridgingBridge(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	struct dm_data *curr_data = (struct dm_data *)ctx->addobj_instance;
	char sec_name[32] = {0}, name[16] = {0};

	snprintf(sec_name, sizeof(sec_name), "br_bridge%s", *instance);
	snprintf(name, sizeof(name), "br-bridge%s", *instance);

	dmuci_add_named_section("bridging", "bridge", sec_name, &curr_data->config_section);
	dmuci_set_value_by_section(curr_data->config_section, "name", name);
	dmuci_set_value_by_section(curr_data->config_section, "enabled", "0");
	dmuci_set_value_by_section(curr_data->config_section, "stp", "0");
	dmuci_set_value_by_section(curr_data->config_section, "priority", "32767");
	dmuci_set_value_by_section(curr_data->config_section, "hello_time", "2");
	dmuci_set_value_by_section(curr_data->config_section, "max_age", "20");
	dmuci_set_value_by_section(curr_data->config_section, "forward_delay", "4");

	dmuci_set_value_by_section(curr_data->dmmap_section, "Name", name);

	return 0;
}

/* Delete a bridge and all its associated ports, VLANs, and VLAN ports */
static int delObjBridgingBridge(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	struct uci_section *s = NULL, *stmp = NULL, *conf_s = NULL;
	char *bridge_inst = NULL, *port_sec_name = NULL, *vlan_sec_name = NULL, *vport_sec_name = NULL;

	switch (del_action) {
		case DEL_INST:
			dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "__instance__", &bridge_inst);

			if (DM_STRLEN(bridge_inst) != 0) {
				/* Delete all port sections for this bridge */
				uci_path_foreach_option_eq_safe(bbfdm, "Bridging", "Port", "Bridge", bridge_inst, stmp, s) {
					dmuci_get_value_by_section_string(s, "__section_name__", &port_sec_name);
					conf_s = get_config_section_from_dmmap_section_name(port_sec_name);

					if (conf_s != NULL)
						dmuci_delete_by_section(conf_s, NULL, NULL);

					dmuci_delete_by_section(s, NULL, NULL);
				}

				/* Delete all vlan sections for this bridge */
				uci_path_foreach_option_eq_safe(bbfdm, "Bridging", "VLAN", "Bridge", bridge_inst, stmp, s) {
					dmuci_get_value_by_section_string(s, "__section_name__", &vlan_sec_name);
					conf_s = get_config_section_from_dmmap_section_name(vlan_sec_name);

					if (conf_s != NULL)
						dmuci_delete_by_section(conf_s, NULL, NULL);

					dmuci_delete_by_section(s, NULL, NULL);
				}

				/* Delete all vlanport sections for this bridge */
				uci_path_foreach_option_eq_safe(bbfdm, "Bridging", "VLANPort", "Bridge", bridge_inst, stmp, s) {
					dmuci_get_value_by_section_string(s, "__section_name__", &vport_sec_name);
					conf_s = get_config_section_from_dmmap_section_name(vport_sec_name);

					if (conf_s != NULL)
						dmuci_delete_by_section(conf_s, NULL, NULL);

					dmuci_delete_by_section(s, NULL, NULL);
				}
			}

			/* Delete the bridge itself */
			dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
			dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);
			break;
		case DEL_ALL:
			break;
	}

	return 0;
}

/* Add a new bridge port to the bridging configuration */
static int addObjBridgingBridgePort(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	char port_section_name[32] = {0};
	char *br_inst = NULL;
	struct dm_data *curr_data = (struct dm_data *)ctx->addobj_instance;

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

	/* Create bridge name from instance */
	snprintf(port_section_name, sizeof(port_section_name), "br_%s_p_%s", br_inst, *instance);

	/* Add port section to bridging UCI config */
	dmuci_add_named_section("bridging", "port", port_section_name, &curr_data->config_section);
	dmuci_set_value_by_section(curr_data->config_section, "bridge", section_name(((struct dm_data *)data)->config_section));
	dmuci_set_value_by_section(curr_data->config_section, "enabled", "0");
	dmuci_set_value_by_section(curr_data->dmmap_section, "Name", port_section_name);

	return 0;
}

/* Delete a bridge port from the bridging configuration */
static int delObjBridgingBridgePort(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	struct uci_section *s = NULL, *stmp = NULL;
	char *port_section_name = NULL, *bridge = NULL;

	switch (del_action) {
		case DEL_INST:
			port_section_name = section_name(((struct dm_data *)data)->config_section);
			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "bridge", &bridge);

			/* Unset all vlanport referencing to this Port */
			uci_foreach_option_eq_safe("bridging", "vlanport", "port", port_section_name, stmp, s) {
				char *vport_br = NULL;
				dmuci_get_value_by_section_string(s, "bridge", &vport_br);

				if (DM_STRCMP(bridge, vport_br) != 0)
					continue;

				dmuci_set_value_by_section(s, "port", "");
			}

			/* Delete the port itself */
			dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
			dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);
			break;
		case DEL_ALL:
			break;
	}

	return 0;
}

/* Add a new bridge VLAN to the bridging configuration */
static int addObjBridgingBridgeVLAN(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	char bv_section_name[32] = {0};
	char *br_inst = NULL;
	struct dm_data *curr_data = (struct dm_data *)ctx->addobj_instance;

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

	/* Create bridge name from instance */
	snprintf(bv_section_name, sizeof(bv_section_name), "br_%s_bv_%s", br_inst, *instance);

	/* Add port section to bridging UCI config */
	dmuci_add_named_section("bridging", "vlan", bv_section_name, &curr_data->config_section);
	dmuci_set_value_by_section(curr_data->config_section, "bridge", section_name(((struct dm_data *)data)->config_section));
	dmuci_set_value_by_section(curr_data->config_section, "enabled", "0");

	return 0;
}

/* Delete a bridge VLAN from the bridging configuration */
static int delObjBridgingBridgeVLAN(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	struct uci_section *s = NULL, *stmp = NULL;
	char *vlan_section_name = NULL, *bridge = NULL;

	switch (del_action) {
		case DEL_INST:
			vlan_section_name = section_name(((struct dm_data *)data)->config_section);
			dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "bridge", &bridge);

			/* Unset all vlanport referencing to this VLAN */
			uci_foreach_option_eq_safe("bridging", "vlanport", "vlan", vlan_section_name, stmp, s) {
				char *vport_br = NULL;
				dmuci_get_value_by_section_string(s, "bridge", &vport_br);

				if (DM_STRCMP(bridge, vport_br) != 0)
					continue;

				dmuci_set_value_by_section(s, "vlan", "");
			}

			/* Delete the bridge-vlan itself */
			dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
			dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);
			break;
		case DEL_ALL:
			break;
	}

	return 0;
}

/* Add a new VLAN port to the bridging configuration */
static int addObjBridgingBridgeVLANPort(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
	char vp_section_name[32] = {0};
	char *br_inst = NULL;
	struct dm_data *curr_data = (struct dm_data *)ctx->addobj_instance;

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

	/* Create bridge name from instance */
	snprintf(vp_section_name, sizeof(vp_section_name), "br_%s_vp_%s", br_inst, *instance);

	/* Add port section to bridging UCI config */
	dmuci_add_named_section("bridging", "vlanport", vp_section_name, &curr_data->config_section);
	dmuci_set_value_by_section(curr_data->config_section, "bridge", section_name(((struct dm_data *)data)->config_section));
	dmuci_set_value_by_section(curr_data->config_section, "enabled", "0");
	dmuci_set_value_by_section(curr_data->config_section, "untagged", "0");

#ifdef BRIDGEMNGR_COPY_PBITS
	dmuci_set_value_by_section(curr_data->config_section, "pbit_inheritance", "1");
#else
	dmuci_set_value_by_section(curr_data->config_section, "pbit_inheritance", "0");
#endif
	return 0;
}

/* Delete a VLAN port from the bridging configuration */
static int delObjBridgingBridgeVLANPort(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
	switch (del_action) {
		case DEL_INST:
			dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL);
			dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL);
			break;
		case DEL_ALL:
			break;
	}

	return 0;
}

/* ============================================================================
 * GET / SET PARAMETER OPERATIONS
 * Get and set values for bridge, port, VLAN, and VLAN port parameters
 * ============================================================================ */

/* Bridging object 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_BridgeNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	int cnt = get_number_of_entries(ctx, data, instance, NULL);
	dmasprintf(value, "%d", cnt);
	return 0;
}

/* ============================================================================
 * BRIDGE PARAMETERS
 * Get and set values for bridge-level parameters
 * ============================================================================ */

/* Get bridge enable status from enabled option */
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;
}

/* Set bridge enable status */
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;
}

/* Get bridge status from device status */
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;
}

/* Get bridge alias for user-friendly reference */
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)->config_section, "Alias", instance, value);
}

/* Set bridge alias for user-friendly reference */
static int set_BridgingBridge_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "Alias", instance, value);
	return bbf_set_alias(ctx, ((struct dm_data *)data)->config_section, "Alias", instance, value);
}

/* Get bridge name from name option */
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)->dmmap_section, "Name", value);
	return 0;
}

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

/* Set bridge standard (no-op, always uses 802.1Q-2011) */
static int set_BridgingBridge_Standard(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			/* Standard valid values */
			char *Bridge_Standard[] = {"802.1D-2004", "802.1Q-2005", "802.1Q-2011", NULL};
			if (bbfdm_validate_string(ctx, value, -1, -1, Bridge_Standard, NULL))
				return FAULT_9007;
			return 0;
		case VALUESET:
			/* No-op: we always use 802.1Q-2011 */
			return 0;
	}
	return 0;
}

/* Get port count for this bridge */
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, NULL);
	dmasprintf(value, "%d", cnt);
	return 0;
}

/* Get VLAN count for this bridge */
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, NULL);
	dmasprintf(value, "%d", cnt);
	return 0;
}

/* Get VLAN port count for this bridge */
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, NULL);
	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 */

/* ============================================================================
 * BRIDGE STP PARAMETERS
 * Get and set values for STP (Spanning Tree Protocol) parameters
 * ============================================================================ */

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, *enable = 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;

	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)
{
	switch (action) {
		case VALUECHECK:
			char *Protocol[] = {"STP", NULL};
			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);
	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:
			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);
	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:
			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;
}

/* ============================================================================
 * BRIDGE PORT PARAMETERS
 * Get and set values for bridge port parameters
 * ============================================================================ */

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)->config_section, "enabled", value);
	return 0;
}

static int set_BridgingBridgePort_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;
}

static int get_BridgingBridgePort_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *port = NULL;
	bool is_mgmt = false;
	const char *mgmt = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "management", "0");

	string_to_bool(mgmt, &is_mgmt);
	if (is_mgmt) {
		char *bridge = NULL;
		struct uci_section *br_sec = NULL;

		dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "bridge", &bridge);
		br_sec = get_origin_section_from_config("bridging", "bridge", bridge);

		dmuci_get_value_by_section_string(br_sec, "name", &port);
	} else {
		dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &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)->config_section, "Alias", instance, value);
}

static int set_BridgingBridgePort_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "Alias", instance, value);
	return bbf_set_alias(ctx, ((struct dm_data *)data)->config_section, "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, "Name", value);
	return 0;
}

static int get_BridgingBridgePort_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	bool is_mgmt = false;
	const char *mgmt = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "management", "0");

	string_to_bool(mgmt, &is_mgmt);

	if (is_mgmt == true) {
		char *br_inst = NULL;
		struct uci_section *port_s = NULL;
		char buf[2048] = {0};
		int len = 0;

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

		uci_path_foreach_option_eq(bbfdm, "Bridging", "Port", "Bridge", br_inst, port_s) {
			if (port_s == ((struct dm_data *)data)->dmmap_section)
				continue;

			char *port_inst = NULL;
			dmuci_get_value_by_section_string(port_s, "__instance__", &port_inst);
			if (DM_STRLEN(port_inst) == 0)
				continue;

			char ref[64] = {0};
			snprintf(ref, sizeof(ref), "Device.Bridging.Bridge.%s.Port.%s", br_inst, port_inst);

			len = DM_STRLEN(buf);
			if ((sizeof(buf) - len) < strlen(ref)) {
				BBF_ERR("Buffer overflow detected. Buffer is not large enough to hold the complete data");
				return 0;
			}

			snprintf(&buf[len], sizeof(buf) - len, "%s%s", (len > 0) ? "," : "", ref);
		}

		*value = dmstrdup(buf);
	} else {
		char *lower_layers = NULL;

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

		_bbfdm_get_references(ctx, "Device.Ethernet.Interface.", "Name", lower_layers, value);
	}

	return 0;
}

static int set_BridgingBridgePort_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *allowed_objects[] = {
		"Device.Ethernet.Interface.",
		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:
			bbfdm_get_reference_linker(ctx, value, &reference);
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "name", reference.value);

			break;
	}
	return 0;
}

static int get_BridgingBridgePort_ManagementPort(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, "management", "0");
	return 0;
}

static int set_BridgingBridgePort_ManagementPort(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);
			if (b) {
				char *bridge = NULL, *bridge_dev_name = NULL;
				struct uci_section *br_sec = NULL;

				dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "bridge", &bridge);
				br_sec = get_origin_section_from_config("bridging", "bridge", bridge);

				if (br_sec) {
					dmuci_get_value_by_section_string(br_sec, "name", &bridge_dev_name);
					dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Name", bridge_dev_name);
				}
			} else {
				char *bridge_inst = NULL, *port_inst = NULL;
				char name[64] = {0};

				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "Bridge", &bridge_inst);
				dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "__instance__", &port_inst);

				snprintf(name, sizeof(name), "br_%s_p_%s", bridge_inst, port_inst);
				dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Name", name);
			}

			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "management", b ? "1" : "0");
			return 0;
	}
	return 0;
}

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

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

static int get_BridgingBridgePort_PriorityTagging(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_tagging", "0");
	return 0;
}

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

static int get_BridgingBridgePort_AcceptableFrameTypes(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, "accept_type", "");
	return 0;
}

static int set_BridgingBridgePort_AcceptableFrameTypes(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	// AdmitAll will lead to vlan transparency being set for the port and any vlan ports created with this port
	// Rest of the two options are only present to unset AdmitAll, and admittance will depend on the VLANPort's Untagged param
	char *AcceptableFrameTypes[] = {"AdmitAll", "", NULL};

	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, AcceptableFrameTypes, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "accept_type", value);
			break;
	}

	return 0;
}

/* Bridge port statistics - read from sysfs */
static int get_BridgingBridgePortStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *port = NULL;

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/tx_bytes", value);
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/rx_bytes", value);
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/tx_packets", value);
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/rx_packets", value);
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/tx_errors", value);
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/rx_errors", value);
}

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

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

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/tx_dropped", value);
}

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/rx_dropped", value);
}

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

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

	dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "name", &port);
	return get_net_device_sysfs(port, "statistics/multicast", value);
}

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

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

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

/* ============================================================================
 * BRIDGE VLAN PARAMETERS
 * Get and set values for bridge VLAN parameters
 * ============================================================================ */

static int get_BridgingBridgeVLAN_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_BridgingBridgeVLAN_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;
}

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, "Alias", instance, value);
}

static int set_BridgingBridgeVLAN_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "Alias", instance, value);
	return bbf_set_alias(ctx, ((struct dm_data *)data)->config_section, "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)
{
	*value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "vlan", "1");
	return 0;
}

static int set_BridgingBridgeVLAN_VLANID(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"1","4094"}}, 1))
				return FAULT_9007;
			return 0;
		case VALUESET:
			dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "vlan", (DM_STRTOUL(value) == 1) ? "" : value);
			dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "Name", (DM_STRTOUL(value) == 1) ? "" : value);
			return 0;
	}
	return 0;
}

/* ============================================================================
 * BRIDGE VLAN PORT PARAMETERS
 * Get and set values for bridge VLAN port parameters
 * ============================================================================ */

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;
			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;
}

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)->config_section, "Alias", instance, value);
}

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

static int get_BridgingBridgeVLANPort_VLAN(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *br_inst = NULL, *vlan_inst = NULL;
	char br_vlan_path[256] = {0}, vlan_sec_name[64] = {0};
	char *vlan = NULL;

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

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

	snprintf(vlan_sec_name, sizeof(vlan_sec_name), "bridging.%s", vlan);

	struct uci_section *vlan_s = get_dup_section_in_dmmap_opt("Bridging", "VLAN", "__section_name__", vlan_sec_name);
	if (vlan_s == NULL)
		return 0;

	dmuci_get_value_by_section_string(vlan_s, "__instance__", &vlan_inst);
	snprintf(br_vlan_path, sizeof(br_vlan_path), "Device.Bridging.Bridge.%s.VLAN.%s", br_inst, vlan_inst);

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

static int set_BridgingBridgeVLANPort_VLAN(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *br_inst = NULL;
	char lower_layer_path[256] = {0};
	struct dm_reference reference = {0};
	unsigned int br_id = 0, vl_id = 0;
	char b_inst[12] = {0}, v_inst[12] = {0};

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

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

        		snprintf(lower_layer_path, sizeof(lower_layer_path), "Device.Bridging.Bridge.%s.VLAN.", br_inst);
			char *allowed_objects[] = {lower_layer_path, NULL};
			bbfdm_get_reference_linker(ctx, value, &reference);

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

			break;
		case VALUESET:
			// Empty value set
			if (DM_STRLEN(value) == 0) {
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "vlan", "");
				break;
			}

			// Bridge vlan reference set
        		sscanf(value, "Device.Bridging.Bridge.%u.VLAN.%u", &br_id, &vl_id);
			if (br_id == 0 || vl_id == 0)
				return FAULT_9007;

			snprintf(b_inst, sizeof(b_inst), "%u", br_id);
			snprintf(v_inst, sizeof(v_inst), "%u", vl_id);
			struct uci_section *vlan_sec = get_section_in_dmmap_with_options_eq("Bridging", "VLAN", "Bridge", b_inst, "__instance__", v_inst);
			if (vlan_sec == NULL)
				return FAULT_9007;

			char *vlanorig_sec_name = NULL;
			dmuci_get_value_by_section_string(vlan_sec, "__section_name__", &vlanorig_sec_name);
			if (DM_STRLEN(vlanorig_sec_name) == 0)
				return FAULT_9007;

			struct uci_section *orig_s = get_config_section_from_dmmap_section_name(vlanorig_sec_name);
			if (orig_s == NULL)
				return FAULT_9007;

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

static int get_BridgingBridgeVLANPort_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	char *br_inst = NULL, *port_inst = NULL;
	char br_port_path[256] = {0}, port_sec_name[64] = {0};
	char *port = NULL;

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

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

	snprintf(port_sec_name, sizeof(port_sec_name), "bridging.%s", port);

	struct uci_section *port_s = get_dup_section_in_dmmap_opt("Bridging", "Port", "__section_name__", port_sec_name);
	if (port_s == NULL)
		return 0;

	dmuci_get_value_by_section_string(port_s, "__instance__", &port_inst);
	snprintf(br_port_path, sizeof(br_port_path), "Device.Bridging.Bridge.%s.Port.%s", br_inst, port_inst);

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

static int set_BridgingBridgeVLANPort_Port(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char *br_inst = NULL;
	char lower_layer_path[256] = {0};
	struct dm_reference reference = {0};
	unsigned int br_id = 0, p_id = 0;
	char b_inst[12] = {0}, p_inst[12] = {0};

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

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

        		snprintf(lower_layer_path, sizeof(lower_layer_path), "Device.Bridging.Bridge.%s.Port.", br_inst);
			char *allowed_objects[] = {lower_layer_path, NULL};
			bbfdm_get_reference_linker(ctx, value, &reference);

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

			break;
		case VALUESET:
			// Empty value set
			if (DM_STRLEN(value) == 0) {
				dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "port", "");
				break;
			}

			// Bridge port reference set
        		sscanf(value, "Device.Bridging.Bridge.%u.Port.%u", &br_id, &p_id);
			if (br_id == 0 || p_id == 0)
				return FAULT_9007;

			snprintf(b_inst, sizeof(b_inst), "%u", br_id);
			snprintf(p_inst, sizeof(p_inst), "%u", p_id);
			struct uci_section *port_sec = get_section_in_dmmap_with_options_eq("Bridging", "Port", "Bridge", b_inst, "__instance__", p_inst);
			if (port_sec == NULL)
				return FAULT_9007;

			char *portorig_sec_name = NULL;
			dmuci_get_value_by_section_string(port_sec, "__section_name__", &portorig_sec_name);
			if (DM_STRLEN(portorig_sec_name) == 0)
				return FAULT_9007;

			struct uci_section *orig_s = get_config_section_from_dmmap_section_name(portorig_sec_name);
			if (orig_s == NULL)
				return FAULT_9007;

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

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

#ifdef BRIDGE_ENABLE_VENDOR_EXT
static int get_BridgingBridgeVLANPort_TPID(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, "tpid", "0");
	return 0;
}

static int set_BridgingBridgeVLANPort_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{{"0","65535"}}, 1))
				return FAULT_9007;

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

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

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

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

static int set_BridgingBridgeVLANPort_PBIT_INHERITANCE(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, "pbit_inheritance", b ? "1" : "0");
			return 0;
	}
	return 0;
}
#endif /* BRIDGE_ENABLE_VENDOR_EXT */

/* ============================================================================
 * INIT & SYNC Handlers
 * ============================================================================ */
static void remove_stale_bridging_child_dmmap_sections(const char *type)
{
	struct uci_section *s = NULL, *tmp = NULL;

	uci_path_foreach_sections_safe(bbfdm, "Bridging", type, tmp, s) {
		char *orig_sec_name = NULL;

		dmuci_get_value_by_section_string(s, "__section_name__", &orig_sec_name);
		if (DM_STRLEN(orig_sec_name) == 0) {
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}

		struct uci_section *orig_sec = get_config_section_from_dmmap_section_name(orig_sec_name);
		if (orig_sec == NULL) {
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}

		char *bridge_ref = NULL;
		dmuci_get_value_by_section_string(orig_sec, "bridge", &bridge_ref);
		if (DM_STRLEN(bridge_ref) == 0) {
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}

		char br_sec_name[128] = {0};
		snprintf(br_sec_name, sizeof(br_sec_name), "bridging.%s", bridge_ref);
		struct uci_section *br_dmmap_s = get_dup_section_in_dmmap_opt("Bridging", "Bridge", "__section_name__", br_sec_name);
		if (br_dmmap_s == NULL) {
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}
	}
}

static void sync_bridging_bridge_port(struct dmctx *dmctx, struct uci_section *bridge_config_s, const char *bridge_instance)
{
	struct uci_section *s = NULL;

	uci_foreach_option_eq("bridging", "port", "bridge", section_name(bridge_config_s), s) {
		char *instance = NULL;
		char *alias    = NULL;
		char *management = NULL;

		char sec_name[128] = {0};
		snprintf(sec_name, sizeof(sec_name), "%s.%s", section_config(s), section_name(s));

		struct uci_section *dmmap_s = get_dup_section_in_dmmap_opt("Bridging", "Port", "__section_name__", sec_name);
		if (dmmap_s == NULL) {
			dmmap_s = create_dmmap_obj(dmctx, 1, "Bridging", "Port", s, &instance);
			if (dmmap_s && DM_STRLEN(instance)) {
				bool b = false;

				dmuci_get_value_by_section_string(s, "management", &management);
				string_to_bool(management, &b);
				if (b) {
					char *bridge_dev_name = NULL;

					dmuci_get_value_by_section_string(bridge_config_s, "name", &bridge_dev_name);
					dmuci_set_value_by_section(dmmap_s, "Name", bridge_dev_name);
				} else {
					dmuci_set_value_by_section(dmmap_s, "Name", section_name(s));
				}

				dmuci_set_value_by_section(dmmap_s, "Bridge", bridge_instance);

				dmuci_get_value_by_section_string(s, "Alias", &alias);
				dmuci_set_value_by_section(dmmap_s, "Alias", alias);
			}
		} else {
			dmuci_get_value_by_section_string(dmmap_s, "__instance__", &instance);
			dmctx->obj_buf[1] = "Port";
			dmctx->inst_buf[1] = instance;
		}
	}
}

static void sync_bridging_bridge_vlan(struct dmctx *dmctx, struct uci_section *bridge_config_s, const char *bridge_instance)
{
	struct uci_section *s = NULL;

	uci_foreach_option_eq("bridging", "vlan", "bridge", section_name(bridge_config_s), s) {
		char *instance = NULL;
		char *vlan_id  = NULL;
		char *alias    = NULL;

		char sec_name[128] = {0};
		snprintf(sec_name, sizeof(sec_name), "%s.%s", section_config(s), section_name(s));

		struct uci_section *dmmap_s = get_dup_section_in_dmmap_opt("Bridging", "VLAN", "__section_name__", sec_name);
		if (dmmap_s == NULL) {
			dmmap_s = create_dmmap_obj(dmctx, 1, "Bridging", "VLAN", s, &instance);
			if (dmmap_s && DM_STRLEN(instance)) {
				dmuci_set_value_by_section(dmmap_s, "Bridge", bridge_instance);

				dmuci_get_value_by_section_string(s, "vlan", &vlan_id);
				dmuci_set_value_by_section(dmmap_s, "Name", vlan_id);

				dmuci_get_value_by_section_string(s, "Alias", &alias);
				dmuci_set_value_by_section(dmmap_s, "Alias", alias);
			}
		} else {
			dmuci_get_value_by_section_string(dmmap_s, "__instance__", &instance);
			dmctx->obj_buf[1] = "VLAN";
			dmctx->inst_buf[1] = instance;
		}
	}
}

static void sync_bridging_bridge_vlanport(struct dmctx *dmctx, struct uci_section *bridge_config_s, const char *bridge_instance)
{
	struct uci_section *s = NULL;

	uci_foreach_option_eq("bridging", "vlanport", "bridge", section_name(bridge_config_s), s) {
		char *instance = NULL;
		char *alias    = NULL;

		char sec_name[128] = {0};
		snprintf(sec_name, sizeof(sec_name), "%s.%s", section_config(s), section_name(s));

		struct uci_section *dmmap_s = get_dup_section_in_dmmap_opt("Bridging", "VLANPort", "__section_name__", sec_name);
		if (dmmap_s == NULL) {
			dmmap_s = create_dmmap_obj(dmctx, 1, "Bridging", "VLANPort", s, &instance);
			if (dmmap_s && DM_STRLEN(instance)) {
				dmuci_set_value_by_section(dmmap_s, "Bridge", bridge_instance);

				dmuci_get_value_by_section_string(s, "Alias", &alias);
				dmuci_set_value_by_section(dmmap_s, "Alias", alias);
			}
		} else {
			dmuci_get_value_by_section_string(dmmap_s, "__instance__", &instance);
			dmctx->obj_buf[1] = "VLANPort";
			dmctx->inst_buf[1] = instance;
		}
	}
}

static void dmmap_sync_bridging_bridge(struct dmctx *dmctx)
{
	struct uci_section *s = NULL, *tmp = NULL;

	/* Forward pass: ensure every bridge in UCI config has a dmmap entry */
	uci_foreach_sections("bridging", "bridge", s) {
		char *instance = NULL;

		char sec_name[128] = {0};
		snprintf(sec_name, sizeof(sec_name), "%s.%s", section_config(s), section_name(s));

		struct uci_section *dmmap_s = get_dup_section_in_dmmap_opt("Bridging", "Bridge", "__section_name__", sec_name);

		if (dmmap_s == NULL) {
			/* New bridge - create dmmap entry and populate all config-derived values */
			dmmap_s = create_dmmap_obj(dmctx, 0, "Bridging", "Bridge", s, &instance);
			if (dmmap_s && DM_STRLEN(instance)) {
				char *name = NULL;
				char *alias = NULL;

				dmuci_get_value_by_section_string(s, "name", &name);
				dmuci_set_value_by_section(dmmap_s, "Name", name);

				dmuci_get_value_by_section_string(s, "Alias", &alias);
				dmuci_set_value_by_section(dmmap_s, "Alias", alias);
			}
		} else {
			/* Existing entry - just refresh the instance pointers in dmctx */
			dmuci_get_value_by_section_string(dmmap_s, "__instance__", &instance);
			dmctx->obj_buf[0] = "Bridge";
			dmctx->inst_buf[0] = instance;
		}

		sync_bridging_bridge_port(dmctx, s, instance);
		sync_bridging_bridge_vlan(dmctx, s, instance);
		sync_bridging_bridge_vlanport(dmctx, s, instance);
	}

	/* Reverse pass: remove dmmap entries whose originating UCI section is gone */
	s = NULL;
	uci_path_foreach_sections_safe(bbfdm, "Bridging", "Bridge", tmp, s) {
		char *orig_sec_name = NULL;

		dmuci_get_value_by_section_string(s, "__section_name__", &orig_sec_name);
		if (DM_STRLEN(orig_sec_name) == 0) {
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}

		struct uci_section *orig_sec = get_config_section_from_dmmap_section_name(orig_sec_name);
		if (orig_sec == NULL) {
			dmuci_delete_by_section(s, NULL, NULL);
			continue;
		}
	}

	remove_stale_bridging_child_dmmap_sections("Port");
	remove_stale_bridging_child_dmmap_sections("VLAN");
	remove_stale_bridging_child_dmmap_sections("VLANPort");
}

static void dmmap_synchronize_bridging(struct dmctx *dmctx)
{
	bbfdm_create_empty_file("/etc/bbfdm/dmmap/Bridging");

	dmmap_sync_bridging_bridge(dmctx);

	dmuci_commit_package_bbfdm("Bridging");
}

int init_bridging_module(void *data)
{
	struct dmctx bbf_ctx = {0};

	bbf_ctx_init(&bbf_ctx, NULL);

	if (file_exists("/etc/config/bridging")) {
		dmmap_synchronize_bridging(&bbf_ctx);
	}

	bbf_ctx_clean(&bbf_ctx);
	return 0;
}

int sync_bridging_module(void *data)
{
	struct bbfdm_context *bbfdm_ctx = (struct bbfdm_context *)data;
	if (bbfdm_ctx == NULL)
		return 0;

	if (DM_STRCMP(bbfdm_ctx->uci_change_proto, "external") == 0 && !list_empty(&bbfdm_ctx->changed_uci)) {
		struct apply_handler_node *node = NULL;
		list_for_each_entry(node, &bbfdm_ctx->changed_uci, list) {
			if (DM_STRCMP(node->file_path, "/etc/config/bridging") == 0) {
				BBF_DEBUG("Syncing bridging module config");
				init_bridging_module(data);
				break;
			}
		}
	}

	return 0;
}

/* ============================================================================
 * DATA MODEL PARAMETER DEFINITIONS
 * Define the structure of the data model objects and parameters
 * ============================================================================ */

/*** Bridging.Bridge.{i}.STP. ***/
DMLEAF tBridgingBridgeSTPParams[] = {
{"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[] = {
{"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[] = {
{"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},
#ifdef BRIDGE_ENABLE_VENDOR_EXT
{BBF_VENDOR_PREFIX"TPID", &DMWRITE, DMT_UNINT, get_BridgingBridgeVLANPort_TPID, set_BridgingBridgeVLANPort_TPID, BBFDM_BOTH},
{BBF_VENDOR_PREFIX"SVLANID", &DMWRITE, DMT_INT, get_BridgingBridgeVLANPort_SVLANID, set_BridgingBridgeVLANPort_SVLANID, BBFDM_BOTH},
{BBF_VENDOR_PREFIX"PBIT_INHERITANCE", &DMWRITE, DMT_BOOL, get_BridgingBridgeVLANPort_PBIT_INHERITANCE, set_BridgingBridgeVLANPort_PBIT_INHERITANCE, BBFDM_BOTH},
#endif
{0}
};

/*** Bridging.Bridge.{i}.Port.{i}.Stats. ***/
DMLEAF tBridgingBridgePortStatsParams[] = {
{"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[] = {
{"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[] = {
{"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},
{"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},
{"DefaultUserPriority", &DMWRITE, DMT_UNINT, get_BridgingBridgePort_DefaultPriority, set_BridgingBridgePort_DefaultPriority, BBFDM_BOTH},
{"PriorityTagging", &DMWRITE, DMT_BOOL, get_BridgingBridgePort_PriorityTagging, set_BridgingBridgePort_PriorityTagging, BBFDM_BOTH},
{"AcceptableFrameTypes", &DMWRITE, DMT_STRING, get_BridgingBridgePort_AcceptableFrameTypes, set_BridgingBridgePort_AcceptableFrameTypes, BBFDM_BOTH},
#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[] = {
{"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[] = {
{"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[] = {
{"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},
{"BridgeNumberOfEntries", &DMREAD, DMT_UNINT, get_Bridging_BridgeNumberOfEntries, NULL, BBFDM_BOTH},
{0}
};

DMOBJ tBridgingObj[] = {
{"Bridge", &DMWRITE, addObjBridgingBridge, delObjBridgingBridge, NULL, browseBridgingBridgeInst, NULL, NULL, tBridgingBridgeObj, tBridgingBridgeParams, NULL, BBFDM_BOTH, NULL},
{0}
};

/*** Device. ***/
DMOBJ tDeviceObjs[] = {
{"Bridging", &DMREAD, NULL, NULL, "file:/etc/config/bridging", NULL, NULL, NULL, tBridgingObj, tBridgingParams, NULL, BBFDM_BOTH, NULL},
{0}
};

/* ========== DynamicObj ========== */
DM_MAP_OBJ tDynamicObj[] = {
{"Device.", tDeviceObjs, NULL, init_bridging_module, NULL, sync_bridging_module},
{0}
};
