#ifndef _IF_H
#define _IF_H

#include "socket.h"
#include "buf.h"

/* net interface flags */
#define IFF_UP		0x0001		/* if is up */
#define IFF_BROADCAST	0x0002		/* if supports broadcasting */
#define IFF_DEBUG	0x0004		/* if debugging is on */
#define IFF_LOOPBACK	0x0008		/* if is software loopback */
#define IFF_POINTOPOINT	0x0010		/* if for p2p connection */
#define IFF_NOTRAILERS	0x0020		/* if should not use trailer encaps. */
#define IFF_RUNNING	0x0040		/* if ressources are allocated */
#define IFF_NOARP	0x0080		/* if should not use arp */
#define IFF_MASK	(IFF_UP|IFF_DEBUG|IFF_NOTRAILERS|IFF_NOARP)

#define IF_NAMSIZ		16	/* maximum if name len */
#define IF_MAXQ			60	/* maximum if queue len */
#define IF_SLOWTIMEOUT		1000	/* one second */
#define IF_PRIORITY_BITS	1
#define IF_PRIORITIES		(1 << IF_PRIORITY_BITS)

/*
 * socket address carrying a hardware address
 */
struct sockaddr_hw {
	unsigned short	shw_family;
	unsigned short	shw_type;
	unsigned short	shw_len;
	unsigned char	shw_addr[8];
};

struct netif;

/* structure for holding address information, assumes internet style */
struct ifaddr {
	struct sockaddr	addr;		/* local address */
	union {
		struct sockaddr	broadaddr;	/* broadcast address */
		struct sockaddr	dstaddr;	/* point2point dst address */
	} ifu;
	struct netif	*ifp;		/* interface this belongs to */
	struct ifaddr	*next;		/* next ifaddr */
	short		family;		/* address family */
	unsigned short	flags;		/* flags */

/* AF_INET specific */
	unsigned long	net;		/* network id */
	unsigned long	netmask;	/* network mask */
	unsigned long	subnet;		/* subnet id */
	unsigned long	subnetmask;	/* subnet mask */
	unsigned long	net_broadaddr;	/* logical broadcast addr */
};

/* Interface packet queue */
struct ifq {
	short	maxqlen;
	short	qlen;
	short	curr;
	BUF	*qfirst[IF_PRIORITIES];
	BUF	*qlast[IF_PRIORITIES];
};

/* Hardware address */
struct hwaddr {
	short		len;
	unsigned char	addr[10];
};

/* structure describing a net interface */
struct netif {
	char		name[IF_NAMSIZ];/* interface name */
	short		unit;		/* interface unit */

	unsigned short	flags;		/* interface flags */
	unsigned long	metric;		/* routing metric */
	unsigned long	mtu;		/* maximum transmission unit */
	unsigned long	timer;		/* timeout delta in ms */
	short		hwtype;		/* hardware type */
/*
 * These must match the ARP hardware types in arp.h
 */
#define HWTYPE_NONE	200		/* for SLIP, PLIP, loop etc. */
#define HWTYPE_ETH	1		/* ethernet */

	struct hwaddr	hwlocal;	/* local hardware address */
	struct hwaddr	hwbrcst;	/* broadcast hardware address */

	struct ifaddr	*addrlist;	/* addresses for this interf. */
	struct ifq	snd;		/* send and recv queue */
	struct ifq	rcv;

	long		(*open) (struct netif *);
	long		(*close) (struct netif *);
	long		(*output) (struct netif *, BUF *, char *, short, short);
	long		(*ioctl) (struct netif *, short, long);
	void		(*timeout) (struct netif *);

	void		*data;		/* extra data the if may want */

	unsigned long	in_packets;	/* # input packets */
	unsigned long	in_errors;	/* # input errors */
	unsigned long	out_packets;	/* # output packets */
	unsigned long	out_errors;	/* # output errors */
	unsigned long	collisions;	/* # collisions */

	struct netif	*next;		/* next interface */
};

/* interface statistics */
struct ifstat {
	unsigned long	in_packets;	/* # input packets */
	unsigned long	in_errors;	/* # input errors */
	unsigned long	out_packets;	/* # output packets */
	unsigned long	out_errors;	/* # output errors */
	unsigned long	collisions;	/* # collisions */
};

/* argument structure for the SIOC* ioctl()'s on sockets */
struct ifreq {
	char	ifr_name[IF_NAMSIZ];		/* interface name */
	union {
		struct	sockaddr addr;		/* local address */
		struct	sockaddr dstaddr;	/* p2p dst address */
		struct	sockaddr broadaddr;	/* broadcast addr */
		struct	sockaddr netmask;	/* network mask */
		short	flags;			/* if flags, IFF_* */
		long	metric;			/* routing metric */
		long	mtu;			/* max transm. unit */
		struct	ifstat stats;		/* interface statistics */
		void	*data;			/* other data */
	} ifru;
};

/* result structure for the SIOCGIFCONF socket ioctl() */
struct ifconf {
	short	len;				/* buffer len */
	union {
		void 		*buf;		/* the actual buffer */
		struct ifreq 	*req;		/* ifreq structure */
	} ifcu;
};

#ifndef NOEXTERNS
extern struct netif	*allinterfaces;

extern short		if_enqueue	(struct ifq *, BUF *, short pri);
extern BUF		*if_dequeue	(struct ifq *);
extern void		if_flushq	(struct ifq *);
extern long		if_register	(struct netif *);
extern long		if_init		(void);
extern short		if_input	(struct netif *, BUF *, long, short);
#endif

/*
 * These must match ethernet protcol types
 */
#define PKTYPE_IP	0x0800
#define PKTYPE_ARP	0x0806
#define PKTYPE_RARP	0x8035

#ifndef NOEXTERNS
extern long		if_ioctl	(short cmd, long arg);
extern long		if_config	(struct ifconf *);

extern struct netif	*if_name2if	(char *);
extern struct netif	*if_net2if	(unsigned long);
extern long		if_setifaddr	(struct netif *, struct sockaddr *);
extern struct ifaddr	*if_af2ifaddr	(struct netif *, short fam);
extern struct netif	*if_primary	(void);
extern struct netif	*if_lo		(void);
extern short		if_getfreeunit	(char *);

extern long		if_open		(struct netif *);
extern long		if_close	(struct netif *);
extern long		if_send		(struct netif *, BUF *, unsigned long, short);
extern void		if_load		(void);
#endif

#endif /* _IF_H */
