/* $Id: veth.h,v 1.21 2004/06/19 12:49:26 yumo Exp $ */
/* VETH: A virtual ethernet device driver for Linux header file. 
 *
 * This device driver is an implementation of Aggregation of Multiple
 * Link Segments (IEEE 802.3ad).
 *
 * Author: Yumo (Katsuyuki Yumoto) 2000-2004
 *         yumo@st.rim.or.jp
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifndef VETH_H
#define VETH_H

/* Maximum number of devices to support. */
#define MAX_VETH  8
#define MAX_PHYIF 8

#define VETH_VER_MAJOR 0
#define VETH_VER_MINOR 6
#define VETH_VER_PATCH 5

#define VETH_MAGIC 0x3be5

/* actions */
#define VETHCTL_ADD_PHYIF 1
#define VETHCTL_DEL_PHYIF 2
#define VETHCTL_GET_PORT_INFO 3
#define VETHCTL_SET_PORT_INFO 4
#define VETHCTL_GET_AGG_INFO 5
#define VETHCTL_SET_AGG_INFO 6
#define VETHCTL_VERSION 7

#define SUBKEY_UNKNOWN 0
#define SUBKEY_10M 1
#define SUBKEY_100M 2
#define SUBKEY_1000M 3

#define SUBKEY_MASK_UPPER 0xff00
#define SUBKEY_MASK_LOWER 0x00ff

	/* 43.4.2.2 */
#define PS_LACP_ACTIVITY    0x1
#define PS_LACP_TIMEOUT     0x2
#define PS_AGGREGATION      0x4
#define PS_SYNCHRONIZATION  0x8
#define PS_COLLECTING      0x10
#define PS_DISTRIBUTING    0x20
#define PS_DEFAULTED       0x40
#define PS_EXPIRED         0x80


/* Distributing Algorithm */
#define DIST_TCPUDPHASH 0x1
#define DIST_ROUNDROBIN 0x2

enum selected_val {
		SELECTED,
		UNSELECTED,
		STANDBY
};

struct u_port_info
{
	unsigned short actor_port_num; /* this is the port # assigned to this port */
	unsigned short actor_port_pri;
	int actor_port_agg_id;
	unsigned short actor_admin_port_key;
	unsigned short actor_oper_port_key;
	unsigned char actor_admin_port_state;
	unsigned char actor_oper_port_state;

	unsigned char partner_admin_sys[ETH_ALEN];
	unsigned char partner_oper_sys[ETH_ALEN];
	unsigned short partner_admin_sys_pri;
	unsigned short partner_oper_sys_pri;
	unsigned short partner_admin_key;
	unsigned short partner_oper_key;
	unsigned short partner_admin_port_num;
	unsigned short partner_oper_port_num;
	unsigned short partner_admin_port_pri;
	unsigned short partner_oper_port_pri;
	unsigned char partner_admin_port_state;
	unsigned char partner_oper_port_state;

	enum selected_val selected;
};


struct u_agg_info
{
	unsigned char agg_mac[ETH_ALEN];
	int agg_id;
	int ind_agg;
	int actor_admin_agg_key;
	int actor_oper_agg_key;
	unsigned char partner_sys[ETH_ALEN];
	int partner_sys_pri;
	int partner_oper_agg_key;
	int ready; /* calculated from ready_N of each port */

	unsigned long distmode;
};


struct u_drv_info {
	unsigned char major;
	unsigned char minor;
	unsigned char patch;
	char name[20]; /* driver name */
	char author[50];
};



/* vethconf is used for adding or removing physical i/f to/from
   virtual i/f by using ioctl() */

struct vethconf {
	unsigned short magic;
	int action;

	char pif_name[8];
	char vif_name[8];
	char pif_module[40];
	unsigned int size;
	unsigned char *buf;
};

#ifdef __KERNEL__
/* debug section */
#define VETH_DEBUG_LEVEL_MASK 0xf
#define VETH_DEBUG_RCVM 0x1 << 4
#define VETH_DEBUG_MUXM 0x2 << 4
#define VETH_DEBUG_CHUM 0x4 << 4
#define VETH_DEBUG_PERM 0x8 << 4
#define VETH_DEBUG_SEL  0x10 << 4
#define VETH_DEBUG_CTLP 0x20 << 4

#define VETH_DEBUG_NONE 0x0
#define VETH_DEBUG_ALL  0xfffffff0
#define VETH_DEBUG_STATE VETH_DEBUG_RCVM | VETH_DEBUG_MUXM | VETH_DEBUG_CHUM | VETH_DEBUG_PERM

static unsigned int veth_debug = VETH_DEBUG_NONE;

#define VETH_DEBUG(x,y) (((x)&veth_debug)&&((VETH_DEBUG_LEVEL_MASK&veth_debug)>=(y)))
/* end of debug section */


/* Linux version dependency */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
/* for 2.2.x */
#define netdevice_start(dev) dev->start = 1
#define netdevice_stop(dev) dev->start = 0
#define netif_start_queue(dev) dev->tbusy = 0
#define netif_stop_queue(dev) dev->tbusy = 1
#define net_device device
#define dev_get_by_name dev_get
#else
#define netdevice_start(dev)
#define netdevice_stop(dev)
#endif



/* Distributing Algorithm */
#define DIST_TCPIPHASH 0x1
#define DIST_ROUNDROBIN 0x2



/* IEEE 802.3ad constants */

typedef enum _bool {
	_TRUE = 1,
	_FALSE = 0
}bool;

static char Slow_Protocols_Multicast[ETH_ALEN] = {0x01,0x80,0xc2,0x00,0x00,0x02}; /* Tbl 43B-1 */
static unsigned short Slow_Protocols_Type = __constant_htons(0x8809); /* Tbl 43B-2 */

static unsigned char Marker_Subtype = 0x2; /* 43.2.7.1.1 */
static unsigned char LACP_Subtype = 0x1; /* 43.2.9.1.1 */
static unsigned char LACP_Version = 0x1; /* 43.4.2.2 */

static unsigned char Marker_Information = 0x1; /* 43.2.7.1.1 */
static unsigned char Marker_Response_Information = 0x2; /* 43.2.7.1.1 */


/* 43.4.2.2 (LACPDU structure) */
struct lacpdu {
	u8 subtype; /* 0 */
	u8 version_number; /* 1 */
	u8 first_tlv_type; /* 2 */
	u8 actor_info_len; /* 3 */
	u16 actor_sys_pri; /* 4 */
	u8 actor_sys[ETH_ALEN]; /* 6 */
	u16 actor_key; /* 12 */
	u16 actor_port_pri; /* 14 */
	u16 actor_port; /* 16 */
	u8 actor_state; /* 18 */
	u8 pad1[3];
	u8 second_tlv_type; /* 22 */
	u8 partner_info_len; /* 23 */
	u16 partner_sys_pri; /* 24 */
	u8 partner_sys[ETH_ALEN]; /* 26 */
	u16 partner_key; /* 32 */
	u16 partner_port_pri; /* 34 */
	u16 partner_port; /* 36 */
	u8 partner_state; /* 38 */
	u8 pad2[3];
	u8 third_tlv_type; /* 42 */
	u8 collector_info_len; /* 43 */
	u8 collector_max_del; /* 44 */
	u8 pad3[13];
	u8 fourth_tlv_type; /* 58 */
	u8 terminator_len; /* 59 */
	u8 pad4[50];
};
#define LACPDU_LEN sizeof(struct lacpdu)



/* 43.4.4 */
static int Fast_Periodic_Time = 1*10; /* 1 sec */
static int Slow_Periodic_Time = 30*10;   /* 30 sec */
static int Short_Timeout_Time = 3*10; /* 3 sec */
static int Long_Timeout_Time = 90*10; /* 90 sec */
static int Churn_Detection_Time = 60*10; /* 60 sec */
static int Aggregate_Wait_Time = 2*10; /* 2 sec */

/* 43.4.5 */
struct system_var {
	unsigned char actor_sys[ETH_ALEN];
	unsigned short actor_sys_pri;
	int collector_max_del;
} veth_sysvar;

/* 43.4.6 */
struct agg_var {
	unsigned char agg_mac[ETH_ALEN];
	int agg_id;
	int ind_agg;
	int actor_admin_agg_key;
	int actor_oper_agg_key;
	unsigned char partner_sys[ETH_ALEN];
	int partner_sys_pri;
	int partner_oper_agg_key;
	enum _ena_dis {
		ENABLED = 1,
		DISABLED = 0
	} recv_state, xmit_state;
	int lag_ports[MAX_PHYIF];
	bool ready; /* calculated from ready_N of each port */

};
	
/* 43.4.7 */
struct port_var {
	unsigned short actor_port_num; /* this is the port # assigned to this port */
	unsigned short actor_port_pri;
	int actor_port_agg_id;
	int need_to_xmit;
	unsigned short actor_admin_port_key;
	unsigned short actor_oper_port_key;
	unsigned char actor_admin_port_state;
	unsigned char actor_oper_port_state;

	unsigned char partner_admin_sys[ETH_ALEN];
	unsigned char partner_oper_sys[ETH_ALEN];
	unsigned short partner_admin_sys_pri;
	unsigned short partner_oper_sys_pri;
	unsigned short partner_admin_key;
	unsigned short partner_oper_key;
	unsigned short partner_admin_port_num;
	unsigned short partner_oper_port_num;
	unsigned short partner_admin_port_pri;
	unsigned short partner_oper_port_pri;
	unsigned char partner_admin_port_state;
	unsigned char partner_oper_port_state;
	int port_enabled;

	/* vars for managing the operation of the state machine */
	/* 43.4.8 */
	bool begin;
	bool lacp_ena;
	bool actor_churn;
	bool partner_churn;
	bool ready_n;
	enum selected_val selected;
	bool port_moved;

	/* following variables are not defined in the standard */
	bool attached;
	bool xmit_ena;
	int xmit_tim_update;
	int xmit_count;
	bool tbd_cnt; /* "to be deleted" counter */
#define VETH_PORT_MON_INTERVAL 10 /* 1 sec */
	int pm_intval;
	bool loop; /* loopback connection detection */
};

/* 43.4.12 (receive machine) */
enum rcvm_state {
	INITIALIZE,
	PORT_DISABLED,
	EXPIRED,
	LACP_DISABLED,
	DEFAULTED,
	CURRENT
};

enum acm_state {
	NO_ACTOR_CHURN,
	ACTOR_CHURN_MONITOR,
	ACTOR_CHURN
};

enum pcm_state {
	NO_PARTNER_CHURN,
	PARTNER_CHURN_MONITOR,
	PARTNER_CHURN
};

/* (independent control model) */
enum muxm_state {
	DETACHED,
	WAITING,
	ATTACHED,
	COLLECTING,
	DISTRIBUTING
};

/* (periodic timer) */
enum perio_state {
	NO_PERIODIC,
	FAST_PERIODIC,
	SLOW_PERIODIC,
	PERIODIC_TX
};


/* 43.4.10 (timers) */
struct veth_timer {
	struct veth_timer *next;
	int exp;
	int tim;
	bool active;
	void (*tick_func)(struct veth_timer *vtp); /* tick function */
};

static struct veth_timer *vth = NULL;

static struct timer_list tl;


#define MAX_RING 128

struct ring_buf {
	int r;
	int w;
	unsigned char *buf[MAX_RING];
};


/* state machines */
struct rcv_mach {
	enum rcvm_state state;
	bool do_it;
	struct ring_buf ring;
};

struct mux_mach {
	enum muxm_state state;
	bool do_it;
};

struct pc_mach {
	enum pcm_state state;
	bool do_it;
};

struct ac_mach {
	enum acm_state state;
	bool do_it;
};

struct perio_mach {
	enum perio_state state;
	bool do_it;
};


struct veth_port {

	struct port_var pv;

	/* timers */
	struct veth_timer current_while_timer;
	struct veth_timer actor_churn_timer;
	struct veth_timer periodic_timer;
	struct veth_timer partner_churn_timer;
	struct veth_timer wait_while_timer;

	struct veth_timer xmit_timer;

	/* state machines */
	struct rcv_mach rcvm;
	struct mux_mach muxm;
	struct pc_mach pcm;
	struct ac_mach acm;
	struct perio_mach prm;

	struct net_device *dev;
	char module_name[40]; /* module name of physical i/f */

	int avrlen;
};


/* for solving correct hash value for IP fragments 
 * in TCP/IP port based hash algorithm */
struct dist_hash_table {
	struct dist_hash_table *next;
	u16 id; /* packet id */
	u32 saddr; /* source IPv4 address */
	u32 daddr; /* destination IPv4 address */
	int hash;
};

struct veth_agg {
	struct net_device *dev;
	struct agg_var av;
	unsigned long distmode;
	unsigned long count;
	struct dist_hash_table *dht[32];

	int ports[MAX_PHYIF];/* which holds ports which is in DIST state */
	int n_ports; /* which holds number of ports which is in DIST state */
	spinlock_t lock;
};

/* veth_private is built-in device structure */
struct veth_private {
	struct net_device_stats enet_stats;
	struct veth_agg *agg;
};



/* These are pool of ports used by aggregators */
static struct veth_port veth_ports[MAX_PHYIF];
static struct veth_agg veth_aggs[MAX_VETH];

/* for port prioritizing */
static struct veth_port *opl[MAX_PHYIF];
static bool need_to_rebuild_opl = _FALSE;


#define VP(n) \
		struct veth_private *vp; \
		vp = (struct veth_private *)veth_aggs[(n)].dev->priv 

#endif /* __KERNEL__ */
#endif /* VETH_H */

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 *  indent-tabs-mode: t
 * End:
 */
