/*
*            Copyright (c) 1998-2001 by NETsilicon Inc.
*
*  This software is copyrighted by and is the sole property of
*  NETsilicon.  All rights, title, ownership, or other interests
*  in the software remain the property of NETsilicon.  This
*  software may only be used in accordance with the corresponding
*  license agreement.  Any unauthorized use, duplication, transmission,
*  distribution, or disclosure of this software is expressly forbidden.
*
*  This Copyright notice may not be removed or modified without prior
*  written consent of NETsilicon.
*
*  NETsilicon, reserves the right to modify this software
*  without notice.
*
*  NETsilicon
*  411 Waverley Oaks Road                  USA 781.647.1234
*  Suite 227                               http://www.netsilicon.com
*  Waltham, MA 02452                       AmericaSales@netsilicon.com
*
*************************************************************************
*  $Name:  $
*  $Date: 2004/08/30 20:53:15 $
*  $Source: /cvs_tick/netsilicon_netos2/netos/h/tcpip/netdev.h,v $
*  $Revision: 1.10.2.4 $
**************************************************************************
*  File Description:  Definitions and Macros for dealing with the
*                     `netdev' structure
**************************************************************************/

#ifndef _NETDEV_
#define _NETDEV_

#include "config.h"
#include "ccdep.h"
#include "std.h"
#include "dsu.h"
#include "socket.h"
#include "q.h"
#include "timer.h"
#include "in.h"
#include "select.h"
#include "fpublic.h"


#ifdef IGMP_PROTOCOL
#include "igmp.h"
#endif
#ifdef __cplusplus
extern "C"
{
#endif

/* Max number of IP addresses per Fusion device */
#ifndef ND_MAX_IPAS
#ifdef  AUTO_IPV4_CONF
#define ND_MAX_IPAS 2
#else
#define ND_MAX_IPAS 1
#endif
#endif

/**************************************************************************
 *
 * Flags for the ndp->nd_flags member of the netdev structure.
 *
 * Take care not to cause any duplications.
 *
 *
 */
#define F_N_INITIALIZED			0x00000001  /* has been initialized */
#define F_N_ONLINE				0x00000002  /* device is on line */
#define F_N_NONEXISTENT			0x00000004  /* no response during probe */
#define F_N_PRESERVE_MSG		0x00000008  /* Fusion must preseve message pending tx complete -- 
											   see note below */
#define F_N_ZEROCOPY			0x00000010  /* This indicates that the driver can 
											   support scatter-gather and 
											   TCP zero-copy and has no alignment
											   issues.
											 */
#define F_N_ZEROCOPY_NOALIGN	0x00000020  /* If F_N_ZEROCOPY then if this bit
											   is also set the driver supports
											   odd-byte alignment on transmit buffer
											   descriptors.  The stack won't generate
											   odd-alignment on the 1st (mp->m_hp)
											   but might on other TBDs.
											*/
#define F_N_AUTO_IPV4_CONF      0x00001000  /* Using Automatic IPv4 link-local address config */
#ifdef BOOTP_CLIENT_PROTOCOL
#define F_N_BOOTP_CLIENT        0x00002000 /* Presently running BOOTP on this interface */
#endif

#ifdef PING_ARP
#define F_N_PINGARP_CLIENT      0x00004000 /* Using Ping ARP to get address on interface */
#endif


#define F_N_B42CAST				0x00010000  /* This net uses B42 broadcast */
#define F_N_GOING_DOWN			0x00020000  /* on its way out */
#define F_N_IMMEDIATE			0x00040000  /* can't do delayed down -- see note below */
#define F_N_MAINT_BUF			0x00080000  /* lwq buffers re-allocated from os_maint() */

#define F_N_LINE_COMING_UP		0x00100000  /* device is bringing the line up (PPP)*/
#define F_N_IPADDRESS_SET		0x00200000  /* IP address has been set */
#define F_N_ROUTERADDRESS_SET	0x00400000  /* Default router address has been set */
#define F_N_CONFIGIP	    	0x00800000  /* Ip dynamically set by PPP provider */
#define F_N_AUTH_SERVER     	0x01000000  /* ppp authenticator */
#define F_N_DHCP_CLIENT     	0x02000000
#define F_N_TESTING         	0x04000000  /*  Currently unused by Fusion.  Indicates the
												interface is in the MIB-II testing state.
											 */
#define F_N_USER_DEFINE     	0x08000000  /* Presently running user defined address 
                                               resolution protocol on this interface
                                             */
#define VLAN_SHIFT	0	/* up to 3 */
#define MAX_VLAN	(1<<VLAN_SHIFT)



/* NOTE: F_N_IMMEDIATE, if set, means that the Fusion simply submits any outgoing
   packet to the driver immediately, and upon return from the driver's "start"
   function, the packet is assumed to have been transmitted and Fusion is free
   to dispose of the packet. Driver will "block" until the packet is transmitted,
   then return. There is no need for the driver to call Fusion's transmit completion
   routine. */
/* NOTE: F_N_PRESERVE_MSG, if set, means that when Fusion a packet to
   the driver, Fusion must not "free" it until it has received a transmit
   completion notification message from the driver for that packet.
   Presumably, this is because the driver, rather than copying the 
   data of the message into its own internal buffer, leaves it in place  
   in the message during the transmit operation. This is preferable from a
   performance standpoint, because it saves a copy */
/* NOTE: The F_N_PRESERVE_MSG flag is not used if the F_N_IMMEDIATE flag is set,
   because there is no possible need for Fusion to preserve messages in that situation */
/* It is up to the driver, within the driver intialization routine, to set the
   F_N_IMMEDIATE and/or F_N_PRESERVE_MSG as appropriate. If F_N_IMMEDIATE flag is not
   set,then the driver must indicate the limit of how many packets it can accept before 
   FUSION stops submitting them (pending transmit completes). The driver must call the
   Fusion transmit completion notification routine ("ndq_restart") for each packet that
   completes transmission. */

/* The driver should use the mcaros defined below instead of explicitly referring to 
   these flags, which are simply an internal Fusion implementation. However, for backward
   compatibility with pre-Fusion-5.5 drivers, which may or may not have had references
   to the F_N_IMMEDIATE flag, Fusion 5.5 should be backward compatible with these
   drivers. */


/**********************************************************************************/
/*************** Macros to tell fusion the driver's operating mode ****************/
/*************** These macros hide the flags from the driver **********************/
/**********************************************************************************/

#define FUSION_IMMEDIATE(n) n->nd_flags |= F_N_IMMEDIATE
#define FUSION_NO_IMMEDIATE(n) n->nd_flags &= ~F_N_IMMEDIATE
#define FUSION_PENDLIMIT(n,l) n->nd_txpendlimit = l
#define FUSION_PRESERVE_MSGS(n)  n->nd_flags |= F_N_PRESERVE_MSG
#define FUSION_DONT_PRESERVE_MSGS(n) n->nd_flags &= ~F_N_PRESERVE_MSG

#define FUSION_PRESERVING_MSGS(n) ( (!(n->nd_flags & F_N_IMMEDIATE)) && \
	                                (n->nd_flags & F_N_PRESERVE_MSG) )

/* The following macro can be used in the driver initialization to tell Fusion
   that it will wait until a packet submitted to it has completed transmission
   before returning from the function by which the packet is submitted to it.
   This is equivalent to setting the F_N_IMMEDIATE flag */
#define FUSION_DRV_BLOCK_UNTIL_TXCOMPLETE(n) FUSION_IMMEDIATE(n)

/* The following macro can be used in the driver initialization to tell Fusion 
   that it will not block (but will notify Fusion when a packet's transmission
   completes), can accept up to "limit" outgoing packets at a time pending transmit
   completion, and will copy submitted packets into its internal buffers (so that
   Fusion need not preserve the packet while transmission complete is pending). */
#define FUSION_DRV_TXCOMPLETE_NOTIFY_COPY(n,limit) FUSION_NO_IMMEDIATE(n);\
	                                               FUSION_DONT_PRESERVE_MSGS(n);\
                                                   FUSION_PENDLIMIT(n,limit)
	                               
/* The following macro can be used in the driver initialization to tell Fusion
   that it will not block (but will notify Fusion when a packet's transmission
   completes, can accept up to "limit" outgoing packets at a time pending transmit
   completion, and will NOT copy submitted packets into internal buffers (therefore,
   Fusion must preserve the packets while transmission complete is pending). */
#define FUSION_DRV_TXCOMPLETE_NOTIFY_NOCOPY(n,limit) FUSION_NO_IMMEDIATE(n);\
	                                                 FUSION_PRESERVE_MSGS(n);\
                                                     FUSION_PENDLIMIT(n,limit)



/* This one tells Fusion that all the same things as FUSION_DRV_TXCOMPLETE_NOTIFY_NOCOPY
   but in addition this driver is capable of supporting complete zero-copy stack
   operation and implements scatter-gather where the data for a single Fusion packet
   is spread over multiple discrete addresses contained in the m structure.
   See the Fusion porting guide for more info.  Note that this driver does NOT
   require that the individual buffers be aligned in any particular way, other
   than that the 1st (pointed to by mp->m_hp) perhaps cannot be aligned on an odd 
   address.  The stack will never align that one on an odd boundary.  But additional
   "cells" of data in the mp->m_datacells array MAY be on odd address boundaries.
   If this isn't acceptal see the FUSION_DRV_NEAR_ZEROCOPY macro.

*/
#ifdef FNS_ZERO_COPY_DRIVER
   
#define FUSION_DRV_ZEROCOPY(n, limit )	FUSION_NO_IMMEDIATE(n); \
										FUSION_PRESERVE_MSGS(n); \
										FUSION_PENDLIMIT(n, limit); \
										(n)->nd_flags |= F_N_ZEROCOPY; \
										(n)->nd_flags |= F_N_ZEROCOPY_NOALIGN											 

/* FUSION_DRV_NEAR_ZEROCOPY is like FUSION_DRV_ZEROCOPY except that Fusion will 
   perform a copy if necessary to prevent any buffer pointers from being on an 
   odd address.
*/
#define FUSION_DRV_NEAR_ZEROCOPY(n, limit ) FUSION_NO_IMMEDIATE(n); \
											FUSION_PRESERVE_MSGS(n); \
											FUSION_PENDLIMIT(n, limit); \
											(n)->nd_flags |= F_N_ZEROCOPY	


#endif

/*************************************************************************************/
	 
	 
/* The following macro indicates whether or not Fusion requires the driver to
   call "ndq_restart" for each packet that completes transmission */
#define NDQ_NEED_TX_COMPLETE(n) (!( (n->nd_flags) & F_N_IMMEDIATE))


#if ( defined(BOOTP_CLIENT_PROTOCOL) && defined(PING_ARP) )
#define F_N_OFFLINE_OK   ((u32)(F_N_DHCP_CLIENT | F_N_BOOTP_CLIENT | F_N_AUTO_IPV4_CONF \
	                                | F_N_PINGARP_CLIENT | F_N_USER_DEFINE))
#elif ( defined(BOOTP_CLIENT_PROTOCOL) )
#define F_N_OFFLINE_OK   ((u32)(F_N_DHCP_CLIENT | F_N_BOOTP_CLIENT | F_N_AUTO_IPV4_CONF | F_N_USER_DEFINE ))
#elif ( defined(PING_ARP) )
#define F_N_OFFLINE_OK   ((u32)(F_N_DHCP_CLIENT | F_N_PINGARP_CLIENT | F_N_AUTO_IPV4_CONF | F_N_USER_DEFINE ))
#else
#define F_N_OFFLINE_OK   ((u32)(F_N_DHCP_CLIENT | F_N_AUTO_IPV4_CONF | F_N_USER_DEFINE))
#endif


/* flags for ndp->nd_xflags */
#define F_X_MULTI_ENBL	0x0001	/* multicast enabled */
#define	F_X_MULTI_ADDR	0x0004	/* to communicate KFR that this is multi.route */
#define F_X_SHARING_NIC 0x0008  /* We are sharing this NIC (MAC address) with another TCP/IP stack */
#define F_X_PPPOE_AC    0x0010  /* enable PPPoE access concentrator on this interface */
#define F_X_PPPOE_HOST  0x0020  /* enable PPPoE Host on this interface */


#ifdef IGMP_PROTOCOL
typedef struct smulti_addr {
	struct smulti_addr	*next;
	a48			        addr;
    i16                 refcount; /* Multiple IP multicast addresses map to the same
                                  MAC address.  This is not an error.  But we
                                  must maintain a reference count.
                                  */

} multi_addr;

typedef struct saddr_list {
	multi_addr	*head;
	multi_addr	*tail;
} addr_list;
#endif /* IGMP_PROTOCOL */

typedef struct st_blk { /* Ethernet Based */
	u32 sb_rcnt;    /* Receive packet count */
	u32 sb_xcnt;    /* Transmit packet count */
	u32 sb_recnt;   /* Receive error count */
	u32 sb_xecnt;   /* Transmit error count */
	u32 sb_jam;     /* Jam retry count */
#if defined(SNMP) || defined(WANT_NETWORK_STATISTICS)
	u32 ifInOctets;
	u32 ifInUcastPkts;
	u32 ifInNUcastPkts;
	u32 ifInDiscards;
	u32 ifInErrors;
	u32 ifInUnknownProtos;
	u32 ifOutOctets;
	u32 ifOutUcastPkts;
	u32 ifOutNUcastPkts;
	u32 ifOutDiscards;
	u32 ifOutErrors;
#endif 
	u32	sb_rxtime;	/*  The value of Fusion's t_time variable 
					    the last time a packet was received on 
						the interface.
					*/
} st_blk;

/* macros to map ndp index to a non-zero (1 or greater)
   circuit index used with routing circuits.
*/
#define ndp_2_cid(ndp)		(((int)ndp->nd_ix+1))
#define cid_2_ndix(cid)		(((int)cid)-1)

/* WARNING: The following flags MUST ONLY be used for the nd_ipflags field in the 
            nd_ipaddr structure.  Using these flags for nd_flags in the ndp will 
            duplicate other flags.
*/

#define F_N_IPV4ADDR_SET		0x0001 /* IP address has been set */
#define F_N_IPV4_ROUTER_ADV     0x0002 /* We're sending IPv4 router advertisements
                                          on this interface.  Now OFF by default.
                                       */

typedef struct _nd_ipa_ {
    u32             nd_ipaddr;
    u32             nd_ipmask;
    u32             nd_ipbcast;
    u16             nd_ipflags;
    int             nd_secidx; /* This stores the secondary IP address index.  When,
                                  for example, "eth0" has three addresses, one
                                  primary and two secondary, then we'll have
                                  "eth0", "eth0:0", and "eth0:1".  The value
                                  of nd_secidx will be 0 and 1 respectivly for
                                  the preceding addresses.  Now if the address
                                  corresponding to "eth0:0" is removed then 
                                  while the location in the nd_ipas[] array 
                                  corresponding to "eth0:1" will change (to [1])
                                  the nd_secidx will remain equal to 1 and this
                                  is important since the routing protocol APIs like
                                  for OSPF and RIP take device names of the form
                                  "eth0:N".
                              */
    void            *ip_circ;    /* Routing code's IP circuit pointer */
    void            *nd_parent;  /* Parent netdev* for this entry */
    struct _nd_ipa_ *next;       /* We keep a linked list these circuits */

}nd_ipaddr, *nd_ipaddr_pt;

/* The following struct holds the info we need to send ARP probes for duplicate
   addresses on a given interface.  Multiple such probes can be going on concurrently.
*/

#define ND_ARP_PROBE         1   /* Sending a probe - source IP is zero */
#define ND_ARP_GRATUITOUS    2   /* Sending a gratuitous ARP */

typedef struct _addr_probe {
    q               addr_probe_q;     /* The link to the nd_addr_probe_q */
    u8              nd_probe_type;    /* ND_ARP_PROBE or ND_ARP_GRATUITOUS */
    u8              nd_blocking;      /* Set to true if somebody blocking for result
                                         of a probe.
                                       */
    u8              nd_duplicate;     /* Set to 1 if a collision is detected */
    u32             nd_probe_addr;    /* The address being probed */
    tcb             *nd_probe_timer;  /* The probe timer for ARP probes.  Set by
                                         ll_probe_addr.
                                       */
    u32              nd_probe_intvl;    /* The probe interval set by ll_probe_addr */
    u32              nd_probe_count;    /* Number of probes to send set by ll_probe_addr */
    void            *nd_parent;        /* The netdev* (ndp) to which we belong.  Useful
                                          for probe_timer or anybody who wants the
                                          nd_ipaddr but also needs to know the associated
                                          ndp and doesn't want to waste cycles calling
                                          a function to get it from the name.
                                        */
}nd_addr_probe, *p_nd_addr_probe;

/* net device switch */
typedef struct netdev {
	char    nd_name[MAX_DEV_NAME];  /* device name */
	u16     nd_devid;       /* Minor device id, ie a board # */
	u16     nd_xflags;  /* Filler field */
	u32     nd_p0;      /* device specific init values */
	u32     nd_p1;
	u32     nd_p2;
	u32     nd_p3;
	so_addr	nd_lladdr;  /* link layer address of board - user fills in address family
                           in device table.  Fusion queries device driver for link
                           layer address.
                        */
	int (* nd_init)(struct netdev * ndp);
	int (* nd_updown)(struct netdev * ndp, u16 flags, char * options);
	st  (* nd_send)(struct m * mp);
	int (* nd_start)(struct m * mp);
	int (* nd_ioctl)(struct netdev * ndp, int cmnd, char * addr);


	/*********************************************************************
	 * NOTE: Everything below this line must stay there.  Any new fields
	 * which require OEM initialization must be added above this line and
	 * macros for devtable.h must be created for them (see below).  Fields which
	 * which can be initialized to 0 and wouldn't require OEM initialization
	 * go below this line.  See example devtable.h for device table
	 * declaration.  CAUTION: Care MUST be taken to keep the order of entries
     * in devtable.h and the netdev structure the same.
	 */
	u32         nd_flags;       /* Flags - changed to 32 bits on 3/12/02 since we're
                                   running out.
                                 */
	u16         nd_ix;          /* 'ndp_tbl' index (back ptr) - initialized by Fusion */
	st_blk	    nd_stat;        /* statistics */
    /* Note: we use a simple array rather than a linked list since it is
       unlikely we'd have very many addresses per interface so it will
       be higher performance to walk an array than a linked list for
       each packet received.  The logic for adding/deleting addresses
       on interfaces will make sure that there are no gaps, i.e., if 
       nd_ipa[n] is unconfigured then nd_ipa[n+1] and beyond will be shifted
       downward.
    */
	nd_ipaddr   nd_ipas[ND_MAX_IPAS];  /* ipa addresses for this physical link */
    int         nd_numipas;     /* The current number of addresses configured
                                   this interface 
                                */
    u32	    nd_ipmasks[MAX_VLAN]; /* parallel subnet mask */

	int	        nd_ipmtu;	    /* IP MTU          same for all addresses*/
	u32	        nd_ifspeed;		/* Interface Speed "                      " */
	q           nd_xmitq;       /* Transmit message queue for messages that have been
	                               submitted to the driver and for which transmit 
	                               completion notifications are being awaited. Used
	                               only if F_N_PRESERVE_MSG flag is set. 
                                 */

    /* The following three fields are used only if the driver has a limited capacity
	   to inernally queue outgoing messages (i.e., the F_N_IMMEDIATE flag is not set */
	q		nd_holdq;       /* Queue to hold messages which cannot be submitted to
							   the driver because we've maxed out on the capacity of 
							   the driver to internally queue messages (nd_txpendlimit) */
	int     nd_txpendlimit; /* Maximum number of outstanding "packets" that can be 
							   submitted to the driver. */
	int     nd_txnumpending; /* The number of outgoing packets presently pending 
							    transmission by the driver. This field is touched
								only by Fusion, driver should not touch it. */
	struct so_t * nd_sop;   /* Socket backptr. for RAW stuff */
	struct netdev   * nd_next;  /* Link to next similar device */
	dsu	    nd_dsu;     /* Device board specific union */
#ifdef IGMP_PROTOCOL
	addr_list	nd_multiaddr;  /* pointer to multicast addr. list */
    u16     nd_mcast_addr_count;  /* Number of addresses in the list.  May be used
                                  by the driver to know when to enable/disable 
                                  reception of multicast packets.
                                */
   	u8	    v1_router_present; /* Set to true (1) if a v1 router is present */
	tcb		*v1_router_tcb;	   /* TCB for v1 router present timeout */
#endif
#ifdef AUTO_IPV4_CONF
    void    *auto_ipv4_cookie; /* Private (state etc.) info for Auto IPv4 link-local
                                  address configuration finite state machine.
                                */
    u32     link_local_addr;    /* The link-local address assigned by automatic
                                   IPv4 link-local address configuration.
                                   Only one interface at any time will have a 
                                   non-zero link-local IPv4 address. 
                                */
#endif

#ifdef RARP_CLIENT
   fns_rarp_callback    nd_rarp_callback;     /* If this is not null then we're doing RARP 
                                                  on this interface.  That is, we are awaiting 
                                                  a response to a RARP request for an IP 
                                                  address for the interface.
                                                */
    tcb     nd_rarp_tcb;      /* The tcb for the RARP timeout */
    u8      nd_rarp_rexint;   /* RARP retransmit interval in seconds */
    u8      nd_rarp_sent;     /* Counts sent packets but main use is to dither the 
                                 rex timer so all boxes booting at once won't send
                                 out RARP packets at the same exact time.
                               */
    void *nd_rarp_user_handle;
#endif

#ifdef PING_ARP
    fns_ping_arp_callback nd_ping_arp_callback;  /* If nonzero then we're doing ping ARP
                                                    on the interface.
                                                 */
    void *nd_ping_arp_user_handle;
    int nd_ping_arp_ipas_index;                  /* Ping ARP interface alias IP addr index */ 
#endif

#ifdef BOOTP_CLIENT_PROTOCOL
	void                  *bp_context;           /* If non-zero, the BOOTP context for
												    this interface */
#endif
#ifdef DHCP
	void                  *dh_context;           /* If non-zero, the DHCP context for
												    this interface */
	void				  *dh_old_context;       /* Context which application has "stopped"
												    waiting for DHCP state machine to free
													it */
#endif
    q                     nd_addr_probe_q;      /* Queue of addresses on which we're doing
                                                    ARP probes.  
                                                 */
    addr_conflict_cb nd_dup_addr_cb;             /* Callback registered with ll_probe_addr
                                                    is called when a duplicate address is
                                                    detected for this address.  
                                                  */
} netdev;

/* This macro is used to iterate through the active addresses in
   a device table entry, i.e., the nd_ipas[] array entries configured
   with an address.  A macro is used so that if the representation
   is changed later (e.g. from an array to a linked list perhaps)
   it might be easier to make the transition.  We expect that 
   ND_MAX_IPAS will be quite small (typically 2) and therefore the
   overhead of a linked list walk is likely worse than the overhead
   of setting up a simple for loop and the possibility of there
   being holes in the array which cause unecessary iterations.
*/

#define FOR_ACTIVE_ADDRESSES(xxxndp, x_for_dev_i ) { \
    for( x_for_dev_i = 0; x_for_dev_i < ND_MAX_IPAS; x_for_dev_i++ ) { \
        if(!(xxxndp->nd_ipas[x_for_dev_i].nd_ipflags & F_N_IPV4ADDR_SET)) continue; \

#define END_FOR_ACTIVE_ADDRESSES }}

/* This macro is used to iterate thru the devices of the device table,
   without the code doing the iterating being concerned with whether 
   or not the device table is stored as an array or linked list or
   whatever.
*/
#define FOR_DEVICE_TABLE_ENTRIES( dev_ptr ) { \
	extern netdev **ndp_tbl; \
	netdev **ndpp; \
    for (ndpp = ndp_tbl; ( (dev_ptr = *ndpp) != (netdev *) 0 ); ndpp++ ) { 

#define END_FOR_DEVICE_TABLE_ENTRIES }}


/* Macros for devtable.h used to enter OEM specific required values into
 * the device table for each device.
 */
#define NIL_DEV_NAME   " "

#define  DEV_ADDRESS_FAMILY 0 /* Just a place holder for clarity */


int loopback_driver_init (struct netdev * ndp);
int loopback_driver_updown(struct netdev * ndp, u16 flags, char * options);
int loopback_driver_ioctl(struct netdev * ndp, int cmnd, char * addr);
st  loopback_driver_send (struct m * mp);
int loopback_driver_start (struct m * mp);

export int  noent_updown(struct netdev * ndp, u16 flags, char * cp);
export st   noent_send(struct m * mp);
export int  noent_start(struct m * mp);
export int  noent_ioctl(struct netdev * ndp, int cmnd, char * addr);


#ifndef MAX_RUNTIME_DEVICES
#ifdef PPPOE_PROTOCOL
#define MAX_RUNTIME_DEVICES     16  /* PPPoE default = 16 extra devices */
#else
#define MAX_RUNTIME_DEVICES     4   /* non PPPoE default = 4 */
#endif
#endif

/* Just to keep example in table from compiling */
#define  FNS_DEVICE_TABLE_TEMPLATE_ENTRY( a )        

#define  FNS_STR_DEV_NAME(a)                    a, 
#define  FNS_U16_DEV_MINOR_ID(a)                (u16)a,
#define  FNS_U16_DEV_XFLAGS(a)                  (u16)a, 
#define  FNS_U32_DEV_OEM_FIELD1(a)              (u32)a, 
#define  FNS_U32_DEV_OEM_FIELD2(a)              (u32)a, 
#define  FNS_U32_DEV_OEM_FIELD3(a)              (u32)a, 
#define  FNS_U32_DEV_OEM_FIELD4(a)              (u32)a,
#ifdef __FUSION_NCDEV_C__
#define  FNS_U16_DEV_ADDRESS_FAMILY(a)          {a, 0},
#else
#define  FNS_U16_DEV_ADDRESS_FAMILY(a)          (u16)a,
#endif
#define  FNS_FPTR_DEV_INIT(a)                   a,
#define  FNS_FPTR_DEV_UPDOWN(a)                 a,
#define  FNS_FPTR_DEV_SEND(a)                   a,
#define  FNS_FPTR_DEV_TX_START(a)               a,
#define  FNS_FPTR_DEV_IOCTL(a)                  a,

#ifdef __FUSION_NCDEV_C__

/* The device table only compiles into ncdev.c */

/* See note above regarding BEGIN_FUSION_DEVICE_TABLE and END_FUSION_DEVICE_TABLE macros.
*/

#define  FUSION_DEVICE_TABLE(a) export netdev ndevsw[] = { \
{"im", 0, 0, 0, 0, 0, 0, {AF_INTRA,0}, noent_init, noent_updown, im_send, noent_start, noent_ioctl }, \
{"lo", 0, 0, 0, 0, 0, 0, {AF_LOOPBACK}, loopback_driver_init, loopback_driver_updown, \
  loopback_driver_send, loopback_driver_start, loopback_driver_ioctl}, \
  a \
};

#define  BEGIN_FUSION_DEVICE_TABLE export netdev ndevsw[] = { \
    {"im", 0, 0, 0, 0, 0, 0, {AF_INTRA,0}, noent_init, noent_updown, im_send, noent_start, noent_ioctl }, \
	{"lo", 0, 0, 0, 0, 0, 0, {AF_LOOPBACK}, loopback_driver_init, loopback_driver_updown, \
		loopback_driver_send, loopback_driver_start, loopback_driver_ioctl}, \


/* END_FUSION_DEVICE_TABLE */
#define END_FUSION_DEVICE_TABLE	};


/* NOTE:  As discussed above, the following macros are considered deprecated.
          See the new devtable.hhh.
*/

#ifdef SLIP_PROTOCOL 
#define FUSION_GENERIC_SLIP_DEVICE_ENTRY(a) {a},
#else
#define FUSION_GENERIC_SLIP_DEVICE_ENTRY(a) 
#endif

#ifdef PPP_PROTOCOL 
#define FUSION_GENERIC_PPP_DEVICE_ENTRY(a) {a},
#else
#define FUSION_GENERIC_PPP_DEVICE_ENTRY(a) 
#endif

#ifdef ETHER_PROTOCOL 
#define FUSION_GENERIC_ETHER_DEVICE_ENTRY(a) {a},
#else
#define FUSION_GENERIC_ETHER_DEVICE_ENTRY(a) 
#endif

/* Generic entry for devices other than Ethernet, SLIP, and PPP 
   NOTE:  As discussed above, the following macros are considered deprecated.
          See the new devtable.hhh.
*/

#define  FUSION_DEVICE_TABLE_ENTRY(a) {a}, 

#define  BEGIN_FUSION_DEVICE_TABLE_ENTRY {
#define  END_FUSION_DEVICE_TABLE_ENTRY },

#endif /* __FUSION_NCDEV_C__ */
#ifdef __cplusplus
}
#endif
#endif /* _NETDEV_ */
