/*
 * node.c - hosts housing possible multiple network interfaces, viz. 1905
 * device, router, repeater etc.
 *
 * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
 *
 * See LICENSE file for license related information.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <arpa/inet.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 <easy/easy.h>

#include "util.h"
#include "debug.h"
#include "timer.h"
#include "neigh.h"
#include "hostmngr.h"


void ageout_node_cb(atimer_t *t)
{
	struct node *n = container_of(t, struct node, ageout);

	n->invalid = true;
}

struct node *alloc_node(uint8_t *macaddr)
{
	struct node *n = calloc(1, sizeof(*n));

	if (!n) {
		dbg("%s: -ENOMEM\n", __func__);
		return NULL;
	}

	memcpy(n->macaddr, macaddr, 6);
	INIT_LIST_HEAD(&n->iflist);
	INIT_LIST_HEAD(&n->ipv4list);
	INIT_LIST_HEAD(&n->ipv6list);
	INIT_LIST_HEAD(&n->brlist);
	INIT_LIST_HEAD(&n->nbrlist);
	INIT_LIST_HEAD(&n->n1905nbrlist);
	INIT_LIST_HEAD(&n->l2devlist);
	INIT_LIST_HEAD(&n->linklist);
	time(&n->last_updated);
	timer_init(&n->ageout, ageout_node_cb);

	return n;
}

void free_node(struct node *n)
{
	if (n) {
		timer_del(&n->ageout);

		list_del(&n->list);

		list_flush(&n->linklist, struct node_link, list);
		list_flush(&n->nbrlist, struct node_neighbor, list);
		list_flush(&n->n1905nbrlist, struct non1905_neighbor, list);
		//list_flush(&n->l2devlist, struct l2device, list);
		//list_flush(&n->brlist, struct node_brtuple, list);
		list_flush(&n->ipv4list, struct node_ipv4, list);
		list_flush(&n->ipv6list, struct node_ipv6, list);
		list_flush(&n->iflist, struct node_interface, list);

		free(n);
	}
}

int add_node(struct hostmngr_private *priv, struct list_head *list,
	     uint8_t *macaddr, bool is1905)
{
	struct node *n;

	n = alloc_node(macaddr);
	if (!n)
		return -1;

	n->is1905 = is1905;

	if (list)
		list_add_tail(&n->list, list);

	return 0;
}

int del_node(struct hostmngr_private *priv, struct list_head *plist,
	     uint8_t *macaddr)
{
	struct node *n = NULL, *tmp;

	list_for_each_entry_safe(n, tmp, plist, list) {
		if (!memcmp(n->macaddr, macaddr, 6)) {
			free_node(n);
			return 0;
		}
	}

	return -1;
}

struct node *lookup_node(struct hostmngr_private *priv, struct list_head *list,
			 uint8_t *macaddr)
{
	struct node *n = NULL;

	list_for_each_entry(n, list, list) {
		if (!memcmp(n->macaddr, macaddr, 6)) {
			return n;
		}
	}

	return NULL;
}
