From 828895c45d5113aa80e3beced3a16e24f54c93a0 Mon Sep 17 00:00:00 2001
From: "nevadita.chatterjee" <nevadita.chatterjee@iopsys.eu>
Date: Mon, 16 May 2022 15:18:51 +0530
Subject: [PATCH] dataelement2: Adding the code for assoc/disassoc event

---
 src/cmdu_validate.c     |  32 +++++++++++
 src/cmdu_validate.h     |   1 +
 src/cntlr.c             |  16 ++++++
 src/cntlr.h             |   6 +++
 src/cntlr_map.c         | 114 +++++++++++++++++++++++++++++++++++++++-
 src/utils/utils.c       |  38 ++++++++++++++
 src/utils/utils.h       |   1 +
 src/wifi_dataelements.h |  10 ++--
 8 files changed, 212 insertions(+), 6 deletions(-)

diff --git a/src/cmdu_validate.c b/src/cmdu_validate.c
index 2fb70d2b..08c1e4bd 100644
--- a/src/cmdu_validate.c
+++ b/src/cmdu_validate.c
@@ -817,3 +817,35 @@ bool validate_ap_autoconfig_response(struct cmdu_buff *cmdu, struct tlv *tv[][16
 
 	return true;
 }
+
+bool validate_topology_notification(struct cmdu_buff *cmdu, struct tlv *tv[][16])
+{
+        int ret;
+        struct tlv_policy d_policy[] = {
+                [0] = {
+                        .type = TLV_TYPE_AL_MAC_ADDRESS_TYPE,
+                        .present = TLV_PRESENT_ONE,
+                        .minlen = 6,
+                        .maxlen = 6,
+                },
+                [1] = {
+                        .type = MAP_TLV_CLIENT_ASSOCIATION_EVENT,
+                        .present = TLV_PRESENT_OPTIONAL_ONE,
+                        .minlen = 13,
+                        .maxlen = 13,
+                }
+        };
+
+        ret = cmdu_parse_tlvs(cmdu, tv, d_policy, 2);
+        if (ret) {
+                fprintf(stderr, "%s: parse_tlv failed\n", __func__);
+                return false;
+        }
+
+        if (!tv[0][0]) {
+                fprintf(stderr, "%s: required tlv missing\n", __func__);
+                return false;
+        }
+
+        return true;
+}
diff --git a/src/cmdu_validate.h b/src/cmdu_validate.h
index d173b6da..61f8052c 100644
--- a/src/cmdu_validate.h
+++ b/src/cmdu_validate.h
@@ -9,5 +9,6 @@ bool validate_topology_response(struct cmdu_buff *cmdu, struct tlv *tv_tsp[][16]
 bool validate_ap_autoconfig_wsc(struct cmdu_buff *cmdu, struct tlv *tv[][16]);
 bool validate_ap_autoconfig_search(struct cmdu_buff *cmdu, struct tlv *tv[][16]);
 bool validate_ap_autoconfig_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]);
+bool validate_topology_notification(struct cmdu_buff *cmdu, struct tlv *tv[][16]);
 
 #endif	// CMDU_VALIDATE
diff --git a/src/cntlr.c b/src/cntlr.c
index 5bf06c36..51031f64 100644
--- a/src/cntlr.c
+++ b/src/cntlr.c
@@ -2503,6 +2503,18 @@ void run_controller(void)
 
 	cntlr_wait_for_ieee1905(c);
 
+	/*Allocating memory for assoc/disassoc events */
+	c->sta_events.assoc_events = (struct wifi_assoc_events *) calloc
+                        (MAX_ASSOC_EVENTS, sizeof(struct wifi_assoc_events));
+        if (c->sta_events.assoc_events == NULL)
+                goto out_exit;
+	c->sta_events.disassoc_events = (struct wifi_disassoc_events *) calloc
+                        (MAX_DISASSOC_EVENTS, sizeof(struct wifi_disassoc_events));
+        if (c->sta_events.disassoc_events == NULL)
+                goto out_exit;
+	c->sta_events.front_assoc_events = c->sta_events.rear_assoc_events = -1;
+	c->sta_events.front_disassoc_events = c->sta_events.rear_disassoc_events = -1;
+
 	cntlr_config_defaults(c, &c->cfg);
 
 	{
@@ -2561,6 +2573,10 @@ void run_controller(void)
 	uloop_run();
 
 out_exit:
+	if (c->sta_events.assoc_events)
+		free(c->sta_events.assoc_events);
+	if (c->sta_events.disassoc_events)
+		free(c->sta_events.disassoc_events);
 	map_unsubscribe(ctx, c->subscriber);
 	cntlr_clean_nodelist(c);
 	ubus_unregister_event_handler(ctx, &c->evh);
diff --git a/src/cntlr.h b/src/cntlr.h
index bd5a73ac..17825ed8 100644
--- a/src/cntlr.h
+++ b/src/cntlr.h
@@ -20,6 +20,11 @@
 
 #include "wifi_dataelements.h"
 
+#define MAX_ASSOC_EVENTS 32
+#define MAX_DISASSOC_EVENTS 32
+#define CNTRL_ASSOC_EVENT 1
+#define CNTRL_DISASSOC_EVENT 2
+
 extern const char *ubus_socket;
 
 typedef uint32_t object_t;
@@ -382,6 +387,7 @@ struct controller {
 	struct steer_control *sctrl;	/* active steer-control module */
 
 	struct wifi_data_element dlem; /* wifi data elements */
+	struct wifi_sta_events sta_events; /* wifi_sta_events */
 };
 
 struct sta_channel_report {
diff --git a/src/cntlr_map.c b/src/cntlr_map.c
index b2d62077..871ad800 100644
--- a/src/cntlr_map.c
+++ b/src/cntlr_map.c
@@ -60,10 +60,120 @@ struct map_cmdu_calltable_t {
 	map_cmdu_handler_t debug;
 };
 
+/* Check if the event queue is full */
+int is_full_event_queue(struct controller *c, int event_type)
+{
+	if (event_type == CNTRL_ASSOC_EVENT) {
+        	if ((c->sta_events.front_assoc_events == c->sta_events.rear_assoc_events + 1)
+			|| (c->sta_events.front_assoc_events == 0 && 
+				c->sta_events.rear_assoc_events == MAX_ASSOC_EVENTS - 1))
+                	return 1;
+	}
+	else {
+		if ((c->sta_events.front_disassoc_events == c->sta_events.rear_disassoc_events + 1)
+                        || (c->sta_events.front_disassoc_events == 0 &&
+                                c->sta_events.rear_disassoc_events == MAX_DISASSOC_EVENTS - 1))
+                        return 1;
+	}
+        return 0;
+}
+
+/* Enqueue of assoc events*/ 
+void cntrl_enqueue_assoc_events(struct controller *c, struct wifi_assoc_events *event)
+{
+        dbg("Inside %s\n", __func__);
+        struct wifi_assoc_events *elem;
+
+        if (is_full_event_queue(c, CNTRL_ASSOC_EVENT)) {
+                dbg("assoc event queue full del front node\n");
+                c->sta_events.front_assoc_events = (c->sta_events.front_assoc_events + 1)
+		       					% MAX_ASSOC_EVENTS;
+                c->sta_events.num_assoc_events--;
+        }
+
+
+        if (c->sta_events.front_assoc_events == -1)
+		c->sta_events.front_assoc_events = 0;
+
+        c->sta_events.rear_assoc_events = (c->sta_events.rear_assoc_events + 1)
+							% MAX_ASSOC_EVENTS;
+        elem = &(c->sta_events.assoc_events[c->sta_events.rear_assoc_events]);
+        memset(elem, 0, sizeof(struct wifi_assoc_events));
+        memcpy(elem->macaddr, event->macaddr, 6);
+        memcpy(elem->bssid, event->bssid, 6);
+	get_timestamp(NULL, elem->tsp);
+        c->sta_events.num_assoc_events++;
+}
+
+/* Enqueue of disassoc events*/
+void cntrl_enqueue_disassoc_events(struct controller *c, struct wifi_disassoc_events *event)
+{
+        dbg("Inside %s\n", __func__);
+        struct wifi_disassoc_events *elem;
+
+        if (is_full_event_queue(c, CNTRL_DISASSOC_EVENT)) {
+                dbg("disassoc event queue full del front node\n");
+                c->sta_events.front_disassoc_events = (c->sta_events.front_disassoc_events + 1)
+                                                        % MAX_DISASSOC_EVENTS;
+                c->sta_events.num_disassoc_events--;
+        }
+
+        if (c->sta_events.front_disassoc_events == -1)
+                c->sta_events.front_disassoc_events = 0;
+
+        c->sta_events.rear_disassoc_events = (c->sta_events.rear_disassoc_events + 1)
+                                                        % MAX_DISASSOC_EVENTS;
+        elem = &(c->sta_events.disassoc_events[c->sta_events.rear_disassoc_events]);
+        memset(elem, 0, sizeof(struct wifi_disassoc_events));
+        memcpy(elem->sta_data.macaddr, event->sta_data.macaddr, 6);
+        memcpy(elem->bssid, event->bssid, 6);
+	get_timestamp(NULL, elem->tsp);
+        c->sta_events.num_disassoc_events++;
+}
+
+
+
 int handle_topology_notification(void *cntlr, struct cmdu_buff *cmdu)
 {
-	trace("%s: --->\n", __func__);
-	return 0;
+	cntlr = (struct controller *)cntlr;
+        struct wifi_assoc_events assoc_ev;
+        struct wifi_disassoc_events disassoc_ev;
+        struct tlv *tv[2][16];
+	struct cmdu_buff *ret = NULL ;
+
+	if (!validate_topology_notification(cmdu, tv)) {
+                err("%s: cmdu validation "\
+                                "[TOPOLOGY_NOTIFICATION] failed\n", __func__);
+                return -1;
+        }
+
+        if (tv[1][0]) {
+                struct tlv_client_assoc_event *p =
+                        (struct tlv_client_assoc_event *)tv[1][0]->data;
+
+                if (p->event & CLIENT_EVENT_MASK) {
+                        /* client association */
+			memcpy(assoc_ev.macaddr, p->macaddr, 6);
+                        memcpy(assoc_ev.bssid, p->bssid, 6);
+			cntrl_enqueue_assoc_events(cntlr, &assoc_ev);
+			
+			/* Send client capability query */
+			ret = cntlr_gen_client_caps_query((struct controller *)cntlr, cmdu->origin, 
+					p->macaddr, p->bssid);
+                        if (ret) {
+                                err("Error in sending client capability query\n");
+                                return -1;
+                        }
+
+                } else {
+                        /* client disassociation */
+                        memcpy(disassoc_ev.bssid, p->bssid, 6);
+                        memcpy(disassoc_ev.sta_data.macaddr, p->macaddr, 6);
+			cntrl_enqueue_disassoc_events(cntlr, &disassoc_ev);
+                }
+        }
+
+        return 0;
 }
 
 static void _cntlr_update_steer_params(struct controller *c, struct opclass *op)
diff --git a/src/utils/utils.c b/src/utils/utils.c
index b4cd5836..3554eb6b 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -539,3 +539,41 @@ int writeto_configfile(const char *filename, void *in, size_t len)
 	close(fp);
 	return 0;
 }
+
+char *get_timestamp(time_t *t, char *tbuf)
+{
+        char tmpbuf[64] = {0};
+        struct tm res;
+        char sign;
+        long int toff, toff_hour, toff_min;
+        const time_t now = time(t);
+
+        if (!tbuf)
+                return NULL;
+
+        /* E.g. "2019-02-11T06:42:31.23039-08:00" */
+
+        localtime_r(&now, &res);
+        tzset();
+        toff = timezone;
+        sign = toff > 0 ? '-' : '+';
+        toff *= -1L;
+
+        toff_hour = toff / 3600;
+        toff_min = (toff % 3600) / 60;
+
+        snprintf(tmpbuf, 63, "%04d-%02d-%02dT%02d:%02d:%02d%c%02ld:%02ld",
+                                        res.tm_year + 1900,
+                                        res.tm_mon + 1,
+                                        res.tm_mday,
+                                        res.tm_hour,
+                                        res.tm_min,
+                                        res.tm_sec,
+                                        sign,
+                                        toff_hour,
+                                        toff_min);
+	 snprintf(tbuf, 64, "%s", tmpbuf);
+
+        return tbuf;
+}
+
diff --git a/src/utils/utils.h b/src/utils/utils.h
index 9edf07b6..3f18ef81 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -170,5 +170,6 @@ void do_daemonize(const char *pidfile);
 
 int writeto_configfile(const char *filename, void *in, size_t len);
 int readfrom_configfile(const char *filename, uint8_t **out, size_t *olen);
+char *get_timestamp(time_t *t, char *tbuf);
 
 #endif /* UTILS_H */
diff --git a/src/wifi_dataelements.h b/src/wifi_dataelements.h
index 88551cde..de836a83 100644
--- a/src/wifi_dataelements.h
+++ b/src/wifi_dataelements.h
@@ -617,12 +617,14 @@ struct wifi_disassoc_events {
 };
 
 struct wifi_sta_events {
-	uint32_t old_assoc_events;
-	uint32_t old_disassoc_events;
+	uint32_t front_assoc_events;
+	uint32_t rear_assoc_events;
+	uint32_t front_disassoc_events;
+	uint32_t rear_disassoc_events;
 	uint32_t num_assoc_events;
 	uint32_t num_disassoc_events;
-	struct list_head assoc_eventlist;	/* list of wifi_assoc_events */
-	struct list_head disassoc_eventlist;	/* list of wifi_disassoc_events */
+	struct wifi_assoc_events *assoc_events; /* wifi_assoc_events */
+	struct wifi_disassoc_events *disassoc_events; /* wifi_disassoc_events */
 };
 
 struct wifi_channel_data {
-- 
GitLab