/* **********************************************************
 * Copyright (C) 1998-2000 VMware, Inc.
 * All Rights Reserved
 * **********************************************************/

#ifndef _VNETINT_H
#define _VNETINT_H

#ifdef KERNEL_2_1
#  define EXPORT_SYMTAB
#  ifndef __KERNEL__
#    define __KERNEL__
#  endif
#  define memcpy_fromfs	copy_from_user
#  define memcpy_tofs	copy_to_user
#  define KFREE_SKB(skb, type)		kfree_skb(skb)
#  define DEV_KFREE_SKB(skb, type)	dev_kfree_skb(skb)
#  define SKB_INCREF(skb)		atomic_inc(&(skb)->users)
#  define SKB_IS_CLONE_OF(clone, skb)	( \
      skb_datarefp(clone) == skb_datarefp(skb) \
   )
#  define SK_ALLOC(pri)			sk_alloc(0, pri, 1)
#  define DEV_QUEUE_XMIT(skb, dev, pri)	( \
      (skb)->dev = (dev), \
      (skb)->priority = (pri), \
      (skb)->mac.raw = (skb)->data, \
      (skb)->nh.raw = (skb)->data + sizeof (struct ethhdr), \
      dev_queue_xmit(skb) \
   )
/* pjh NOTE dev_queue_xmit is a kernel function--this is what
 * actually sends the skb onto the ethernet  */
#ifdef KERNEL_2_3_15
#  define dev_lock_list()		read_lock(&dev_base_lock)
#  define dev_unlock_list()		read_unlock(&dev_base_lock)
#  define DEV_GET(x)                    __dev_get_by_name(x)
#  define device			net_device
#else
#  define DEV_GET(x)			dev_get(x)
#endif
#  define DEV_LOCK_LIST()		dev_lock_list()
#  define DEV_UNLOCK_LIST()		dev_unlock_list()
#else
#  define KFREE_SKB(skb, type)		kfree_skb(skb, type)
#  define DEV_KFREE_SKB(skb, type)	dev_kfree_skb(skb, type)
#  define SKB_INCREF(skb)		atomic_inc(&(skb)->count)
#  define SKB_IS_CLONE_OF(clone, skb)	( \
      (clone)->data_skb != NULL && \
      ((clone)->data_skb == (skb) || (clone)->data_skb == (skb)->data_skb) \
   )
#  define SK_ALLOC(pri)			sk_alloc(pri)
#  define DEV_QUEUE_XMIT(skb, dev, pri)	dev_queue_xmit(skb, dev, pri)
#  define DEV_GET(x)			dev_get(x)
#  define DEV_LOCK_LIST()		// dev_lockct missing from ksyms
#  define DEV_UNLOCK_LIST()		// dev_lockct missing from ksyms
#endif

#define INLINE inline

     
/* 
 * Logging
 */

#ifdef notdef
#ifdef VMX86_RELEASE
#define LOGLEVEL 0
#else
#define LOGLEVEL 1
#endif
#endif
     
#define LOGLEVEL 1

#if LOGLEVEL >= 0
#define LOG(level, args) ((void) (LOGLEVEL >= (level) ? (printk args) : 0))
#else
#define LOG(level, args)
#endif

#define MAX(_a, _b)   (((_a) > (_b)) ? (_a) : (_b))

/*
 * Ethernet
 */

#define MAC_EQ(_a, _b)         !memcmp((_a), (_b), ETH_ALEN)
#define SKB_2_DESTMAC(_skb)    (((struct ethhdr *)(_skb)->data)->h_dest)
#define SKB_2_SRCMAC(_skb)     (((struct ethhdr *)(_skb)->data)->h_source)
#define UP_AND_RUNNING(_flags) (((_flags) & (IFF_RUNNING|IFF_UP)) == \
				(IFF_RUNNING|IFF_UP))
#ifdef KERNEL_2_3_47
#define NETDEV_UP_AND_RUNNING(dev) ((((dev)->flags) & IFF_UP) && netif_running(dev))
#else
#ifdef KERNEL_2_3_43
#define NETDEV_UP_AND_RUNNING(dev) ((((dev)->flags) & IFF_UP) && test_bit(LINK_STATE_START, &(dev)->state))
#else
#define NETDEV_UP_AND_RUNNING(dev) UP_AND_RUNNING((dev)->flags)
#endif
#endif

/*
 * Types
 */

typedef u_char uint8;
typedef u_short uint16;
typedef u_long uint32;
typedef long int32;
typedef char Bool;

#define TRUE  1
#define FALSE 0


/*
 * Fundamental sizes
 */

#define VNET_NUM_VNETS         256
#define VNET_MAJOR_NUMBER      119

#define VNET_NUM_HUBS          VNET_NUM_VNETS
#define NUM_JACKS_PER_HUB      16
#define VNET_MAX_QLEN          32

#define VNET_NUM_IPBASED_MACS  64
#define VNET_MAX_JACK_NAME_LEN 16


/*
 * Data structures
 */

typedef struct proc_dir_entry VNetProcEntry;

typedef struct VNetJack VNetJack;
typedef struct VNetPort VNetPort;
typedef struct VNetJackStats VNetJackStats;


/*
 * Record statistics about packets through this jack.
 */

struct VNetJackStats {
   unsigned  rxPackets;
   unsigned  txPackets;
};


/*
 *  The jack is the basic mechanism for connecting to objects
 *  that send packet between them.
 */

struct VNetJack {
   VNetJack      *peer;
   int            numPorts;
   char           name[VNET_MAX_JACK_NAME_LEN];
   void          *private;     // private field for containing object
   int            index;       // private field for containing object
   VNetProcEntry *procEntry;   // private field for containing object
   
   void         (*free)(VNetJack *this);
   void         (*rcv)(VNetJack *this, struct sk_buff *skb);
   Bool         (*cycleDetect)(VNetJack *this, int generation);
   void         (*portsChanged)(VNetJack *this);
   int          (*isBridged)(VNetJack *this);
};


/*
 *  The port is an extention of the jack. It has a user level
 *  interface and an ethernet address. There are 3 types of ports:
 *  userif, netif, and bridge.
 */

struct VNetPort {
   VNetJack    jack;     // must be first
   unsigned    id;
   uint32      flags;
   uint8       paddr[ETH_ALEN];
   uint8       ladrf[8];
   
   VNetPort   *next;
   
   int       (*fileOpRead)(VNetPort *this, struct file *filp,
                           char *buf, size_t count);
   int       (*fileOpWrite)(VNetPort *this, struct file *filp,
                            const char *buf, size_t count);
   int       (*fileOpIoctl)(VNetPort *this, struct file *filp,
                            unsigned int iocmd, unsigned long ioarg);   
#ifdef KERNEL_2_1
   int       (*fileOpPoll)(VNetPort *this, struct file *filp,
                           poll_table *wait);
#else
   int       (*fileOpSelect)(VNetPort *this, struct file *filp,
                             int sel_type, select_table *wait);
#endif
};



/*
 *  Functions exported from vnet module
 */

typedef int (*VNetIoctlHandler)(void *clientData,
                                VNetPort *this,
                                struct file *filp,
                                int iocmd,
                                unsigned long ioarg);

int  VNet_RegisterIoctlHandler(int ioctlNum,
                               VNetIoctlHandler handler,
                               void *clientData);
void VNet_UnregisterIoctlHandler(int ioctlNum);

VNetJack *VNetHub_Alloc(int hubNum);

int VNetConnect(VNetJack *jack1, VNetJack *jack2);

VNetJack *VNetDisconnect(VNetJack *jack);

void VNetSend(VNetJack *jack, struct sk_buff *skb);

int VNetProc_MakeEntry(VNetProcEntry *parent, char *name, int mode,
                       VNetProcEntry **ret);

void VNetProc_RemoveEntry(VNetProcEntry *node, VNetProcEntry *parent);

int VNetPrintJack(VNetJack *jack, char *buf);

     
/*
 *  Utility functions
 */

extern uint8 AllMultiFilter[8];

Bool VNetPacketMatch(uint8 *destAddr, uint8 *ifAddr, uint8 *ladrf, uint32 flags);

Bool VNetCycleDetectIf(char *name, int generation);

void VNetIncrModCount(int delta);

int VNetPrintPort(VNetPort *port, char *buf);


/*
 *  Procfs file system
 */

extern int VNetProc_Init(void);

extern void VNetProc_Cleanup(void);


/*
 *----------------------------------------------------------------------
 *
 * VNetCycleDetect --
 *
 *      Perform the cycle detect alogorithm for this generation.
 *
 * Results: 
 *      TRUE if a cycle was detected, FALSE otherwise.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static INLINE Bool
VNetCycleDetect(VNetJack *jack,
                int       generation)
{
   if (jack && jack->cycleDetect) {
      return jack->cycleDetect(jack, generation);
   }

   return FALSE;
}


/*
 *----------------------------------------------------------------------
 *
 * VNetPortsChanged --
 *
 *      Notify a jack that the number of connected ports has changed.
 *
 * Results: 
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static INLINE void
VNetPortsChanged(VNetJack *jack)
{
   if (jack && jack->portsChanged) {
      jack->portsChanged(jack);
   }
}


/*
 *----------------------------------------------------------------------
 *
 * VNetIsBridged --
 *
 *      Check whether we are bridged.
 *
 * Results:
 *      0 - not bridged
 *      1 - we are bridged but the interface is down
 *      2 - we are bridged and the interface is up
 *      3 - some bridges are down
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static INLINE int
VNetIsBridged(VNetJack *jack)
{
   if (jack && jack->peer && jack->peer->isBridged) {
      return jack->peer->isBridged(jack->peer);
   }

   return 0;
}


/*
 *----------------------------------------------------------------------
 *
 * VNetFree --
 *
 *      Free the resources owned by the jack.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static INLINE void
VNetFree(VNetJack *jack)
{
   if (jack && jack->free) {
      jack->free(jack);
   }
}


/*
 *----------------------------------------------------------------------
 *
 * VNetGetAttachedPorts --
 *
 *      Get the number of ports attached to this jack through its peer.
 *
 * Results:
 *      The number of attached ports to this jack through its peer.
 *
 * Side effects:
 *      None.
 *
 *----------------------------------------------------------------------
 */

static INLINE int
VNetGetAttachedPorts(VNetJack *jack)
{
   if (!jack) {
      // assert failed
      return 0;
   }

   if (!jack->peer) {
      return 0;
   }

   return jack->peer->numPorts;
}


#endif
