// SPDX-License-Identifier: BSD-3-Clause
/*
 * i1905_extension.h
 * IEEE-1905 extension modules definitions and functions.
 *
 * Copyright (C) 2021-2024 IOPSYS Software Solutions AB. All rights reserved.
 * Copyright (C) 2025 Genexis AB.
 *
 * Author: anjan.chanda@iopsys.eu
 */

#ifndef I1905_EXTENSION_H
#define I1905_EXTENSION_H


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

#ifdef __cplusplus
extern "C" {
#endif


enum cmdu_extension_policy {
	EXTMODULE_CMDU_NOP,		/* don't extend; default behavior */
	EXTMODULE_CMDU_EXTEND,		/* extend with new/changed tlvs */
	EXTMODULE_CMDU_OVERRIDE,	/* full override by extension */
};

struct i1905_cmdu_extension {
	uint16_t type;
	enum cmdu_extension_policy policy;
};

struct i1905_context {
	void *bus;
	void *context;
};

typedef int (*extmodule_init_t)(void **priv, struct i1905_context *ieee1905);
typedef int (*extmodule_exit_t)(void *priv);
typedef int (*extmodule_func_t)(void *priv);

typedef enum cmdu_process_result {
	CMDU_NOP = -2,	/* not processed */
	CMDU_NOK = -1,	/* not OK */
	CMDU_OK,
	CMDU_DONE,	/* done processing */
	CMDU_DROP,	/* discard */
	CMDU_SKIP,
	CMDU_RELAY,	/* relay multicast */
} cmdu_res_t;


struct i1905_extmodule {
	char name[128];
	uint8_t id[16];
	uint32_t paused;
	void *priv;
	extmodule_init_t init;
	extmodule_exit_t exit;
	extmodule_func_t start;
	extmodule_func_t stop;
	struct i1905_cmdu_extension *ext;
	int num_ext;
	uint16_t from_newtype;
	uint16_t to_newtype;
	cmdu_res_t (*process_cmdu)(void *priv, struct cmdu_buff *rxf);
	int (*event_cb)(void *priv, const char *event, size_t len);
	void *handle;
	struct list_head list;
};

struct i1905_non1905_ifneighbor {
	uint8_t if_macaddr[6];		/* interface macaddress */
	uint32_t num_non1905;
	uint8_t non1905_macaddr[];	/* packed array of 6-byte macaddresses */
} __attribute__ ((packed));

/** Get all non-1905 neighbors of this device.
 *
 * @param[in] ieee1905 1905-context received by extension during registration.
 * @param[out] buf output buffer returning packed array of 'struct i1905_non1905_ifneighbor'.
 * @param[out] sz size of output buffer.
 * @return 0 on success, -1 on error.
 */
int ieee1905_get_non1905_neighbors(void *ieee1905, void *buf, size_t *sz);

/* struct i1905_ifneighbor represents connection between local and a remote 1905 device */
struct i1905_ifneighbor {
	uint8_t if_macaddr[6];		/* interface macaddress */
	uint32_t num_links;
	struct i1905_ifneighbor_link {
		uint8_t macaddr[6];	/* interface macaddress of remote 1905 device */
		uint8_t aladdr[6];	/* AL-address of remote 1905 device */
		bool direct;		/* true when remote 1905 device is one hop away */
		uint32_t media;		/* one of 'enum i1905_mediatype' */
	} __attribute__ ((packed)) link[];
} __attribute__ ((packed));

#define MAX_NUM_MEDIAINFO	4

struct i1905_local_interface {
	uint8_t if_macaddr[6];
	uint16_t mediatype;	/* One of the MEDIA_TYPE_* values */
	uint8_t mediainfo[64];	/* array of ieee80211_info, ieee1901_info etc. */
};

int ieee1905_get_local_interfaces(void *ieee1905, void *buf, size_t *sz);

struct i1905_interface_ipaddress {
	uint8_t if_macaddr[6];
	size_t num;		/* number of struct ip_address entries following */
	struct ip_address addr[];
} __attribute__ ((packed));

int ieee1905_get_interface_ipaddrs(void *ieee1905, void *buf, size_t *sz);

struct i1905_brtuple {
	size_t num;
	uint8_t macaddrs[];
} __attribute__ ((packed));

int ieee1905_get_bridge_tuples(void *ieee1905, void *buf, size_t *sz);

struct i1905_device_ident {
	uint8_t aladdr[6];		/**< 1905 AL address */
	uint8_t regband;		/**< bitmap of IEEE80211_FREQUENCY_BAND_* */
	uint32_t version;		/**< 1905 profile version */
	char name[65];			/**< friendly device name */
	char manufacturer[65];		/**< manufacturer name */
	char model[65];			/**< model name */
	char url[256];			/**< control url of the device */
};

int ieee1905_get_selfdevice_misc_info(void *ieee1905, void *buf, size_t *sz);

struct i1905_dev_interface {
	uint8_t if_macaddr[6];
	uint16_t mediatype;	/* One of the MEDIA_TYPE_* values */
	uint8_t mediainfo[32];	/* ieee80211_info, ieee1901_info etc. */
};

struct i1905_neighbor_device {
	uint8_t aladdr[6];
	uint32_t version;
	char name[65];			/**< friendly device name */
	char manufacturer[65];		/**< manufacturer name */
	char model[65];			/**< model name */
	char url[256];			/**< control url of the device */
	uint32_t num_interface;		/**< number of 1905 interfaces */
	uint32_t num_ipv4;		/**< number of IPv4 addresses this device has */
	uint32_t num_ipv6;		/**< number of IPv6 addresses this device has */
	uint8_t data[];
} __attribute__ ((packed));

int ieee1905_get_neighbor_info(void *ieee1905, uint8_t *aladdr, void *buf, size_t *sz);

/** Get links to all reachable 1905 devices in the network.
 *
 * @param[in] ieee1905 1905-context received by extension during registration
 * @param[out] buf output buffer returning the links as array of 'struct i1905_ifneighbor'.
 * @param[out] sz size of output buffer.
 * @return 0 on success, -1 on error.
 */
int ieee1905_get_links(void *ieee1905, void *buf, size_t *sz);

int ieee1905_send_cmdu(void *ieee1905, uint8_t *dst, uint8_t *src, uint16_t type,
		       uint16_t *mid, uint8_t *data, int len);

int ieee1905_get_alid(void *ieee1905, uint8_t *aladdr);


#ifdef __cplusplus
}
#endif

#endif /* I1905_EXTENSION_H */
