/*
 * decollector.h
 * WiFi DataElements Collector private header file.
 *
 * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
 *
 * Author: anjan.chanda@iopsys.eu
 *
 * See LICENSE file for license related information.
 *
 */

#ifndef DECOLLECTOR_H
#define DECOLLECTOR_H

#include "timer.h"
#include "wifi_dataelements.h"

#include <cmdu.h>

#include <libubus.h>
#include <libubox/list.h>
#include <stdint.h>


struct decollector_useropts {
	const char *ubus_sockpath;
	const char *pidfile;
	const char *objname;
	bool daemonize;
	int debug_level;
	const char *logfile;
	bool logfile_isfifo;
	bool syslogging;
	uint32_t refresh_int;	/* automatic refresh interval in seconds */
	uint32_t em_profile;	/* EasyMesh profile */
	char mapcontroller_conffile[256];
};

/* default options */
#define DECOLLECTOR_REFRESH_INT	30  /* seconds */
#define DECOLLECTOR_PIDFILE	"/var/run/decollector.pid"

#define NUM_EVENTS_MAX		500
#define AGE_EVENTS_MAX		86400 * 2	/* in seconds */

#define WIFI_DEVICE_MAX_NUM	16

enum {
	WIFI_IFACE_FH,
	WIFI_IFACE_BK,
};

typedef uint32_t object_t;

#define OBJECT_INVALID 0

#define IEEE1905_OBJECT			"ieee1905"
#define MAP_PLUGIN_OBJECT		"ieee1905.map"
#define WIFI_DATAELEMENTS_OBJECT	"wifi.dataelements"
#define MAP_CONTROLLER_OBJECT		"map.controller"

struct wifi_assoc_frame {
	uint16_t len;
	uint8_t macaddr[6];
	uint8_t *frame;
	struct list_head list;
};

struct decollector_config {
	uint32_t refresh_int;
	bool is_collector;
	uint32_t profile;
	struct ubus_context *uctx;
	char mapcontroller_conffile[256];
};

#define DELM_OBJECT_PLACEHOLDER			\
	struct ubus_context *ctx;		\
	struct ubus_object obj;			\
	struct ubus_event_handler ubus_obj_ev;

enum collection_state {
	CT_IDLE = 0,
	CT_RUNNING,
	CT_DONE,
};

#define DECOLLECTOR_COLLECTION_EPOCH	10000	/* collection cycle <= 10s */

struct decollector_private {
	struct decollector_useropts opts;
	uint32_t event_maxnum;		/* max events stored per event-type per wifi_network_device */
	uint32_t event_maxage;		/* how long to keep events per event-type per wifi_network_device */
	uint64_t refresh_cnt;
	time_t refresh_time;
	uint64_t ticks;
	atimer_t hbt;			/* heartbeat timer */
	atimer_t t;			/* auto refresh timer */
	atimer_t ct;			/* collection duration timer */
	uint8_t cstate;			/* collector state */
	uint8_t cntlr_id[6];		/* controller id */
	bool dm_available;
	struct wifi_data_element *dm;
	int pending;
	object_t i1905;			/* i1905 UBUS object */
	object_t i1905_map;		/* i1905.map UBUS object */
	uint8_t ieee1905_macaddr[6];	/* self node macaddr */
	void *subscriber;
	DELM_OBJECT_PLACEHOLDER
};

struct assoc_req_body {
	uint16_t capab_info;
	uint16_t listen_interval;
	uint8_t variable[];
} __attribute__ ((packed));

#define CMDU_TYPE_INVALID	-1


void decollector_start_collection(void *arg);

int decollector_publish_object(struct decollector_private *p, const char *objname);
int decollector_register_events(struct decollector_private *p);
int decollector_subscribe_for_cmdus(struct decollector_private *priv);
uint32_t decollector_lookup_object(struct decollector_private *p, const char *objname);
int decollector_wait_for_object_timeout(struct decollector_private *p,
		const char *objname, int tmo_msecs, object_t *res);

bool is_network_device_alive(struct wifi_network_device *dev);
bool is_network_device_agent(struct wifi_network_device *dev);
struct wifi_network_device *find_network_device(struct wifi_data_element *dm, uint8_t *alid);
struct wifi_radio_element *find_radio(const struct wifi_network_device *dev,
		const uint8_t *macaddr);

struct wifi_assoc_event *find_assoc_event(struct list_head *evlist, uint8_t *sta_macaddr, uint8_t *bssid);
struct wifi_disassoc_event *find_dissassoc_event(struct list_head *evlist, uint8_t *sta_macaddr, uint8_t *bssid);

int decollector_dump_all(struct decollector_private *p, struct blob_buf *bb);
int decollector_dump2_all(struct decollector_private *p, struct blob_buf *bb);
int decollector_event_dump(struct decollector_private *p, struct blob_buf *bb);
int decollector_notify_events(struct decollector_private *p, struct wifi_network_device *dev);
int decollector_collect_node(struct decollector_private *p, struct wifi_network_device *dev);
struct wifi_network_device *decollector_get_origin_dev(
		struct decollector_private *p, struct wifi_data_element *dm,
		uint8_t *origin);

int decollector_send_cmdu_request(struct decollector_private *priv,
					 struct cmdu_buff *req, uint8_t *dst);

int decollector_get_deagents(struct decollector_private *p, int *num, uint8_t **macaddrs);
int decollector_get_ieee1905id(struct decollector_private *p);
int decollector_get_local_ifaces(struct decollector_private *p, void *ifaces, int max_ifaces);
int decollector_get_network_steer_stats(struct decollector_private *p);
int decollector_get_sta_steer_stats(struct decollector_private *p);
int decollector_get_policy_config(struct decollector_private *p);
int decollector_get_dpp_uri(struct decollector_private *p);
int decollector_get_sta_blocks(struct decollector_private *p);


int decollector_alloc_deagents(struct decollector_private *priv);
void decollector_getter_run(void *data);
void decollector_getter_run_init(struct decollector_private *p);
void decollector_refresh_all(struct decollector_private *priv);

void decollector_free_dm(struct wifi_data_element *dm);
void free_network_device(struct wifi_network_device *dev);
void free_sta(struct wifi_sta_element *sta);
void free_bss(struct wifi_bss_element *bss);
void free_radio(struct wifi_radio_element *r);
void free_apmld(struct wifi_apmld_element *apmld);
void free_apmldlist(struct wifi_network_device *dev);
void free_stamld(struct wifi_stamld_element *stamld);
void free_bstamld(struct wifi_network_device *dev);
void free_scanresults(struct wifi_scanres_element *scanres);
void free_anticipated_ch_usagelist(struct wifi_network_device *dev);
void free_wifi_cac_status(struct wifi_cac_status *cac_status);
void free_sta_meas_reportlist(struct wifi_sta_element *sta);
void clear_supported_opclasses(struct wifi_radio_element *radio);
void clear_current_opclasses(struct wifi_radio_element *radio);
void clear_preference_opclasses(struct wifi_radio_element *radio);

struct wifi_sta_element *alloc_sta(uint8_t *macaddr);
struct wifi_stamld_element *alloc_stamld(uint8_t *macaddr);
struct wifi_bss_element *alloc_bss(uint8_t *bssid);
struct wifi_radio_element *alloc_radio(uint8_t *ruid);

int prepare_autoconfig_search(struct decollector_private *priv, uint8_t band);


int decollector_alloc_getter(struct decollector_private *p, struct wifi_network_device *dev);
int decollector_free_getters(struct decollector_private *p);
int decollector_free_getter(struct wifi_network_device *dev);
int decollector_sched_getter(struct decollector_private *p,
				    struct wifi_network_device *dev,
				    uint32_t after_ms);


void decollector_stop_collection(struct decollector_private *priv);

int decollector_stop_getter(struct decollector_private *p, struct wifi_network_device *dev);
int decollector_reset_getter(struct decollector_private *p, struct wifi_network_device *dev);
void decollector_stop_getter_all(struct decollector_private *p);
int decollector_getter_running(struct decollector_private *p, struct wifi_network_device *dev);

int decollector_getter_get_state(struct decollector_private *p,
		struct wifi_network_device *dev, uint8_t *state);
int decollector_getter_set_state(struct decollector_private *p,
		struct wifi_network_device *dev, uint8_t state);

int prepare_1905_query(struct decollector_private *priv, uint16_t cmdu_type,
				struct wifi_network_device *dev, uint8_t *dst);

#endif /* DECOLLECTOR_H */
