/*
 * config.h - MAP Controller configuration header file
 *
 * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
 *
 * Author: anjan.chanda@iopsys.eu
 *
 */

#ifndef CONFIG_H
#define CONFIG_H

#include <uci.h>
#include <easymesh.h>
#include <stdint.h>
#include <time.h>
#include <libubox/list.h>
#include <stdbool.h>
#include <easy/easy.h>
#include <wifidefs.h>
#include <i1905_wsc.h>

#include "wifi_dataelements.h"

struct controller;

#define CONFIG_DEFAULT_RCPI_TH_6G               86
#define CONFIG_DEFAULT_RCPI_TH_5G               86
#define CONFIG_DEFAULT_RCPI_TH_2G               70

#define CONFIG_DEFAULT_REPORT_RCPI_TH_6G	96
#define CONFIG_DEFAULT_REPORT_RCPI_TH_5G	96
#define CONFIG_DEFAULT_REPORT_RCPI_TH_2G	80

enum cred_diff {
	CONFIG_DIFF_DEBUG            = 1 << 0,
	CONFIG_DIFF_CREDENTIALS      = 1 << 1,
	CONFIG_DIFF_AGENT_POLICY     = 1 << 2,
	CONFIG_DIFF_VLAN             = 1 << 3,
	CONFIG_DIFF_AGENT_POLICY_CNT = 1 << 4,
	CONFIG_DIFF_BTM_EXCLUDE      = 1 << 5,
	CONFIG_DIFF_DISALLOWED_OPC   = 1 << 6,
#if (EASYMESH_VERSION >= 3)
	CONFIG_DIFF_QOS              = 1 << 7,
#endif
#if (EASYMESH_VERSION >= 6)
	CONFIG_DIFF_AP_MLD           = 1 << 8,
	CONFIG_DIFF_BSTA_MLD         = 1 << 9,
	CONFIG_DIFF_PUNCT_BITMAP     = 1 << 10,
#endif
};

struct stax {
	uint8_t macaddr[6];
	struct list_head list;
};

struct agent {
	uint8_t agent_id[6];     /* ':' separated mac address string */
	struct list_head list;
};

struct iface_credential {
	enum wifi_band band;
	enum wifi_security sec;
	struct wps_credential cred;
	uint16_t vlanid;
	uint8_t multi_ap;
	uint8_t disallow_bsta;
	bool enabled;
#if (EASYMESH_VERSION >= 6)
	bool hidden;
#endif
	struct list_head list;
#define VEN_IES_MAX 16
	uint8_t num_ven_ies;
	struct wsc_vendor_ie ven_ies[VEN_IES_MAX];
#if (EASYMESH_VERSION >= 6)
	uint8_t mld_id; /* set to non-zero if iface belongs to an MLD section */
#endif
};

#if (EASYMESH_VERSION >= 6)
struct mld_credential {
	uint8_t id;
	enum wifi_security sec;
	struct wps_credential cred;
	uint8_t disallow_bsta;
	uint16_t vlanid;
	uint8_t multi_ap;
	bool enabled;
	struct list_head list;

	uint8_t num_affiliated_aps;
};
#endif

enum agent_steer_policy {
	AGENT_STEER_DISALLOW,                /* agent shall not steer based on rcpi */
	AGENT_STEER_RCPI_MANDATE,            /* agent shall steer based on rcpi */
	AGENT_STEER_RCPI_ALLOW,              /* agent may steer based on rcpi */
};

enum backhaul_type {
	BK_TYPE_NONE
};

struct node_policy {
	uint8_t agent_id[6];
	uint8_t bk_ul_mac[6];
	uint8_t bk_dl_mac[6];
	enum backhaul_type type;
	uint8_t pvid;
	uint8_t pcp;
	bool report_scan;                     /* report independent scans */
	bool report_sta_assocfails;           /* report STA assoc fails */
	uint32_t report_sta_assocfails_rate;  /* reporting rate for STA assoc fails (attempts per minute) */
	uint8_t report_metric_periodic;       /* 0 = disable, else 1 - 255 in secs */
	bool steer_disallow;
	bool coordinated_cac;
	bool traffic_separation;

	int num_steer_stas;                   /* num of stas excluded from steering */
	int num_btmsteer_stas;                /* num of stas excluded from BTM steering */
	bool sta_steer;

	bool is_policy_diff;                  /* whether section changed when reloaded */

	struct list_head list;                /* attached to nodelist */
	/* custom policies follow */
	struct list_head radiolist;           /* struct radio_policy list */
	struct list_head steer_exlist;	      /* struct stax list */
	struct list_head btmsteer_exlist;     /* struct stax list */
};

struct radio_policy {
	uint8_t macaddr[6];
	uint8_t agent_id[6];
	enum wifi_band band;                  /* frequency band */
	enum agent_steer_policy policy;       /* 0, 1, 2 - see MultiAP specs */
	uint8_t util_threshold;               /* utilization as in BSS load IE */
	uint8_t rcpi_threshold;               /* 0 - 220; threshold for steering */
	uint8_t report_rcpi_threshold;        /* 0, or 1 - 220; threshold for reporting */
	uint8_t report_util_threshold;        /* 0, or channel utilization value */
	uint8_t report_rcpi_hysteresis_margin;/* 0, or > 0 - hysteresis margin */
	bool include_sta_stats;               /* sta stats in AP metric response */
	bool include_sta_metric;              /* sta metric in AP metric response */
#if (EASYMESH_VERSION > 2)
	bool include_wifi6_sta_status;        /* wifi6 sta status report in AP metric responce */
#endif
	struct wifi_radio_opclass dis_opclass;/* disallow opclass */
	struct list_head list;                /* link to next policy */

	/** variables placed after list are excluded from policy config comparison **/
#if (EASYMESH_VERSION >= 6)
	uint8_t punct_bitmap[2];	      /* wifi7 puncture pattern bitmap */
#endif
};

enum {
	STEER_PLUGIN_POLICY_OR = 0,           /* steer when any OK */
	STEER_PLUGIN_POLICY_AND = 1,          /* steer when all OK */
};

/* STA steering config options as described in 'STA Steering TLV'.
 * Each (steering) plugin may bring it's own config.
 */
struct steer_policy {
	bool enable_sta_steer;
	bool enable_bsta_steer;
	bool use_usta_metrics;
	uint8_t rcpi_threshold_2g;            /* 0 - 220 */
	uint8_t rcpi_threshold_5g;            /* 0 - 220 */
	uint8_t rcpi_threshold_6g;            /* 0 - 220 */
	uint8_t report_rcpi_threshold_2g;     /* 0, or 1 - 220 */
	uint8_t report_rcpi_threshold_5g;     /* 0, or 1 - 220 */
	uint8_t report_rcpi_threshold_6g;     /* 0, or 1 - 220 */

	bool plugin_enabled;                  /* steer plugins enabled */
	uint8_t plugin_policy;                /* STEER_PLUGIN_POLICY_* */
};

struct cntlr_plugin_name {
	char name[32];
	struct list_head list;
};

#if (EASYMESH_VERSION > 2)
enum qos_rule_type {
	QOS_RULE_TYPE_DSCP_PCP,
	QOS_RULE_TYPE_MSCS,
	QOS_RULE_TYPE_SCS,
	QOS_RULE_TYPE_MGMT,
};

/* Main QoS rule container */
struct qos_rule {
	uint32_t id; /**< Rule Identifier. */
	uint8_t precedence; /**< Rule Precedence. */
	uint8_t output;     /**< The value of, or method used to select, the
	                         802.1Q C-TAG PCP output value.
	                         See WiFi Mesh specification 17.2.70. */
	bool always_match;  /**< Rule Always Matches.
	                         See WiFi Mesh specification 17.2.70. */

	enum qos_rule_type type;/**< Real rule type */
	union {
		struct tlv_dscp_pcp dscp_pcp;
		struct {
			uint16_t qmid;
			uint8_t bssid[6];
			uint8_t sta[6];
			union {
				struct mscs_desc_usr mscs;
				struct scs_desc_usr scs;
				struct qos_mgmt_attr_usr qm;
			};
		} mgmt;
	};

	struct list_head list;  /**< List head (must be last so list_memcmp() compares all fields) */
};

struct qos_mgmt_policy_elem {
	struct list_head list;
	uint8_t mac[6];
};

struct qos_mgmt_policy {
	struct list_head mscs_disallowed; /* struct qos_mgmt_policy_elem list */
	struct list_head scs_disallowed; /* struct qos_mgmt_policy_elem list */
	int mscs_num;
	int scs_num;
};

struct qos_control_config {
	bool enabled;
	struct list_head rule; /* struct qos_rule list */
	struct qos_mgmt_policy policy;
};

#endif

#if (EASYMESH_VERSION > 2)
struct dpp_controller_cfg {
	char ifname[16];
	enum wifi_band band;
	char device[16];
	uint16_t port;
	struct list_head list;
};
#endif

struct wsc_metadata {
	char manufacturer[65];          /* with terminating '\0' */
	char model_name[33];
	char device_name[33];
	char model_number[33];
	char serial_number[33];
	uint8_t device_type[8];         /* <category>0050F204<subcategory> */
};

struct controller_config {
	bool enabled;
	bool update_config;       /* true if writeback to config is pending */
	uint8_t id[6];            /* 1905 AL-macaddress of this Controller */
	uint8_t network_id[16];   /* UUID of the Multi-AP network */
	bool has_registrar_6g;
	bool has_registrar_5g;
	bool has_registrar_2g;
	int debug_level;
	uint32_t log_features;
	int resend_num;
#define BCN_METRICS_MAX_NUM 10
	int bcn_metrics_max_num;  /* max num of metrics stored per STA */
	int num_bss;
	int num_apolicy;
	bool acs;
	int acs_timeout;
	bool acs_skip_dfs;
	bool acs_prevent_cac;
	bool acs_highest_bandwidth;
	bool acs_scan_before_recalc;
	bool dfs_cleanup;
#define MAX_STALE_STA_TIMEOUT (30 * 86400) /* max timeout can now be 30 days */
#define ULOOP_MAX_TIMEOUT (24 * 86400) /* uloop max timeout is 24days due to int32 limit */
	int stale_sta_timeout;
	unsigned int primary_vid;
	unsigned int default_pcp;
	int map_profile;
	bool enable_ts;
	unsigned int max_node_bh_hops;
#if (EASYMESH_VERSION > 2)
	char *dpp_uri_file;
#endif
#if (EASYMESH_VERSION >= 6)
	int num_mlds;
#endif
	struct list_head nodelist;      /* struct node_policy list */
	struct list_head aplist;        /* struct iface_credential list */
	struct list_head radiolist;     /* struct radio_policy list */
	struct steer_policy steer;	/* global STA steering config */
	struct list_head steerplugins;  /* struct cntlr_plugin_name list */	//TODO: remove
	struct list_head btmsteer_exlist;     /* controller BTM exclusion list - struct stax list */
	int num_btmsteer_excl_stas;

	bool plugin_enabled;            /* steer plugins enabled */
	struct list_head plugins;       /* struct cntlr_plugin_name list */
#if (EASYMESH_VERSION >= 6)
	struct list_head mldlist;	    /* struct mld_credential list */
#endif
#if (EASYMESH_VERSION > 2)
	struct list_head dpp_cntlrlist; /* struct dpp_controller_cfg list */
	struct qos_control_config qos;
#endif
	struct wsc_metadata wscdev;
	struct timespec	last_change;		/* timestamp of most recent config change */
#if (EASYMESH_VERSION >= 6)
	struct timespec	last_apmld_change;	/* timestamp of most recent apmld config change */
	struct timespec	last_bstamld_change;	/* timestamp of most recent bstamld config change */
#endif
};

struct node_policy *cntlr_get_node_policy(struct controller_config *cfg, uint8_t *agent);
struct radio_policy *cntlr_get_radio_policy(struct controller_config *cfg, uint8_t *radio_mac);

struct dpp_controller_cfg *get_dpp_controller_by_band(struct controller_config *c,
		enum wifi_band band);

int set_value_by_string(const char *package, const char *section,
		const char *key, const char *value, enum uci_option_type type);
int cntlr_config_add_node(struct controller_config *c, char *al_mac);
int cntlr_config_add_node_radio(struct controller_config *c, uint8_t *alid,
				uint8_t *ruid, enum wifi_band band);
bool uci_set_option(char *package_name, char *section_type,
		char *search_key, char *search_val,
		char *option, char *value);

uint32_t cntlr_config_reload(struct controller_config *cfg);
int cntlr_config_defaults(struct controller *c, struct controller_config *cfg);
void cntlr_config_dump(struct controller_config *cfg);
int cntlr_config_clean(struct controller_config *cfg);

bool is_sta_in_controller_btm_exclude(struct controller *c, uint8_t *sta_mac);
int cntlr_config_del_node(uint8_t *almacaddr);
int cntlr_config_del_radio(uint8_t *almacaddr);

#if (EASYMESH_VERSION > 2)
/* QoS functions */
int clean_qos_rule_list(struct list_head *rule_list);
int clean_qos_policy_list(struct list_head *rule_list);

uint32_t cntlr_qos_diff(struct controller_config *cfg,
                       struct controller_config *prev);

uint32_t cntlr_qos_rule_diff(struct controller_config *cfg,
                            struct controller_config *prev);
uint32_t cntlr_qos_mgmt_policy_diff(struct controller_config *cfg,
                                   struct controller_config *prev,
                                   bool mscs);
int cntlr_config_get_qos(struct controller_config *cc,
                         struct uci_section *s);
#endif

#if (EASYMESH_VERSION >= 6)
struct mld_credential *cntlr_config_get_mld_by_id(struct controller_config *cfg,
						  uint8_t id);
#endif

#endif
