/*
 * sta.h - STA management header file
 *
 * Copyright (C) 2020-2024 IOPSYS Software Solutions AB.
 *
 * See LICENSE file for source code license information.
 *
 */

#ifndef STA_H
#define STA_H

#include <stdint.h>
#include <time.h>
#include <easy/easy.h>
#include <stdbool.h>

#include "timer_impl.h"

#ifndef MAC_ADDR_HASH
#define MAC_ADDR_HASH(a)    (a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5])
#endif

#define STA_HASHTABLE_SIZE	256
#define sta_hash(o)		(MAC_ADDR_HASH(o) & (STA_HASHTABLE_SIZE - 1))

enum rm_caps {
	RM_CAP_NBR_REPORT  = 1 << 0,
	RM_CAP_BCN_ACTIVE  = 1 << 1,
	RM_CAP_BCN_PASSIVE = 1 << 2,
	RM_CAP_BCN_TABLE   = 1 << 3,
};

/* STA states */
enum sta_state {
	STA_ASSOCIATED,		/* associated */
	STA_CONNECTED,		/* authorized */
	STA_LOWRCPI,		/* low RCPI */
	STA_STEERING,		/* steer check ongoing */
	STA_STEERED,		/* successfully steered */
	STA_UNKNOWN,		/* no response to steer-request */
	STA_DISCONNECTED,	/* disconnected */
};

/* represents a STA or bSTA */
struct sta {
	uint8_t macaddr[6];
	uint8_t bssid[6];
	uint8_t ssidlen;
	uint8_t ssid[33];
	bool is_bsta;
	enum sta_state state;

	time_t assoc_time;
	time_t disassoc_time;
	uint16_t disassoc_reason;
	atimer_t ageout_timer;
	uint8_t nref;	/* num of nodes STA is associated to */

	struct wifi_sta_element *de_sta;

	uint8_t agent_almacaddr[6];       /* Agent to which this sta is connected to */
	uint8_t bsta_agent_almacaddr[6];  /* Agent hosting this sta when it is bSTA */

	bool bcn_response_tmo;
	atimer_t bcn_metrics_timer;
	struct timespec last_bcn_metrics_query;
	int bcn_report_wait_time;	/* in seconds */
	int latest_assoc_cntrl_mid;

#define BTM_RESP_EXP_TIMEOUT 5
	atimer_t btm_req_timer;

	time_t lookup_time;

	struct steer_sta *steer_data;

	/* Cached WiFi capabilities from association frame */
	struct {
		bool valid;
		uint8_t rm_caps;
		bool btm_support;
		bool mbo_ie_cdc_attr;
		bool multiband;
		bool agile_multiband;
	} sta_caps;

	void *cntlr;
	struct hlist_node hlist;	/* link in sta_table */
	struct list_head list;		/* link in node */
};

struct sta *cntlr_find_sta(struct hlist_head *table, uint8_t *macaddr);
struct sta *cntlr_add_sta(void *cntlr, struct hlist_head *table, uint8_t *macaddr);
void cntlr_free_sta(struct sta *s);
void cntlr_del_sta_hash(struct hlist_head *table, uint8_t *macaddr);
void cntlr_del_sta(struct hlist_head *table, struct sta *del);

int sta_link_metrics_process(struct sta *s);
void sta_free_bcn_metrics(struct sta *s);
void sta_free_usta_metrics(struct sta *s);
void sta_free_assoc_frame(struct sta *s);

void sta_update_capabilities(struct sta *s);
bool sta_is_agile_multiband(struct sta *s);

int sta_inc_ref(struct sta *s);
int sta_dec_ref(struct sta *s);
#endif /* STA_H */
