From b51812b183a58d990f02c9ca9552496dedd0b441 Mon Sep 17 00:00:00 2001
From: arbala <bala.arunachalam@iopsys.eu>
Date: Tue, 27 May 2025 17:43:50 +0200
Subject: [PATCH] Add vendor extension to reset agents multiap stack

---
 src/cntlr_commands.c      | 12 ++++++++
 src/cntlr_commands.h      | 13 +++++++++
 src/cntlr_commands_impl.c | 38 +++++++++++++++++++++++++
 src/cntlr_commands_impl.h |  1 +
 src/cntlr_extension.c     | 59 +++++++++++++++++++++++++++++++++++++++
 src/cntlr_extension.h     |  7 +++++
 src/cntlr_ubus.c          | 27 ++++++++++++++++++
 7 files changed, 157 insertions(+)

diff --git a/src/cntlr_commands.c b/src/cntlr_commands.c
index 97596f80..deaaa015 100644
--- a/src/cntlr_commands.c
+++ b/src/cntlr_commands.c
@@ -915,6 +915,17 @@ DEFINE_ATTR(disassociate_sta) = {
 		.help = "Reason code for the disassociation.",
 	}
 };
+
+DEFINE_ATTR(reset_agent) = {
+	[DISASSOCIATE_STA_ATTR_AGENT] = {
+		.optional = 0,
+		.pol = {
+			.name = "agent",
+			.type = BLOBMSG_TYPE_STRING,
+		},
+		.help = "AL-address of Agent to which the reset_agent CMDU is to be sent",
+	}
+};
 #endif
 
 DEFINE_ATTR(dump_topology) = {
@@ -1008,6 +1019,7 @@ static struct controller_command cntlr_commandlist[] = {
 #endif
 #ifdef EASYMESH_VENDOR_EXT
 	CNTLR_CMD(disassociate_sta, "Tell an agent to disassociate a STA."),
+	CNTLR_CMD(reset_agent, "Reset the multiap stack of an agent."),
 #endif
 	CNTLR_CMD(dump_topology, "Show tree topology of the Multi-AP network"),
 	CNTLR_CMD(null_command, ""),
diff --git a/src/cntlr_commands.h b/src/cntlr_commands.h
index 297e7fdb..3f87e281 100644
--- a/src/cntlr_commands.h
+++ b/src/cntlr_commands.h
@@ -572,6 +572,19 @@ enum disassociate_sta_attrs {
 	DISASSOCIATE_STA_ATTR_REASON,
 	NUM_ATTRS_DISASSOCIATE_STA,
 };
+
+/**
+ * @enum reset_agent_attrs
+ * @brief Reset Agent attributes
+ *
+ * @ingroup cmdattrs
+ * @RESET_AGENT_ATTR_AGENT: Agent's AL-address.
+ * @NUM_ATTRS_RESET_AGENT: Number of reset_agent attributes.
+ */
+enum reset_agent_attrs {
+	RESET_AGENT_ATTR_AGENT,
+	NUM_ATTRS_RESET_AGENT,
+};
 #endif
 
 /**
diff --git a/src/cntlr_commands_impl.c b/src/cntlr_commands_impl.c
index be560792..6f1f1d2d 100644
--- a/src/cntlr_commands_impl.c
+++ b/src/cntlr_commands_impl.c
@@ -3319,6 +3319,44 @@ int COMMAND(disassociate_sta)(void *priv, void *args, void *out)
 
 	return mid != 0xffff ? 0 : -1;
 }
+
+int COMMAND(reset_agent)(void *priv, void *args, void *out)
+{
+	struct controller *c = (struct controller *)priv;
+	struct blob_buf *bb = (struct blob_buf *)out;
+	struct blob_attr *tb[NUM_ATTRS_RESET_AGENT];
+	struct cmdu_buff *cmdu;
+	uint8_t agent[6] = {0};
+	char agentstr[18] = {0};
+	uint16_t mid = 0xffff;
+	int ret;
+
+	ret = controller_command_parse("reset_agent", args, tb);
+	if (ret) {
+		err("%s: Error (ret = %d)\n", __func__, ret);
+		return -EINVAL;
+	}
+
+	strncpy(agentstr, blobmsg_data(tb[RESET_AGENT_ATTR_AGENT]), sizeof(agentstr) - 1);
+	if (!hwaddr_aton(agentstr, agent))
+		return -EINVAL;
+
+	cmdu = cntlr_gen_vendor_specific_reset_agent(c);
+	if (!cmdu)
+		return -1;
+
+	memcpy(cmdu->origin, agent, 6);
+
+	mid = send_cmdu(c, cmdu);
+	cmdu_free(cmdu);
+
+	/* reply with mid */
+	blobmsg_add_string(bb, "status", mid != 0xffff ? "ok" : "fail");
+	if (mid != 0xffff)
+		blobmsg_add_u32(bb, "mid", mid);
+
+	return mid != 0xffff ? 0 : -1;
+}
 #endif
 
 int COMMAND(dump_topology)(void *priv, void *args, void *out)
diff --git a/src/cntlr_commands_impl.h b/src/cntlr_commands_impl.h
index 84f4dd25..b1ae36eb 100644
--- a/src/cntlr_commands_impl.h
+++ b/src/cntlr_commands_impl.h
@@ -69,6 +69,7 @@ DECLARE_COMMAND(dpp_advertise_cce);
 #endif
 #ifdef EASYMESH_VENDOR_EXT
 DECLARE_COMMAND(disassociate_sta);
+DECLARE_COMMAND(reset_agent);
 #endif
 DECLARE_COMMAND(dump_topology);
 #endif /* CONTROLLER_COMMAND_IMPL_H */
diff --git a/src/cntlr_extension.c b/src/cntlr_extension.c
index 1f3304e5..5283156d 100644
--- a/src/cntlr_extension.c
+++ b/src/cntlr_extension.c
@@ -156,4 +156,63 @@ out:
 	return NULL;
 }
 
+int cntlr_gen_vendor_specific_reset_agent_tlv(struct controller *c, struct cmdu_buff *frm)
+{
+	struct tlv *t;
+	struct tlv_vendor_reset_agent *data;
+	int ret;
+	const uint8_t vendor_oui[4] = {0};
+	uint32_t oui = 0;
+
+	BUF_PUT_BE24(vendor_oui, EASYMESH_VENDOR_EXT_OUI_DEFAULT);
+#ifdef EASYMESH_VENDOR_EXT_OUI
+	oui = EASYMESH_VENDOR_EXT_OUI;
+	BUF_PUT_BE24(vendor_oui, oui);
+#endif
+
+	/* prepare TLVs */
+	t = cmdu_reserve_tlv(frm, 32);
+	if (!t) {
+		dbg("%s: -ENOMEM\n", __func__);
+		return -1;
+	}
+
+	t->type = TLV_TYPE_VENDOR_SPECIFIC;
+	t->len = sizeof(struct tlv_vendor_reset_agent);
+	data = (struct tlv_vendor_reset_agent *)t->data;
+
+	memcpy(data->vendor_impl.vendor.oui, vendor_oui, 3);
+	data->vendor_impl.vendor_type = TLV_VENDOR_TYPE_IMPL_RESET_AGENT;
+
+	ret = cmdu_put_tlv(frm, t);
+	if (ret) {
+		err("%s: error: cmdu_put_tlv()\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+struct cmdu_buff *cntlr_gen_vendor_specific_reset_agent(struct controller *c)
+{
+	struct cmdu_buff *frm;
+	int ret;
+	uint16_t mid = 0;
+
+	frm = cmdu_alloc_simple(CMDU_TYPE_VENDOR_SPECIFIC, &mid);
+	if (!frm) {
+		dbg("%s: -ENOMEM\n", __func__);
+		return NULL;
+	}
+
+	ret = cntlr_gen_vendor_specific_reset_agent_tlv(c, frm);
+	if (ret)
+		goto out;
+
+	cmdu_put_eom(frm);
+	return frm;
+out:
+	cmdu_free(frm);
+	return NULL;
+}
 #endif
diff --git a/src/cntlr_extension.h b/src/cntlr_extension.h
index 17d8de48..00940e5c 100644
--- a/src/cntlr_extension.h
+++ b/src/cntlr_extension.h
@@ -13,6 +13,7 @@ enum tlv_vendor_type_impl {
 	TLV_VENDOR_TYPE_IMPL_UNSPEC = 0,
 	TLV_VENDOR_TYPE_IMPL_PROBE_REQ = 1, /* Probe Requests */
 	TLV_VENDOR_TYPE_IMPL_DISASSOCIATE_STA = 2, /* Disassociate STA */
+	TLV_VENDOR_TYPE_IMPL_RESET_AGENT = 3, /* Reset agent's MultiAP stack */
 };
 
 /* Vendor TLV structure for our implementation */
@@ -34,6 +35,10 @@ struct tlv_vendor_probe_req {
 	uint8_t rcpi;
 } __attribute__((packed));
 
+struct tlv_vendor_reset_agent {
+	struct tlv_vendor_impl vendor_impl;
+} __attribute__((packed));
+
 #ifdef PROPAGATE_PROBE_REQ
 int handle_vendor_specific_probe_req(void *cntlr, struct cmdu_buff *rx_cmdu,
 		struct tlv_vendor_probe_req *tlv);
@@ -42,8 +47,10 @@ int handle_vendor_specific_probe_req(void *cntlr, struct cmdu_buff *rx_cmdu,
 int handle_vendor_extension(void *cntlr, struct cmdu_buff *rx_cmdu, struct node *n);
 int cntlr_gen_vendor_specific_disassociate_sta_tlv(struct controller *c,
 		struct cmdu_buff *frm, uint8_t *sta, uint16_t reason);
+int cntlr_gen_vendor_specific_reset_agent_tlv(struct controller *c, struct cmdu_buff *frm);
 struct cmdu_buff *cntlr_gen_vendor_specific_disassociate_sta(struct controller *c,
 		uint8_t *sta, uint16_t reason);
+struct cmdu_buff *cntlr_gen_vendor_specific_reset_agent(struct controller *c);
 #endif
 
 #endif /* CNTLR_EXTENSION_H */ 
diff --git a/src/cntlr_ubus.c b/src/cntlr_ubus.c
index d26eeb77..d035e25c 100644
--- a/src/cntlr_ubus.c
+++ b/src/cntlr_ubus.c
@@ -973,6 +973,32 @@ out:
 	blob_buf_free(&bb);
 	return ret;
 }
+
+int cntlr_ubus_reset_agent(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	struct controller *c = container_of(obj, struct controller, obj);
+	struct blob_buf bb;
+	int ret;
+
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
+
+	ret = COMMAND(reset_agent)(c, msg, &bb);
+	if (ret) {
+		if (ret == -EINVAL)
+			ret = UBUS_STATUS_INVALID_ARGUMENT;
+
+		goto out;
+	}
+
+	ubus_send_reply(ctx, req, bb.head);
+out:
+	blob_buf_free(&bb);
+	return ret;
+
+}
+
 #endif
 
 static int cntlr_ubus_dump_topology(struct ubus_context *ctx,
@@ -1129,6 +1155,7 @@ int cntlr_publish_object(struct controller *c, const char *objname)
 #endif
 #ifdef EASYMESH_VENDOR_EXT
 		{ "disassociate_sta", cntlr_ubus_disassociate_sta },
+		{ "reset_agent", cntlr_ubus_reset_agent },
 #endif
 #endif
 		{ "dump_topology", cntlr_ubus_dump_topology },
-- 
GitLab