diff -urN -X exclude 2.3.99-pre3-fixed/CREDITS 2.3.99-pre3-vlan/CREDITS
--- 2.3.99-pre3-fixed/CREDITS	Thu Mar 23 20:34:53 2000
+++ 2.3.99-pre3-vlan/CREDITS	Sun Apr  2 10:47:18 2000
@@ -1769,6 +1769,13 @@
 S: 10000 Zagreb
 S: Croatia
 
+N: Gleb Natapov
+E: gleb@tochna.technion.ac.il
+D: IEEE 802.1q VLAN tagging
+S: Keren Haesod 36/12
+S: 36641 Nesher
+S: Israel
+
 N: Jonathan Naylor
 E: g4klx@g4klx.demon.co.uk
 E: g4klx@amsat.org
diff -urN -X exclude 2.3.99-pre3-fixed/Documentation/Configure.help 2.3.99-pre3-vlan/Documentation/Configure.help
--- 2.3.99-pre3-fixed/Documentation/Configure.help	Thu Mar 23 18:38:57 2000
+++ 2.3.99-pre3-vlan/Documentation/Configure.help	Tue Mar 28 14:59:40 2000
@@ -4415,6 +4415,19 @@
 
   If unsure, say N.
 
+IEEE 802.1q VLAN tagging
+CONFIG_VLAN
+  If you say Y here, your linux box will be able to send and receive
+  IEEE 802.1q VLAN tagged frames. The IEEE 802.1q standard is a
+  standard for running multiple 'virtual' ethernets over one single
+  ethernet. As this is a standard, linux will interwork properly with
+  other third-party IEEE 802.1q-conformant products.
+
+  In order to use the VLAN tagging, you'll need the vlan configuration
+  tool available at http://vlan.sourceforge.net.
+
+  If unsure, say N.
+
 Packet socket
 CONFIG_PACKET
   The Packet protocol is used by applications which communicate
diff -urN -X exclude 2.3.99-pre3-fixed/Makefile 2.3.99-pre3-vlan/Makefile
--- 2.3.99-pre3-fixed/Makefile	Wed Mar 22 09:38:26 2000
+++ 2.3.99-pre3-vlan/Makefile	Tue Mar 28 14:49:14 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 3
 SUBLEVEL = 99
-EXTRAVERSION = -pre3
+EXTRAVERSION = -pre3vlan
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN -X exclude 2.3.99-pre3-fixed/drivers/net/net_init.c 2.3.99-pre3-vlan/drivers/net/net_init.c
--- 2.3.99-pre3-fixed/drivers/net/net_init.c	Mon Mar 20 18:01:14 2000
+++ 2.3.99-pre3-vlan/drivers/net/net_init.c	Sun Apr  2 10:54:22 2000
@@ -275,6 +275,7 @@
 
 	/* New-style flags. */
 	dev->flags		= IFF_BROADCAST|IFF_MULTICAST;
+	dev->vlan_slaves_lock   = RW_LOCK_UNLOCKED;
 
 	dev_init_buffers(dev);
 }
diff -urN -X exclude 2.3.99-pre3-fixed/include/linux/if_ether.h 2.3.99-pre3-vlan/include/linux/if_ether.h
--- 2.3.99-pre3-fixed/include/linux/if_ether.h	Tue Sep  7 19:14:37 1999
+++ 2.3.99-pre3-vlan/include/linux/if_ether.h	Tue Mar 28 18:39:35 2000
@@ -54,6 +54,7 @@
 #define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
 #define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
 #define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
+#define ETH_P_VLAN      0x8100          /* VLAN-tagged (IEEE 802.1q)    */
 #define ETH_P_IPX	0x8137		/* IPX over DIX			*/
 #define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
 
diff -urN -X exclude 2.3.99-pre3-fixed/include/linux/if_vlan.h 2.3.99-pre3-vlan/include/linux/if_vlan.h
--- 2.3.99-pre3-fixed/include/linux/if_vlan.h	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/include/linux/if_vlan.h	Wed Mar 29 09:34:23 2000
@@ -0,0 +1,45 @@
+/*
+ *	Linux 802.1q VLAN tagging
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *	Gleb Natapov			<gleb@tochna.technion.ac.il>
+ *
+ *	$Id$
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_VLAN_H
+#define _LINUX_IF_VLAN_H
+
+#ifdef __KERNEL__
+
+#define VLAN_HLEN 18
+
+struct vlanhdr
+{
+	unsigned char v_dest[ETH_ALEN];
+	unsigned char v_source[ETH_ALEN];
+	unsigned short v_prio;
+	unsigned short v_vid;
+	unsigned short v_proto;
+};
+
+
+struct device;
+struct sk_buff;
+struct vlan_slave;
+struct net_proto;
+
+extern int vlan_init(struct net_proto *);
+extern int (*vlan_ioctl_hook)(struct device *dev, int cmd, int vlan);
+extern int (*vlan_possibly_create_device_hook)(const char *dev);
+extern int vlan_enabled;
+
+#endif
+
+#endif
diff -urN -X exclude 2.3.99-pre3-fixed/include/linux/netdevice.h 2.3.99-pre3-vlan/include/linux/netdevice.h
--- 2.3.99-pre3-fixed/include/linux/netdevice.h	Fri Mar 24 01:36:18 2000
+++ 2.3.99-pre3-vlan/include/linux/netdevice.h	Thu Mar 30 15:46:07 2000
@@ -27,6 +27,7 @@
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
+#include <linux/if_vlan.h>
 
 #include <asm/atomic.h>
 #include <asm/cache.h>
@@ -363,6 +364,13 @@
 
 	/* bridge stuff */
 	struct net_bridge_port	*br_port;
+
+	/* VLAN stuff */
+	struct vlan_slave       **vlan_slaves;
+	rwlock_t                vlan_slaves_lock;
+	unsigned short          vlan_count;
+	
+
 
 #ifdef CONFIG_NET_FASTROUTE
 #define NETDEV_FASTROUTE_HMASK 0xF
diff -urN -X exclude 2.3.99-pre3-fixed/include/linux/skbuff.h 2.3.99-pre3-vlan/include/linux/skbuff.h
--- 2.3.99-pre3-fixed/include/linux/skbuff.h	Fri Mar 24 01:36:08 2000
+++ 2.3.99-pre3-vlan/include/linux/skbuff.h	Thu Mar 30 15:46:07 2000
@@ -94,6 +94,7 @@
 	union 
 	{	
 	  	struct ethhdr	*ethernet;
+		struct vlanhdr  *vlan;
 	  	unsigned char 	*raw;
 	} mac;
 
diff -urN -X exclude 2.3.99-pre3-fixed/include/linux/sockios.h 2.3.99-pre3-vlan/include/linux/sockios.h
--- 2.3.99-pre3-fixed/include/linux/sockios.h	Sat Jan 22 21:54:57 2000
+++ 2.3.99-pre3-vlan/include/linux/sockios.h	Tue Mar 28 17:39:34 2000
@@ -65,6 +65,8 @@
 #define SIOCDIFADDR	0x8936		/* delete PA address		*/
 #define	SIOCSIFHWBROADCAST	0x8937	/* set hardware broadcast addr	*/
 #define SIOCGIFCOUNT	0x8938		/* get number of devices */
+#define SIOCADDVLAN     0x8939          /* Virtual LANs                 */
+#define SIOCDELVLAN     0x893a
 
 #define SIOCGIFBR	0x8940		/* Bridging support		*/
 #define SIOCSIFBR	0x8941		/* Set bridging options 	*/
diff -urN -X exclude 2.3.99-pre3-fixed/net/Config.in 2.3.99-pre3-vlan/net/Config.in
--- 2.3.99-pre3-fixed/net/Config.in	Fri Mar 17 20:56:20 2000
+++ 2.3.99-pre3-vlan/net/Config.in	Tue Mar 28 15:02:46 2000
@@ -63,6 +63,7 @@
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
    tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
    bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
+   tristate '802.1q Virtual LAN tagging' CONFIG_VLAN
 #   if [ "$CONFIG_LLC" = "y" ]; then
 #      bool '  Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
 #   fi
diff -urN -X exclude 2.3.99-pre3-fixed/net/Makefile 2.3.99-pre3-vlan/net/Makefile
--- 2.3.99-pre3-fixed/net/Makefile	Fri Mar 17 20:56:20 2000
+++ 2.3.99-pre3-vlan/net/Makefile	Thu Mar 30 17:37:46 2000
@@ -188,6 +188,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_VLAN),y)
+SUB_DIRS += vlan
+else
+  ifeq ($(CONFIG_VLAN),m)
+  MOD_SUB_DIRS += vlan
+  endif
+endif
+
+
 # We must attach netsyms.o to socket.o, as otherwise there is nothing
 # to pull the object file from the archive.
 
diff -urN -X exclude 2.3.99-pre3-fixed/net/core/dev.c 2.3.99-pre3-vlan/net/core/dev.c
--- 2.3.99-pre3-fixed/net/core/dev.c	Wed Mar 22 09:38:27 2000
+++ 2.3.99-pre3-vlan/net/core/dev.c	Tue Mar 28 18:12:05 2000
@@ -948,6 +948,11 @@
 	br_handle_frame_hook(skb);
 }
 
+#if defined(CONFIG_VLAN) || defined(CONFIG_VLAN_MODULE)
+int vlan_enabled = 0;
+int (*vlan_ioctl_hook)(struct device *dev, int cmd, int vlan) = NULL;
+#endif
+
 
 static void net_rx_action(struct softirq_action *h)
 {
@@ -1000,11 +1005,14 @@
 			}
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-			if (skb->dev->br_port != NULL &&
-			    br_handle_frame_hook != NULL) {
-				handle_bridge(skb, pt_prev);
-				continue;
-			}
+#if defined(CONFIG_VLAN) || defined(CONFIG_VLAN_MODULE)
+			if (!vlan_enabled || type != __constant_htons(ETH_P_VLAN))
+#endif
+				if (skb->dev->br_port != NULL &&
+				    br_handle_frame_hook != NULL) {
+					handle_bridge(skb, pt_prev);
+					continue;
+				}
 #endif
 
 			for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
@@ -1642,7 +1650,18 @@
 			dev->name[IFNAMSIZ-1] = 0;
 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
 			return 0;
+               case SIOCADDVLAN:
+               case SIOCDELVLAN:
+#ifdef CONFIG_KMOD
+		       if (vlan_ioctl_hook == NULL)
+			       request_module("vlan");
+#endif
+                       if (vlan_ioctl_hook != NULL)
+                               return vlan_ioctl_hook(dev, cmd, ifr->ifr_mtu);
+		       
+                       return -ENOPKG;
 
+ 
 		/*
 		 *	Unknown or private ioctl
 		 */
@@ -1760,6 +1779,8 @@
 		case SIOCSIFHWBROADCAST:
 		case SIOCSIFTXQLEN:
 		case SIOCSIFNAME:
+	        case SIOCADDVLAN:
+	        case SIOCDELVLAN:
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			dev_load(ifr.ifr_name);
diff -urN -X exclude 2.3.99-pre3-fixed/net/netsyms.c 2.3.99-pre3-vlan/net/netsyms.c
--- 2.3.99-pre3-fixed/net/netsyms.c	Fri Mar 17 20:56:20 2000
+++ 2.3.99-pre3-vlan/net/netsyms.c	Thu Mar 30 17:43:24 2000
@@ -29,6 +29,7 @@
 #include <net/pkt_sched.h>
 #include <net/scm.h>
 #include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 #include <linux/random.h>
 
 #ifdef CONFIG_NET
@@ -221,6 +222,12 @@
 #endif
 #endif
 
+#if defined(CONFIG_VLAN) || defined(CONFIG_VLAN_MODULE)
+EXPORT_SYMBOL(vlan_enabled);                           
+EXPORT_SYMBOL(vlan_ioctl_hook);
+#endif
+
+
 #ifdef CONFIG_INET
 /* Internet layer registration */
 EXPORT_SYMBOL(inetdev_lock);
@@ -417,6 +424,7 @@
 
 EXPORT_SYMBOL(dev_set_allmulti);
 EXPORT_SYMBOL(dev_set_promiscuity);
+EXPORT_SYMBOL(dev_change_flags);
 EXPORT_SYMBOL(sklist_remove_socket);
 EXPORT_SYMBOL(rtnl_sem);
 EXPORT_SYMBOL(rtnl_lock);
diff -urN -X exclude 2.3.99-pre3-fixed/net/protocols.c 2.3.99-pre3-vlan/net/protocols.c
--- 2.3.99-pre3-fixed/net/protocols.c	Mon Aug 23 19:56:32 1999
+++ 2.3.99-pre3-vlan/net/protocols.c	Wed Mar 29 11:41:56 2000
@@ -100,6 +100,10 @@
 #include <net/p8022call.h>
 #endif
 
+#ifdef CONFIG_VLAN
+extern void vlan_init(struct net_proto *);
+#endif
+
 /*
  *	Protocol Table
  */
@@ -176,6 +180,10 @@
 
 #ifdef CONFIG_IRDA
   { "IrDA",     irda_proto_init },                     /* IrDA protocols */
+#endif
+  
+#ifdef CONFIG_VLAN
+  {"VLAN",      vlan_init },                           /* IEEE 802.1q vlan tagging */
 #endif
 
   { NULL,	NULL		}			/* End marker			*/
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/Makefile 2.3.99-pre3-vlan/net/vlan/Makefile
--- 2.3.99-pre3-fixed/net/vlan/Makefile	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/Makefile	Tue Mar 28 15:04:24 2000
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux ethernet VLAN tagging layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET	:= vlan.o
+O_OBJS		:= vlan_device.o vlan_init.o vlan_input.o vlan_ioctl.o \
+			vlan_notify.o vlan_mcast.o
+M_OBJS		:= $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/vlan_device.c 2.3.99-pre3-vlan/net/vlan/vlan_device.c
--- 2.3.99-pre3-fixed/net/vlan/vlan_device.c	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/vlan_device.c	Thu Mar 30 16:58:56 2000
@@ -0,0 +1,252 @@
+/*
+ *	Device handling code
+ *	IEEE 802.1q VLAN tagging
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *	Gleb Natapov			<gleb@tochna.technion.ac.il>
+ *
+ *	$Id$
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <net/neighbour.h>
+#include <net/arp.h>
+#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
+#include "vlan_private.h"
+
+static int vlan_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
+{
+	return -1;
+}
+
+static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev)
+{
+	struct vlan_slave *v = dev->priv;
+	return &v->statistics;
+}
+
+static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vlan_slave *slave;
+
+	slave = dev->priv;
+	slave->statistics.tx_packets++;
+	slave->statistics.tx_bytes += skb->len;
+
+	skb->dev = slave->master;
+	dev_queue_xmit(skb);
+	return 0;
+}
+
+static void vlan_dev_set_multicast_list(struct net_device *dev)
+{
+	struct dev_mc_list *dmi;
+	struct vlan_slave *slave = dev->priv;
+	int inc = dev->promiscuity - slave->promiscuity;
+
+
+	if(inc) {
+		printk(KERN_INFO "vlan: dev_set_promiscuity(master, %d)\n",inc);
+		dev_set_promiscuity(slave->master, inc);
+		slave->promiscuity = dev->promiscuity;
+	}
+
+	inc = dev->allmulti - slave->allmulti;
+
+	if(inc) {
+		printk(KERN_INFO "vlan: dev_set_allmulti(master, %d)\n", inc);
+		dev_set_allmulti(slave->master, inc);
+		slave->allmulti = dev->allmulti;
+	}
+	
+	/* looking for addresses to add to master's list */
+	for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) {
+		if(vlan_should_add_mc(dmi, slave->mc_list)) {
+			dev_mc_add(slave->master, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+			printk(KERN_INFO "vlan: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n",
+			       dmi->dmi_addr[0],
+			       dmi->dmi_addr[1],
+			       dmi->dmi_addr[2],
+			       dmi->dmi_addr[3],
+			       dmi->dmi_addr[4],
+			       dmi->dmi_addr[5]);
+		}
+	}
+
+	/* looking for addresses to delete from master's list */
+	for(dmi=slave->mc_list; dmi!=NULL; dmi=dmi->next) {
+		if(vlan_should_delete_mc(dmi, dev->mc_list)) {
+			dev_mc_delete(slave->master, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+			printk(KERN_INFO "vlan: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
+			       dmi->dmi_addr[0],
+			       dmi->dmi_addr[1],
+			       dmi->dmi_addr[2],
+			       dmi->dmi_addr[3],
+			       dmi->dmi_addr[4],
+			       dmi->dmi_addr[5]);
+		}
+	}
+
+	/* save multicast list */
+	vlan_copy_mc_list(dev->mc_list, slave);
+}
+
+static int vlan_dev_change_mtu(struct net_device *dev, int mtu)
+{
+	if (mtu >= 68 && mtu <= 1500) {
+		dev->mtu = mtu;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int vlan_dev_header(struct sk_buff *skb,
+			   struct net_device *dev,
+			   unsigned short type,
+			   void *daddr,
+			   void *saddr,
+			   unsigned len)
+{
+	struct vlan_slave *slave = dev->priv;
+	struct vlanhdr *vlan = (struct vlanhdr *)skb_push(skb, VLAN_HLEN);
+
+	vlan->v_prio = __constant_htons(ETH_P_VLAN);
+	vlan->v_vid = htons(slave->vid);
+
+	if (type != ETH_P_802_3)
+		vlan->v_proto = htons(type);
+	else
+		vlan->v_proto = htons(len);
+
+	if (saddr)
+		memcpy(vlan->v_source, saddr, dev->addr_len);
+	else
+		memcpy(vlan->v_source, dev->dev_addr, dev->addr_len);
+
+	if (daddr) {
+		memcpy(vlan->v_dest, daddr, dev->addr_len);
+		return VLAN_HLEN;
+	}
+
+	return -VLAN_HLEN;
+}
+
+static int vlan_dev_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+	struct vlanhdr *vlan = skb->mac.vlan;
+
+	memcpy(haddr, vlan->v_source, ETH_ALEN);
+	return ETH_ALEN;
+}
+
+static int vlan_dev_rebuild_header(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	struct vlanhdr *vlan = (struct vlanhdr *)skb->data;
+
+	switch (vlan->v_proto)
+	{
+#ifdef CONFIG_INET
+	case __constant_htons(ETH_P_IP):
+		return arp_find(vlan->v_dest, skb);
+#endif
+
+	default:
+		printk(KERN_DEBUG
+		       "%s: unable to resolve type %X addresses.\n",
+		       dev->name, (int)vlan->v_proto);
+
+		memcpy(vlan->v_source, dev->dev_addr, dev->addr_len);
+		break;
+	}
+
+	return 0;
+}
+
+int vlan_open(struct net_device *dev)
+{
+	struct vlan_slave *slave = dev->priv;
+	
+	if( !(slave->master->flags & IFF_UP) )
+		return -ENETDOWN;
+
+	return 0;
+}
+
+int vlan_stop(struct net_device *dev)
+{
+	struct vlan_slave *slave = dev->priv;
+
+	vlan_flush_mc_list(slave->master, &slave->mc_list);
+
+	return 0;
+}
+
+void vlan_uninit(struct net_device *dev)
+{
+	struct vlan_slave *slave = dev->priv;
+	struct net_device *master = slave->master;
+	
+	printk(KERN_ALERT "vlan: vlan_uninit\n");
+
+	master->vlan_count--;
+	if(master->vlan_count == 0) {
+		kfree(master->vlan_slaves);
+		master->vlan_slaves = NULL;
+	}
+	dev_put(dev);
+	dev_put(master);
+}
+
+void vlan_destructor(struct net_device *dev)
+{
+	printk(KERN_ALERT "vlan: vlan_destructor\n");
+	vlan_dec_use_count();
+}
+
+void vlan_dev_setup(struct net_device *dev, struct net_device *master)
+{
+	memcpy(dev->dev_addr, master->dev_addr, ETH_ALEN);
+	dev->change_mtu = vlan_dev_change_mtu;
+	dev->hard_header = vlan_dev_header;
+	dev->rebuild_header = vlan_dev_rebuild_header;
+	dev->set_mac_address = NULL;
+	dev->hard_header_cache = NULL;
+	dev->header_cache_update = NULL;
+	dev->hard_header_parse = vlan_dev_header_parse;
+	dev->open = vlan_open;
+	dev->stop = vlan_stop;
+	dev->uninit = vlan_uninit;
+	dev->destructor = vlan_destructor;
+	
+	dev->type = ARPHRD_ETHER;
+	dev->hard_header_len = 18;
+	dev->mtu = 1500;
+	dev->addr_len = ETH_ALEN;
+	dev->tx_queue_len = 0;
+
+	memset(dev->broadcast, 0xFF, ETH_ALEN);
+	dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+
+	dev_init_buffers(dev);
+
+	dev->get_stats = vlan_dev_get_stats;
+	dev->hard_start_xmit = vlan_dev_hard_start_xmit;
+	dev->set_multicast_list = vlan_dev_set_multicast_list;
+	dev->accept_fastpath = vlan_dev_accept_fastpath;
+	dev->do_ioctl = NULL;
+	dev->neigh_setup = NULL;
+}
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/vlan_init.c 2.3.99-pre3-vlan/net/vlan/vlan_init.c
--- 2.3.99-pre3-fixed/net/vlan/vlan_init.c	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/vlan_init.c	Thu Mar 30 16:27:42 2000
@@ -0,0 +1,73 @@
+/*
+ *	Initialization
+ *	IEEE 802.1q VLAN tagging
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *	Gleb Natapov			<gleb@tochna.technion.ac.il>
+ *
+ *	$Id$
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include "vlan_private.h"
+
+static struct packet_type vlan_packet_type =
+{
+        __constant_ntohs(ETH_P_VLAN),
+        NULL,
+        vlan_handle_frame,
+        (void*)1,
+        NULL
+};
+
+
+void vlan_dec_use_count()
+{
+	MOD_DEC_USE_COUNT;
+}
+
+void vlan_inc_use_count()
+{
+	MOD_INC_USE_COUNT;
+}
+
+int __init vlan_init(struct net_proto *nproto)
+{
+	printk(KERN_INFO "NET4: VLAN tagging 001 for NET4.0\n");
+
+	dev_add_pack(&vlan_packet_type);
+	vlan_enabled = 1;
+	vlan_ioctl_hook = vlan_ioctl; 
+	register_netdevice_notifier(&vlan_device_notifier);
+
+	return 0;
+}
+
+static void __exit vlan_cleanup(void)
+{
+	unregister_netdevice_notifier(&vlan_device_notifier);
+	dev_remove_pack(&vlan_packet_type);
+	vlan_ioctl_hook = NULL;
+	vlan_enabled = 0;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+module_init(vlan_init)
+module_exit(vlan_cleanup)
+#endif
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/vlan_input.c 2.3.99-pre3-vlan/net/vlan/vlan_input.c
--- 2.3.99-pre3-fixed/net/vlan/vlan_input.c	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/vlan_input.c	Thu Mar 30 16:56:25 2000
@@ -0,0 +1,132 @@
+/*
+ *	Handle incoming frames
+ *	IEEE 802.1q VLAN tagging
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *	Gleb Natapov			<gleb@tochna.technion.ac.il>
+ *
+ *	$Id$
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include "vlan_private.h"
+
+static unsigned short vlan_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned char *rawp;
+	struct vlanhdr *veth;
+	
+	skb->mac.raw = skb->data;
+	skb_pull(skb, VLAN_HLEN);
+	veth = skb->mac.vlan;
+	
+	if (veth->v_dest[0] & 1) {
+		if(memcmp(veth->v_dest, dev->broadcast, ETH_ALEN)==0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	} else {
+		if(memcmp(veth->v_dest, dev->dev_addr, ETH_ALEN))
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+	
+	if (ntohs(veth->v_proto) >= 1536)
+		return veth->v_proto;
+		
+	rawp = skb->data;
+	
+	/*
+	 *	This is a magic hack to spot IPX packets. Older Novell
+	 *	breaks the protocol design and runs IPX over 802.3
+	 *	without an 802.2 LLC layer. We look for FFFF which
+	 *	isn't a used 802.2 SSAP/DSAP. This won't work for
+	 *	fault tolerant netware but does for the rest.
+	 */
+	if (*(unsigned short *)rawp == 0xFFFF)
+		return htons(ETH_P_802_3);
+		
+	/*
+	 *	Real 802.2 LLC
+	 */
+	return htons(ETH_P_802_2);
+}
+
+extern __inline__ void dump_skb(struct sk_buff *skb)
+{
+	int i;
+	int len;
+
+	printk("skb %p: data%p mac%p nh%p head%p tail%p end%p\n",
+	       skb, skb->data, skb->mac.raw, skb->nh.raw, skb->head,
+	       skb->tail, skb->end);
+
+	len = 32;
+	if (skb->len < len)
+		len = skb->len;
+
+	for (i=0;i<len;i++) {
+		printk("%.2x ", skb->mac.raw[i]);
+		if (i%7 == 7)
+			printk("\n");
+	}
+}
+
+
+int vlan_handle_frame(struct sk_buff *skb, struct net_device *dev,
+		      struct packet_type* ptype)
+{
+        struct vlan_slave *slave = NULL;
+        struct vlanhdr *veth;
+	int vid;
+
+	if (skb_headroom(skb) < ETH_HLEN) {
+		printk(KERN_INFO "vlan: received packet with headroom %i\n",
+		       skb_headroom(skb));
+		kfree_skb(skb);
+		return 0;
+	}
+
+        veth = (struct vlanhdr *)skb_push(skb, ETH_HLEN);
+        vid = ntohs(veth->v_vid) & 0xFFF;
+	
+	read_lock(&dev->vlan_slaves_lock);
+	if(dev->vlan_slaves)
+		slave = dev->vlan_slaves[VLAN_HASH_VALUE(vid)];
+
+	while (slave != NULL) {
+		if (slave->vid == vid) {
+			if( !(skb = skb_unshare(skb, GFP_ATOMIC)) ) {
+				printk(KERN_ERR "vlan: failed to unshare skbuff\n");
+				slave->statistics.rx_dropped++;
+				return 0;
+			}
+			slave->statistics.rx_packets++;
+			slave->statistics.rx_bytes += skb->len;
+			skb->pkt_type = PACKET_HOST;
+			skb->dev = slave->device;
+			skb->protocol = vlan_type_trans(skb, skb->dev);
+			memmove(skb->data - (VLAN_HLEN - 4), skb->data - VLAN_HLEN, 12);
+			skb->mac.raw+=4;
+			netif_rx(skb);
+			read_unlock(&dev->vlan_slaves_lock);
+			return 0;
+		}
+
+		slave = slave->next;
+	}
+	read_unlock(&dev->vlan_slaves_lock);
+	kfree_skb(skb);
+	return 0;
+}
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/vlan_ioctl.c 2.3.99-pre3-vlan/net/vlan/vlan_ioctl.c
--- 2.3.99-pre3-fixed/net/vlan/vlan_ioctl.c	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/vlan_ioctl.c	Thu Mar 30 15:57:24 2000
@@ -0,0 +1,140 @@
+/*
+ *	Ioctl handler
+ *	IEEE 802.1q VLAN tagging
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *	Gleb Natapov			<gleb@tochna.technion.ac.il>
+ *
+ *	$Id$
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include "vlan_private.h"
+
+
+static struct vlan_slave **vlan_find(struct net_device *dev, int vid)
+{
+	struct vlan_slave **slave;
+	int hash_value = VLAN_HASH_VALUE(vid);
+
+	if(!dev->vlan_slaves)
+		return NULL;
+
+	slave = &(dev->vlan_slaves[hash_value]);
+	while (*slave != NULL) {
+		if ((*slave)->vid == vid) 
+			return slave;
+
+		slave = &((*slave)->next);
+	}
+
+	return NULL;
+}
+
+
+int vlan_add(struct net_device *dev, int vid)
+{
+	struct vlan_slave *slave;
+	struct net_device *slave_dev;
+	char vlanid[8];
+	int hash_value = VLAN_HASH_VALUE(vid);
+
+	if (strchr(dev->name, '.') != NULL)
+		return -EINVAL;
+
+
+	if (vlan_find(dev, vid) != NULL)
+		return -EBUSY;
+	
+	slave_dev = kmalloc(sizeof(struct vlan_slave) + sizeof(struct net_device), GFP_KERNEL);
+
+	if (slave_dev == NULL)
+		return -ENOMEM;
+
+	if(!dev->vlan_slaves) {
+		dev->vlan_slaves = 
+			kmalloc(sizeof(*dev->vlan_slaves)*VLAN_HASH_SIZE, GFP_KERNEL);
+		if(!dev->vlan_slaves) {
+		        kfree(slave_dev);
+			return -ENOMEM;
+		}
+		memset(dev->vlan_slaves, 0, sizeof(*dev->vlan_slaves)*VLAN_HASH_SIZE);
+	}
+
+	memset(slave_dev, 0, sizeof(struct vlan_slave) + sizeof(struct net_device));
+	
+	slave_dev->priv = (void *)(slave_dev+1);
+	slave = (struct vlan_slave*)slave_dev->priv;
+	slave->device = slave_dev;
+	slave_dev->name = slave->name;
+	slave_dev->new_style = 1;
+	
+	strncpy(slave_dev->name, dev->name, IFNAMSIZ);
+	sprintf(vlanid, ".%i", vid);
+	strncat(slave_dev->name, vlanid, IFNAMSIZ);
+	vlan_dev_setup(slave_dev, dev);
+
+	slave->next = dev->vlan_slaves[hash_value];
+	dev->vlan_slaves[hash_value] = slave;
+	slave->master = dev;
+	slave->vid = vid;
+	dev->vlan_count++;
+
+	dev_hold(slave_dev);
+	dev_hold(dev);
+	vlan_inc_use_count();
+	register_netdevice(slave_dev);
+
+	return 0;
+}
+
+int vlan_del(struct net_device *dev, int vid)
+{
+	struct vlan_slave *sl;
+	struct vlan_slave **slave;
+
+	if ((slave = vlan_find(dev, vid)) == NULL) 
+		return -ENFILE;
+	
+
+	sl = *slave;
+	*slave = sl->next;
+
+	unregister_netdevice(sl->device);
+	return 0;
+}
+
+DECLARE_MUTEX(vlan_ioctl_lock);
+
+int vlan_ioctl(struct net_device *dev, int cmd, int vlan)
+{
+	int err = -ENOPKG;
+
+	if (vlan & ~0xFFF || dev->type != ARPHRD_ETHER)
+		return -EINVAL;
+
+	down(&vlan_ioctl_lock);
+	write_lock_bh(&dev->vlan_slaves_lock);
+	if (cmd == SIOCADDVLAN) 
+		err = vlan_add(dev, vlan);
+	if (cmd == SIOCDELVLAN) 
+		err = vlan_del(dev, vlan);
+	write_unlock_bh(&dev->vlan_slaves_lock);
+	up(&vlan_ioctl_lock);
+
+	return err;
+}
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/vlan_mcast.c 2.3.99-pre3-vlan/net/vlan/vlan_mcast.c
--- 2.3.99-pre3-fixed/net/vlan/vlan_mcast.c	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/vlan_mcast.c	Tue Mar 28 18:16:21 2000
@@ -0,0 +1,99 @@
+/*
+ *	Multicast handling code
+ *	IEEE 802.1q VLAN tagging
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *	Gleb Natapov			<gleb@tochna.technion.ac.il>
+ *
+ *	$Id$
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/config.h>
+#include <linux/netdevice.h>
+
+#include "vlan_private.h"
+
+static inline int dmi_equals(struct dev_mc_list *dmi1,
+			     struct dev_mc_list *dmi2)
+{
+	return memcmp(dmi1->dmi_addr,dmi2->dmi_addr,dmi1->dmi_addrlen) == 0 &&
+	       dmi1->dmi_addrlen == dmi2->dmi_addrlen;
+}
+
+static inline void destroy_mc_list(struct dev_mc_list *mc_list)
+{
+	struct dev_mc_list *dmi;
+	for(dmi=mc_list; dmi!=NULL; dmi=dmi->next)
+		kfree(dmi);
+}
+
+int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list)
+{
+	struct dev_mc_list *idmi;
+
+	for(idmi=mc_list; idmi!=NULL;) {
+		if(dmi_equals(dmi, idmi)) {
+			if(dmi->dmi_users > idmi->dmi_users)
+				return 1;
+			else
+				return 0;
+		} else
+			idmi=idmi->next;
+	}
+	
+	return 1;
+}
+
+int vlan_should_delete_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list)
+{
+	return vlan_should_add_mc(dmi, mc_list);
+}
+
+void vlan_copy_mc_list(struct dev_mc_list *mc_list, struct vlan_slave *slave)
+{
+	struct dev_mc_list *dmi, *new_dmi;
+	
+	destroy_mc_list(slave->mc_list);
+	slave->mc_list = NULL;
+	for(dmi=mc_list; dmi!=NULL; dmi=dmi->next) {
+		new_dmi = kmalloc(sizeof(*new_dmi), GFP_KERNEL);
+		if(new_dmi == NULL) {
+			printk(KERN_ERR "vlan: cannot allocate memory. Multicast may not work properly from now.\n");
+			return;
+		}
+
+		new_dmi->next = slave->mc_list;
+		slave->mc_list = new_dmi;
+		
+		new_dmi->dmi_addrlen = dmi->dmi_addrlen;
+		memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen);
+		new_dmi->dmi_users = dmi->dmi_users;
+		new_dmi->dmi_gusers = dmi->dmi_gusers;
+	}
+}
+
+void vlan_flush_mc_list(struct net_device *dev, struct dev_mc_list **mc_list)
+{
+	struct dev_mc_list *dmi;
+
+	for(dmi = *mc_list; dmi!=NULL; dmi=dmi->next) { 
+		dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+                printk(KERN_INFO "vlan: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
+				dmi->dmi_addr[0],
+				dmi->dmi_addr[1],
+				dmi->dmi_addr[2],
+				dmi->dmi_addr[3],
+				dmi->dmi_addr[4],
+				dmi->dmi_addr[5]);
+	}
+
+	destroy_mc_list(*mc_list);
+	*mc_list = NULL;
+}
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/vlan_notify.c 2.3.99-pre3-vlan/net/vlan/vlan_notify.c
--- 2.3.99-pre3-fixed/net/vlan/vlan_notify.c	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/vlan_notify.c	Thu Mar 30 16:44:07 2000
@@ -0,0 +1,107 @@
+/*
+ *	Device event handling
+ *	IEEE 802.1q VLAN tagging
+ *
+ *	Authors:
+ *	Lennert Buytenhek		<buytenh@gnu.org>
+ *	Gleb Natapov			<gleb@tochna.technion.ac.il>
+ *
+ *	$Id$
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include "vlan_private.h"
+
+static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr);
+
+
+struct notifier_block vlan_device_notifier =
+{
+	vlan_device_event,
+	NULL,
+	0
+};
+
+static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+	struct net_device *dev;
+	struct vlan_slave *sl;
+	int i;
+
+	dev = ptr;
+	if(!dev->vlan_slaves)
+		return NOTIFY_DONE;
+
+
+	switch (event)
+	{
+	case NETDEV_CHANGEADDR:
+		read_lock(&dev->vlan_slaves_lock);
+		for(i = 0; i < VLAN_HASH_SIZE; i++) {
+		sl = dev->vlan_slaves[i];
+			while (sl != NULL) {
+				memcpy(sl->device->dev_addr, dev->dev_addr, ETH_ALEN);
+				sl = sl->next;
+			}
+		}
+		read_unlock(&dev->vlan_slaves_lock);
+		break;
+
+	case NETDEV_GOING_DOWN:
+	case NETDEV_DOWN:
+		read_lock(&dev->vlan_slaves_lock);
+		for(i = 0; i < VLAN_HASH_SIZE; i++) {
+		sl = dev->vlan_slaves[i];
+			while (sl != NULL) {
+				sl->saved_flags &= ~IFF_UP;
+				sl->saved_flags |= (sl->device->flags & IFF_UP);
+				dev_change_flags(sl->device,
+						 sl->device->flags & ~IFF_UP);
+				sl = sl->next;
+			}
+		}
+		read_unlock(&dev->vlan_slaves_lock);
+		break;
+
+	case NETDEV_UP:
+		read_lock(&dev->vlan_slaves_lock);
+		for(i = 0; i < VLAN_HASH_SIZE; i++) {
+		sl = dev->vlan_slaves[i];
+			while (sl != NULL) {
+				if(sl->saved_flags & IFF_UP)
+					dev_change_flags(sl->device,
+							 sl->device->flags | IFF_UP);
+				sl = sl->next;
+			}
+		}
+		read_unlock(&dev->vlan_slaves_lock);
+		break;
+
+	case NETDEV_UNREGISTER:
+		write_lock_bh(&dev->vlan_slaves_lock);
+		for(i = 0; i < VLAN_HASH_SIZE; i++) {
+			sl = dev->vlan_slaves[i];
+			while (sl != NULL) {
+				struct vlan_slave *slnext;
+				
+				slnext = sl->next;
+				vlan_del(dev, sl->vid);
+				sl = slnext;
+			}
+		}
+		write_unlock_bh(&dev->vlan_slaves_lock);
+		break;
+	}
+	return NOTIFY_DONE;
+}
diff -urN -X exclude 2.3.99-pre3-fixed/net/vlan/vlan_private.h 2.3.99-pre3-vlan/net/vlan/vlan_private.h
--- 2.3.99-pre3-fixed/net/vlan/vlan_private.h	Thu Jan  1 02:00:00 1970
+++ 2.3.99-pre3-vlan/net/vlan/vlan_private.h	Thu Mar 30 15:03:52 2000
@@ -0,0 +1,39 @@
+#ifndef _VLAN_PRIVATE_H
+#define _VLAN_PRIVATE_H
+
+#include <linux/netdevice.h>
+
+#define VLAN_HASH_SIZE 16
+#define VLAN_HASH_VALUE(x) ((x)%VLAN_HASH_SIZE)
+
+struct vlan_slave
+{
+	struct 			vlan_slave *next;
+	struct net_device 	*master;
+	int 			vid;
+
+	char 			name[IFNAMSIZ];
+	struct net_device       *device;
+	struct net_device_stats statistics;
+	struct dev_mc_list 	*mc_list;
+	int 			promiscuity;
+	int 			allmulti;
+	unsigned short 		saved_flags;
+};
+
+extern struct notifier_block vlan_device_notifier;
+
+int vlan_add(struct net_device *dev, int vid);
+void vlan_copy_mc_list(struct dev_mc_list *mc_list, struct vlan_slave *slave);
+void vlan_dec_use_count(void);
+int vlan_del(struct net_device *dev, int vid);
+void vlan_dev_setup(struct net_device *dev, struct net_device *master);
+int vlan_handle_frame(struct sk_buff *skb, struct net_device *dev,
+		      struct packet_type* ptype);
+void vlan_inc_use_count(void);
+int vlan_ioctl(struct net_device *dev, int cmd, int vlan);
+int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list);
+int vlan_should_delete_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list);
+void vlan_flush_mc_list(struct net_device *dev, struct dev_mc_list **mc_list);
+
+#endif
