/*
 * steer_module.h - header for defining a new steering module
 *
 * Copyright (C) 2025 IOPSYS Software Solutions AB. All rights reserved.
 *
 * Author: anjan.chanda@iopsys.eu
 *
 * See LICENSE file for license related information.
 *
 */

#ifndef STEER_MODULE_H
#define STEER_MODULE_H

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

struct cmdu_buff;

#ifdef __cplusplus
extern "C" {
#endif

#define DEFAULT_MAX_STEER_ATTEMPT	-1	// no limit to steer attempts

enum steer_verdict {
	STEER_VERDICT_UNDECIDED,
	STEER_VERDICT_OK,	/* steer STA */
	STEER_VERDICT_MAYBE,	/* Gray zone.. Use other methods to decide */
	STEER_VERDICT_NOK,	/* do not steer STA */
	STEER_VERDICT_EXCLUDE,	/* exclude the STA from subsequent steering */
};

/* MBO Transition Reason Code values from Wi-Fi Agile Multiband Specification Table 18 */
enum steer_reason {
	STEER_REASON_UNDEFINED = 0, /* MBO steer unspecified */
	STEER_REASON_LOW_RCPI  = 5, /* MBO steer low rssi */
	STEER_REASON_LOW_THPUT = 3, /* MBO steer insufficient bandwidth */
	STEER_REASON_HIGH_PER  = 7, /* MBO steer high interference */
	STEER_REASON_OTHER,

};

enum steer_mode {
	STEER_MODE_UNDEFINED,
	STEER_MODE_BTM_REQ,
	STEER_MODE_ASSOC_CTL,
	STEER_MODE_OPPORTUNITY,
};

enum steer_result {
	STEER_RESULT_SUCCESS,
	STEER_RESULT_FAIL_RSP,       /* got BTM response frame with result != 0 */
	STEER_RESULT_FAIL_TIMEOUT,   /* no BTM response recvd within specified time */
	STEER_RESULT_FAIL_ASOC_CTRL, /* tried to assoc control an associated STA */
};

typedef enum steer_verdict steer_verdict_t;
typedef enum steer_reason steer_reason_t;
typedef enum steer_mode steer_mode_t;


/* Represent a fBSS neighbor in the network */
struct steer_sta_target_bss {
	uint8_t bssid[6];
	uint8_t ruid[6];
	uint8_t opclass;	/* operating opclass */
	uint8_t channel;	/* beacon channel (20MHz) */
	uint8_t agent[6];	/* agent AL-macaddress this bss belongs to */
	uint8_t ul_rcpi;        /* STA's rcpi in UL directiion */
	uint8_t dl_rcpi;        /* STA's rcpi in DL direction */
	struct list_head list;
};

/* Represents current BSS to which the STA is connected */
struct steer_sta_current_bss {
	uint8_t bssid[6];
	uint8_t opclass;	/* operating opclass */
	uint8_t channel;	/* beacon channel (20MHz) */
	uint8_t agent[6];	/* agent AL-macaddress this bss belongs to */
	uint8_t ssidlen;
	uint8_t ssid[33];
	uint8_t connected;

	/* following are filled-in from radio-policy of the agent node */
	uint8_t rcpi_threshold;
	uint8_t report_rcpi_threshold;
	uint8_t report_rcpi_hysteresis_margin;
	uint8_t util_threshold;
	uint8_t report_util_threshold;
};

#define MAX_NUM_NBRS	24

/* Steering candiate */
struct steer_sta {
	uint8_t macaddr[6];
	struct steer_sta_current_bss bss;
	struct steer_sta_target_bss target;
	uint8_t num_nbr;
	struct steer_sta_target_bss nbrlist[MAX_NUM_NBRS];
	struct list_head *meas_reportlist;          /* list of struct wifi_sta_meas_report */
	struct list_head *unassoc_metriclist;       /* list of struct wifi_sta_unassoc_metrics */

	steer_verdict_t verdict;
	steer_reason_t reason;
};

/* STA steer plugin */
struct steer_control {
	char name[32];		/* name of the steer plugin */
	void *priv;		/* private context of the steer plugin */
	bool enabled;

	/* callbacks from controller */
	int (*init)(void **priv);
	int (*exit)(void *priv);
	int (*steer)(void *priv, struct steer_sta *candidate, uint16_t rxcmdu_type);
	int (*config)(void *priv, void *cfg);
	int (*cmdu_notifier)(void *priv, struct cmdu_buff *cmdu);

	void *handle;		/* points to dlopen()'d plugin object */
	void *controller;	/* controller context */

	/* received CMDUs that the plugin wants to be notified of */
	int num_cmdu;
	uint16_t *cmdulist;	/* array of cmdu types */

	struct list_head list;
};

#ifdef __cplusplus
}
#endif

int cntlr_configure_steer_module(struct steer_control *sc, void *cfg);
int cntlr_maybe_steer_sta(struct steer_control *sc, struct steer_sta *s, uint16_t rxcmdu_type);
int cntlr_notify_steer_module(struct steer_control *sc, struct cmdu_buff *cmdu);

#endif /* STEER_MODULE_H */
