// SPDX-License-Identifier: BSD-3-Clause
/*
 * i1905.h - header file for ieee1905d daemon.
 *
 * Copyright (C) 2021-2024 IOPSYS Software Solutions AB. All rights reserved.
 * Copyright (C) 2025 Genexis AB.
 *
 * Author: anjan.chanda@iopsys.eu
 */

#ifndef I1905_H
#define I1905_H


#include "neigh.h"
#include "i1905_wsc.h"

#ifdef HAS_UBUS
#include <libubus.h>
#endif

#define OBJECT_INVALID ((uint32_t)-1)

#define IEEE1905_NBR_REMOVED		0x1
#define IEEE1905_NBR_ADDED		0x2
#define IEEE1905_LINK_ADDED		0x4
#define IEEE1905_LINK_REMOVED		0x8
#define IEEE1905_TOPOLOGY_CHANGED	0x10

struct i1905_private {
	struct i1905_useropts uopts;
	struct i1905_config cfg;
	atimer_t hbtimer;
	atimer_t topotimer;
	atimer_t refreshtimer;
	struct list_head extlist;
	struct list_head iflist;
	struct i1905_dm dm;
	struct cmdu_ackq txack_q;
	struct neigh_queue neigh_q;

	/* XXX: */
	int al_ifindex;
	char al_ifname[16];

	bool paused;
	int start_apconfig;

	int cmdsock;
	char *cmdpath;
	struct uloop_fd cmdloop;

#ifdef HAS_UBUS
	struct ubus_context *ctx;
	struct ubus_object obj;
	struct ubus_event_handler evh;
	struct ubus_object objext;
#endif
};


struct i1905_interface_private {
	int sock_1905;
	int sock_lldp;
	uint32_t flags;
	struct uloop_fd uloop_1905;
	struct uloop_fd uloop_lldp;
	struct cmdufrag_queue rxfrag_queue;
	void *i1905private;

	bool registrar;
	bool configured;

#define I1905_MID_LOOKBACK_MAX	4
	uint16_t lastmid[I1905_MID_LOOKBACK_MAX];
	int lastmid_idx;
	struct i1905_interface_private_wsc *wsc;

	void *iface;	/* points to i1905_interface */
#ifdef HAS_UBUS
	struct ubus_object obj;
	struct ubus_object_type obj_type;
#endif
};

static inline void *i1905_interface_priv(struct i1905_interface_private *p)
{
	return p->iface;
}

struct i1905_private *i1905_selfdevice_to_context(struct i1905_selfdevice *dev);

int i1905_init(void **priv, void *user_opts);
int i1905_exit(void *priv);
void i1905_run(void *priv);
int i1905_start();
int i1905_stop(struct i1905_private *p);

int i1905_start_cmdserver(struct i1905_private *priv, struct i1905_useropts *u);
void i1905_stop_cmdserver(struct i1905_private *priv);

int i1905_get_known_neighbors(struct i1905_private *priv, char *ifname);


int i1905_register_nlevents(struct i1905_private *priv);
void i1905_unregister_nlevents(struct i1905_private *priv);

bool i1905_has_registrar(void *priv, uint8_t freqband);
bool i1905_is_registrar(void *priv);

int i1905_enumerate_local_interfaces(struct i1905_private *priv);
int i1905_handle_iflink_change(struct i1905_private *priv, const char *ifname);

#if 0
int i1905_handle_if_newlink(struct i1905_private *priv, const char *ifname,
			    bool is_brif, int br_ifindex);

int i1905_handle_if_dellink(struct i1905_private *priv, const char *ifname);
#endif

int i1905_init_apsettings_for_band(void *priv, uint8_t band,
				   struct wps_credential *ap);

int i1905_get_apsettings_for_band(void *priv, uint8_t band,
				  struct wps_credential *cred);

int i1905_apconfig_request(void *priv, uint8_t band);
int i1905_apconfig_renew(void *priv, uint8_t band);

bool i1905_lookup_interface_in_config(struct i1905_private *priv, char *ifname);
char *i1905_brport_to_ifname(struct i1905_private *priv, uint16_t port);

struct i1905_interface *i1905_ifname_to_interface(struct i1905_private *priv,
						  const char *ifname);


struct i1905_interface *i1905_setup_interface(struct i1905_private *priv,
					      const char *ifname);
void i1905_teardown_interface(struct i1905_private *priv, const char *ifname);

int i1905_rebind_interface(const struct i1905_private *priv, struct i1905_interface *iface);

void i1905_print_interfaces(struct i1905_private *priv);

int i1905_get_fragment_scheme(struct i1905_private *priv, uint8_t *dst);
int i1905_set_fragment_scheme(struct i1905_private *priv, uint8_t *dst,
			      uint8_t scheme);

int i1905_cmdu_tx(struct i1905_interface_private *ifpriv, uint16_t vid,
		  uint8_t *dst, uint8_t *src, uint16_t type,
		  uint16_t *mid, uint8_t *data, int datalen,
		  bool loopback);

int i1905_send_cmdu(struct i1905_interface_private *ifpriv, uint16_t vid,
		    uint8_t *dst, uint8_t *src, uint16_t ethtype,
		    struct cmdu_buff *frm);

int i1905_send_cmdu_relay_mcast(struct i1905_private *priv, const char *ifname,
				uint8_t *dst, uint8_t *src, uint16_t ethtype,
				struct cmdu_buff *frm);

int i1905_relay_cmdu(struct i1905_private *priv, const char *ifname,
		     uint8_t *dst, uint8_t *src, uint16_t ethtype,
		     struct cmdu_buff *frm);


int i1905_process_cmdu(struct i1905_private *priv, struct cmdu_buff *rxf);
int i1905_process_lldp(struct i1905_private *priv, struct cmdu_buff *rxf);


int i1905_send_bridge_discovery(struct i1905_interface *iface);


struct cmdu_buff *i1905_build_topology_discovery(struct i1905_interface *iface);
struct cmdu_buff *i1905_build_topology_notification(struct i1905_interface *iface);
struct cmdu_buff *i1905_build_topology_response(struct i1905_interface *iface);
struct cmdu_buff *i1905_build_higher_layer_response(struct i1905_interface *iface);
struct cmdu_buff *i1905_build_link_metric_query(struct i1905_interface *iface);
struct cmdu_buff *i1905_build_link_metric_response(struct i1905_interface *iface,
						   uint8_t *neighbor,
						   uint8_t query_type);

struct cmdu_buff *i1905_build_ap_autoconfig_search(struct i1905_interface *iface,
						   uint8_t freqband);

struct cmdu_buff *i1905_build_ap_autoconfig_renew(struct i1905_interface *iface,
						  uint8_t freqband);

struct cmdu_buff *i1905_build_ap_autoconfig_response(struct i1905_interface *iface,
						     uint8_t freqband);

struct cmdu_buff *i1905_build_vendor_specific(struct i1905_interface *iface,
					      int argc, char *argv[]);

int i1905_send_topology_discovery(struct i1905_interface *iface);

#ifdef WIFI_EASYMESH
static inline int i1905_send_topology_notification(struct i1905_private *priv,
						   const char *ifname)
{
	/* EasyMesh Agent will generate the topology notification. Therefore
	 * suppress the in-stack generated one.
	 */
	return 0;
}
#else
int i1905_send_topology_notification(struct i1905_private *priv, const char *ifname);
#endif

int i1905_send_topology_query(struct i1905_interface *iface, uint8_t *dest);

int i1905_send_topology_response(struct i1905_interface *iface, uint8_t *dest,
				 uint16_t mid);


int i1905_send_link_metric_query(struct i1905_interface *iface, uint8_t *dest);

int i1905_send_link_metric_response(struct i1905_interface *iface, uint8_t *dest,
				    uint8_t *neighbor, uint8_t query_type,
				    uint16_t mid);

int i1905_send_ap_autoconfig_search(struct i1905_private *priv, uint8_t rf_band);
int i1905_send_ap_autoconfig_renew(struct i1905_private *priv, uint8_t rf_band);

int i1905_send_ap_autoconfig_response(struct i1905_interface *pif, uint8_t *dest,
				      uint8_t band, uint16_t mid);

int i1905_send_ap_autoconfig_wsc_m1(struct i1905_interface_private *out_pif,
				    struct i1905_interface_private *pif,
				    uint8_t *dest);

int i1905_send_ap_autoconfig_wsc_m2(struct i1905_interface_private *out_pif,
				    struct wps_credential *cred,
				    uint16_t mid, uint8_t *dest,
				    uint8_t *m1, uint16_t m1_size);

int i1905_send_higherlayer_query(struct i1905_interface *pif, uint8_t *dest);

int i1905_send_higherlayer_response(struct i1905_interface *pif, uint8_t *dest,
				    uint16_t mid);

int i1905_send_pbc_event_notification(struct i1905_private *priv,
				      uint8_t num_media, uint16_t media_type[],
				      void *media_info[]);

int i1905_send_pbc_join_notification(struct i1905_private *priv, uint8_t *macaddr,
				     uint8_t *new_macaddr);
#ifdef EXTENSION_ALLOWED
int extmodule_maybe_process_cmdu(struct list_head *extensions,
				 struct cmdu_buff *rxf);

struct i1905_extmodule *i1905_load_extmodule(struct i1905_private *priv,
					     const char *name);

int i1905_unload_extmodule(struct i1905_extmodule *mod);

int i1905_extmodules_notify(struct i1905_private *priv, uint32_t event, ...);

int extmodules_load(int argc, char *argv[], struct list_head *extensions);
int extmodules_unload(struct list_head *extensions);

int i1905_extension_register(struct i1905_private *p, char *name);
int i1905_extension_unregister(struct i1905_private *p, char *name);
int i1905_extension_start(struct i1905_private *p, char *name);
int i1905_extension_stop(struct i1905_private *p, char *name);

#else
static inline int extmodule_maybe_process_cmdu(struct list_head *extensions,
					       struct cmdu_buff *rxf)
{
	return -2;
}

static inline struct i1905_extmodule *i1905_load_extmodule(struct i1905_private *priv,
							   const char *name)
{
	return NULL;
}

static inline int i1905_unload_extmodule(struct i1905_extmodule *mod)
{
	return 0;
}

static inline int extmodules_load(int argc, char *argv[], struct list_head *extensions)
{
	return 0;
}

static inline int extmodules_unload(struct list_head *extensions)
{
	return 0;
}

static inline int i1905_extmodules_notify(struct i1905_private *priv, uint32_t event, ...)
{
	return 0;
}

static inline int i1905_extension_register(struct i1905_private *p, char *name)
{
	return 0;
}

static inline int i1905_extension_unregister(struct i1905_private *p, char *name)
{
	return 0;
}

static inline int i1905_extension_start(struct i1905_private *p, char *name)
{
	return 0;
}

static inline int i1905_extension_stop(struct i1905_private *p, char *name)
{
	return 0;
}
#endif /* EXTENSION_ALLOWED */

#ifdef HAS_UBUS
int i1905_publish_object(struct i1905_private *p, const char *objname);
int i1905_remove_object(struct i1905_private *p);
int i1905_publish_interface_object(struct i1905_private *priv, const char *ifname);
int i1905_remove_interface_object(struct i1905_private *priv, const char *ifname);

int i1905_register_misc_events(struct i1905_private *priv);
int i1905_unregister_misc_events(struct i1905_private *priv);

#else
/* TODO: socket based cli */
static inline int i1905_publish_object(struct i1905_private *p, const char *objname)
{
	return 0;
}

static inline int i1905_remove_object(struct i1905_private *p)
{
	return 0;
}

static inline int i1905_publish_interface_object(struct i1905_private *priv, const char *ifname)
{
	return 0;
}

static inline int i1905_remove_interface_object(struct i1905_private *priv, const char *ifname)
{
	return 0;
}

static inline int i1905_register_misc_events(struct i1905_private *priv)
{
	return 0;
}

static inline int i1905_unregister_misc_events(struct i1905_private *priv)
{
	return 0;
}
#endif

struct i1905_dm *i1905_dm_get();
int i1905_dm_init(struct i1905_dm *dm, struct i1905_config *cfg);
int i1905_dm_free(struct i1905_dm *dm);

int i1905_dm_refresh_self(struct i1905_private *p);

int i1905_dm_neighbor_discovered(struct i1905_interface *iface, uint8_t *aladdr,
				 uint8_t *macaddr, uint16_t cmdu_type);

int i1905_dm_neighbor_changed(struct i1905_interface *iface, uint8_t *aladdr);

int i1905_dm_neighbor_update(struct i1905_interface *iface, uint8_t *aladdr,
			     struct tlv *t);

void i1905_dm_neighbor_free(struct i1905_device *dev);

struct i1905_device *i1905_dm_neighbor_lookup(struct i1905_interface *iface,
					      uint8_t *aladdr);

struct i1905_device *i1905_get_neigh_device(struct i1905_interface *iface,
					    uint8_t *aladdr);

struct i1905_interface *i1905_lookup_interface(struct i1905_private *p,
					       char *ifname);

struct i1905_interface *i1905_dm_neighbor_interface_lookup(struct i1905_device *rdev,
							   uint8_t *ifmacaddr);

struct i1905_neighbor_interface *i1905_link_lookup_partial(struct i1905_interface *iface,
							   uint8_t *macaddr, uint8_t *aladdr);

void i1905_free_interface_links(struct i1905_interface *iface);

void i1905_free_interface_neighbors(struct i1905_interface *iface);

void i1905_remote_link_invalidate_all(struct i1905_interface *iface, uint8_t *aladdr);
void i1905_remote_link_free_all_invalid(struct i1905_interface *iface, uint8_t *aladdr);

void i1905_free_all_non1905_nbrs_of_neighbor(struct i1905_interface *iface, uint8_t *aladdr);

int i1905_dm_neighbor_update_non1905_neighbors(struct i1905_interface *iface,
					       uint8_t *aladdr);

int if_getmediatype(const char *ifname, enum if_mediatype *mtype);

int i1905_cmdu_parse_tlvs(struct cmdu_buff *cmdu, struct tlv *tv[][TLV_MAXNUM], int num_tv);


int i1905_dump_info(struct i1905_private *priv, void *out);
int i1905_dump_neighbors(struct i1905_private *priv, void *out);
int i1905_dump_links(struct i1905_private *priv, void *out);
int i1905_dump_non1905neighbors(struct i1905_private *priv, void *out);
int i1905_do_cmdu_tx(struct i1905_private *priv, void *args, void *out);
int i1905_do_cmdu_rx(struct i1905_private *priv, void *args, void *out);
int i1905_do_cmdu_prepare(struct i1905_private *priv, void *args, void *out);
int i1905_do_apconfig(struct i1905_private *priv, void *args, void *out);
int i1905_interface_add(struct i1905_private *priv, void *args, void *out);
int i1905_interface_del(struct i1905_private *priv, void *args, void *out);
bool i1905_is_interface_excluded(struct i1905_private *priv, const char *ifname);


bool i1905_interface_supports_freqband(struct i1905_interface *iface, uint8_t band);
bool i1905_interface_supports_role(struct i1905_interface *iface, uint8_t role);
uint32_t i1905_interface_get_role(struct i1905_interface *iface);
uint8_t *i1905_interface_get_bssid(struct i1905_interface *iface);

int i1905_add_master_interface(struct i1905_private *priv, const char *ifname);
void i1905_free_master_interface(struct i1905_private *priv, const char *ifname);
void i1905_free_master_interfaces(struct i1905_private *priv);
struct i1905_master_interface *i1905_ifname_to_master_interface(struct i1905_private *priv,
								const char *ifname);

#endif /* I1905_H */
