From d77996abeaf667e27ed1c2296b31208020ec38b0 Mon Sep 17 00:00:00 2001
From: Anjan Chanda <anjan.chanda@iopsys.eu>
Date: Mon, 27 Jul 2020 13:44:46 +0200
Subject: [PATCH] refactor and cleanup codebase

---
 .gitignore          |  13 ++
 src/Makefile        |  12 +-
 src/config.c        | 150 ++++++++++++
 src/config.h        |  17 ++
 src/debug.c         |  45 ++++
 src/debug.h         |  20 ++
 src/hlist.h         | 101 ++++++++
 src/json_utils.c    |  44 ++++
 src/json_utils.h    |  11 +
 src/main.c          | 110 ++++++++-
 src/nodes.c         | 110 +++++++++
 src/nodes.h         |  17 ++
 src/topo_ieee1905.c | 196 ++++++++++++++++
 src/topologyd.c     | 558 ++++++++++++++++++++++++++++++++++++++++++++
 src/topologyd.h     | 102 ++++++++
 src/topomap.c       | 258 --------------------
 src/topomap.h       |  33 ---
 src/topoubus.c      | 310 ------------------------
 src/topoubus.h      |  21 --
 src/topoutils.c     |  36 ---
 src/topoutils.h     |  36 ---
 21 files changed, 1496 insertions(+), 704 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 src/config.c
 create mode 100644 src/config.h
 create mode 100644 src/debug.c
 create mode 100644 src/debug.h
 create mode 100644 src/hlist.h
 create mode 100644 src/json_utils.c
 create mode 100644 src/json_utils.h
 create mode 100644 src/nodes.c
 create mode 100644 src/nodes.h
 create mode 100644 src/topo_ieee1905.c
 create mode 100644 src/topologyd.c
 create mode 100644 src/topologyd.h
 delete mode 100644 src/topomap.c
 delete mode 100644 src/topomap.h
 delete mode 100644 src/topoubus.c
 delete mode 100644 src/topoubus.h
 delete mode 100644 src/topoutils.c
 delete mode 100644 src/topoutils.h

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0a72759
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+.built
+.built_check
+.configured_
+.dep_files
+.git_update
+.prepared_*
+ipkg-*
+**/*.o
+**/*.so
+src/tags
+src/topologyd
+.configured_*
+.pkgdir
diff --git a/src/Makefile b/src/Makefile
index 53af95c..9d76775 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,18 +1,20 @@
-CFLAGS+=-I. -Iinclude -D_GNU_SOURCE
+PROG=topologyd
+
+CFLAGS+=-I. -D_GNU_SOURCE
 CFLAGS+= -g -Wall -pthread
 
-OBJS = main.o topomap.o topoubus.o topoutils.o
+OBJS = main.o debug.o config.o json_utils.o nodes.o topo_ieee1905.o topologyd.o
 
 LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -pthread -leasy -lmaputils
 
 .PHONY: all check clean FORCE
 
-all: topo1905d
+all: $(PROG)
 
 %.o: %.c
 	$(CC) $(CFLAGS) -c -o $@ $<
 
-topo1905d: $(OBJS)
+$(PROG): $(OBJS)
 	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
 
 check: FORCE
@@ -26,6 +28,6 @@ check: FORCE
 		. 2> cppcheck.out
 
 clean:
-	rm -f *.o src/*.o topo1905d
+	rm -f *.o src/*.o $(PROG)
 
 FORCE:
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..1b11f35
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,150 @@
+/*
+ * config.c - configuration handling
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * See LICENSE and CREDITS file for related information.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <json-c/json.h>
+#include <libubox/blobmsg.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/uloop.h>
+#include <libubox/ustream.h>
+#include <libubox/utils.h>
+#include <libubus.h>
+#include <uci.h>
+
+#include "debug.h"
+#include "topologyd.h"
+#include "config.h"
+
+
+void topologyd_config_dump(struct topologyd_config *cfg)
+{
+	dbg("Topologyd config ---------\n");
+	dbg("Enabled           : %d\n", cfg->enabled);
+	dbg("Depth             : %d\n", cfg->depth);
+	dbg("Refresh interval  : %d seconds\n", cfg->refresh_int);
+	dbg("Log entries       : %d max\n", cfg->maxlog);
+
+	dbg("---------------------------\n");
+}
+
+int topologyd_config_defaults(struct topologyd_config *cfg)
+{
+	if (!cfg)
+		return -1;
+
+	cfg->enabled = false;
+	cfg->depth = TOPOLOGY_DEPTH;
+	cfg->refresh_int = TOPOLOGY_REFRESH_INT;
+	cfg->maxlog = TOPOLOGY_LOG_MAX;
+
+	return 0;
+}
+
+static int config_get_section_topology(struct topologyd_config *cfg,
+						struct uci_section *s)
+{
+	enum {
+		TOPOLOGY_ATTR_ENABLED,
+		TOPOLOGY_ATTR_DEPTH,
+		TOPOLOGY_ATTR_INTERVAL,
+		TOPOLOGY_ATTR_MAXLOG,
+		NUM_TOPOLOGY_ATTRS,
+	};
+	const struct uci_parse_option opts[] = {
+		{ .name = "enabled", .type = UCI_TYPE_STRING },
+		{ .name = "depth", .type = UCI_TYPE_STRING },
+		{ .name = "interval", .type = UCI_TYPE_STRING },
+		{ .name = "maxlog", .type = UCI_TYPE_STRING },
+	};
+	struct uci_option *tb[NUM_TOPOLOGY_ATTRS];
+
+
+	uci_parse_section(s, opts, NUM_TOPOLOGY_ATTRS, tb);
+
+	if (tb[TOPOLOGY_ATTR_ENABLED]) {
+		const char *val = tb[TOPOLOGY_ATTR_ENABLED]->v.string;
+
+		cfg->enabled = atoi(val) == 1 ? true : false;
+	}
+
+	if (tb[TOPOLOGY_ATTR_DEPTH]) {
+		const char *val = tb[TOPOLOGY_ATTR_DEPTH]->v.string;
+		int v = atoi(val);
+
+		if (v > 0)
+			cfg->depth = v;
+	}
+
+	if (tb[TOPOLOGY_ATTR_INTERVAL]) {
+		const char *val = tb[TOPOLOGY_ATTR_INTERVAL]->v.string;
+		int v = atoi(val);
+
+		if (v > 0)
+			cfg->refresh_int = v;
+	}
+
+	if (tb[TOPOLOGY_ATTR_MAXLOG]) {
+		const char *val = tb[TOPOLOGY_ATTR_MAXLOG]->v.string;
+		int v = atoi(val);
+
+		if (v > 0)
+			cfg->maxlog = v;
+	}
+
+	return 0;
+}
+
+static int config_get_section_extra(struct topologyd_config *cfg,
+						struct uci_section *s)
+{
+	//TODO
+
+	return 0;
+}
+
+int topologyd_config_user(struct topologyd_config *cfg)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_element *e;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return -1;
+
+	if (uci_load(ctx, TOPOLOGY_CONFIG, &pkg)) {
+		uci_free_context(ctx);
+		return -1;
+	}
+
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
+
+		if (!strcmp(s->type, "topology")) {
+			config_get_section_topology(cfg, s);
+		} else if (!strcmp(s->type, "extra")) {
+			config_get_section_extra(cfg, s);
+		}
+	}
+
+	uci_free_context(ctx);
+
+	topologyd_config_dump(cfg);
+
+	return 0;
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..841d0ab
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,17 @@
+/*
+ * config.h - configuration header file
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * See LICENSE and CREDITS file for related information.
+ */
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+int topologyd_config_defaults(struct topologyd_config *cfg);
+int topologyd_config_user(struct topologyd_config *cfg);
+void topologyd_config_dump(struct topologyd_config *cfg);
+
+
+#endif /* CONFIG_H */
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..7cdf17a
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,45 @@
+/*
+ * debug.c - for debug and logging
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "debug.h"
+
+extern bool syslogging;
+static const int syslog_level[] = { LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG };
+
+void start_logging(const char *prog)
+{
+	if (syslogging)
+		openlog(prog, 0, LOG_DAEMON);
+}
+
+void stop_logging(void)
+{
+	if (syslogging)
+		closelog();
+}
+
+void log_message(int level, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	if (syslogging && level >= 0)
+		vsyslog(syslog_level[level], fmt, args);
+
+	va_end(args);
+}
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..c3bb189
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,20 @@
+/*
+ * debug.h - debug and logging header file
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+void start_logging(const char *prog);
+void stop_logging(void);
+void log_message(int level, const char *fmt, ...);
+
+#define err(...)	log_message(0, __VA_ARGS__)
+#define warn(...)	log_message(1, __VA_ARGS__)
+#define info(...)	log_message(2, __VA_ARGS__)
+#define dbg(...)	log_message(3, __VA_ARGS__)
+
+#endif /* DEBUG_H */
diff --git a/src/hlist.h b/src/hlist.h
new file mode 100644
index 0000000..faf0078
--- /dev/null
+++ b/src/hlist.h
@@ -0,0 +1,101 @@
+/*
+ * hlist.h - stripped down version of hash list implementation using
+ * singly linked list.
+ * Doubly linked list is wastage of space for big hash-tables. If cost of
+ * iterating a hash list is significant, it means the hash function is NOT
+ * formulated well and should be revisited.
+ *
+ * Copyright (C) 2019 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: anjan.chanda@iopsys.eu
+ *
+ */
+
+#ifndef _HLIST_H
+#define _HLIST_H
+
+struct hlist_node {
+	struct hlist_node *next;
+};
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+#define HLIST_HEAD_INIT(name) { &(name) }
+
+#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT(name)
+
+static inline void INIT_HLIST_HEAD(struct hlist_head *h)
+{
+	h->first = NULL;
+}
+
+static inline void INIT_HLIST_NODE(struct hlist_node *n)
+{
+	n->next = NULL;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+	return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *prev, struct hlist_node *n)
+{
+	prev->next = n->next;
+	n->next = NULL;
+}
+
+static inline void hlist_del(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *p;
+
+	if (h->first == n) {
+		h->first = NULL;
+		n->next = NULL;
+		return;
+	}
+
+	for (p = h->first; p; p = p->next) {
+		if (p->next == n)
+			__hlist_del(p, n);
+	}
+}
+
+static inline void _hlist_add(struct hlist_node *_new, struct hlist_head *h)
+{
+	_new->next = h->first;
+	h->first = _new;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	_hlist_add(n, h);
+}
+
+#define hlist_for_each(pos, head) \
+	for (pos = (head)->first; pos ; pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+	     pos = n)
+
+#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define hlist_entry_safe(ptr, type, member) \
+	({ typeof(ptr) ____ptr = (ptr); \
+	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+	})
+
+#define hlist_for_each_entry(pos, head, member)                                \
+	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);    \
+	     pos;                                                              \
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_safe(pos, n, head, member)                   \
+	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member); \
+	     pos && ({ n = pos->member.next; 1; });                       \
+	     pos = hlist_entry_safe(n, typeof(*pos), member))
+
+#endif /* _HLIST_H */
diff --git a/src/json_utils.c b/src/json_utils.c
new file mode 100644
index 0000000..f7e2436
--- /dev/null
+++ b/src/json_utils.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "debug.h"
+#include "json_utils.h"
+
+char *_json_obj_get_string(json_object *j, const char *key)
+{
+	json_object *t;
+
+	if (j == NULL)
+		return NULL;
+
+	if (json_object_object_get_ex(j, key, &t)) {
+		char *str = strdup(json_object_get_string(t));
+		return str;
+	}
+
+	dbg("|%s| not found", key);
+
+	return NULL;
+}
+
+int _json_obj_get_int(json_object *j, const char *key)
+{
+	json_object *t;
+	int ret = 0;
+
+	if (j == NULL)
+		return 0;
+
+	if (json_object_object_get_ex(j, key, &t))
+		ret = json_object_get_int(t);
+
+	return ret;
+}
+
+void json_safe_put(json_object *j)
+{
+	if (j != NULL) {
+		json_object_put(j);
+		j = NULL;
+	}
+}
diff --git a/src/json_utils.h b/src/json_utils.h
new file mode 100644
index 0000000..ee26592
--- /dev/null
+++ b/src/json_utils.h
@@ -0,0 +1,11 @@
+#ifndef JSON_UTILS_H
+#define JSON_UTILS_H
+
+#include <json-c/json.h>
+
+
+char *_json_obj_get_string(json_object *j, const char *key);
+int _json_obj_get_int(json_object *j, const char *key);
+void json_safe_put(json_object *j);
+
+#endif /* JSON_UTILS_H */
diff --git a/src/main.c b/src/main.c
index d89674b..2937843 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,10 +1,110 @@
-#include "topoubus.h"
-#include <syslog.h>
+/*
+ * main.c - topologyd main
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * See LICENSE file for license terms.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "debug.h"
+
+extern int topologyd_start(void);
+extern int topologyd_stop(void);
+
+const char *ubus_socket = NULL;
+const char *pidfile_path = NULL;
+int refresh_int;
+bool syslogging = false;
+bool daemonize = true;
+
+void do_daemonize()
+{
+	char buf[128] = {0};
+	int flags;
+	int f;
+
+	if (daemonize) {
+		info("daemonizing ...\n");
+		daemon(0,0);
+	}
+
+	pidfile_path = "/var/run/topologyd.pid";
+	f = open(pidfile_path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+	if (f) {
+		flags = fcntl(f, F_GETFD);
+		if (flags != -1) {
+			flags |= FD_CLOEXEC;
+			fcntl(f, F_SETFD, flags);
+		}
+		if (lockf(f, F_TLOCK, 0) < 0) {
+			fprintf(stderr, "File '%s' exists. Aborting...\n",
+					pidfile_path);
+			exit(-1);
+		}
+		ftruncate(f,0);
+		snprintf(buf, sizeof(buf), "%ld\n", (long)getpid());
+		write(f, buf, strlen(buf));
+	}
+}
+
+void usage(char *prog)
+{
+    fprintf(stderr, "Usage: %s [options]\n", prog);
+    fprintf(stderr, "\n");
+    fprintf(stderr, "options:\n");
+    fprintf(stderr, "   -s <socket path>     ubus socket\n");
+    fprintf(stderr, "   -d,                  debug mode; i.e. don't daemonize\n");
+    fprintf(stderr, "   -l,                  log to syslog\n");
+    fprintf(stderr, "   -p <pidfile>         pid file path\n");
+    fprintf(stderr, "   -t                   refresh interval in seconds\n");
+    fprintf(stderr, "\n");
+}
 
 int main(int argc, char * argv[])
 {
-	openlog("topo1905d", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
-	init_topology();
-	closelog();
+	int ch;
+
+	while ((ch = getopt(argc, argv, "hlt:ds:p:")) != -1) {
+		switch (ch) {
+		case 's':
+			ubus_socket = optarg;
+			break;
+		case 't':
+			refresh_int = atoi(optarg);
+			break;
+		case 'l':
+			syslogging = true;
+			break;
+		case 'd':
+			daemonize = false;
+			break;
+		case 'p':
+			pidfile_path = optarg;
+			break;
+		case 'h':
+			usage(argv[0]);
+			exit(0);
+		default:
+			break;
+		}
+	}
+
+	if (daemonize)
+		syslogging = true;
+
+	do_daemonize();
+	start_logging(argv[0]);
+
+	topologyd_start();
+
+	stop_logging();
+
 	return 0;
 }
diff --git a/src/nodes.c b/src/nodes.c
new file mode 100644
index 0000000..72e287d
--- /dev/null
+++ b/src/nodes.c
@@ -0,0 +1,110 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <libubox/list.h>
+#include <libubox/uloop.h>
+#include <libubus.h>
+
+#include <easy/easy.h>
+#include "debug.h"
+#include "hlist.h"
+#include "topologyd.h"
+
+
+void node_destroy(struct node *n)
+{
+	free(n);
+}
+
+struct node *node_create(uint8_t *hwaddr)
+{
+	struct node *n;
+
+	n = calloc(1, sizeof(struct node));
+	if (!n) {
+		warn("OOM: Node alloc failed!\n");
+		return NULL;
+	}
+
+	memcpy(n->hwaddr, hwaddr, 6);
+
+	return n;
+}
+
+struct node *node_lookup(struct hlist_head *table, uint8_t *hwaddr)
+{
+	int hidx = node_hash(hwaddr);
+	struct node *n;
+
+	if (hwaddr_is_zero(hwaddr))
+		return NULL;
+
+	hlist_for_each_entry(n, &table[hidx], hlist) {
+		if (!memcmp(hwaddr, n->hwaddr, 6))
+			return n;
+	}
+
+	return NULL;
+}
+
+int node_del(struct hlist_head *table, uint8_t *hwaddr)
+{
+	int hidx = node_hash(hwaddr);
+	struct node *n;
+
+	n = node_lookup(table, hwaddr);
+	if (!n)
+		return -1;
+
+	hlist_del(&n->hlist, &table[hidx]);
+	dbg("Node " MACFMT " removed from topology\n", MAC2STR(n->hwaddr));
+
+	node_destroy(n);
+	return 0;
+}
+
+struct node *node_add(struct hlist_head *table, uint8_t *hwaddr)
+{
+	struct node *n;
+
+	n = node_lookup(table, hwaddr);
+	if (n) {
+		dbg("Node " MACFMT " already in topology\n", MAC2STR(hwaddr));
+		return n;
+	}
+
+	n = node_create(hwaddr);
+	if (n) {
+		int hidx = node_hash(hwaddr);
+
+		hlist_add_head(&n->hlist, &table[hidx]);
+		dbg("Node " MACFMT " added to topology\n", MAC2STR(hwaddr));
+	}
+
+	return n;
+}
+
+void node_print_all(struct hlist_head *table)
+{
+	struct node *n;
+	int i;
+
+	dbg("Nodes:\n");
+	for (i = 0; i < NODE_HTABLE_SIZE; i++) {
+		if (hlist_empty(&table[i]))
+			continue;
+
+		hlist_for_each_entry(n, &table[i], hlist) {
+			dbg("Node: " MACFMT "\n", MAC2STR(n->hwaddr));
+		}
+	}
+}
diff --git a/src/nodes.h b/src/nodes.h
new file mode 100644
index 0000000..59ca558
--- /dev/null
+++ b/src/nodes.h
@@ -0,0 +1,17 @@
+
+#ifndef NODES_H
+#define NODES_H
+
+#include <stdint.h>
+#include "hlist.h"
+
+
+struct node *node_create(uint8_t *hwaddr);
+void node_free(struct node *n);
+
+struct node *node_add(struct hlist_head *table, uint8_t *hwaddr);
+int node_del(struct hlist_head *table, uint8_t *hwaddr);
+struct node *node_lookup(struct hlist_head *table, uint8_t *hwaddr);
+void node_print_all(struct hlist_head *table);
+
+#endif /* NODES_H */
diff --git a/src/topo_ieee1905.c b/src/topo_ieee1905.c
new file mode 100644
index 0000000..b9a9e8b
--- /dev/null
+++ b/src/topo_ieee1905.c
@@ -0,0 +1,196 @@
+/*
+ * topo_ieee1905.c - topology for ieee1905 multiap network
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * See LICENSE file for license related information.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <libubox/uloop.h>
+#include <libubus.h>
+
+#include <easy/easy.h>
+
+#include "debug.h"
+#include "topologyd.h"
+#include "nodes.h"
+
+
+static int topologyd_copy_update_node(struct node *dest, struct node *src)
+{
+	if (dest == NULL || src == NULL)
+		return -1;
+
+	dest->nbr_num =  src->nbr_num;
+	dest->non1905_nbr_num = src->non1905_nbr_num;
+
+	memset(dest->nbrlist, 0, sizeof(dest->nbrlist));
+	memset(dest->non1905_nbrlist, 0, sizeof(dest->non1905_nbrlist));
+
+
+	memcpy(dest->nbrlist, src->nbrlist, 6 * src->nbr_num);
+	memcpy(dest->non1905_nbrlist, src->non1905_nbrlist,
+						6 * src->non1905_nbr_num);
+
+        time(&dest->last_recv);
+
+	return 0;
+}
+
+static void topologyd_node_expired(struct uloop_timeout *t)
+{
+	struct node *p = container_of(t, struct node, validity_timer);
+	struct topologyd_private *priv = p->priv;
+
+	if (priv) {
+		node_del(priv->topo.node_htable, p->hwaddr);
+	}
+}
+
+int topologyd_node_add(struct topologyd_private *priv, struct node *node)
+{
+	struct node *p = NULL;
+
+
+	if (!node || !priv)
+		return -1;
+
+	if (priv->topo.num_nodes >= TOPOLOGY_NODE_MAX)
+		return -1;
+
+	if (!memcmp(node->hwaddr, priv->ieee1905_macaddr, 6)) {
+		p = &priv->selfnode;
+		topologyd_copy_update_node(p, node);
+		return 0;
+	}
+
+	/* Add node if not present in topology.
+	 *
+	 * In case the node is present, update the node's values
+	 * and the timestamp.
+	 */
+	p = node_lookup(priv->topo.node_htable, node->hwaddr);
+	if (!p) {
+		p = node_add(priv->topo.node_htable, node->hwaddr);
+		topologyd_copy_update_node(p, node);
+
+		p->validity_timer.cb = topologyd_node_expired;
+		p->priv = priv;
+		priv->topo.num_nodes++;
+	} else {
+		topologyd_copy_update_node(p, node);
+	}
+
+	/* reset validity timer for the node */
+	uloop_timeout_set(&p->validity_timer, 180 * 1000);
+
+	return 0;
+}
+
+#if 0
+//Here we need to check if the node is a stale node and no response
+//has been received for more than TOPOLOGY_VALIDITY
+void check_node_validity()
+{
+        int i =0, j=0;
+	double diff_t;
+	time_t curr_time ;
+	time(&curr_time);
+        for (i = 0; i < gs_topotree.num_nodes; i++) {
+		diff_t = difftime(curr_time, gs_topotree.node[i].last_recv);
+                if (diff_t > TOPOLOGY_VALIDITY) {
+			//Here we need to delete the node 
+			DEBUG("Deleting the node in index [%d] difftime[%f] ", i, diff_t);
+			for( j = i; j < gs_topotree.num_nodes -1 ; j++) {
+				topologyd_copy_update_node(&(gs_topotree.node[j]), &(gs_topotree.node[j+1]));
+			}
+			gs_topotree.num_nodes = gs_topotree.num_nodes- 1;
+                }
+        }
+	//Here we may have deleted the node so get self node interfaces
+	//updated
+	//get_interface_neighbors(NULL);
+	topologyd_send_ieee1905_topology_query(priv, NULL);
+
+        return;
+}
+#endif
+
+/* Build full topology tree using a dumb but effective algo.
+ * It uses ieee1905 topology query to probe the neighbor nodes.
+ *
+ * Assumption: all nodes keep up-to-date list of their immediate neighbors.
+ *
+ * At any node 'P' in the network -
+ *
+ * Intial state:
+ *		Nbr(P) = {N0,..Nn}  <== immediate neighbors of P.
+ *		G{P, N0,..Nn} <== graph of all known nodes at P.
+ *
+ * Step 1:
+ *		for all Ni in G:
+ *			Send Topology Request to Ni.
+ *
+ * Step 2:
+ *		Read Topology Response from Ni.
+ *		if Nbr(Ni) is not in G:
+ *			Insert Nbr(Ni) in G
+ *
+ * Step 3:
+ *		Repeat Step 1-2 until no new Nbr(Ni) can be inserted in G.
+ *
+ */
+void topologyd_algo_run(struct topologyd_private *priv)
+{
+	struct node *p;
+	int i, j;
+
+	if (priv->algo_running)
+		return;
+
+	dbg("\n======Building Topology======\n");
+
+	priv->algo_running = true;
+
+	if (priv->topo.num_nodes == 0) {
+		/* send query to own neighbors */
+		p = &priv->selfnode;
+
+		if (hwaddr_is_zero(p->hwaddr))
+			topologyd_send_ieee1905_topology_query(priv, NULL);
+
+		dbg("Processing " MACFMT " AL\n", MAC2STR(p->hwaddr));
+
+		for (j = 0; j < p->nbr_num; j++) {
+			dbg("sending req to " MACFMT "\n", MAC2STR(p->nbrlist[j]));
+			topologyd_send_ieee1905_topology_query(priv, p->nbrlist[j]);
+		}
+	}
+
+	for (i = 0; i < NODE_HTABLE_SIZE; i++) {
+		if (hlist_empty(&priv->topo.node_htable[i]))
+			continue;
+
+		hlist_for_each_entry(p, &priv->topo.node_htable[i], hlist) {
+
+			if (hwaddr_is_zero(p->hwaddr))	// TODO: unlikely..
+				continue;
+
+			for (j = 0; j < p->nbr_num; j++) {
+				dbg("sending req to " MACFMT "\n", MAC2STR(p->nbrlist[j]));
+				topologyd_send_ieee1905_topology_query(priv, p->nbrlist[j]);
+			}
+		}
+	}
+
+	priv->algo_running = false;
+
+	dbg("\n====== Done Building Topology======\n");
+}
diff --git a/src/topologyd.c b/src/topologyd.c
new file mode 100644
index 0000000..6ebad98
--- /dev/null
+++ b/src/topologyd.c
@@ -0,0 +1,558 @@
+/*
+ * topologyd.c - topology for multiap network ubus interface
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * See LICENSE file for license related information.
+ *
+ */
+#include <stdbool.h>
+#include <pthread.h>
+#include <json-c/json.h>
+#include <libubox/blobmsg.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/uloop.h>
+#include <libubus.h>
+
+#include <easy/easy.h>
+#include <map1905/map2.h>
+
+#include "debug.h"
+#include "topologyd.h"
+#include "config.h"
+#include "json_utils.h"
+
+static int signal_pending;
+extern int refresh_int;
+extern const char *ubus_socket;
+
+static void topologyd_sighandler(int sig)
+{
+	signal_pending = sig;
+}
+
+static void ieee1905_info_response_cb(struct ubus_request *req,
+					int mtype, struct blob_attr *msg)
+{
+	struct topologyd_private *p;
+	json_object *jroot = NULL;
+	char *mac_str;
+	char *str;
+
+	if (!msg || !req->priv)
+		return;
+
+	p = (struct topologyd_private *)req->priv;
+
+	str = blobmsg_format_json_indent(msg, true, -1);
+	if (str) {
+		jroot = json_tokener_parse(str);
+		free(str);
+	}
+
+	if (jroot) {
+		//FIXME: "ieee1905id" -> "id"
+		mac_str = _json_obj_get_string(jroot, "ieee1905id");
+		if (mac_str) {
+			hwaddr_aton(mac_str, p->ieee1905_macaddr);
+			free(mac_str);
+		}
+
+		json_safe_put(jroot);
+	}
+}
+
+int topologyd_get_ieee1905_macaddr(struct topologyd_private *p)
+{
+	struct blob_buf bb = { 0 };
+	int ret = 0;
+
+	blob_buf_init(&bb, 0);
+	ret = ubus_invoke(p->ctx, p->ieee1905, "info", bb.head,
+				ieee1905_info_response_cb, p, 1000);
+	if (ret)
+		err("Failed to get ieee1905 info\n");
+
+	blob_buf_free(&bb);
+
+	return ret;
+}
+
+int topologyd_send_ieee1905_topology_query(struct topologyd_private *p,
+						uint8_t *dest)
+{
+	char dest_macstr[18] = { 0 };
+	struct blob_buf bb = { 0 };
+	int ret = 0;
+
+
+	blob_buf_init(&bb, 0);
+	if (dest) {
+		hwaddr_ntoa(dest, dest_macstr);
+		blobmsg_add_string(&bb, "remote_mac", dest_macstr);
+	}
+
+	ret = ubus_invoke(p->ctx, p->ieee1905, "query_topology", bb.head,
+					NULL, NULL, 1000);
+	if (ret)
+		err("Failed to send ieee1905 topology query\n");
+
+
+	blob_buf_free(&bb);
+
+	return ret;
+}
+
+void topologyd_event_handler(struct ubus_context *ctx,
+			struct ubus_event_handler *ev, const char *type,
+			struct blob_attr *msg)
+{
+	char *str;
+	int i, j;
+	struct node n = { 0 };
+	struct cmdu_cstruct *cstruct;
+	struct topologyd_private *priv =
+			container_of(ev, struct topologyd_private, ev);
+
+	if (!msg)
+		return;
+
+
+	str = blobmsg_format_json(msg, true);
+	if (str == NULL)
+		return;
+
+	cstruct = map_get_structs(str);		// TODO: check progress ?
+	if (cstruct == NULL) {
+		free(str);
+		return;
+	}
+	// We get the json_object now str can be freed
+	free(str);
+
+	// topology response is only required to build the topology tree
+	if (cstruct->message_type != CMDU_TYPE_TOPOLOGY_RESPONSE) {
+		map_free_cmdu_cstruct(cstruct);
+		return;
+	}
+
+	for (i = 0; i < cstruct->nbr_tlv_cstructs; i++) {
+		switch (*cstruct->tlv_cstruct_list[i]) {
+		case TLV_TYPE_DEVICE_INFORMATION_TYPE:
+		{
+			struct tlv_device_info *tlv =
+				(struct tlv_device_info *) cstruct->tlv_cstruct_list[i];
+
+			memcpy(&n.hwaddr, &tlv->al_mac_address, 6);
+		}
+		break;
+		case TLV_TYPE_NEIGHBOR_DEVICE_LIST:
+		{
+			struct tlv_neighbor_device *tlv =
+				(struct tlv_neighbor_device *) cstruct->tlv_cstruct_list[i];
+
+			n.nbr_num = tlv->neighbors_nr;
+			for (j = 0; j < n.nbr_num; j++) {
+				memcpy(n.nbrlist[j], &tlv->neighbors[j].mac_address, 6);
+			}
+		}
+		break;
+		case TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST:
+		{
+			struct tlv_non1905_neighbor *tlv =
+				(struct tlv_non1905_neighbor *) cstruct->tlv_cstruct_list[i];
+
+			n.non1905_nbr_num = tlv->non_1905_neighbors_nr;
+			for (j = 0; j < n.non1905_nbr_num; j++) {
+				memcpy(n.non1905_nbrlist[j], &tlv->non_1905_neighbors[j].mac_address, 6);
+			}
+		}
+		break;
+		case TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES:
+		case MAP_TLV_SUPPORTED_SERVICE:
+		case MAP_TLV_AP_OPERATIONAL_BSS:
+		case MAP_TLV_ASSOCIATED_CLIENTS:
+			break;
+		}
+	}
+
+	if (n.nbr_num || n.non1905_nbr_num) {
+		dbg("Updating Node" MACFMT " from topology response\n",
+						MAC2STR(n.hwaddr));
+		topologyd_node_add(priv, &n);
+	}
+
+	map_free_cmdu_cstruct(cstruct);
+}
+
+static int topologyd_refresh(struct ubus_context *ctx,
+				struct ubus_object *obj,
+				struct ubus_request_data *req,
+				const char *method,
+				struct blob_attr *msg)
+{
+	struct topologyd_private *priv =
+			container_of(obj, struct topologyd_private, obj);
+
+	if (!priv->algo_running)
+		topologyd_algo_run(priv);
+
+	return 0;
+}
+
+void topologyd_dump_tree(struct topologyd_private *priv, struct blob_buf *bb)
+{
+	void *nodes_array, *table, *nbr_array, *non1905_array = NULL;
+	char mac_str[18] = { 0x0 };
+	struct node *p;
+	int i, j;
+
+	/* Add details of own node first */
+	p = &priv->selfnode;
+	hwaddr_ntoa(p->hwaddr, mac_str);
+
+	table = blobmsg_open_table(bb, "self");
+	blobmsg_add_string(bb, "ieee1905_macaddr", mac_str);
+	blobmsg_add_u32(bb, "num_neighbors", p->nbr_num);
+
+	nbr_array = blobmsg_open_array(bb, "neighbors");
+	for (j = 0; j < p->nbr_num; j++) {
+		hwaddr_ntoa(p->nbrlist[j], mac_str);
+		blobmsg_add_string(bb, NULL, mac_str);
+	}
+	blobmsg_close_array(bb, nbr_array);
+
+	blobmsg_add_u32(bb, "num_non1905_neighbors", p->non1905_nbr_num);
+	non1905_array = blobmsg_open_array(bb, "non1905_neighbors");
+	for (j = 0; j < p->non1905_nbr_num; j++) {
+		hwaddr_ntoa(p->non1905_nbrlist[j], mac_str);
+		blobmsg_add_string(bb, NULL, mac_str);
+	}
+	blobmsg_close_array(bb, non1905_array);
+	blobmsg_close_table(bb, table);
+
+	nodes_array = blobmsg_open_array(bb, "nodes");
+	for (i = 0; i < NODE_HTABLE_SIZE; i++) {
+		if (hlist_empty(&priv->topo.node_htable[i]))
+			continue;
+
+		hlist_for_each_entry(p, &priv->topo.node_htable[i], hlist) {
+
+			if (hwaddr_is_zero(p->hwaddr))	// TODO: unlikely..
+				continue;
+
+			table = blobmsg_open_table(bb, NULL);
+
+			hwaddr_ntoa(p->hwaddr, mac_str);
+
+			blobmsg_add_string(bb, "ieee1905_macaddr", mac_str);
+			blobmsg_add_u32(bb, "num_neighbors", p->nbr_num);
+
+			nbr_array = blobmsg_open_array(bb, "neighbors");
+			for (j = 0; j < p->nbr_num; j++) {
+				hwaddr_ntoa(p->nbrlist[j], mac_str);
+				blobmsg_add_string(bb, NULL, mac_str);
+			}
+			blobmsg_close_array(bb, nbr_array);
+
+			blobmsg_add_u32(bb, "num_non1905_neighbors", p->non1905_nbr_num);
+			non1905_array = blobmsg_open_array(bb, "non1905_neighbors");
+			for (j = 0; j < p->non1905_nbr_num; j++) {
+				hwaddr_ntoa(p->non1905_nbrlist[j], mac_str);
+				blobmsg_add_string(bb, NULL, mac_str);
+			}
+			blobmsg_close_array(bb, non1905_array);
+			blobmsg_close_table(bb, table);
+		}
+	}
+	blobmsg_close_array(bb, nodes_array);
+}
+
+static int topologyd_dump(struct ubus_context *ctx,
+				struct ubus_object *obj,
+				struct ubus_request_data *req,
+				const char *method,
+				struct blob_attr *msg)
+{
+	struct blob_buf bb;
+	struct topologyd_private *priv =
+			container_of(obj, struct topologyd_private, obj);
+
+	memset(&bb, 0, sizeof(struct blob_buf));
+	blob_buf_init(&bb, 0);
+
+	topologyd_dump_tree(priv, &bb);
+
+	ubus_send_reply(ctx, req, bb.head);
+	blob_buf_free(&bb);
+
+	return 0;
+}
+
+void topologyd_dump_changelog(struct topologyd_private *priv, struct blob_buf *bb)
+{
+	struct topology_changelog *log;
+	char rpt_ifmacstr[18] = { 0 };
+	char rpt_macstr[18] = { 0 };
+	char nbr_macstr[18] = { 0 };
+	void *a, *t;
+	int i;
+
+	blobmsg_add_u32(bb, "num_changelog", priv->topo.num_changelog);
+
+	a = blobmsg_open_array(bb, "changelog");
+	for (i = 0; i < priv->topo.num_changelog; i++) {
+		log = &priv->topo.changelog[i];
+
+		t = blobmsg_open_table(bb, NULL);
+
+		hwaddr_ntoa(log->rpt_macaddr, rpt_macstr);
+		blobmsg_add_string(bb, "reporter", rpt_macstr);
+
+		hwaddr_ntoa(log->rpt_ifmacaddr, rpt_ifmacstr);
+		blobmsg_add_string(bb, "reporter_interface", rpt_ifmacstr);
+
+		hwaddr_ntoa(log->nbr_macaddr, nbr_macstr);
+		blobmsg_add_string(bb, "neighbor", nbr_macstr);
+
+		blobmsg_add_string(bb, "is1905_neighbor",
+				log->is1905_nbr ? "true" : "false");
+
+		blobmsg_close_table(bb, t);
+	}
+	blobmsg_close_array(bb, a);
+}
+
+static int topologyd_changelog(struct ubus_context *ctx,
+				struct ubus_object *obj,
+				struct ubus_request_data *req,
+				const char *method,
+				struct blob_attr *msg)
+{
+	struct blob_buf bb;
+	struct topologyd_private *priv =
+			container_of(obj, struct topologyd_private, obj);
+
+	memset(&bb, 0, sizeof(struct blob_buf));
+	blob_buf_init(&bb, 0);
+
+	topologyd_dump_changelog(priv, &bb);
+
+	ubus_send_reply(ctx, req, bb.head);
+	blob_buf_free(&bb);
+
+	return 0;
+}
+
+static int topologyd_status(struct ubus_context *ctx,
+				struct ubus_object *obj,
+				struct ubus_request_data *req,
+				const char *method,
+				struct blob_attr *msg)
+{
+	struct blob_buf bb;
+	struct topologyd_private *priv =
+			container_of(obj, struct topologyd_private, obj);
+
+	memset(&bb, 0, sizeof(struct blob_buf));
+	blob_buf_init(&bb, 0);
+
+	blobmsg_add_string(&bb, "status", priv->status == AVAILABLE ?
+					"available" : "incomplete");
+
+	ubus_send_reply(ctx, req, bb.head);
+	blob_buf_free(&bb);
+
+	return 0;
+}
+
+static void topologyd_periodic_refresh(struct uloop_timeout *t)
+{
+	struct topologyd_private *priv =
+		container_of(t, struct topologyd_private, refresh_timer);
+
+	dbg("Refresh topology...\n");
+
+	topologyd_algo_run(priv);
+
+	if (priv->refresh_int)
+		uloop_timeout_set(&priv->refresh_timer, priv->refresh_int * 1000);
+}
+
+static void topologyd_start_heartbeat(struct uloop_timeout *t)
+{
+	struct topologyd_private *priv =
+			container_of(t, struct topologyd_private, heartbeat);
+
+	if (!signal_pending)
+		uloop_timeout_set(&priv->heartbeat, 1 * 1000);
+
+	switch(signal_pending) {
+	case SIGTERM:
+	case SIGINT:
+		//topologyd_exit(priv);
+		break;
+	case SIGHUP:
+		//topologyd_reload(priv);
+		break;
+	default:
+		break;
+	}
+}
+
+static int topologyd_run(struct topologyd_private *priv)
+{
+	int ret;
+
+	ret = topologyd_get_ieee1905_macaddr(priv);
+	ret |= topologyd_send_ieee1905_topology_query(priv, NULL);
+
+	if (ret) {
+		err("Failed to run topologyd...\n");
+		return -1;
+	}
+
+	topologyd_start_heartbeat(&priv->heartbeat);
+	topologyd_periodic_refresh(&priv->refresh_timer);
+
+	return 0;
+}
+
+static uint32_t topologyd_get_ieee1905_object(struct topologyd_private *priv)
+{
+	uint32_t id;
+	int status;
+
+	status = ubus_lookup_id(priv->ctx, IEEE1905_OBJECT, &id);
+	if (status != UBUS_STATUS_OK) {
+		err("object '%s' not present!\n", IEEE1905_OBJECT);
+		return OBJECT_INVALID;
+	}
+
+	return id;
+}
+
+int topologyd_publish_object(struct topologyd_private *priv, const char *objname)
+{
+	struct ubus_object *obj;
+	struct ubus_object_type *obj_type;
+	struct ubus_method *obj_methods;
+	struct ubus_method m[4] = {
+		UBUS_METHOD_NOARG("refresh", topologyd_refresh),
+		UBUS_METHOD_NOARG("status", topologyd_status),
+		UBUS_METHOD_NOARG("dump", topologyd_dump),
+		UBUS_METHOD_NOARG("changelog", topologyd_changelog),
+	};
+	int num_methods = ARRAY_SIZE(m);
+	int ret;
+
+
+	obj = &priv->obj;
+	memset(obj, 0, sizeof(*obj));
+
+	obj_type = calloc(1, sizeof(struct ubus_object_type));
+	if (!obj_type)
+		return -1;
+
+	obj_methods = calloc(num_methods, sizeof(struct ubus_method));
+	if (!obj_methods) {
+		free(obj_type);
+		return -1;
+	}
+
+	obj->name = objname;
+	memcpy(obj_methods, m, num_methods * sizeof(struct ubus_method));
+	obj->methods = obj_methods;
+	obj->n_methods = num_methods;
+
+	obj_type->name = obj->name;
+	obj_type->n_methods = obj->n_methods;
+	obj_type->methods = obj->methods;
+	obj->type = obj_type;
+
+	ret = ubus_add_object(priv->ctx, obj);
+	if (ret) {
+		fprintf(stderr, "Failed to add 'obj' err = %s\n",
+							ubus_strerror(ret));
+		free(obj_methods);
+		free(obj_type);
+
+		return ret;
+	}
+
+	fprintf(stderr, "Added object '%s'\n", objname);
+
+	return 0;
+}
+
+int topologyd_start(void)
+{
+	struct topologyd_private *priv;
+
+	signal_pending = 0;
+	set_sighandler(SIGINT, topologyd_sighandler);
+	set_sighandler(SIGTERM, topologyd_sighandler);
+	set_sighandler(SIGHUP, topologyd_sighandler);
+	set_sighandler(SIGPIPE, SIG_IGN);
+
+	priv = calloc(1, sizeof(*priv));
+	if (!priv)
+		return -ENOMEM;
+
+	info("Starting topologyd...");
+
+	uloop_init();
+	priv->ctx = ubus_connect(ubus_socket);
+	if (!priv->ctx) {
+		err("Failed to connect to ubus\n");
+		free(priv);
+		return -1;
+	}
+
+	ubus_add_uloop(priv->ctx);
+
+	priv->ieee1905 = topologyd_get_ieee1905_object(priv);
+	if (priv->ieee1905 == OBJECT_INVALID)
+		goto out_and_exit;
+
+	//topologyd_load_extras();	//TODO
+
+	topologyd_config_defaults(&priv->config);
+	topologyd_config_user(&priv->config);
+
+	priv->ev.cb = topologyd_event_handler;
+	ubus_register_event_handler(priv->ctx, &priv->ev, IEEE1905_EVENTS);
+
+	priv->refresh_timer.cb = topologyd_periodic_refresh;
+	priv->heartbeat.cb = topologyd_start_heartbeat;
+
+	if (!priv->config.enabled) {
+		info("topologyd not enabled.\n");
+	} else {
+		topologyd_publish_object(priv, TOPOLOGY_OBJECT);
+		topologyd_run(priv);
+	}
+
+	uloop_run();
+
+	ubus_unregister_event_handler(priv->ctx, &priv->ev);
+	//topologyd_remove_object(priv->ctx);	//TODO
+out_and_exit:
+	ubus_free(priv->ctx);
+	uloop_done();
+	free(priv);
+
+	return 0;
+}
+
+void topologyd_stop(struct topologyd_private *priv)
+{
+	if (!priv)
+		exit(0);
+
+	ubus_unregister_event_handler(priv->ctx, &priv->ev);
+	//topologyd_remove_object(priv->ctx);
+	ubus_free(priv->ctx);
+	uloop_done();
+	free(priv);
+}
diff --git a/src/topologyd.h b/src/topologyd.h
new file mode 100644
index 0000000..04987b6
--- /dev/null
+++ b/src/topologyd.h
@@ -0,0 +1,102 @@
+/*
+ * topologyd.h - topologyd header file
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: anjan.chanda@iopsys.eu
+ *
+ */
+#ifndef TOPOLOGYD_H
+#define TOPOLOGYD_H
+
+#include <time.h>
+#include "hlist.h"
+
+#define IEEE1905_OBJECT		"ieee1905"
+#define IEEE1905_EVENTS		"ieee1905*"
+#define TOPOLOGY_OBJECT		"topology"
+
+#define TOPOLOGY_CONFIG		"topology"
+
+
+#define TOPOLOGY_NODE_MAX	32
+#define TOPOLOGY_NEIGHBOR_MAX	32
+#define TOPOLOGY_VALIDITY	120   // 120 sec
+
+typedef uint32_t ieee1905_object_t;
+
+#define OBJECT_INVALID	(uint32_t)-1
+
+#define TOPOLOGY_DEPTH		16	/* max depth */
+#define TOPOLOGY_REFRESH_INT	120	/* default refresh interval in secs */
+#define TOPOLOGY_LOG_MAX	32	/* max entries in topology changelog */
+
+struct node {
+	uint8_t hwaddr[6];
+	void *priv;
+	struct hlist_node hlist;
+	uint32_t nbr_num;
+	time_t last_recv;
+	struct uloop_timeout validity_timer;
+	uint32_t non1905_nbr_num;
+	uint8_t nbrlist[TOPOLOGY_NEIGHBOR_MAX][6];
+	uint8_t non1905_nbrlist[TOPOLOGY_NEIGHBOR_MAX][6];
+};
+
+struct topology_changelog {
+	uint8_t rpt_macaddr[6];
+	uint8_t rpt_ifmacaddr[6];
+	enum { NBR_NODE_ADD, NBR_NODE_DEL } type;
+	bool is1905_nbr;
+	uint8_t nbr_macaddr[6];
+	time_t timestamp;
+};
+
+#define NODE_HTABLE_SIZE	128
+#define node_hash(n)	\
+	((n[0] ^ n[1] ^ n[2] ^ n[3] ^ n[4] ^ n[5]) % NODE_HTABLE_SIZE)
+
+
+struct topology {
+	void *priv;
+	uint32_t state;
+	int32_t num_nodes;
+	uint32_t num_changelog;
+	struct topology_changelog changelog[TOPOLOGY_LOG_MAX];
+	struct hlist_head node_htable[NODE_HTABLE_SIZE];
+};
+
+struct topologyd_config {
+	bool enabled;
+	uint32_t depth;
+	uint32_t refresh_int;
+	uint32_t maxlog;
+};
+
+struct topologyd_private {
+	int debug;
+	uint32_t refresh_int;
+	bool algo_running;
+	enum { INCOMPLETE, AVAILABLE } status;
+	struct ubus_context *ctx;
+	struct ubus_event_handler ev;
+	struct uloop_timeout heartbeat;
+	struct uloop_timeout refresh_timer;
+	struct ubus_object obj;
+	struct topologyd_config config;
+	ieee1905_object_t ieee1905;
+	uint8_t ieee1905_macaddr[6];
+	struct node selfnode;
+	struct topology topo;
+};
+
+
+void topologyd_algo_run(struct topologyd_private *p);
+int topologyd_node_add(struct topologyd_private *priv, struct node *n);
+
+int topologyd_get_ieee1905_macaddr(struct topologyd_private *p);
+int topologyd_send_ieee1905_topology_query(struct topologyd_private *p,
+								uint8_t *dest);
+
+
+#endif /* TOPOLOGYD_H */
diff --git a/src/topomap.c b/src/topomap.c
deleted file mode 100644
index 136c0e1..0000000
--- a/src/topomap.c
+++ /dev/null
@@ -1,258 +0,0 @@
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdbool.h>
-#include <errno.h>
-
-#include "topomap.h"
-#include "topoutils.h"
-
-static struct topo1905 gs_topotree;
-static struct node1905 gs_selfnode;
-static uint8_t gs_self_al_mac[6];
-
-bool topomap_init()
-{
-	uint8_t *al = gs_self_al_mac;
-	get_al_mac(al);
-	get_interface_neighbors(NULL);
-	memset(&gs_topotree, 0, sizeof(struct topo1905));
-	return true;
-}
-
-static bool _copy_node1905(struct node1905 *dest, struct node1905 *src)
-{
-	uint8_t i;
-
-	if (dest == NULL || src == NULL)
-		return false;
-
-	//Here we memset the dest node first before copying
-	memset(dest,0, sizeof(struct node1905));
-
-	memcpy(dest->hwaddr, src->hwaddr, 6);
-	dest->nbr_num =  src->nbr_num;
-	dest->non1905_nbr_num = src->non1905_nbr_num;
-
-	for (i = 0; i < dest->nbr_num; i++) {
-		memcpy(dest->nbrlist[i], src->nbrlist[i], 6);
-	}
-
-	for (i = 0; i < dest->non1905_nbr_num; i++) {
-		memcpy(dest->non1905_nbrlist[i], src->non1905_nbrlist[i], 6);
-	}
-
-	return true;
-}
-
-static bool topomap_node_present(uint8_t *almac, int *index)
-{
-	int i;
-
-	for (i = 0; i < gs_topotree.num_nodes; i++) {
-		if (!memcmp(gs_topotree.node[i].hwaddr, almac, 6)) {
-			*index = i;
-			return true;
-		}
-	}
-
-	return false;
-}
-
-int topomap_node_add(struct node1905 *node)
-{
-	bool node_present = true;
-	int index =0;
-	struct node1905 *p = NULL;
-
-	if (node == NULL)
-		return -1;
-
-	if (gs_topotree.num_nodes >= NODE_MAX_NUM)
-		return -1;
-
-	if (memcmp(node->hwaddr, gs_self_al_mac, 6) == 0) {
-		p = &gs_selfnode;
-		_copy_node1905(p, node);
-		time(&(p->last_recv));
-		return 0;
-	}
-	// Add the node if already not present update the recv time
-	// In case the node is already present update the node values and the 
-	// last recv time
-	node_present = topomap_node_present(node->hwaddr, &index);
-	if (node_present == false) {
-		p = &(gs_topotree.node[gs_topotree.num_nodes]);
-		_copy_node1905(p, node);
-		//As the node is newly added set the timestamp
-                time(&(p->last_recv));
-		gs_topotree.num_nodes++;
-	}
-	else {
-		//As the node is already present get the index of the node
-		p = &(gs_topotree.node[index]);
-		_copy_node1905(p, node);
-		//Here we update the time at which the node was last received
-		time(&(p->last_recv));
-	}
-	return 0;
-}
-
-
-//Here we need to check if the node is a stale node and no response
-//has been received for more than TOPOLOGY_VALIDITY
-void check_node_validity()
-{
-        int i =0, j=0;
-	double diff_t;
-	time_t curr_time ;
-	time(&curr_time);
-        for (i = 0; i < gs_topotree.num_nodes; i++) {
-		diff_t = difftime(curr_time, gs_topotree.node[i].last_recv);
-                if (diff_t > TOPOLOGY_VALIDITY) {
-			//Here we need to delete the node 
-			DEBUG("Deleting the node in index [%d] difftime[%f] ", i, diff_t);
-			for( j = i; j < gs_topotree.num_nodes -1 ; j++) {
-			_copy_node1905(&(gs_topotree.node[j]), &(gs_topotree.node[j+1]));
-			}
-			gs_topotree.num_nodes = gs_topotree.num_nodes- 1;
-                }
-        }
-	//Here we may have deleted the node so get self node interfaces
-	//updated
-	get_interface_neighbors(NULL);
-        return;
-}
-
-/* Build full topology tree using a dumb but effective algo.
- *
- * Assumption: all nodes keep up-to-date list of their immediate neighbors.
- *
- * At any node 'P' in the network -
- *
- * Intial state:
- *		Nbr(P) = {N0,..Nn}  <== immediate neighbors of P.
- *		G{P, N0,..Nn} <== graph of all known nodes at P.
- *
- * Step 1:
- *		for all Ni in G:
- *			Send Topology Request to Ni.
- *
- * Step 2:
- *		Read Topology Response from Ni.
- *		if Nbr(Ni) is not in G:
- *			Insert Nbr(Ni) in G
- *
- * Step 3:
- *		Repeat Step 1-2 until no new Nbr(Ni) can be inserted in G.
- *
- */
-void topomap_build_thread()
-{
-	struct node1905 *p;
-	int i, j;
-	char addr[18] = {0};
-
-	DEBUG("\n======Building Topology Tree======\n");
-	//Here we call a function first to check the stale node 
-	check_node_validity();
-
-	if (gs_topotree.num_nodes == 0) {
-		// send query to own neighbors
-		p = &gs_selfnode;
-
-		if (hwaddr_is_zero(p->hwaddr)) {
-			get_interface_neighbors(NULL);
-		}
-
-		hwaddr_ntoa(p->hwaddr, addr);
-		DEBUG("Processing (%s) AL", addr);
-
-		for (j = 0; j < p->nbr_num; j++) {
-			hwaddr_ntoa(p->nbrlist[j], addr);
-			DEBUG("sending req to (%s)", addr);
-			get_interface_neighbors(p->nbrlist[j]);
-		}
-	}
-
-	for (i = 0; i < gs_topotree.num_nodes; i++) {
-		p = &gs_topotree.node[i];
-
-		if (hwaddr_is_zero(p->hwaddr))
-			continue;
-
-		hwaddr_ntoa(p->hwaddr, addr);
-		DEBUG("Processing (%s) AL", addr);
-
-		for (j = 0; j < p->nbr_num; j++) {
-			hwaddr_ntoa(p->nbrlist[j], addr);
-			DEBUG("sending req to (%s)", addr);
-			get_interface_neighbors(p->nbrlist[j]);
-		}
-	}
-
-	DEBUG("\n====== Done Building Topology Tree======\n");
-}
-
-void dump_topology_tree(struct blob_buf *bb)
-{
-	char mac_str[18] = { 0x0 };
-	struct node1905 *p;
-	int i, j;
-	void *nodes_array, *table, *nbr_array, *non1905_array = NULL;
-
-	// Add details of own node first
-	p = &gs_selfnode;
-	hwaddr_ntoa(p->hwaddr, mac_str);
-
-	table = blobmsg_open_table(bb, "self");
-	blobmsg_add_string(bb, "al_mac", mac_str);
-	blobmsg_add_u32(bb, "neighbors_nr", p->nbr_num);
-
-	nbr_array = blobmsg_open_array(bb, "neighbors");
-	for (j = 0; j < p->nbr_num; j++) {
-		hwaddr_ntoa(p->nbrlist[j], mac_str);
-		blobmsg_add_string(bb, NULL, mac_str);
-	}
-	blobmsg_close_array(bb, nbr_array);
-
-	blobmsg_add_u32(bb, "non_1905_neighbors_nr", p->non1905_nbr_num);
-	non1905_array = blobmsg_open_array(bb, "non_1905_neighbors");
-	for (j = 0; j < p->non1905_nbr_num; j++) {
-		hwaddr_ntoa(p->non1905_nbrlist[j], mac_str);
-		blobmsg_add_string(bb, NULL, mac_str);
-	}
-	blobmsg_close_array(bb, non1905_array);
-	blobmsg_close_table(bb, table);
-
-	nodes_array = blobmsg_open_array(bb, "Nodes");
-	for (i = 0; i < gs_topotree.num_nodes; i++) {
-		p = &gs_topotree.node[i];
-		if (hwaddr_is_zero(p->hwaddr))
-			continue;
-
-		table = blobmsg_open_table(bb, NULL);
-
-		hwaddr_ntoa(p->hwaddr, mac_str);
-
-		blobmsg_add_string(bb, "al_mac", mac_str);
-		blobmsg_add_u32(bb, "neighbors_nr", p->nbr_num);
-
-		nbr_array = blobmsg_open_array(bb, "neighbors");
-		for (j = 0; j < p->nbr_num; j++) {
-			hwaddr_ntoa(p->nbrlist[j], mac_str);
-			blobmsg_add_string(bb, NULL, mac_str);
-		}
-		blobmsg_close_array(bb, nbr_array);
-
-		blobmsg_add_u32(bb, "non_1905_neighbors_nr", p->non1905_nbr_num);
-		non1905_array = blobmsg_open_array(bb, "non_1905_neighbors");
-		for (j = 0; j < p->non1905_nbr_num; j++) {
-			hwaddr_ntoa(p->non1905_nbrlist[j], mac_str);
-			blobmsg_add_string(bb, NULL, mac_str);
-		}
-		blobmsg_close_array(bb, non1905_array);
-		blobmsg_close_table(bb, table);
-	}
-	blobmsg_close_array(bb, nodes_array);
-}
diff --git a/src/topomap.h b/src/topomap.h
deleted file mode 100644
index 2b1722d..0000000
--- a/src/topomap.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "topoubus.h"
-#include <libubox/blobmsg.h>
-#include <time.h>
-
-#ifndef TOPOMAP_H
-#define TOPOMAP_H
-
-#define NODE_MAX_NUM		32
-#define NEIGHBOR_MAX_NUM	32
-#define TOPOLOGY_VALIDITY 120   // 120 sec
-
-struct node1905 {
-	uint8_t hwaddr[6];
-	uint32_t nbr_num;
-	time_t last_recv;
-	uint32_t non1905_nbr_num;
-	uint8_t nbrlist[NEIGHBOR_MAX_NUM][6];
-	uint8_t non1905_nbrlist[NEIGHBOR_MAX_NUM][6];
-};
-
-struct topo1905 {
-	uint32_t state;
-	int32_t num_nodes;
-	struct node1905 node[NODE_MAX_NUM];
-};
-
-// Topology build thread function. For internal use.
-void topomap_build_thread();
-bool topomap_init();
-int topomap_node_add(struct node1905 *node);
-void dump_topology_tree(struct blob_buf *bb);
-
-#endif /* TOPOMAP_H */
diff --git a/src/topoubus.c b/src/topoubus.c
deleted file mode 100644
index f283bc6..0000000
--- a/src/topoubus.c
+++ /dev/null
@@ -1,310 +0,0 @@
-#include "topoubus.h"
-#include "topomap.h"
-#include "topoutils.h"
-
-#include <stdbool.h>
-#include <pthread.h>
-#include <json-c/json.h>
-#include <libubox/blobmsg.h>
-#include <libubox/blobmsg_json.h>
-#include <libubox/uloop.h>
-#include <libubus.h>
-
-#include <map1905/map2.h>
-
-static void topology_schedule();
-
-
-static void al_mac_cb(struct ubus_request *req,
-			  int mtype __attribute__((unused)),
-			  struct blob_attr *msg)
-{
-	char *str;
-	uint8_t *al_mac;
-
-	if (!msg)
-		return;
-
-	al_mac = (uint8_t *) req->priv;
-
-	if (al_mac == NULL)
-		return;
-
-	str = blobmsg_format_json_indent(msg, true, -1);
-	if (str == NULL)
-		return;
-
-	json_object *jroot = json_tokener_parse(str);
-	free(str);
-
-	if (jroot == NULL)
-		return;
-
-	char *mac_str = _json_obj_get_string(jroot, "ieee1905id");
-
-	if (mac_str) {
-		hwaddr_aton(mac_str, al_mac);
-	}
-
-	free(mac_str);
-	json_safe_put(jroot);
-}
-
-int get_al_mac(uint8_t *al_mac)
-{
-	int ret = 0;
-	unsigned int id;
-	struct ubus_context *ctx = NULL;
-	struct blob_buf bb;
-
-	ctx = ubus_connect(NULL);
-	if (!ctx) {
-		ERROR("ubus connect failed\n");
-		return -1;
-	}
-
-	if (UBUS_STATUS_OK != ubus_lookup_id(ctx, GET_TOPOLOGY_OBJECT, &id)) {
-		ERROR("lookup Object %s failed\n", GET_TOPOLOGY_OBJECT);
-		return -1;
-	}
-
-
-	memset(&bb, 0, sizeof(struct blob_buf));
-	blob_buf_init(&bb, 0);
-
-	ret = ubus_invoke(ctx, id, "info", bb.head, al_mac_cb, al_mac, 1000);
-	if (ret) {
-		ERROR("Failed to get ieee1905 topology\n");
-	}
-
-	blob_buf_free(&bb);
-	ubus_free(ctx);
-	return ret;
-}
-
-int get_interface_neighbors(uint8_t *dmac)
-{
-	int ret = 0;
-	unsigned int id;
-	char macstr[18] = {0x0};
-	struct ubus_context *ctx = NULL;
-	struct blob_buf bb;
-
-	ctx = ubus_connect(NULL);
-	if (!ctx) {
-		ERROR("ubus connect failed\n");
-		return -1;
-	}
-
-	if (UBUS_STATUS_OK != ubus_lookup_id(ctx, GET_TOPOLOGY_OBJECT, &id)) {
-		ERROR("lookup Object %s failed\n", GET_TOPOLOGY_OBJECT);
-		return -1;
-	}
-
-
-	memset(&bb, 0, sizeof(struct blob_buf));
-	blob_buf_init(&bb, 0);
-
-	if (dmac) {
-		hwaddr_ntoa(dmac, macstr);
-		blobmsg_add_string(&bb, "remote_mac", macstr);
-	}
-
-	ret = ubus_invoke(ctx, id, GET_TOPOLOGY, bb.head, NULL, NULL, 1000);
-	if (ret) {
-		ERROR("Failed to get ieee1905 topology\n");
-	}
-
-	blob_buf_free(&bb);
-	ubus_free(ctx);
-	return ret;
-}
-
-void ieee1905_event_handler(struct ubus_context *ctx,
-			    struct ubus_event_handler *ev,
-			    const char *type, struct blob_attr *msg)
-{
-	char *str;
-	int i, j;
-	struct node1905 node;
-	struct cmdu_cstruct *cstruct;
-
-	if (!msg)
-		return;
-
-	memset(&node, 0, sizeof(struct node1905));
-
-	str = blobmsg_format_json(msg, true);
-	if (str == NULL)
-		return;
-
-	cstruct = map_get_structs(str);
-
-	if (cstruct == NULL) {
-		free(str);
-		return;
-	}
-	// We get the json_object now str can be freed
-	free(str);
-
-	// topology response is only required to build the topology tree
-	if (cstruct->message_type != CMDU_TYPE_TOPOLOGY_RESPONSE) {
-		map_free_cmdu_cstruct(cstruct);
-		return;
-	}
-
-	for (i = 0; i < cstruct->nbr_tlv_cstructs; i++) {
-		switch (*cstruct->tlv_cstruct_list[i]) {
-		case TLV_TYPE_DEVICE_INFORMATION_TYPE:
-			{
-				struct tlv_device_info *tlv =
-					(struct tlv_device_info *) cstruct->tlv_cstruct_list[i];
-
-				memcpy(&node.hwaddr, &tlv->al_mac_address, 6);
-			}
-			break;
-		case TLV_TYPE_NEIGHBOR_DEVICE_LIST:
-			{
-				struct tlv_neighbor_device *tlv =
-					(struct tlv_neighbor_device *) cstruct->tlv_cstruct_list[i];
-
-				node.nbr_num = tlv->neighbors_nr;
-				for (j = 0; j < node.nbr_num; j++) {
-					memcpy(node.nbrlist[j], &tlv->neighbors[j].mac_address, 6);
-				}
-			}
-			break;
-		case TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST:
-			{
-				struct tlv_non1905_neighbor *tlv =
-					(struct tlv_non1905_neighbor *) cstruct->tlv_cstruct_list[i];
-
-				node.non1905_nbr_num = tlv->non_1905_neighbors_nr;
-				for (j = 0; j < node.non1905_nbr_num; j++) {
-					memcpy(node.non1905_nbrlist[j], &tlv->non_1905_neighbors[j].mac_address, 6);
-				}
-			}
-			break;
-		case TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES:
-		case MAP_TLV_SUPPORTED_SERVICE:
-		case MAP_TLV_AP_OPERATIONAL_BSS:
-		case MAP_TLV_ASSOCIATED_CLIENTS:
-			break;
-		}
-	}
-	if (node.nbr_num || node.non1905_nbr_num) {
-		DEBUG("updating topology response \n");
-		topomap_node_add(&node);
-	}
-	map_free_cmdu_cstruct(cstruct);
-}
-
-static void topology_schedule_cb(struct uloop_timeout *timeout)
-{
-	DEBUG("Building topology tree \n");
-	topomap_build_thread();
-	uloop_timeout_set(timeout, TOPOLOGY_TIMEOUT);
-}
-
-static void topology_schedule()
-{
-	struct uloop_timeout topo_scheduler;
-
-	memset(&topo_scheduler, 0, sizeof(struct uloop_timeout));
-
-	topo_scheduler.cb = topology_schedule_cb;
-	uloop_timeout_set(&topo_scheduler, TOPOLOGY_TIMEOUT);
-}
-
-static int topo1905_build_tree(struct ubus_context *ectx, struct ubus_object *obj __attribute__ ((unused)),
-			       struct ubus_request_data *req, const char *method __attribute__ ((unused)),
-				       struct blob_attr *msg __attribute__ ((unused)))
-{
-	struct blob_buf bb;
-
-	memset(&bb, 0, sizeof(struct blob_buf));
-	blob_buf_init(&bb, 0);
-
-	topomap_build_thread();
-
-	blobmsg_add_u8(&bb, "status", true);
-	ubus_send_reply(ectx, req, bb.head);
-	blob_buf_free(&bb);
-	return 0;
-}
-
-static int topo1905_dump_tree(struct ubus_context *ectx, struct ubus_object *obj __attribute__ ((unused)),
-			      struct ubus_request_data *req, const char *method __attribute__ ((unused)),
-			      struct blob_attr *msg __attribute__ ((unused)))
-{
-	struct blob_buf bb;
-
-	memset(&bb, 0, sizeof(struct blob_buf));
-	blob_buf_init(&bb, 0);
-
-	dump_topology_tree(&bb);
-
-	ubus_send_reply(ectx, req, bb.head);
-	blob_buf_free(&bb);
-	return 0;
-}
-
-static const struct ubus_method topo1905_methods[] = {
-	UBUS_METHOD_NOARG("build_tree", topo1905_build_tree),
-	UBUS_METHOD_NOARG("dump_tree", topo1905_dump_tree),
-};
-
-static struct ubus_object_type topo1905_object_type =
-	UBUS_OBJECT_TYPE("topo1905", topo1905_methods);
-
-static struct ubus_object topo1905_object = {
-	.name = "topo1905",
-	.type = &topo1905_object_type,
-	.methods = topo1905_methods,
-	.n_methods = ARRAY_SIZE(topo1905_methods),
-};
-
-int init_topology()
-{
-	int ret;
-	struct ubus_event_handler listener;
-	struct ubus_context *ectx;
-
-	uloop_init();
-	ectx = ubus_connect(NULL);
-	if (!ectx) {
-		ERROR("ubus connect failed\n");
-		return -1;
-	}
-
-	ubus_add_uloop(ectx);
-
-	memset(&listener, 0, sizeof(struct ubus_event_handler));
-	listener.cb = ieee1905_event_handler;
-
-	ret = ubus_register_event_handler(ectx, &listener, IEEE1905_EVENT);
-	if (0 != ret) {
-		ERROR("ieee1905 event failed(%s)!\n", ubus_strerror(ret));
-		return -1;
-	}
-
-	ret = ubus_add_object(ectx, &topo1905_object);
-	if (ret) {
-		fprintf(stderr, "Failed to add object: %s\n",
-			ubus_strerror(ret));
-
-		return -1;
-	}
-
-	if (topomap_init() == false) {
-		ERROR("Topology init failed");
-		return -1;
-	}
-
-	topology_schedule();
-	uloop_run();
-	ubus_free(ectx);
-	uloop_done();
-
-	return 0;
-}
diff --git a/src/topoubus.h b/src/topoubus.h
deleted file mode 100644
index 4c6596a..0000000
--- a/src/topoubus.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef TOPOUBUS_H
-#define TOPOUBUS_H
-
-#include <libubus.h>
-
-#define IEEE1905_EVENT "ieee1905.event"
-#define GET_TOPOLOGY_OBJECT "ieee1905"
-#define GET_TOPOLOGY "topology"
-#define TOPOLOGY_TIMEOUT 120000   // 120 sec
-
-#define MAX_RESPONSE_NUM 32
-#define TLV_NAME_LEN 128
-#define MAX_NBRS 32
-#define NAME_LEN 64
-#define MAX_MID 32
-
-int init_topology();
-int get_interface_neighbors(uint8_t *dmac);
-int get_al_mac(uint8_t *al_mac);
-
-#endif
diff --git a/src/topoutils.c b/src/topoutils.c
deleted file mode 100644
index debb893..0000000
--- a/src/topoutils.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "topoutils.h"
-
-char* _json_obj_get_string(json_object *j, const char *key)
-{
-	if(j == NULL)
-		return NULL;
-
-	json_object *t;
-	if(json_object_object_get_ex(j, key, &t)) {
-		char *str = strdup(json_object_get_string(t));
-		return(str);
-	}
-	DEBUG("|%s| not found", key);
-	return NULL;
-}
-
-int _json_obj_get_int(json_object *j, const char *key)
-{
-	int ret = 0;
-	if(j == NULL)
-		return 0;
-
-	json_object *t;
-	if(json_object_object_get_ex(j, key, &t)) {
-		ret = json_object_get_int(t);
-	}
-	return(ret);
-}
-
-void json_safe_put(json_object *j) {
-	if(j != NULL) {
-		json_object_put(j);
-	}
-	j = NULL;
-}
-
diff --git a/src/topoutils.h b/src/topoutils.h
deleted file mode 100644
index e87c0b0..0000000
--- a/src/topoutils.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef TOPOUTILS_H
-#define TOPOUTILS_H
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <json-c/json.h>
-
-#include <easy/easy.h>
-#include <stdbool.h>
-
-char* _json_obj_get_string(json_object *j, const char *key);
-int _json_obj_get_int(json_object *j, const char *key);
-void json_safe_put(json_object *j);
-void print_info(const char *format, ...);
-
-#define DEBUG_ENABLED 0
-#define DEBUG(fmt, args...) \
-do { \
-	if (DEBUG_ENABLED) \
-		syslog(LOG_DEBUG, "[%s:%d] " fmt, __func__, __LINE__, ##args); \
-} while (0)
-
-#define INFO(fmt, args...) \
-do { \
-	syslog(LOG_INFO, "[%s:%d] " fmt, __func__, __LINE__, ##args); \
-} while (0)
-
-#define ERROR(fmt, args...) \
-do { \
-	syslog(LOG_ERR, "[%s:%d] " fmt, __func__, __LINE__, ##args); \
-} while (0)
-
-#endif
-- 
GitLab