diff -u --recursive --new-file linux-1.2.2/arch/i386/config.in linux/arch/i386/config.in
--- linux-1.2.2/arch/i386/config.in	Tue Mar  7 09:25:26 1995
+++ linux/arch/i386/config.in	Fri Mar 31 23:05:10 1995
@@ -119,6 +119,7 @@
 fi
 bool 'PPP (point-to-point) support' CONFIG_PPP n
 bool 'PLIP (parallel port) support' CONFIG_PLIP n
+bool 'EQL (serial line load balancing) support' CONFIG_EQUALIZER y
 bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
 bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
 if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
diff -u --recursive --new-file linux-1.2.2/drivers/net/Makefile linux/drivers/net/Makefile
--- linux-1.2.2/drivers/net/Makefile	Thu Feb 23 06:51:27 1995
+++ linux/drivers/net/Makefile	Fri Mar 31 23:05:10 1995
@@ -254,6 +254,10 @@
 MODULES := 8390.o $(MODULES)
 endif
 
+ifdef CONFIG_EQUALIZER
+NETDRV_OBJS := $(NETDRV_OBJS) eql.o
+endif
+
 net.a: $(NETDRV_OBJS)
 	rm -f net.a
 	$(AR) rcs net.a $(NETDRV_OBJS)
diff -u --recursive --new-file linux-1.2.2/drivers/net/Space.c linux/drivers/net/Space.c
--- linux-1.2.2/drivers/net/Space.c	Sun Mar 26 02:49:58 1995
+++ linux/drivers/net/Space.c	Fri Mar 31 23:05:10 1995
@@ -309,6 +309,22 @@
 #   define	NEXT_DEV	(&dummy_dev)
 #endif
 
+#ifdef CONFIG_EQUALIZER
+extern int eql_init(struct device *dev);
+struct device eql_dev = {
+  "eql",			/* Master device for IP traffic load 
+				   balancing */
+  0x0, 0x0, 0x0, 0x0,		/* recv end/start; mem end/start */
+  0,				/* base I/O address */
+  0,				/* IRQ */
+  0, 0, 0,			/* flags */
+  NEXT_DEV,			/* next device */
+  eql_init			/* set up the rest */
+};
+#   undef       NEXT_DEV
+#   define      NEXT_DEV        (&eql_dev)
+#endif
+
 extern int loopback_init(struct device *dev);
 struct device loopback_dev = {
 	"lo",			/* Software Loopback interface		*/
diff -u --recursive --new-file linux-1.2.2/drivers/net/eql.c linux/drivers/net/eql.c
--- linux-1.2.2/drivers/net/eql.c	Wed Dec 31 19:00:00 1969
+++ linux/drivers/net/eql.c	Fri Mar 31 23:15:11 1995
@@ -0,0 +1,1168 @@
+/*
+ * Equalizer Load-balancer for serial network interfaces.
+ *
+ * (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Mangement, Inc.
+ *
+ *
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
+ * 
+ * The author may be reached as simon@ncm.com, or C/O
+ *    NCM
+ *    Attn: Simon Janes
+ *    6803 Whittier Ave
+ *    McLean VA 22101
+ *    Phone: 1-703-847-0040 ext 103
+ */
+
+static char *version = 
+	"EQL Multilink Driver: $Revision: 1.2 $ $Date: 1995/03/25 18:16:32 $ Simon Janes (simon@ncm.com)\n";
+
+#include <linux/config.h>
+
+/*
+ * Sources:
+ *   skeleton.c by Donald Becker.
+ * Inspirations:
+ *   The Harried and Overworked Alan Cox
+ * Conspiracies:
+ *   The Alan Cox and Arisian plot to get someone else to do the code, which
+ *   turned out to be me.
+ */
+
+/*
+ * $Log: eql.c,v $
+ * Revision 1.2  1995/03/25  18:16:32  guru
+ * Will have to make this the 4.0 branch
+ *
+ * Revision 1.1  1995/03/25  18:14:05  guru
+ * Initial revision
+ *
+ * Revision 3.11  1995/01/19  23:14:31  guru
+ * 		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued * 8;
+ *
+ * Revision 3.10  1995/01/19  23:07:53  guru
+ * back to
+ * 		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued;
+ *
+ * Revision 3.9  1995/01/19  22:38:20  guru
+ * 		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued * 4;
+ *
+ * Revision 3.8  1995/01/19  22:30:55  guru
+ *       slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued * 2;
+ *
+ * Revision 3.7  1995/01/19  21:52:35  guru
+ * printk's trimmed out.
+ *
+ * Revision 3.6  1995/01/19  21:49:56  guru
+ * This is working pretty well. I gained 1 K/s in speed.. now its just
+ * robustness and printk's to be diked out.
+ *
+ * Revision 3.5  1995/01/18  22:29:59  guru
+ * still crashes the kernel when the lock_wait thing is woken up.
+ *
+ * Revision 3.4  1995/01/18  21:59:47  guru
+ * Broken set-bit locking snapshot
+ *
+ * Revision 3.3  1995/01/17  22:09:18  guru
+ * infinite sleep in a lock somewhere..
+ *
+ * Revision 3.2  1995/01/15  16:46:06  guru
+ * Log trimmed of non-pertinant 1.x branch messages
+ *
+ * Revision 3.1  1995/01/15  14:41:45  guru
+ * New Scheduler and timer stuff...
+ *
+ * Revision 1.15  1995/01/15  14:29:02  guru
+ * Will make 1.14 (now 1.15) the 3.0 branch, and the 1.12 the 2.0 branch, the one
+ * with the dumber scheduler
+ *
+ * Revision 1.14  1995/01/15  02:37:08  guru
+ * shock.. the kept-new-versions could have zonked working
+ * stuff.. shudder
+ *
+ * Revision 1.13  1995/01/15  02:36:31  guru
+ * big changes
+ *
+ * 	scheduler was torn out and replaced with something smarter
+ *
+ * 	global names not prefixed with eql_ were renamed to protect
+ * 	against namespace collisions
+ *
+ * 	a few more abstract interfaces were added to facilitate any
+ * 	potential change of datastructure.  the driver is still using
+ * 	a linked list of slaves.  going to a heap would be a bit of
+ * 	an overkill.
+ *
+ * 	this compiles fine with no warnings.
+ *
+ * 	the locking mechanism and timer stuff must be written however,
+ * 	this version will not work otherwise
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>              
+
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/timer.h>
+
+#include "eql.h"
+
+#ifndef EQL_DEBUG
+/* #undef EQL_DEBUG      -* print nothing at all, not even a boot-banner */
+/* #define EQL_DEBUG 1   -* print only the boot-banner */
+/* #define EQL_DEBUG 5   -* print major function entries */
+/* #define EQL_DEBUG 20  -* print subfunction entries */
+/* #define EQL_DEBUG 50  -* print utility entries */
+/* #define EQL_DEBUG 100 -* print voluminous function entries */
+#define EQL_DEBUG 1
+#endif
+static unsigned int eql_debug = EQL_DEBUG;
+
+int        eql_init(struct device *dev); /*  */
+static int eql_open(struct device *dev); /*  */
+static int eql_close(struct device *dev); /*  */
+static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd); /*  */
+static int eql_slave_xmit(struct sk_buff *skb, struct device *dev); /*  */
+
+static struct enet_statistics *eql_get_stats(struct device *dev); /*  */
+static int eql_header(unsigned char *buff, struct device *dev, 
+		      unsigned short type, void *daddr, void *saddr, 
+		      unsigned len, struct sk_buff *skb); /*  */
+static int eql_rebuild_header(void *buff, struct device *dev, 
+			      unsigned long raddr, struct sk_buff *skb); /*  */
+static unsigned short eql_type_trans (struct sk_buff *skb, 
+				      struct device *dev);	/*  */
+
+/* ioctl() handlers
+   ---------------- */
+static int eql_enslave(struct device *dev,  slaving_request_t *srq); /*  */
+static int eql_emancipate(struct device *dev, slaving_request_t *srq); /*  */
+
+static int eql_g_slave_cfg(struct device *dev, slave_config_t *sc); /*  */
+static int eql_s_slave_cfg(struct device *dev, slave_config_t *sc); /*  */
+
+static int eql_g_master_cfg(struct device *dev, master_config_t *mc); /*  */
+static int eql_s_master_cfg(struct device *dev, master_config_t *mc); /*  */
+
+static inline int eql_is_slave(struct device *dev); /*  */
+static inline int eql_is_master(struct device *dev); /*  */
+
+static slave_t *eql_new_slave(void); /*  */
+static void eql_delete_slave(slave_t *slave); /*  */
+
+/* static long eql_slave_priority(slave_t *slave); -*  */
+static inline int eql_number_slaves(slave_queue_t *queue); /*  */
+
+static inline int eql_is_empty(slave_queue_t *queue); /*  */
+static inline int eql_is_full(slave_queue_t *queue); /*  */
+
+static slave_queue_t *eql_new_slave_queue(struct device *dev); /*  */
+static void eql_delete_slave_queue(slave_queue_t *queue); /*  */
+
+static int eql_insert_slave(slave_queue_t *queue, slave_t *slave); /*  */
+static slave_t *eql_remove_slave(slave_queue_t *queue, slave_t *slave); /*  */
+
+/* static int eql_insert_slave_dev(slave_queue_t *queue, struct device *dev); -*  */
+static int eql_remove_slave_dev(slave_queue_t *queue, struct device *dev); /*  */
+
+static inline struct device *eql_best_slave_dev(slave_queue_t *queue); /*  */
+static inline slave_t *eql_best_slave(slave_queue_t *queue); /*  */
+static inline slave_t *eql_first_slave(slave_queue_t *queue); /*  */
+static inline slave_t *eql_next_slave(slave_queue_t *queue, slave_t *slave); /*  */
+
+static inline void eql_set_best_slave(slave_queue_t *queue, slave_t *slave); /*  */
+static inline void eql_schedule_slaves(slave_queue_t *queue); /*  */
+
+static slave_t *eql_find_slave_dev(slave_queue_t *queue, struct device *dev); /*  */
+
+/* static inline eql_lock_slave_queue(slave_queue_t *queue); -*  */
+/* static inline eql_unlock_slave_queue(slave_queue_t *queue); -*  */
+
+static void eql_timer(unsigned long param);	/*  */
+
+/* struct device * interface functions 
+   ---------------------------------------------------------
+   */
+
+int
+eql_init(struct device *dev)
+{
+  static unsigned version_printed = 0;
+  /* static unsigned num_masters     = 0; */
+  equalizer_t *eql = 0;
+  int i;
+
+  if ( version_printed++ == 0 && eql_debug > 0)
+    printk(version);
+
+  /* Initialize the device structure. */
+  dev->priv = kmalloc (sizeof (equalizer_t), GFP_KERNEL);
+  memset (dev->priv, 0, sizeof (equalizer_t));
+  eql = (equalizer_t *) dev->priv;
+
+  eql->stats = kmalloc (sizeof (struct enet_statistics), GFP_KERNEL);
+  memset (eql->stats, 0, sizeof (struct enet_statistics));
+
+  init_timer (&eql->timer);
+  eql->timer.data     = (unsigned long) dev->priv;
+  eql->timer.expires  = EQL_DEFAULT_RESCHED_IVAL;
+  eql->timer.function = &eql_timer;
+  eql->timer_on       = 0;
+
+  dev->open		= eql_open;
+  dev->stop		= eql_close;
+  dev->do_ioctl         = eql_ioctl;
+  dev->hard_start_xmit  = eql_slave_xmit;
+  dev->get_stats	= eql_get_stats;
+  
+  /* Fill in the fields of the device structure with ethernet-generic values.
+     This should be in a common file instead of per-driver.  */
+
+  for (i = 0; i < DEV_NUMBUFFS; i++)
+    skb_queue_head_init(&dev->buffs[i]);
+
+  dev->hard_header    = eql_header; 
+  dev->rebuild_header = eql_rebuild_header;
+  dev->type_trans     = eql_type_trans;
+
+  /* now we undo some of the things that eth_setup does that we don't like */
+  dev->mtu        = EQL_DEFAULT_MTU;	/* set to 576 in eql.h */
+  dev->flags      = IFF_MASTER;
+
+  dev->family     = AF_INET;
+  dev->pa_addr    = 0;
+  dev->pa_brdaddr = 0;
+  dev->pa_mask    = 0;
+  dev->pa_alen    = sizeof (unsigned long);
+
+  dev->type       = ARPHRD_SLIP;
+
+  return 0;
+}
+
+
+static
+int
+eql_open(struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+  slave_queue_t *new_queue;
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 5)
+    printk ("%s: open\n", dev->name);
+#endif
+
+   new_queue = eql_new_slave_queue (dev);
+    
+    if (new_queue != 0)
+      {
+	new_queue->master_dev = dev;
+	eql->queue = new_queue;
+	eql->queue->lock = 0;
+	eql->min_slaves = 1;
+	eql->max_slaves = EQL_DEFAULT_MAX_SLAVES; /* 4 usually... */
+
+	eql->timer_on = 1;
+	add_timer (&eql->timer);
+
+	return 0;
+      }
+  return 1;
+}
+
+
+static
+int
+eql_close(struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+
+#ifdef EQL_DEBUG
+  if ( eql_debug >= 5)
+    printk ("%s: close\n", dev->name);
+#endif
+  /* The timer has to be stopped first before we start hacking away
+     at the data structure it scans every so often... */
+  printk ("%s: stopping timer\n", dev->name);
+  eql->timer_on = 0;
+  del_timer (&eql->timer);
+
+  eql_delete_slave_queue (eql->queue);
+
+  return 0;
+}
+
+
+static
+int
+eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{  
+  switch (cmd)
+    {
+    case EQL_ENSLAVE:
+      return eql_enslave (dev, (slaving_request_t *) ifr->ifr_data);
+    case EQL_EMANCIPATE:
+      return eql_emancipate (dev, (slaving_request_t *) ifr->ifr_data);
+
+    case EQL_GETSLAVECFG:
+      return eql_g_slave_cfg (dev, (slave_config_t *) ifr->ifr_data);
+    case EQL_SETSLAVECFG:
+      return eql_s_slave_cfg (dev, (slave_config_t *) ifr->ifr_data);
+
+    case EQL_GETMASTRCFG:
+      return eql_g_master_cfg (dev, (master_config_t *) ifr->ifr_data);
+    case EQL_SETMASTRCFG:
+      return eql_s_master_cfg (dev, (master_config_t *) ifr->ifr_data);
+
+    default:
+      return -EOPNOTSUPP;
+    }
+}
+
+
+static
+int
+eql_slave_xmit(struct sk_buff *skb, struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+  struct device *slave_dev = 0;
+  slave_t *slave;
+
+  if (skb == NULL)
+    {
+      return 0;
+    }
+
+  eql_schedule_slaves (eql->queue);
+  
+  slave_dev = eql_best_slave_dev (eql->queue);
+  slave = eql_best_slave (eql->queue); 
+
+  if ( slave_dev != 0 )
+    {
+#ifdef EQL_DEBUG
+      if (eql_debug >= 100)
+	printk ("%s: %d slaves xmitng %ld B %s\n", 
+		dev->name, eql_number_slaves (eql->queue), skb->len,
+		slave_dev->name);
+#endif
+      
+      dev_queue_xmit (skb, slave_dev, 1);
+      eql->stats->tx_packets++;
+      slave->bytes_queued += skb->len; 
+    }
+  else
+    {
+      /* The alternative for this is the return 1 and have
+         dev_queue_xmit just queue it up on the eql's queue. */
+
+      eql->stats->tx_dropped++;
+      dev_kfree_skb(skb, FREE_WRITE);
+    }	  
+  return 0;
+}
+
+
+static
+struct enet_statistics *
+eql_get_stats(struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+
+  return eql->stats;
+}
+
+
+static 
+int 
+eql_header(unsigned char *buff, struct device *dev, 
+	   unsigned short type, void *daddr, void *saddr, 
+	   unsigned len, struct sk_buff *skb)
+{
+  return 0;
+}
+
+
+static 
+int 
+eql_rebuild_header(void *buff, struct device *dev, 
+		   unsigned long raddr, struct sk_buff *skb)
+{
+  return 0;
+}
+
+
+static
+unsigned short 
+eql_type_trans (struct sk_buff *skb, struct device *dev)
+{
+  return htons (ETH_P_IP);
+}
+
+
+/* private ioctl functions
+   -----------------------------------------------------------------
+   */
+
+static int 
+eql_enslave(struct device *dev, slaving_request_t *srqp)
+{
+  struct device *master_dev;
+  struct device *slave_dev;
+  slaving_request_t srq;
+
+  if (! suser ())
+    return -EPERM;
+
+  memcpy_fromfs (&srq, srqp, sizeof (slaving_request_t));
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: enslave '%s' %ld bps\n", dev->name, 
+	    srq.slave_name, srq.priority);
+#endif
+  
+  master_dev = dev;		/* for "clarity" */
+  slave_dev  = dev_get (srq.slave_name);
+
+  if (master_dev != 0 && slave_dev != 0)
+    {
+      if (! eql_is_master (slave_dev)  &&   /* slave is not a master */
+	  ! eql_is_slave (slave_dev)      ) /* slave is not already a slave */
+	{
+	  slave_t *s = eql_new_slave ();
+	  equalizer_t *eql = (equalizer_t *) master_dev->priv;
+
+	  s->dev = slave_dev;
+	  s->priority = srq.priority;
+	  s->priority_bps = srq.priority;
+	  s->priority_Bps = srq.priority / 8;
+
+	  slave_dev->flags |= IFF_SLAVE;
+
+	  eql_insert_slave (eql->queue, s);
+
+	  return 0;
+	}
+      return -EINVAL;
+    }
+  return -EINVAL;
+}
+
+
+
+static 
+int 
+eql_emancipate(struct device *dev, slaving_request_t *srqp)
+{
+  struct device *master_dev;
+  struct device *slave_dev;
+  slaving_request_t srq;
+
+  if (! suser ())
+    return -EPERM;
+
+  memcpy_fromfs (&srq, srqp, sizeof (slaving_request_t));
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name);
+#endif
+
+
+  master_dev = dev;		/* for "clarity" */
+  slave_dev  = dev_get (srq.slave_name);
+
+  if ( eql_is_slave (slave_dev) )	/* really is a slave */
+    {
+      equalizer_t *eql = (equalizer_t *) master_dev->priv;
+      slave_dev->flags = slave_dev->flags & ~IFF_SLAVE;
+
+      eql_remove_slave_dev (eql->queue, slave_dev);
+
+      return 0;
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_g_slave_cfg(struct device *dev, slave_config_t *scp)
+{
+  slave_t *slave;
+  equalizer_t *eql;
+  struct device *slave_dev;
+  slave_config_t sc;
+
+  memcpy_fromfs (&sc, scp, sizeof (slave_config_t));
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name);
+#endif
+
+  eql = (equalizer_t *) dev->priv;
+  slave_dev = dev_get (sc.slave_name);
+
+  if ( eql_is_slave (slave_dev) )
+    {
+      slave = eql_find_slave_dev (eql->queue,  slave_dev);
+      if (slave != 0)
+	{
+	  sc.priority = slave->priority;
+	  memcpy_tofs (scp, &sc, sizeof (slave_config_t));
+	  return 0;
+	}
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_s_slave_cfg(struct device *dev, slave_config_t *scp)
+{
+  slave_t *slave;
+  equalizer_t *eql;
+  struct device *slave_dev;
+  slave_config_t sc;
+
+  if (! suser ())
+    return -EPERM;
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: set config for slave `%s'\n", dev->name, sc.slave_name);
+#endif
+  
+  memcpy_fromfs (&sc, scp, sizeof (slave_config_t));
+
+  eql = (equalizer_t *) dev->priv;
+  slave_dev = dev_get (sc.slave_name);
+
+  if ( eql_is_slave (slave_dev) )
+    {
+      slave = eql_find_slave_dev (eql->queue, slave_dev);
+      if (slave != 0)
+	{
+	  slave->priority = sc.priority;
+	  slave->priority_bps = sc.priority;
+	  slave->priority_Bps = sc.priority / 8;
+	  return 0;
+	}
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_g_master_cfg(struct device *dev, master_config_t *mcp)
+{
+  equalizer_t *eql;
+  master_config_t mc;
+
+#if EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: get master config\n", dev->name);
+#endif
+
+  if ( eql_is_master (dev) )
+    {
+      eql = (equalizer_t *) dev->priv;
+      mc.max_slaves = eql->max_slaves;
+      mc.min_slaves = eql->min_slaves;
+      memcpy_tofs (mcp, &mc, sizeof (master_config_t));
+      return 0;
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_s_master_cfg(struct device *dev, master_config_t *mcp)
+{
+  equalizer_t *eql;
+  master_config_t mc;
+
+  if (! suser ())
+    return -EPERM;
+
+#if EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: set master config\n", dev->name);
+#endif
+
+  memcpy_fromfs (&mc, mcp, sizeof (master_config_t));
+
+  if ( eql_is_master (dev) )
+    {
+      eql = (equalizer_t *) dev->priv;
+      eql->max_slaves = mc.max_slaves;
+      eql->min_slaves = mc.min_slaves;
+      return 0;
+    }
+  return -EINVAL;
+}
+
+/* private device support functions
+   ------------------------------------------------------------------
+   */
+
+static inline
+int 
+eql_is_slave(struct device *dev)
+{
+  if (dev)
+    {
+      if ((dev->flags & IFF_SLAVE) == IFF_SLAVE)
+	return 1;
+    }
+  return 0;
+}
+
+
+static inline
+int 
+eql_is_master(struct device *dev)
+{
+  if (dev)
+    {
+      if ((dev->flags & IFF_MASTER) == IFF_MASTER)
+	return 1;
+    }
+  return 0;
+}
+
+
+static 
+slave_t *
+eql_new_slave(void)
+{
+  slave_t *slave;
+
+  slave = (slave_t *) kmalloc (sizeof (slave_t), GFP_KERNEL);
+  if (slave)
+    {
+      memset(slave, 0, sizeof (slave_t));
+      return slave;
+    }
+  return 0;
+}
+
+
+static 
+void
+eql_delete_slave(slave_t *slave)
+{
+  kfree (slave);
+}
+
+
+#if 0				/* not currently used, will be used
+				   when we realy use a priority queue */
+static
+long
+slave_Bps(slave_t *slave)
+{
+  return (slave->priority_Bps);
+}
+
+static 
+long
+slave_bps(slave_t *slave)
+{
+  return (slave->priority_bps);
+}
+#endif
+
+
+static inline
+int 
+eql_number_slaves(slave_queue_t *queue)
+{
+  return queue->num_slaves;
+}
+
+
+static inline 
+int 
+eql_is_empty(slave_queue_t *queue)
+{
+  if (eql_number_slaves (queue) == 0)
+    return 1;
+  return 0;
+}
+
+
+static inline
+int 
+eql_is_full(slave_queue_t *queue)
+{
+  equalizer_t *eql = (equalizer_t *) queue->master_dev->priv;
+
+  if (eql_number_slaves (queue) == eql->max_slaves)
+    return 1;
+  return 0;
+}
+
+
+static
+slave_queue_t *
+eql_new_slave_queue(struct device *dev)
+{
+  slave_queue_t *queue;
+  slave_t *head_slave;
+  slave_t *tail_slave;
+
+  queue = (slave_queue_t *) kmalloc (sizeof (slave_queue_t), GFP_KERNEL);
+  memset (queue, 0, sizeof (slave_queue_t));
+
+  head_slave = eql_new_slave ();
+  tail_slave = eql_new_slave ();
+  
+  if ( head_slave != 0 &&
+       tail_slave != 0 )
+    {
+      head_slave->next = tail_slave;
+      tail_slave->next = 0;
+      queue->head = head_slave;
+      queue->num_slaves = 0;
+      queue->master_dev = dev;
+    }
+  else
+    {
+      kfree (queue);
+      return 0;
+    }
+  return queue;
+}
+
+
+static
+void
+eql_delete_slave_queue(slave_queue_t *queue)
+{ 
+  slave_t *zapped;
+
+  /* this should only be called when there isn't a timer running that scans
+     the data periodicaly.. dev_close stops the timer... */
+
+  while ( ! eql_is_empty (queue) )
+    {
+      zapped = eql_remove_slave (queue, queue->head->next);
+      eql_delete_slave (zapped);
+    }
+  kfree (queue->head->next);
+  kfree (queue->head);
+  kfree (queue);
+}
+
+
+static
+int
+eql_insert_slave(slave_queue_t *queue, slave_t *slave)
+{
+  cli ();
+
+  if ( ! eql_is_full (queue) )
+    {
+      slave_t *duplicate_slave = 0;
+
+      duplicate_slave = eql_find_slave_dev (queue, slave->dev);
+
+      if (duplicate_slave != 0)
+	{
+/*	  printk ("%s: found a duplicate, killing it and replacing\n",
+		  queue->master_dev->name); */
+	  eql_delete_slave (eql_remove_slave (queue, duplicate_slave));
+	}
+
+      slave->next = queue->head->next;
+      queue->head->next = slave;
+      queue->num_slaves++;
+      sti ();
+      return 0;
+    }
+
+  sti ();
+
+  return 1;
+}
+
+
+static
+slave_t *
+eql_remove_slave(slave_queue_t *queue, slave_t *slave)
+{
+  slave_t *prev;
+  slave_t *current;
+
+  cli ();
+
+  prev = queue->head;
+  current = queue->head->next;
+  while (current != slave && 
+	 current->dev != 0 )
+    {
+/* printk ("%s: remove_slave; searching...\n", queue->master_dev->name); */
+      prev = current;
+      current = current->next;
+    }
+
+  if (current == slave)
+    {
+      prev->next = current->next;
+      queue->num_slaves--;
+
+      current->dev->flags = current->dev->flags & ~IFF_SLAVE;
+
+      return current;
+    }
+
+  sti ();
+
+  return 0;			/* not found */
+}
+
+
+#if 0
+static 
+int 
+eql_insert_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+  slave_t *slave;
+
+  cli ();
+
+  if ( ! eql_is_full (queue) )
+    {
+      slave = eql_new_slave ();
+      slave->dev = dev;
+      slave->priority = EQL_DEFAULT_SLAVE_PRIORITY;
+      slave->priority_bps = EQL_DEFAULT_SLAVE_PRIORITY;
+      slave->priority_Bps = EQL_DEFAULT_SLAVE_PRIORITY / 8;
+      slave->next = queue->head->next;
+      queue->head->next = slave;
+      sti ();
+      return 0;
+    }
+  sti ();
+  return 1;
+}
+#endif
+
+
+static
+int
+eql_remove_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+  slave_t *prev;
+  slave_t *current;
+  slave_t *target;
+
+  target = eql_find_slave_dev (queue, dev);
+
+  if (target != 0)
+    {
+      cli ();
+
+      prev = queue->head;
+      current = prev->next;
+      while (current != target)
+	{
+	  prev = current;
+	  current = current->next;
+	}
+      prev->next = current->next;
+      queue->num_slaves--;
+
+      sti ();
+
+      eql_delete_slave (current);
+      return 0;
+    }
+  return 1;
+}
+
+
+static inline
+struct device *
+eql_best_slave_dev(slave_queue_t *queue)
+{
+  if (queue->best_slave != 0)
+    {
+      if (queue->best_slave->dev != 0)
+	return queue->best_slave->dev;
+      else
+	return 0;
+    }
+  else
+    return 0;
+}
+
+
+static inline
+slave_t *
+eql_best_slave(slave_queue_t *queue)
+{
+  return queue->best_slave;
+}
+
+static inline
+void
+eql_schedule_slaves(slave_queue_t *queue)
+{
+  struct device *master_dev = queue->master_dev;
+  slave_t *best_slave = 0;
+  slave_t *slave_corpse = 0;
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 100)
+    printk ("%s: schedule %d slaves\n", 
+	    master_dev->name, eql_number_slaves (queue));
+#endif
+
+  if ( eql_is_empty (queue) )
+    {
+      /* no slaves to play with */
+      eql_set_best_slave (queue, (slave_t *) 0);
+      return;
+    }
+  else
+    {				/* make a pass to set the best slave */
+      unsigned long best_load = (unsigned long) ULONG_MAX;
+      slave_t *slave = 0;
+      int i;
+
+      cli ();
+
+      for (i = 1, slave = eql_first_slave (queue);
+	   i <= eql_number_slaves (queue);
+	   i++, slave = eql_next_slave (queue, slave))
+	{
+	  /* go through the slave list once, updating best_slave 
+	     whenever a new best_load is found, whenever a dead
+	     slave is found, it is marked to be pulled out of the 
+	     queue */
+
+	  unsigned long slave_load;
+	  unsigned long bytes_queued; 
+	  unsigned long priority_Bps; 
+	  
+	  if (slave != 0)
+	    {
+	      bytes_queued = slave->bytes_queued;
+	      priority_Bps = slave->priority_Bps;    
+
+	      if ( slave->dev != 0)
+		{
+		  if ( slave->dev->flags & IFF_UP == IFF_UP )
+		    {
+		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 
+			(priority_Bps) + bytes_queued * 8;
+		      
+		      if (slave_load < best_load)
+			{
+			  best_load = slave_load;
+			  best_slave = slave;
+			}
+		    }
+		  else		/* we found a dead slave */
+		    {
+		      /* we only bury one slave at a time, if more than
+			 one slave dies, we will bury him on the next 
+			 reschedule. slaves don't die all at once that much
+			 anyway */
+		      slave_corpse = slave;
+		    }
+		}
+	    }
+	} /* for */
+
+	   sti ();
+	   
+      eql_set_best_slave (queue, best_slave);
+    } /* else */
+
+  if (slave_corpse != 0)
+    {
+      printk ("eql: scheduler found dead slave, burying...\n");
+      eql_delete_slave (eql_remove_slave (queue, slave_corpse));
+    }
+
+  return;
+}
+
+
+static
+slave_t *
+eql_find_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+  slave_t *slave = 0;
+
+  slave = eql_first_slave(queue);
+
+  while (slave != 0 && slave->dev != dev && slave != 0)
+    {
+#if 0
+      if (slave->dev != 0)
+	printk ("eql: find_slave_dev; looked at '%s'...\n", slave->dev->name);
+      else
+	printk ("eql: find_slave_dev; looked at nothing...\n");
+#endif
+
+      slave = slave->next;
+    }
+
+  return slave;
+}
+
+
+static inline
+slave_t *
+eql_first_slave(slave_queue_t *queue)
+{
+  return queue->head->next;
+}
+
+
+static inline
+slave_t *
+eql_next_slave(slave_queue_t *queue, slave_t *slave)
+{
+  return slave->next;
+}
+
+
+static inline
+void
+eql_set_best_slave(slave_queue_t *queue, slave_t *slave)
+{
+  queue->best_slave = slave;
+}
+
+
+#if 0
+static inline
+int
+eql_lock_slave_queue(slave_queue_t *queue)
+{
+  int result = 0;
+
+  printk ("eql: lock == %d\n", queue->lock);
+  if (queue->lock)
+    {
+      printk ("eql: lock_slave-q sleeping for lock\n");
+      sleep_on (&eql_queue_lock);
+      printk ("eql: lock_slave-q woken up\n");
+      queue->lock = 1;
+    }
+  queue->lock = 1;
+  return result;
+}
+
+static inline
+int
+eql_unlock_slave_queue(slave_queue_t *queue)
+{
+  int result = 0;
+
+  if (queue->lock != 0)
+    {
+      queue->lock = 0;
+      printk ("eql: unlock_slave-q waking up lock waiters\n");
+      wake_up (&eql_queue_lock);
+    }
+  return result;
+}
+#endif 
+
+static inline
+int
+eql_is_locked_slave_queue(slave_queue_t *queue)
+{
+  return test_bit(1, (void *) &queue->lock);
+}
+
+static 
+void
+eql_timer(unsigned long param)
+{
+  equalizer_t *eql = (equalizer_t *) param;
+  slave_t *slave;
+  slave_t *slave_corpse = 0;
+  int i;
+
+  if ( ! eql_is_empty (eql->queue) )
+    {
+      cli ();
+
+      for (i = 1, slave = eql_first_slave (eql->queue);
+	   i <= eql_number_slaves (eql->queue);
+	   i++, slave = eql_next_slave (eql->queue, slave))
+	{
+	  if (slave != 0)
+	    {
+	      if ( slave->dev->flags & IFF_UP == IFF_UP )
+		{
+		  slave->bytes_queued -= slave->priority_Bps;
+	      
+		  if (slave->bytes_queued < 0)
+		    slave->bytes_queued = 0;
+		}
+	      else
+		{
+		  slave_corpse = slave;
+		}
+	    }
+	}
+
+      sti ();
+      
+      if (slave_corpse != 0)
+	{
+	  printk ("eql: timer found dead slave, burying...\n");
+	  eql_delete_slave (eql_remove_slave (eql->queue, slave_corpse));
+	}
+
+    }
+
+  if (eql->timer_on != 0) 
+    {
+      eql->timer.expires = EQL_DEFAULT_RESCHED_IVAL;
+      add_timer (&eql->timer);
+    }
+}
+
+/*
+ * Local Variables: 
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c eql.c"
+ * version-control: t
+ * kept-new-versions: 20
+ * End:
+ */
diff -u --recursive --new-file linux-1.2.2/drivers/net/eql.c~ linux/drivers/net/eql.c~
--- linux-1.2.2/drivers/net/eql.c~	Wed Dec 31 19:00:00 1969
+++ linux/drivers/net/eql.c~	Fri Mar 31 23:05:50 1995
@@ -0,0 +1,1169 @@
+/*
+ * Equalizer Load-balancer for serial network interfaces.
+ *
+ * (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Mangement, Inc.
+ *
+ *
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
+ * 
+ * The author may be reached as simon@ncm.com, or C/O
+ *    NCM
+ *    Attn: Simon Janes
+ *    6803 Whittier Ave
+ *    McLean VA 22101
+ *    Phone: 1-703-847-0040 ext 103
+ */
+
+static char *version = 
+	"EQL Multilink Driver: $Revision: 1.2 $ $Date: 1995/03/25 18:16:32 $ Simon Janes (simon@ncm.com)\n";
+
+#include <linux/config.h>
+
+/*
+ * Sources:
+ *   skeleton.c by Donald Becker.
+ * Inspirations:
+ *   The Harried and Overworked Alan Cox
+ * Conspiracies:
+ *   The Alan Cox and Arisian plot to get someone else to do the code, which
+ *   turned out to be me.
+ */
+
+/*
+ * $Log: eql.c,v $
+ * Revision 1.2  1995/03/25  18:16:32  guru
+ * Will have to make this the 4.0 branch
+ *
+ * Revision 1.1  1995/03/25  18:14:05  guru
+ * Initial revision
+ *
+ * Revision 3.11  1995/01/19  23:14:31  guru
+ * 		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued * 8;
+ *
+ * Revision 3.10  1995/01/19  23:07:53  guru
+ * back to
+ * 		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued;
+ *
+ * Revision 3.9  1995/01/19  22:38:20  guru
+ * 		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued * 4;
+ *
+ * Revision 3.8  1995/01/19  22:30:55  guru
+ *       slave_load = (ULONG_MAX - (ULONG_MAX / 2)) -
+ * 			(priority_Bps) + bytes_queued * 2;
+ *
+ * Revision 3.7  1995/01/19  21:52:35  guru
+ * printk's trimmed out.
+ *
+ * Revision 3.6  1995/01/19  21:49:56  guru
+ * This is working pretty well. I gained 1 K/s in speed.. now its just
+ * robustness and printk's to be diked out.
+ *
+ * Revision 3.5  1995/01/18  22:29:59  guru
+ * still crashes the kernel when the lock_wait thing is woken up.
+ *
+ * Revision 3.4  1995/01/18  21:59:47  guru
+ * Broken set-bit locking snapshot
+ *
+ * Revision 3.3  1995/01/17  22:09:18  guru
+ * infinite sleep in a lock somewhere..
+ *
+ * Revision 3.2  1995/01/15  16:46:06  guru
+ * Log trimmed of non-pertinant 1.x branch messages
+ *
+ * Revision 3.1  1995/01/15  14:41:45  guru
+ * New Scheduler and timer stuff...
+ *
+ * Revision 1.15  1995/01/15  14:29:02  guru
+ * Will make 1.14 (now 1.15) the 3.0 branch, and the 1.12 the 2.0 branch, the one
+ * with the dumber scheduler
+ *
+ * Revision 1.14  1995/01/15  02:37:08  guru
+ * shock.. the kept-new-versions could have zonked working
+ * stuff.. shudder
+ *
+ * Revision 1.13  1995/01/15  02:36:31  guru
+ * big changes
+ *
+ * 	scheduler was torn out and replaced with something smarter
+ *
+ * 	global names not prefixed with eql_ were renamed to protect
+ * 	against namespace collisions
+ *
+ * 	a few more abstract interfaces were added to facilitate any
+ * 	potential change of datastructure.  the driver is still using
+ * 	a linked list of slaves.  going to a heap would be a bit of
+ * 	an overkill.
+ *
+ * 	this compiles fine with no warnings.
+ *
+ * 	the locking mechanism and timer stuff must be written however,
+ * 	this version will not work otherwise
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>              
+
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/timer.h>
+
+#include "eql.h"
+
+#ifndef EQL_DEBUG
+/* #undef EQL_DEBUG      -* print nothing at all, not even a boot-banner */
+/* #define EQL_DEBUG 1   -* print only the boot-banner */
+/* #define EQL_DEBUG 5   -* print major function entries */
+/* #define EQL_DEBUG 20  -* print subfunction entries */
+/* #define EQL_DEBUG 50  -* print utility entries */
+/* #define EQL_DEBUG 100 -* print voluminous function entries */
+#define EQL_DEBUG 1
+#endif
+static unsigned int eql_debug = EQL_DEBUG;
+
+int        eql_init(struct device *dev); /*  */
+static int eql_open(struct device *dev); /*  */
+static int eql_close(struct device *dev); /*  */
+static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd); /*  */
+static int eql_slave_xmit(struct sk_buff *skb, struct device *dev); /*  */
+
+static struct enet_statistics *eql_get_stats(struct device *dev); /*  */
+static int eql_header(unsigned char *buff, struct device *dev, 
+		      unsigned short type, void *daddr, void *saddr, 
+		      unsigned len, struct sk_buff *skb); /*  */
+static int eql_rebuild_header(void *buff, struct device *dev, 
+			      unsigned long raddr, struct sk_buff *skb); /*  */
+static unsigned short eql_type_trans (struct sk_buff *skb, 
+				      struct device *dev);	/*  */
+
+/* ioctl() handlers
+   ---------------- */
+static int eql_enslave(struct device *dev,  slaving_request_t *srq); /*  */
+static int eql_emancipate(struct device *dev, slaving_request_t *srq); /*  */
+
+static int eql_g_slave_cfg(struct device *dev, slave_config_t *sc); /*  */
+static int eql_s_slave_cfg(struct device *dev, slave_config_t *sc); /*  */
+
+static int eql_g_master_cfg(struct device *dev, master_config_t *mc); /*  */
+static int eql_s_master_cfg(struct device *dev, master_config_t *mc); /*  */
+
+static inline int eql_is_slave(struct device *dev); /*  */
+static inline int eql_is_master(struct device *dev); /*  */
+
+static slave_t *eql_new_slave(void); /*  */
+static void eql_delete_slave(slave_t *slave); /*  */
+
+/* static long eql_slave_priority(slave_t *slave); -*  */
+static inline int eql_number_slaves(slave_queue_t *queue); /*  */
+
+static inline int eql_is_empty(slave_queue_t *queue); /*  */
+static inline int eql_is_full(slave_queue_t *queue); /*  */
+
+static slave_queue_t *eql_new_slave_queue(struct device *dev); /*  */
+static void eql_delete_slave_queue(slave_queue_t *queue); /*  */
+
+static int eql_insert_slave(slave_queue_t *queue, slave_t *slave); /*  */
+static slave_t *eql_remove_slave(slave_queue_t *queue, slave_t *slave); /*  */
+
+/* static int eql_insert_slave_dev(slave_queue_t *queue, struct device *dev); -*  */
+static int eql_remove_slave_dev(slave_queue_t *queue, struct device *dev); /*  */
+
+static inline struct device *eql_best_slave_dev(slave_queue_t *queue); /*  */
+static inline slave_t *eql_best_slave(slave_queue_t *queue); /*  */
+static inline slave_t *eql_first_slave(slave_queue_t *queue); /*  */
+static inline slave_t *eql_next_slave(slave_queue_t *queue, slave_t *slave); /*  */
+
+static inline void eql_set_best_slave(slave_queue_t *queue, slave_t *slave); /*  */
+static inline void eql_schedule_slaves(slave_queue_t *queue); /*  */
+
+static slave_t *eql_find_slave_dev(slave_queue_t *queue, struct device *dev); /*  */
+
+/* static inline eql_lock_slave_queue(slave_queue_t *queue); -*  */
+/* static inline eql_unlock_slave_queue(slave_queue_t *queue); -*  */
+
+static void eql_timer(unsigned long param);	/*  */
+
+/* struct device * interface functions 
+   ---------------------------------------------------------
+   */
+
+int
+eql_init(struct device *dev)
+{
+  static unsigned version_printed = 0;
+  /* static unsigned num_masters     = 0; */
+  equalizer_t *eql = 0;
+  int i;
+
+  if ( version_printed++ == 0 && eql_debug > 0)
+    printk(version);
+
+  /* Initialize the device structure. */
+  dev->priv = kmalloc (sizeof (equalizer_t), GFP_KERNEL);
+  memset (dev->priv, 0, sizeof (equalizer_t));
+  eql = (equalizer_t *) dev->priv;
+
+  eql->stats = kmalloc (sizeof (struct enet_statistics), GFP_KERNEL);
+  memset (eql->stats, 0, sizeof (struct enet_statistics));
+
+  init_timer (&eql->timer);
+  eql->timer.data     = (unsigned long) dev->priv;
+  eql->timer.expires  = EQL_DEFAULT_RESCHED_IVAL;
+  eql->timer.function = &eql_timer;
+  eql->timer_on       = 0;
+
+  dev->open		= eql_open;
+  dev->stop		= eql_close;
+  dev->do_ioctl         = eql_ioctl;
+  dev->hard_start_xmit  = eql_slave_xmit;
+  dev->get_stats	= eql_get_stats;
+  
+  /* Fill in the fields of the device structure with ethernet-generic values.
+     This should be in a common file instead of per-driver.  */
+
+  for (i = 0; i < DEV_NUMBUFFS; i++)
+    skb_queue_head_init(&dev->buffs[i]);
+
+  dev->hard_header    = eql_header; 
+  dev->rebuild_header = eql_rebuild_header;
+  dev->type_trans     = eql_type_trans;
+
+  /* now we undo some of the things that eth_setup does that we don't like */
+  dev->mtu        = EQL_DEFAULT_MTU;	/* set to 576 in eql.h */
+  dev->flags      = IFF_MASTER;
+
+  dev->family     = AF_INET;
+  dev->pa_addr    = 0;
+  dev->pa_brdaddr = 0;
+  dev->pa_mask    = 0;
+  dev->pa_alen    = sizeof (unsigned long);
+
+  dev->type       = ARPHRD_SLIP;
+
+  return 0;
+}
+
+
+static
+int
+eql_open(struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+  slave_queue_t *new_queue;
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 5)
+    printk ("%s: open\n", dev->name);
+#endif
+
+   new_queue = eql_new_slave_queue (dev);
+    
+    if (new_queue != 0)
+      {
+	new_queue->master_dev = dev;
+	eql->queue = new_queue;
+	eql->queue->lock = 0;
+	eql->min_slaves = 1;
+	eql->max_slaves = EQL_DEFAULT_MAX_SLAVES; /* 4 usually... */
+
+	printk ("%s: adding timer\n", dev->name);
+	eql->timer_on = 1;
+	add_timer (&eql->timer);
+
+	return 0;
+      }
+  return 1;
+}
+
+
+static
+int
+eql_close(struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+
+#ifdef EQL_DEBUG
+  if ( eql_debug >= 5)
+    printk ("%s: close\n", dev->name);
+#endif
+  /* The timer has to be stopped first before we start hacking away
+     at the data structure it scans every so often... */
+  printk ("%s: stopping timer\n", dev->name);
+  eql->timer_on = 0;
+  del_timer (&eql->timer);
+
+  eql_delete_slave_queue (eql->queue);
+
+  return 0;
+}
+
+
+static
+int
+eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{  
+  switch (cmd)
+    {
+    case EQL_ENSLAVE:
+      return eql_enslave (dev, (slaving_request_t *) ifr->ifr_data);
+    case EQL_EMANCIPATE:
+      return eql_emancipate (dev, (slaving_request_t *) ifr->ifr_data);
+
+    case EQL_GETSLAVECFG:
+      return eql_g_slave_cfg (dev, (slave_config_t *) ifr->ifr_data);
+    case EQL_SETSLAVECFG:
+      return eql_s_slave_cfg (dev, (slave_config_t *) ifr->ifr_data);
+
+    case EQL_GETMASTRCFG:
+      return eql_g_master_cfg (dev, (master_config_t *) ifr->ifr_data);
+    case EQL_SETMASTRCFG:
+      return eql_s_master_cfg (dev, (master_config_t *) ifr->ifr_data);
+
+    default:
+      return -EOPNOTSUPP;
+    }
+}
+
+
+static
+int
+eql_slave_xmit(struct sk_buff *skb, struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+  struct device *slave_dev = 0;
+  slave_t *slave;
+
+  if (skb == NULL)
+    {
+      return 0;
+    }
+
+  eql_schedule_slaves (eql->queue);
+  
+  slave_dev = eql_best_slave_dev (eql->queue);
+  slave = eql_best_slave (eql->queue); 
+
+  if ( slave_dev != 0 )
+    {
+#ifdef EQL_DEBUG
+      if (eql_debug >= 100)
+	printk ("%s: %d slaves xmitng %ld B %s\n", 
+		dev->name, eql_number_slaves (eql->queue), skb->len,
+		slave_dev->name);
+#endif
+      
+      dev_queue_xmit (skb, slave_dev, 1);
+      eql->stats->tx_packets++;
+      slave->bytes_queued += skb->len; 
+    }
+  else
+    {
+      /* The alternative for this is the return 1 and have
+         dev_queue_xmit just queue it up on the eql's queue. */
+
+      eql->stats->tx_dropped++;
+      dev_kfree_skb(skb, FREE_WRITE);
+    }	  
+  return 0;
+}
+
+
+static
+struct enet_statistics *
+eql_get_stats(struct device *dev)
+{
+  equalizer_t *eql = (equalizer_t *) dev->priv;
+
+  return eql->stats;
+}
+
+
+static 
+int 
+eql_header(unsigned char *buff, struct device *dev, 
+	   unsigned short type, void *daddr, void *saddr, 
+	   unsigned len, struct sk_buff *skb)
+{
+  return 0;
+}
+
+
+static 
+int 
+eql_rebuild_header(void *buff, struct device *dev, 
+		   unsigned long raddr, struct sk_buff *skb)
+{
+  return 0;
+}
+
+
+static
+unsigned short 
+eql_type_trans (struct sk_buff *skb, struct device *dev)
+{
+  return htons (ETH_P_IP);
+}
+
+
+/* private ioctl functions
+   -----------------------------------------------------------------
+   */
+
+static int 
+eql_enslave(struct device *dev, slaving_request_t *srqp)
+{
+  struct device *master_dev;
+  struct device *slave_dev;
+  slaving_request_t srq;
+
+  if (! suser ())
+    return -EPERM;
+
+  memcpy_fromfs (&srq, srqp, sizeof (slaving_request_t));
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: enslave '%s' %ld bps\n", dev->name, 
+	    srq.slave_name, srq.priority);
+#endif
+  
+  master_dev = dev;		/* for "clarity" */
+  slave_dev  = dev_get (srq.slave_name);
+
+  if (master_dev != 0 && slave_dev != 0)
+    {
+      if (! eql_is_master (slave_dev)  &&   /* slave is not a master */
+	  ! eql_is_slave (slave_dev)      ) /* slave is not already a slave */
+	{
+	  slave_t *s = eql_new_slave ();
+	  equalizer_t *eql = (equalizer_t *) master_dev->priv;
+
+	  s->dev = slave_dev;
+	  s->priority = srq.priority;
+	  s->priority_bps = srq.priority;
+	  s->priority_Bps = srq.priority / 8;
+
+	  slave_dev->flags |= IFF_SLAVE;
+
+	  eql_insert_slave (eql->queue, s);
+
+	  return 0;
+	}
+      return -EINVAL;
+    }
+  return -EINVAL;
+}
+
+
+
+static 
+int 
+eql_emancipate(struct device *dev, slaving_request_t *srqp)
+{
+  struct device *master_dev;
+  struct device *slave_dev;
+  slaving_request_t srq;
+
+  if (! suser ())
+    return -EPERM;
+
+  memcpy_fromfs (&srq, srqp, sizeof (slaving_request_t));
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name);
+#endif
+
+
+  master_dev = dev;		/* for "clarity" */
+  slave_dev  = dev_get (srq.slave_name);
+
+  if ( eql_is_slave (slave_dev) )	/* really is a slave */
+    {
+      equalizer_t *eql = (equalizer_t *) master_dev->priv;
+      slave_dev->flags = slave_dev->flags & ~IFF_SLAVE;
+
+      eql_remove_slave_dev (eql->queue, slave_dev);
+
+      return 0;
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_g_slave_cfg(struct device *dev, slave_config_t *scp)
+{
+  slave_t *slave;
+  equalizer_t *eql;
+  struct device *slave_dev;
+  slave_config_t sc;
+
+  memcpy_fromfs (&sc, scp, sizeof (slave_config_t));
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name);
+#endif
+
+  eql = (equalizer_t *) dev->priv;
+  slave_dev = dev_get (sc.slave_name);
+
+  if ( eql_is_slave (slave_dev) )
+    {
+      slave = eql_find_slave_dev (eql->queue,  slave_dev);
+      if (slave != 0)
+	{
+	  sc.priority = slave->priority;
+	  memcpy_tofs (scp, &sc, sizeof (slave_config_t));
+	  return 0;
+	}
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_s_slave_cfg(struct device *dev, slave_config_t *scp)
+{
+  slave_t *slave;
+  equalizer_t *eql;
+  struct device *slave_dev;
+  slave_config_t sc;
+
+  if (! suser ())
+    return -EPERM;
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: set config for slave `%s'\n", dev->name, sc.slave_name);
+#endif
+  
+  memcpy_fromfs (&sc, scp, sizeof (slave_config_t));
+
+  eql = (equalizer_t *) dev->priv;
+  slave_dev = dev_get (sc.slave_name);
+
+  if ( eql_is_slave (slave_dev) )
+    {
+      slave = eql_find_slave_dev (eql->queue, slave_dev);
+      if (slave != 0)
+	{
+	  slave->priority = sc.priority;
+	  slave->priority_bps = sc.priority;
+	  slave->priority_Bps = sc.priority / 8;
+	  return 0;
+	}
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_g_master_cfg(struct device *dev, master_config_t *mcp)
+{
+  equalizer_t *eql;
+  master_config_t mc;
+
+#if EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: get master config\n", dev->name);
+#endif
+
+  if ( eql_is_master (dev) )
+    {
+      eql = (equalizer_t *) dev->priv;
+      mc.max_slaves = eql->max_slaves;
+      mc.min_slaves = eql->min_slaves;
+      memcpy_tofs (mcp, &mc, sizeof (master_config_t));
+      return 0;
+    }
+  return -EINVAL;
+}
+
+
+static 
+int 
+eql_s_master_cfg(struct device *dev, master_config_t *mcp)
+{
+  equalizer_t *eql;
+  master_config_t mc;
+
+  if (! suser ())
+    return -EPERM;
+
+#if EQL_DEBUG
+  if (eql_debug >= 20)
+    printk ("%s: set master config\n", dev->name);
+#endif
+
+  memcpy_fromfs (&mc, mcp, sizeof (master_config_t));
+
+  if ( eql_is_master (dev) )
+    {
+      eql = (equalizer_t *) dev->priv;
+      eql->max_slaves = mc.max_slaves;
+      eql->min_slaves = mc.min_slaves;
+      return 0;
+    }
+  return -EINVAL;
+}
+
+/* private device support functions
+   ------------------------------------------------------------------
+   */
+
+static inline
+int 
+eql_is_slave(struct device *dev)
+{
+  if (dev)
+    {
+      if ((dev->flags & IFF_SLAVE) == IFF_SLAVE)
+	return 1;
+    }
+  return 0;
+}
+
+
+static inline
+int 
+eql_is_master(struct device *dev)
+{
+  if (dev)
+    {
+      if ((dev->flags & IFF_MASTER) == IFF_MASTER)
+	return 1;
+    }
+  return 0;
+}
+
+
+static 
+slave_t *
+eql_new_slave(void)
+{
+  slave_t *slave;
+
+  slave = (slave_t *) kmalloc (sizeof (slave_t), GFP_KERNEL);
+  if (slave)
+    {
+      memset(slave, 0, sizeof (slave_t));
+      return slave;
+    }
+  return 0;
+}
+
+
+static 
+void
+eql_delete_slave(slave_t *slave)
+{
+  kfree (slave);
+}
+
+
+#if 0				/* not currently used, will be used
+				   when we realy use a priority queue */
+static
+long
+slave_Bps(slave_t *slave)
+{
+  return (slave->priority_Bps);
+}
+
+static 
+long
+slave_bps(slave_t *slave)
+{
+  return (slave->priority_bps);
+}
+#endif
+
+
+static inline
+int 
+eql_number_slaves(slave_queue_t *queue)
+{
+  return queue->num_slaves;
+}
+
+
+static inline 
+int 
+eql_is_empty(slave_queue_t *queue)
+{
+  if (eql_number_slaves (queue) == 0)
+    return 1;
+  return 0;
+}
+
+
+static inline
+int 
+eql_is_full(slave_queue_t *queue)
+{
+  equalizer_t *eql = (equalizer_t *) queue->master_dev->priv;
+
+  if (eql_number_slaves (queue) == eql->max_slaves)
+    return 1;
+  return 0;
+}
+
+
+static
+slave_queue_t *
+eql_new_slave_queue(struct device *dev)
+{
+  slave_queue_t *queue;
+  slave_t *head_slave;
+  slave_t *tail_slave;
+
+  queue = (slave_queue_t *) kmalloc (sizeof (slave_queue_t), GFP_KERNEL);
+  memset (queue, 0, sizeof (slave_queue_t));
+
+  head_slave = eql_new_slave ();
+  tail_slave = eql_new_slave ();
+  
+  if ( head_slave != 0 &&
+       tail_slave != 0 )
+    {
+      head_slave->next = tail_slave;
+      tail_slave->next = 0;
+      queue->head = head_slave;
+      queue->num_slaves = 0;
+      queue->master_dev = dev;
+    }
+  else
+    {
+      kfree (queue);
+      return 0;
+    }
+  return queue;
+}
+
+
+static
+void
+eql_delete_slave_queue(slave_queue_t *queue)
+{ 
+  slave_t *zapped;
+
+  /* this should only be called when there isn't a timer running that scans
+     the data periodicaly.. dev_close stops the timer... */
+
+  while ( ! eql_is_empty (queue) )
+    {
+      zapped = eql_remove_slave (queue, queue->head->next);
+      eql_delete_slave (zapped);
+    }
+  kfree (queue->head->next);
+  kfree (queue->head);
+  kfree (queue);
+}
+
+
+static
+int
+eql_insert_slave(slave_queue_t *queue, slave_t *slave)
+{
+  cli ();
+
+  if ( ! eql_is_full (queue) )
+    {
+      slave_t *duplicate_slave = 0;
+
+      duplicate_slave = eql_find_slave_dev (queue, slave->dev);
+
+      if (duplicate_slave != 0)
+	{
+/*	  printk ("%s: found a duplicate, killing it and replacing\n",
+		  queue->master_dev->name); */
+	  eql_delete_slave (eql_remove_slave (queue, duplicate_slave));
+	}
+
+      slave->next = queue->head->next;
+      queue->head->next = slave;
+      queue->num_slaves++;
+      sti ();
+      return 0;
+    }
+
+  sti ();
+
+  return 1;
+}
+
+
+static
+slave_t *
+eql_remove_slave(slave_queue_t *queue, slave_t *slave)
+{
+  slave_t *prev;
+  slave_t *current;
+
+  cli ();
+
+  prev = queue->head;
+  current = queue->head->next;
+  while (current != slave && 
+	 current->dev != 0 )
+    {
+/* printk ("%s: remove_slave; searching...\n", queue->master_dev->name); */
+      prev = current;
+      current = current->next;
+    }
+
+  if (current == slave)
+    {
+      prev->next = current->next;
+      queue->num_slaves--;
+
+      current->dev->flags = current->dev->flags & ~IFF_SLAVE;
+
+      return current;
+    }
+
+  sti ();
+
+  return 0;			/* not found */
+}
+
+
+#if 0
+static 
+int 
+eql_insert_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+  slave_t *slave;
+
+  cli ();
+
+  if ( ! eql_is_full (queue) )
+    {
+      slave = eql_new_slave ();
+      slave->dev = dev;
+      slave->priority = EQL_DEFAULT_SLAVE_PRIORITY;
+      slave->priority_bps = EQL_DEFAULT_SLAVE_PRIORITY;
+      slave->priority_Bps = EQL_DEFAULT_SLAVE_PRIORITY / 8;
+      slave->next = queue->head->next;
+      queue->head->next = slave;
+      sti ();
+      return 0;
+    }
+  sti ();
+  return 1;
+}
+#endif
+
+
+static
+int
+eql_remove_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+  slave_t *prev;
+  slave_t *current;
+  slave_t *target;
+
+  target = eql_find_slave_dev (queue, dev);
+
+  if (target != 0)
+    {
+      cli ();
+
+      prev = queue->head;
+      current = prev->next;
+      while (current != target)
+	{
+	  prev = current;
+	  current = current->next;
+	}
+      prev->next = current->next;
+      queue->num_slaves--;
+
+      sti ();
+
+      eql_delete_slave (current);
+      return 0;
+    }
+  return 1;
+}
+
+
+static inline
+struct device *
+eql_best_slave_dev(slave_queue_t *queue)
+{
+  if (queue->best_slave != 0)
+    {
+      if (queue->best_slave->dev != 0)
+	return queue->best_slave->dev;
+      else
+	return 0;
+    }
+  else
+    return 0;
+}
+
+
+static inline
+slave_t *
+eql_best_slave(slave_queue_t *queue)
+{
+  return queue->best_slave;
+}
+
+static inline
+void
+eql_schedule_slaves(slave_queue_t *queue)
+{
+  struct device *master_dev = queue->master_dev;
+  slave_t *best_slave = 0;
+  slave_t *slave_corpse = 0;
+
+#ifdef EQL_DEBUG
+  if (eql_debug >= 100)
+    printk ("%s: schedule %d slaves\n", 
+	    master_dev->name, eql_number_slaves (queue));
+#endif
+
+  if ( eql_is_empty (queue) )
+    {
+      /* no slaves to play with */
+      eql_set_best_slave (queue, (slave_t *) 0);
+      return;
+    }
+  else
+    {				/* make a pass to set the best slave */
+      unsigned long best_load = (unsigned long) ULONG_MAX;
+      slave_t *slave = 0;
+      int i;
+
+      cli ();
+
+      for (i = 1, slave = eql_first_slave (queue);
+	   i <= eql_number_slaves (queue);
+	   i++, slave = eql_next_slave (queue, slave))
+	{
+	  /* go through the slave list once, updating best_slave 
+	     whenever a new best_load is found, whenever a dead
+	     slave is found, it is marked to be pulled out of the 
+	     queue */
+
+	  unsigned long slave_load;
+	  unsigned long bytes_queued; 
+	  unsigned long priority_Bps; 
+	  
+	  if (slave != 0)
+	    {
+	      bytes_queued = slave->bytes_queued;
+	      priority_Bps = slave->priority_Bps;    
+
+	      if ( slave->dev != 0)
+		{
+		  if ( slave->dev->flags & IFF_UP == IFF_UP )
+		    {
+		      slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 
+			(priority_Bps) + bytes_queued * 8;
+		      
+		      if (slave_load < best_load)
+			{
+			  best_load = slave_load;
+			  best_slave = slave;
+			}
+		    }
+		  else		/* we found a dead slave */
+		    {
+		      /* we only bury one slave at a time, if more than
+			 one slave dies, we will bury him on the next 
+			 reschedule. slaves don't die all at once that much
+			 anyway */
+		      slave_corpse = slave;
+		    }
+		}
+	    }
+	} /* for */
+
+	   sti ();
+	   
+      eql_set_best_slave (queue, best_slave);
+    } /* else */
+
+  if (slave_corpse != 0)
+    {
+      printk ("eql: scheduler found dead slave, burying...\n");
+      eql_delete_slave (eql_remove_slave (queue, slave_corpse));
+    }
+
+  return;
+}
+
+
+static
+slave_t *
+eql_find_slave_dev(slave_queue_t *queue, struct device *dev)
+{
+  slave_t *slave = 0;
+
+  slave = eql_first_slave(queue);
+
+  while (slave != 0 && slave->dev != dev && slave != 0)
+    {
+#if 0
+      if (slave->dev != 0)
+	printk ("eql: find_slave_dev; looked at '%s'...\n", slave->dev->name);
+      else
+	printk ("eql: find_slave_dev; looked at nothing...\n");
+#endif
+
+      slave = slave->next;
+    }
+
+  return slave;
+}
+
+
+static inline
+slave_t *
+eql_first_slave(slave_queue_t *queue)
+{
+  return queue->head->next;
+}
+
+
+static inline
+slave_t *
+eql_next_slave(slave_queue_t *queue, slave_t *slave)
+{
+  return slave->next;
+}
+
+
+static inline
+void
+eql_set_best_slave(slave_queue_t *queue, slave_t *slave)
+{
+  queue->best_slave = slave;
+}
+
+
+#if 0
+static inline
+int
+eql_lock_slave_queue(slave_queue_t *queue)
+{
+  int result = 0;
+
+  printk ("eql: lock == %d\n", queue->lock);
+  if (queue->lock)
+    {
+      printk ("eql: lock_slave-q sleeping for lock\n");
+      sleep_on (&eql_queue_lock);
+      printk ("eql: lock_slave-q woken up\n");
+      queue->lock = 1;
+    }
+  queue->lock = 1;
+  return result;
+}
+
+static inline
+int
+eql_unlock_slave_queue(slave_queue_t *queue)
+{
+  int result = 0;
+
+  if (queue->lock != 0)
+    {
+      queue->lock = 0;
+      printk ("eql: unlock_slave-q waking up lock waiters\n");
+      wake_up (&eql_queue_lock);
+    }
+  return result;
+}
+#endif 
+
+static inline
+int
+eql_is_locked_slave_queue(slave_queue_t *queue)
+{
+  return test_bit(1, (void *) &queue->lock);
+}
+
+static 
+void
+eql_timer(unsigned long param)
+{
+  equalizer_t *eql = (equalizer_t *) param;
+  slave_t *slave;
+  slave_t *slave_corpse = 0;
+  int i;
+
+  if ( ! eql_is_empty (eql->queue) )
+    {
+      cli ();
+
+      for (i = 1, slave = eql_first_slave (eql->queue);
+	   i <= eql_number_slaves (eql->queue);
+	   i++, slave = eql_next_slave (eql->queue, slave))
+	{
+	  if (slave != 0)
+	    {
+	      if ( slave->dev->flags & IFF_UP == IFF_UP )
+		{
+		  slave->bytes_queued -= slave->priority_Bps;
+	      
+		  if (slave->bytes_queued < 0)
+		    slave->bytes_queued = 0;
+		}
+	      else
+		{
+		  slave_corpse = slave;
+		}
+	    }
+	}
+
+      sti ();
+      
+      if (slave_corpse != 0)
+	{
+	  printk ("eql: timer found dead slave, burying...\n");
+	  eql_delete_slave (eql_remove_slave (eql->queue, slave_corpse));
+	}
+
+    }
+
+  if (eql->timer_on != 0) 
+    {
+      eql->timer.expires = EQL_DEFAULT_RESCHED_IVAL;
+      add_timer (&eql->timer);
+    }
+}
+
+/*
+ * Local Variables: 
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c eql.c"
+ * version-control: t
+ * kept-new-versions: 20
+ * End:
+ */
diff -u --recursive --new-file linux-1.2.2/drivers/net/eql.h linux/drivers/net/eql.h
--- linux-1.2.2/drivers/net/eql.h	Wed Dec 31 19:00:00 1969
+++ linux/drivers/net/eql.h	Fri Mar 31 23:05:10 1995
@@ -0,0 +1,77 @@
+/*
+ * Equalizer Load-balancer for serial network interfaces.
+ *
+ * (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Mangement, Inc.
+ *
+ *
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
+ * 
+ * The author may be reached as simon@ncm.com, or C/O
+ *    NCM
+ *    Attn: Simon Janes
+ *    6803 Whittier Ave
+ *    McLean VA 22101
+ *    Phone: 1-703-847-0040 ext 103
+ */
+
+#define EQL_DEFAULT_SLAVE_PRIORITY 28800
+#define EQL_DEFAULT_MAX_SLAVES     4
+#define EQL_DEFAULT_MTU            576
+#define EQL_DEFAULT_RESCHED_IVAL   100
+
+#define EQL_ENSLAVE     (SIOCDEVPRIVATE)
+#define EQL_EMANCIPATE  (SIOCDEVPRIVATE + 1)
+
+#define EQL_GETSLAVECFG (SIOCDEVPRIVATE + 2)
+#define EQL_SETSLAVECFG (SIOCDEVPRIVATE + 3)
+
+#define EQL_GETMASTRCFG (SIOCDEVPRIVATE + 4)
+#define EQL_SETMASTRCFG (SIOCDEVPRIVATE + 5)
+
+typedef struct slave {
+  struct device *dev;
+  long priority;
+  long priority_bps;
+  long priority_Bps;
+  long bytes_queued;
+  struct slave *next;
+} slave_t;
+
+typedef struct slave_queue {
+  slave_t *head;
+  slave_t *best_slave;
+  int num_slaves;
+  struct device *master_dev;
+  char lock;
+} slave_queue_t;
+
+typedef struct equalizer {
+  slave_queue_t *queue;
+  int min_slaves;
+  int max_slaves;
+  struct enet_statistics *stats;
+  struct timer_list timer;
+  char timer_on;
+} equalizer_t;  
+
+typedef struct master_config {
+  char master_name[16];
+  int max_slaves;
+  int min_slaves;
+} master_config_t;
+
+typedef struct slave_config {
+  char slave_name[16];
+  long priority;
+} slave_config_t;
+
+typedef struct slaving_request {
+  char slave_name[16];
+  long priority;
+} slaving_request_t;
+
+
+
+
