// SPDX-License-Identifier: MIT
/*
Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
*/

#ifndef BABEL_INTERFACE_H
#define BABEL_INTERFACE_H

#include <zebra.h>
#include "zclient.h"
#include "vty.h"
#include "distribute.h"

#define CONFIG_DEFAULT 0
#define CONFIG_NO      1
#define CONFIG_YES     2

/* babeld interface information */
struct babel_interface {
	unsigned short flags; /* see below */
	unsigned short cost;
	int channel;
	struct timeval hello_timeout;
	struct timeval update_timeout;
	struct timeval flush_timeout;
	struct timeval update_flush_timeout;
	unsigned char *ipv4;
	int buffered;
	int bufsize;
	/* Relative position of the Hello message in the send buffer, or
       (-1) if there is none. */
	int buffered_hello;
	char have_buffered_id;
	char have_buffered_nh;
	char have_buffered_prefix;
	unsigned char buffered_id[8];
	unsigned char buffered_nh[4];
	unsigned char buffered_prefix[16];
	unsigned char *sendbuf;
	struct buffered_update *buffered_updates;
	int num_buffered_updates;
	int update_bufsize;
	time_t bucket_time;
	unsigned int bucket;
	time_t last_update_time;
	unsigned short hello_seqno;
	unsigned hello_interval;
	unsigned update_interval;
	/* A higher value means we forget old RTT samples faster. Must be
       between 1 and 256, inclusive. */
	unsigned int rtt_decay;
	/* Parameters for computing the cost associated to RTT. */
	unsigned int rtt_min;
	unsigned int rtt_max;
	unsigned int max_rtt_penalty;

	/* For filter type slot. */
	struct access_list *list[DISTRIBUTE_MAX];   /* Access-list. */
	struct prefix_list *prefix[DISTRIBUTE_MAX]; /* Prefix-list. */
};

typedef struct babel_interface babel_interface_nfo;
static inline babel_interface_nfo *babel_get_if_nfo(struct interface *ifp)
{
	return ((babel_interface_nfo *)ifp->info);
}

/* babel_interface_nfo flags */
#define BABEL_IF_IS_UP	       (1 << 0)
#define BABEL_IF_WIRED	       (1 << 1)
#define BABEL_IF_SPLIT_HORIZON (1 << 2)
#define BABEL_IF_LQ	       (1 << 3)
#define BABEL_IF_FARAWAY       (1 << 4)
#define BABEL_IF_TIMESTAMPS    (1 << 5)

/* Only INTERFERING can appear on the wire. */
#define BABEL_IF_CHANNEL_UNKNOWN	0
#define BABEL_IF_CHANNEL_INTERFERING	255
#define BABEL_IF_CHANNEL_NONINTERFERING -2

static inline int if_up(struct interface *ifp)
{
	return (if_is_operative(ifp) && CHECK_FLAG(babel_get_if_nfo(ifp)->flags, BABEL_IF_IS_UP));
}

struct buffered_update {
	unsigned char id[8];
	unsigned char prefix[16];
	unsigned char plen;
	unsigned char pad[3];
};

/* init function */
void babel_if_init(void);
void babel_if_terminate(void);

/* Callback functions for zebra client */
int babel_interface_up(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id);
int babel_interface_down(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id);
int babel_interface_add(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id);
int babel_interface_delete(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id);
int babel_interface_address_add(int cmd, struct zclient *zclient, zebra_size_t length,
				vrf_id_t vrf_id);
int babel_interface_address_delete(int cmd, struct zclient *zclient, zebra_size_t length,
				   vrf_id_t vrf_id);

int babel_ifp_create(struct interface *ifp);
int babel_ifp_up(struct interface *ifp);
int babel_ifp_down(struct interface *ifp);
int babel_ifp_destroy(struct interface *ifp);

unsigned jitter(babel_interface_nfo *babel_ifp, int urgent);
unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent);
/* return "true" if "address" is one of our ipv6 addresses */
int is_interface_ll_address(struct interface *ifp, const unsigned char *address);
/* Send retraction to all, and reset all interfaces statistics. */
void babel_interface_close_all(void);
extern int babel_enable_if_config_write(struct vty *vty);


#endif
