diff -ruN kernel-source-2.4.14-vanilla/include/linux/nicext.h kernel-source-2.4.14/include/linux/nicext.h
--- kernel-source-2.4.14-vanilla/include/linux/nicext.h	Thu Jan  1 01:00:00 1970
+++ kernel-source-2.4.14/include/linux/nicext.h	Wed Nov 21 13:56:02 2001
@@ -0,0 +1,123 @@
+/****************************************************************************
+ * Copyright(c) 2000-2001 Broadcom Corporation. All rights reserved.
+ *
+ * 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.          
+ *
+ * Name:        nicext.h
+ *
+ * Description: Broadcom Network Interface Card Extension (NICE) is an 
+ *              extension to Linux NET device kernel mode drivers. 
+ *              NICE is designed to provide additional functionalities, 
+ *              such as receive packet intercept. To support Broadcom NICE, 
+ *              the network device driver can be modified by adding an 
+ *              device ioctl handler and by indicating receiving packets 
+ *              to the NICE receive handler. Broadcom NICE will only be 
+ *              enabled by a NICE-aware intermediate driver, such as 
+ *              Broadcom Advanced Server Program Driver (BASP). When NICE 
+ *              is not enabled, the modified network device drivers 
+ *              functions exactly as other non-NICE aware drivers.
+ *
+ * Author:      Frankie Fan
+ *
+ * Created:     September 17, 2000
+ *
+ * Changed: ard@kwaak.net Wed, 21 Nov 2001 13:45:10 +0100
+ *              Added vlan tag magic
+ ****************************************************************************/
+#ifndef _nicext_h_
+#define _nicext_h_
+
+/*
+ * ioctl for NICE
+ */
+#define SIOCNICE                   	SIOCDEVPRIVATE+7
+
+/*
+ * SIOCNICE: 
+ *
+ * The following structure needs to be less than IFNAMSIZ (16 bytes) because
+ * we're overloading ifreq.ifr_ifru.
+ *
+ * If 16 bytes is not enough, we should consider relaxing this because
+ * this is no field after ifr_ifru in the ifreq structure. But we may
+ * run into future compatiability problem in case of changing struct ifreq.
+ */
+struct nice_req
+{
+    __u32 cmd;
+    
+    union
+    {
+#ifdef __KERNEL__
+        /* cmd = NICE_CMD_SET_RX or NICE_CMD_GET_RX */
+        struct
+        {
+            void (*nrqus1_rx)( struct sk_buff*, void* );
+            void* nrqus1_ctx;
+        } nrqu_nrqus1;
+
+        /* cmd = NICE_CMD_QUERY_SUPPORT */
+        struct
+        {
+            __u32 nrqus2_magic;
+            __u32 nrqus2_support_rx:1;
+            __u32 nrqus2_support_vlan:1;
+            __u32 nrqus2_support_get_speed:1;
+        } nrqu_nrqus2;
+#endif
+
+        /* cmd = NICE_CMD_GET_SPEED */
+        struct
+        {
+            unsigned int nrqus3_speed; /* 0 if link is down, */
+                                       /* otherwise speed in Mbps */
+        } nrqu_nrqus3;
+
+        /* cmd = NICE_CMD_BLINK_LED */
+        struct
+        {
+            unsigned int nrqus4_blink_time; /* blink duration in seconds */
+        } nrqu_nrqus4;
+
+    } nrq_nrqu;
+};
+
+typedef struct {
+	unsigned short  tag;
+	unsigned short  signature;
+} vlan_tag_t;
+
+
+#define nrq_rx           nrq_nrqu.nrqu_nrqus1.nrqus1_rx
+#define nrq_ctx          nrq_nrqu.nrqu_nrqus1.nrqus1_ctx
+#define nrq_support_rx   nrq_nrqu.nrqu_nrqus2.nrqus2_support_rx
+#define nrq_magic        nrq_nrqu.nrqu_nrqus2.nrqus2_magic
+#define nrq_support_vlan nrq_nrqu.nrqu_nrqus2.nrqus2_support_vlan
+#define nrq_support_get_speed nrq_nrqu.nrqu_nrqus2.nrqus2_support_get_speed
+#define nrq_speed        nrq_nrqu.nrqu_nrqus3.nrqus3_speed
+#define nrq_blink_time   nrq_nrqu.nrqu_nrqus4.nrqus4_blink_time
+
+/*
+ * magic constants
+ */
+#define NICE_REQUESTOR_MAGIC            0x4543494E // NICE in ascii
+#define NICE_DEVICE_MAGIC               0x4E494345 // ECIN in ascii
+#define NICE_VLAN_TXTAG 0x5555
+#define NICE_VLAN_RXTAG 0x7777
+#define NICE_VLAN_EMPTY 0
+
+
+
+/*
+ * command field
+ */
+#define NICE_CMD_QUERY_SUPPORT          0x00000001
+#define NICE_CMD_SET_RX                 0x00000002
+#define NICE_CMD_GET_RX                 0x00000003
+#define NICE_CMD_GET_SPEED              0x00000004
+#define NICE_CMD_BLINK_LED              0x00000005
+
+#endif  // _nicext_h_ 
+
diff -ruN kernel-source-2.4.14-vanilla/net/8021q/Makefile kernel-source-2.4.14/net/8021q/Makefile
--- kernel-source-2.4.14-vanilla/net/8021q/Makefile	Wed Oct 31 00:08:12 2001
+++ kernel-source-2.4.14/net/8021q/Makefile	Mon Nov 19 18:33:19 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := 8021q.o
 
-obj-y := vlan.o vlanproc.o vlan_dev.o
+obj-y := vlan.o vlanproc.o vlan_dev.o vlan_nice.o
 obj-m := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -ruN kernel-source-2.4.14-vanilla/net/8021q/vlan.c kernel-source-2.4.14/net/8021q/vlan.c
--- kernel-source-2.4.14-vanilla/net/8021q/vlan.c	Wed Oct 31 00:08:12 2001
+++ kernel-source-2.4.14/net/8021q/vlan.c	Mon Nov 19 18:46:32 2001
@@ -34,6 +34,7 @@
 #include <linux/if_vlan.h>
 #include "vlan.h"
 #include "vlanproc.h"
+#include "vlan_nice.h"
 
 /* Global VLAN variables */
 
@@ -156,6 +157,19 @@
 	return NULL;
 }
 
+/** Will search the vlan group table to see if there is a vlan defined
+ */
+
+int vlan_group_empty(struct vlan_group* grp)
+{
+	int i;
+	for(i=0;i<VLAN_GROUP_ARRAY_LEN;i++) {
+		if(grp->vlan_devices[i]) return 0;
+	}
+	return 1;
+}
+
+
 /** This method will explicitly do a dev_put on the device if do_dev_put
  * is TRUE.  This gets around a difficulty with reference counting, and
  * the unregister-by-name (below).  If do_locks is true, it will grab
@@ -201,7 +215,14 @@
 			} else {
 				unregister_netdevice(dev);
 			}
-
+			if(vlan_group_empty(grp)) {
+				struct net_device *real_dev;
+				real_dev=dev_get_by_index(real_dev_ifindex);
+				if(real_dev) {
+					vlan_nice_disable_rx(real_dev);
+					dev_put(real_dev);
+				}
+			}
 			MOD_DEC_USE_COUNT;
 		}
 	}
@@ -252,6 +273,8 @@
 	struct net_device *new_dev;
 	struct net_device *real_dev; /* the ethernet device */
 	int malloc_size = 0;
+	int nice_supported; /* Is the device nice capable */
+
 
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG __FUNCTION__ ": if_name -:%s:-	vid: %i\n",
@@ -285,6 +308,7 @@
 		goto out_put_dev;
 
 	memset(new_dev, 0, malloc_size);
+	nice_supported=vlan_nice_supported(real_dev);
 
 	/* set us up to not use a Qdisc, as the underlying Hardware device
 	 * can do all the queueing we could want.
@@ -351,8 +375,13 @@
 	/* TODO: maybe just assign it to be ETHERNET? */
 	new_dev->type = real_dev->type;
 
-	/* Regular ethernet + 4 bytes (18 total). */
-	new_dev->hard_header_len = VLAN_HLEN + real_dev->hard_header_len;
+	if(nice_supported) {
+		/* Regular ethernet, tag is done seperately */
+		new_dev->hard_header_len=real_dev->hard_header_len;
+	} else {
+		/* Regular ethernet + 4 bytes (18 total). */
+		new_dev->hard_header_len = VLAN_HLEN + real_dev->hard_header_len;
+	}
 
 	new_dev->priv = kmalloc(sizeof(struct vlan_dev_info),
 				GFP_KERNEL);
@@ -375,8 +404,17 @@
 	new_dev->stop = vlan_dev_stop;
 	new_dev->hard_header = vlan_dev_hard_header;
 
-	new_dev->hard_start_xmit = vlan_dev_hard_start_xmit;
-	new_dev->rebuild_header = vlan_dev_rebuild_header;
+	if(nice_supported) {
+		/* We do not have to insert tags */
+		new_dev->hard_header=real_dev->hard_header;
+		/* We must send extra info in the skb */
+		new_dev->hard_start_xmit = vlan_nice_dev_hard_start_xmit;
+	} else {
+		/* We must insert tags */
+		new_dev->hard_header = vlan_dev_hard_header;
+		/* We must make sure it is tagged */
+		new_dev->hard_start_xmit = vlan_dev_hard_start_xmit;
+	}
 	new_dev->hard_header_parse = real_dev->hard_header_parse;
 	new_dev->set_mac_address = vlan_dev_set_mac_address;
 	new_dev->set_multicast_list = vlan_dev_set_multicast_list;
@@ -431,6 +469,12 @@
 	 * so hold on to the reference.
 	 */
 	MOD_INC_USE_COUNT; /* Add was a success!! */
+	/** It is not a problem to re-enable again and again.
+	 * We must do it after MOD_INC_USE_COUNT, since only
+	 * then we are sure that our nice functions will not be removed
+	 */
+	 vlan_nice_enable_rx(real_dev,grp);
+
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "Allocated new device successfully, returning.\n");
 #endif
diff -ruN kernel-source-2.4.14-vanilla/net/8021q/vlan_nice.c kernel-source-2.4.14/net/8021q/vlan_nice.c
--- kernel-source-2.4.14-vanilla/net/8021q/vlan_nice.c	Thu Jan  1 01:00:00 1970
+++ kernel-source-2.4.14/net/8021q/vlan_nice.c	Mon Nov 19 18:47:07 2001
@@ -0,0 +1,148 @@
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/in.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/datalink.h>
+#include <net/p8022.h>
+#include <net/arp.h>
+#include <linux/brlock.h>
+
+
+#include "vlan.h"
+#include "vlanproc.h"
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <linux/nicext.h>
+#include "vlan_nice.h"
+
+int vlan_nice_netif_rx(struct sk_buff *skb, struct vlan_group *grp)
+{
+	unsigned short vid;
+	struct net_device_stats* stats;
+	vlan_tag_t *nice_vlan;
+	struct net_device *dev;
+
+	unsigned short vlan_TCI;
+
+	/* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */
+	nice_vlan=(vlan_tag_t *)&skb->cb[0];
+	if(NICE_VLAN_RXTAG!=nice_vlan->signature) {
+		/* Nope, do a plain netif_rx */
+		return netif_rx(skb);
+	}
+	/* Clear signature just in case */
+	nice_vlan->signature=0;
+	dev=skb->dev;
+	/* Yep, we got vlan */
+	vlan_TCI=nice_vlan->tag;
+	/*vlan_TCI = ntohs(vhdr->h_vlan_TCI);*/
+	vid = (vlan_TCI & 0xFFF);
+
+	/* At this moment we have to:
+	 * check if the vid is valid for this device
+	 * If it is, we do a netif_rx with the right skb->dev
+	 */
+
+#ifdef VLAN_DEBUG
+	printk(VLAN_DBG __FUNCTION__ ": skb: %p vlan_id: %hx\n",
+		   skb, vid);
+#endif
+
+	/* we have 12 bits of vlan ID. */
+	skb->dev = grp->vlan_devices[vid];
+
+	if (!skb->dev) {
+	#ifdef VLAN_DEBUG
+		printk(VLAN_DBG __FUNCTION__ ": ERROR:  No net_device for VID: %i on dev: %s [%i]\n", (unsigned int)(vid), dev->name, dev->ifindex);
+	#endif
+		kfree_skb(skb);
+		return -1;
+	}
+
+	/* Bump the rx counters for the VLAN device. */
+	stats = vlan_dev_get_stats(skb->dev);
+	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
+	return netif_rx(skb);
+}
+
+int vlan_nice_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+        struct net_device_stats* stats = vlan_dev_get_stats(dev);
+		vlan_tag_t *nice_vlan;
+
+        /* Prepare vlan tag insertion by nice driver.
+         */
+                
+		nice_vlan=(vlan_tag_t *)&skb->cb[0];
+		nice_vlan->tag = VLAN_DEV_INFO(dev)->vlan_id;
+		nice_vlan->tag |= vlan_dev_get_egress_qos_mask(dev, skb);
+		nice_vlan->signature=NICE_VLAN_TXTAG;
+
+        skb->dev = VLAN_DEV_INFO(dev)->real_dev;
+        
+        dev_queue_xmit(skb);
+        stats->tx_packets++; /* for statics only */
+        stats->tx_bytes += skb->len;
+        return 0;
+}/* vlan_nice_dev_hard_start_xmit */
+
+int vlan_nice_supported(struct net_device *dev)
+{
+	static struct ifreq ifr;
+	static struct nice_req *nrq;
+	static int (* ioctl)(struct net_device *, struct ifreq *, int);
+	memset(&ifr,0,sizeof(ifr));
+	nrq=&ifr.ifr_ifru;
+	nrq->cmd=NICE_CMD_QUERY_SUPPORT;
+	if (((ioctl = dev->do_ioctl) != NULL) && (ioctl(dev, &ifr, SIOCNICE) == 0)) {
+		/* Now we have something nice? */
+		if(NICE_DEVICE_MAGIC==nrq->nrq_magic && nrq->nrq_support_rx) {
+			/* Yes. It supports _rx and vlan */
+			/* Actually the test is not complete, but the bcm5700 driver is also not complete */
+			return 1;
+		}
+	}
+	printk(KERN_INFO "VLAN NICE: device %s is not NICE capable.\n",dev->name);
+	return 0;
+}
+
+int vlan_nice_enable_rx(struct net_device *dev, void *data)
+{
+	static struct ifreq ifr;
+	static struct nice_req *nrq;
+	static int (* ioctl)(struct net_device *, struct ifreq *, int);
+	memset(&ifr,0,sizeof(ifr));
+	nrq=&ifr.ifr_ifru;
+	if(!vlan_nice_supported(dev)) return 0;
+	nrq->cmd=NICE_CMD_SET_RX;
+	nrq->nrq_rx=vlan_nice_netif_rx;
+	nrq->nrq_ctx=data;
+	printk(KERN_INFO "VLAN NICE: enabling NICE on %s.\n",dev->name);
+	if (((ioctl = dev->do_ioctl) != NULL) && (ioctl(dev, &ifr, SIOCNICE) == 0)) {
+		/* Hmmm, ok.... */
+	}
+	return 0;
+}
+
+int vlan_nice_disable_rx(struct net_device *dev)
+{
+	static struct ifreq ifr;
+	static struct nice_req *nrq;
+	static int (* ioctl)(struct net_device *, struct ifreq *, int);
+	memset(&ifr,0,sizeof(ifr));
+	nrq=&ifr.ifr_ifru;
+	if(!vlan_nice_supported(dev)) return 0;
+	nrq->cmd=NICE_CMD_SET_RX;
+	nrq->nrq_rx=NULL;
+	nrq->nrq_ctx=NULL;
+	printk(KERN_INFO "VLAN NICE: disabling NICE on %s.\n",dev->name);
+	if (((ioctl = dev->do_ioctl) != NULL) && (ioctl(dev, &ifr, SIOCNICE) == 0)) {
+		/* Hmmm, ok.... */
+	}
+	return 0;
+}
+
diff -ruN kernel-source-2.4.14-vanilla/net/8021q/vlan_nice.h kernel-source-2.4.14/net/8021q/vlan_nice.h
--- kernel-source-2.4.14-vanilla/net/8021q/vlan_nice.h	Thu Jan  1 01:00:00 1970
+++ kernel-source-2.4.14/net/8021q/vlan_nice.h	Wed Nov 21 14:41:57 2001
@@ -0,0 +1,15 @@
+/******************************************************************************/
+/*                                                                            */
+/* This file is based on bcm5700.c written by Broadcom                        */
+/*                                                                            */
+/******************************************************************************/
+
+#ifndef VLAN_NICE
+#define VLAN_NICE
+#include <linux/nicext.h>
+
+extern int vlan_nice_enable_rx(struct net_device *dev, void *data);
+extern int vlan_nice_disable_rx(struct net_device *dev);
+extern int vlan_nice_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+#endif
