Merge branch 'openwrt-patches'

Merge all OpenWRT patches from sdk-comcerto-openwrt-c2k_2.1 except for
use_preinit_as_init
diff --git a/Makefile b/Makefile
index fa5acc8..89f46df 100644
--- a/Makefile
+++ b/Makefile
@@ -559,9 +559,9 @@
 all: vmlinux
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS	+= -Os
+KBUILD_CFLAGS	+= -Os -fno-caller-saves
 else
-KBUILD_CFLAGS	+= -O2
+KBUILD_CFLAGS	+= -O2 -fno-reorder-blocks -fno-tree-ch -fno-caller-saves
 endif
 
 include $(srctree)/arch/$(SRCARCH)/Makefile
@@ -620,6 +620,9 @@
 NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
 CHECKFLAGS     += $(NOSTDINC_FLAGS)
 
+# improve gcc optimization
+CFLAGS += $(call cc-option,-funit-at-a-time,)
+
 # warn about C99 declaration after statement
 KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 1e9be5d..4057690 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -81,6 +81,10 @@
 			return -ENOEXEC;
 		}
 
+		if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
+		    ELF_ST_BIND(sym->st_info) == STB_WEAK)
+			continue;
+
 		loc = dstsec->sh_addr + rel->r_offset;
 
 		switch (ELF32_R_TYPE(rel->r_info)) {
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 527a857..6cca0d2 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -31,7 +31,7 @@
 	  this is.
 
 config CRYPTO_ALGAPI
-	tristate
+	tristate "ALGAPI"
 	select CRYPTO_ALGAPI2
 	help
 	  This option provides the API for cryptographic algorithms.
@@ -40,7 +40,7 @@
 	tristate
 
 config CRYPTO_AEAD
-	tristate
+	tristate "AEAD"
 	select CRYPTO_AEAD2
 	select CRYPTO_ALGAPI
 
@@ -49,7 +49,7 @@
 	select CRYPTO_ALGAPI2
 
 config CRYPTO_BLKCIPHER
-	tristate
+	tristate "BLKCIPHER"
 	select CRYPTO_BLKCIPHER2
 	select CRYPTO_ALGAPI
 
@@ -60,7 +60,7 @@
 	select CRYPTO_WORKQUEUE
 
 config CRYPTO_HASH
-	tristate
+	tristate "HASH"
 	select CRYPTO_HASH2
 	select CRYPTO_ALGAPI
 
@@ -69,7 +69,7 @@
 	select CRYPTO_ALGAPI2
 
 config CRYPTO_RNG
-	tristate
+	tristate "RNG"
 	select CRYPTO_RNG2
 	select CRYPTO_ALGAPI
 
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 4035b6d..2a65c65 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -23,6 +23,14 @@
 	  WARNING: some of the tests will ERASE entire MTD device which they
 	  test. Do not use these tests unless you really know what you do.
 
+config MTD_ROOTFS_ROOT_DEV
+	bool "Automatically set 'rootfs' partition to be root filesystem"
+	default y
+
+config MTD_ROOTFS_SPLIT
+	bool "Automatically split 'rootfs' partition for squashfs"
+	default y
+
 config MTD_REDBOOT_PARTS
 	tristate "RedBoot partition table parsing"
 	---help---
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index e7dc732..194b83b 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1026,6 +1026,12 @@
 		break;
 	}
 
+	case MTDREFRESH:
+	{
+		ret = mtd_device_refresh(mtd);
+		break;
+	}
+
 	default:
 		ret = -ENOTTY;
 	}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index a0bd2de..e82ba37 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -29,10 +29,14 @@
 #include <linux/kmod.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/root_dev.h>
+#include <linux/magic.h>
 #include <linux/err.h>
 
 #include "mtdcore.h"
 
+#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */
+
 /* Our partition linked list */
 static LIST_HEAD(mtd_partitions);
 static DEFINE_MUTEX(mtd_partitions_mutex);
@@ -50,7 +54,7 @@
  * the pointer to that structure with this macro.
  */
 #define PART(x)  ((struct mtd_part *)(x))
-
+#define IS_PART(mtd) (mtd->read == part_read)
 
 /*
  * MTD methods which simply translate the effective address and pass through
@@ -256,13 +260,60 @@
 		return -EROFS;
 	if (instr->addr >= mtd->size)
 		return -EINVAL;
+
+	instr->partial_start = false;
+	if (mtd->flags & MTD_ERASE_PARTIAL) {
+		size_t readlen = 0;
+		u64 mtd_ofs;
+
+		instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
+		if (!instr->erase_buf)
+			return -ENOMEM;
+
+		mtd_ofs = part->offset + instr->addr;
+		instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
+
+		if (instr->erase_buf_ofs > 0) {
+			instr->addr -= instr->erase_buf_ofs;
+			ret = part->master->read(part->master,
+				instr->addr + part->offset,
+				part->master->erasesize,
+				&readlen, instr->erase_buf);
+
+			instr->partial_start = true;
+		} else {
+			mtd_ofs = part->offset + part->mtd.size;
+			instr->erase_buf_ofs = part->master->erasesize -
+				do_div(mtd_ofs, part->master->erasesize);
+
+			if (instr->erase_buf_ofs > 0) {
+				instr->len += instr->erase_buf_ofs;
+				ret = part->master->read(part->master,
+					part->offset + instr->addr +
+					instr->len - part->master->erasesize,
+					part->master->erasesize, &readlen,
+					instr->erase_buf);
+			} else {
+				ret = 0;
+			}
+		}
+		if (ret < 0) {
+			kfree(instr->erase_buf);
+			return ret;
+		}
+
+	}
+
 	instr->addr += part->offset;
 	ret = part->master->erase(part->master, instr);
 	if (ret) {
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
 			instr->fail_addr -= part->offset;
 		instr->addr -= part->offset;
+		if (mtd->flags & MTD_ERASE_PARTIAL)
+			kfree(instr->erase_buf);
 	}
+
 	return ret;
 }
 
@@ -270,7 +321,25 @@
 {
 	if (instr->mtd->erase == part_erase) {
 		struct mtd_part *part = PART(instr->mtd);
+		size_t wrlen = 0;
 
+		if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
+			if (instr->partial_start) {
+				part->master->write(part->master,
+					instr->addr, instr->erase_buf_ofs,
+					&wrlen, instr->erase_buf);
+				instr->addr += instr->erase_buf_ofs;
+			} else {
+				instr->len -= instr->erase_buf_ofs;
+				part->master->write(part->master,
+					instr->addr + instr->len,
+					instr->erase_buf_ofs, &wrlen,
+					instr->erase_buf +
+					part->master->erasesize -
+					instr->erase_buf_ofs);
+			}
+			kfree(instr->erase_buf);
+		}
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
 			instr->fail_addr -= part->offset;
 		instr->addr -= part->offset;
@@ -541,18 +610,24 @@
 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
 	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
 		/* Doesn't start on a boundary of major erase size */
-		/* FIXME: Let it be writable if it is on a boundary of
-		 * _minor_ erase size though */
-		slave->mtd.flags &= ~MTD_WRITEABLE;
-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
-			part->name);
+		slave->mtd.flags |= MTD_ERASE_PARTIAL;
+		if (((u32) slave->mtd.size) > master->erasesize)
+			slave->mtd.flags &= ~MTD_WRITEABLE;
+		else
+			slave->mtd.erasesize = slave->mtd.size;
 	}
 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
-		slave->mtd.flags &= ~MTD_WRITEABLE;
-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
-			part->name);
+	    mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
+		slave->mtd.flags |= MTD_ERASE_PARTIAL;
+
+		if ((u32) slave->mtd.size > master->erasesize)
+			slave->mtd.flags &= ~MTD_WRITEABLE;
+		else
+			slave->mtd.erasesize = slave->mtd.size;
 	}
+	if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL)
+		printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n",
+				part->name);
 
 	slave->mtd.ecclayout = master->ecclayout;
 	if (master->block_isbad) {
@@ -650,6 +725,155 @@
 }
 EXPORT_SYMBOL_GPL(mtd_del_partition);
 
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+#define ROOTFS_SPLIT_NAME "rootfs_data"
+#define ROOTFS_REMOVED_NAME "<removed>"
+
+struct squashfs_super_block {
+	__le32 s_magic;
+	__le32 pad0[9];
+	__le64 bytes_used;
+};
+
+
+static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
+{
+	struct squashfs_super_block sb;
+	int len, ret;
+
+	ret = master->read(master, offset, sizeof(sb), &len, (void *) &sb);
+	if (ret || (len != sizeof(sb))) {
+		printk(KERN_ALERT "split_squashfs: error occured while reading "
+			"from \"%s\"\n", master->name);
+		return -EINVAL;
+	}
+
+	if (SQUASHFS_MAGIC != le32_to_cpu(sb.s_magic) ) {
+		printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n",
+			master->name);
+		*split_offset = 0;
+		return 0;
+	}
+
+	if (le64_to_cpu((sb.bytes_used)) <= 0) {
+		printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
+			master->name);
+		*split_offset = 0;
+		return 0;
+	}
+
+	len = (u32) le64_to_cpu(sb.bytes_used);
+	len += (offset & 0x000fffff);
+	len +=  (master->erasesize - 1);
+	len &= ~(master->erasesize - 1);
+	len -= (offset & 0x000fffff);
+	*split_offset = offset + len;
+
+	return 0;
+}
+
+static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part)
+{
+	struct mtd_partition *dpart;
+	struct mtd_part *slave = NULL;
+	struct mtd_part *spart;
+	int ret, split_offset = 0;
+
+	spart = PART(rpart);
+	ret = split_squashfs(master, spart->offset, &split_offset);
+	if (ret)
+		return ret;
+
+	if (split_offset <= 0)
+		return 0;
+
+	dpart = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL);
+	if (dpart == NULL) {
+		printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n",
+			ROOTFS_SPLIT_NAME);
+		return -ENOMEM;
+	}
+
+	memcpy(dpart, part, sizeof(*part));
+	dpart->name = (unsigned char *)&dpart[1];
+	strcpy(dpart->name, ROOTFS_SPLIT_NAME);
+
+	dpart->size = rpart->size - (split_offset - spart->offset);
+	dpart->offset = split_offset;
+
+	if (dpart == NULL)
+		return 1;
+
+	printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%llX, len=%llX \n",
+		ROOTFS_SPLIT_NAME, dpart->offset, dpart->size);
+
+	slave = allocate_partition(master, dpart, 0, split_offset);
+	if (IS_ERR(slave))
+		return PTR_ERR(slave);
+	mutex_lock(&mtd_partitions_mutex);
+	list_add(&slave->list, &mtd_partitions);
+	mutex_unlock(&mtd_partitions_mutex);
+
+	add_mtd_device(&slave->mtd);
+
+	rpart->split = &slave->mtd;
+
+	return 0;
+}
+
+static int refresh_rootfs_split(struct mtd_info *mtd)
+{
+	struct mtd_partition tpart;
+	struct mtd_part *part;
+	char *name;
+	//int index = 0;
+	int offset, size;
+	int ret;
+
+	part = PART(mtd);
+
+	/* check for the new squashfs offset first */
+	ret = split_squashfs(part->master, part->offset, &offset);
+	if (ret)
+		return ret;
+
+	if ((offset > 0) && !mtd->split) {
+		printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name);
+		/* if we don't have a rootfs split partition, create a new one */
+		tpart.name = (char *) mtd->name;
+		tpart.size = mtd->size;
+		tpart.offset = part->offset;
+
+		return split_rootfs_data(part->master, &part->mtd, &tpart);
+	} else if ((offset > 0) && mtd->split) {
+		/* update the offsets of the existing partition */
+		size = mtd->size + part->offset - offset;
+
+		part = PART(mtd->split);
+		part->offset = offset;
+		part->mtd.size = size;
+		printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n",
+			__func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"),
+			(u32) part->offset, (u32) part->mtd.size);
+		name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
+		strcpy(name, ROOTFS_SPLIT_NAME);
+		part->mtd.name = name;
+	} else if ((offset <= 0) && mtd->split) {
+		printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name);
+
+		/* mark existing partition as removed */
+		part = PART(mtd->split);
+		name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
+		strcpy(name, ROOTFS_REMOVED_NAME);
+		part->mtd.name = name;
+		part->offset = 0;
+		part->mtd.size = 0;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_MTD_ROOTFS_SPLIT */
+
 /*
  * This function, given a master MTD object and a partition table, creates
  * and registers slave MTD objects which are bound to the master according to
@@ -666,6 +890,9 @@
 	struct mtd_part *slave;
 	uint64_t cur_offset = 0;
 	int i;
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+	int ret;
+#endif
 
 	printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
 
@@ -680,12 +907,53 @@
 
 		add_mtd_device(&slave->mtd);
 
+		if (!strcmp(parts[i].name, "rootfs")) {
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+			if (ROOT_DEV == 0) {
+				printk(KERN_NOTICE "mtd: partition \"rootfs\" "
+					"set to be root filesystem\n");
+				ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
+			}
+#endif
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+			ret = split_rootfs_data(master, &slave->mtd, &parts[i]);
+			/* if (ret == 0)
+			 * 	j++; */
+#endif
+		}
+
 		cur_offset = slave->offset + slave->mtd.size;
 	}
 
 	return 0;
 }
 
+int mtd_device_refresh(struct mtd_info *mtd)
+{
+	int ret = 0;
+
+	if (IS_PART(mtd)) {
+		struct mtd_part *part;
+		struct mtd_info *master;
+
+		part = PART(mtd);
+		master = part->master;
+		if (master->refresh_device)
+			ret = master->refresh_device(master);
+	}
+
+	if (!ret && mtd->refresh_device)
+		ret = mtd->refresh_device(mtd);
+
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+	if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs"))
+		refresh_rootfs_split(mtd);
+#endif
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtd_device_refresh);
+
 static DEFINE_SPINLOCK(part_parser_lock);
 static LIST_HEAD(part_parsers);
 
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index bc9a4bb..49c6da9 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -856,7 +856,7 @@
 		goto end;
 
 
-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
+	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD,
 			   0, GFP_KERNEL);
 	if (!skb) {
 		error = -ENOMEM;
@@ -864,7 +864,7 @@
 	}
 
 	/* Reserve space for headers. */
-	skb_reserve(skb, dev->hard_header_len);
+	skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD);
 	skb_reset_network_header(skb);
 
 	skb->dev = dev;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 73cd900..ed7d797 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -652,6 +652,71 @@
 }
 EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor);
 
+static struct usb_device *match_device_name(struct usb_device *dev,
+					    const char *name)
+{
+	struct usb_device *ret_dev = NULL;
+	int child;
+
+	dev_dbg(&dev->dev, "check for name %s ...\n", name);
+
+	/* see if this device matches */
+	if (strcmp(dev_name(&dev->dev), name) == 0 ) {
+		dev_dbg(&dev->dev, "matched this device!\n");
+		ret_dev = usb_get_dev(dev);
+		goto exit;
+	}
+
+	/* look through all of the children of this device */
+	for (child = 0; child < dev->maxchild; ++child) {
+		if (dev->children[child]) {
+			usb_lock_device(dev->children[child]);
+			ret_dev = match_device_name(dev->children[child], name);
+			usb_unlock_device(dev->children[child]);
+			if (ret_dev)
+				goto exit;
+		}
+	}
+exit:
+	return ret_dev;
+}
+
+/**
+ * usb_find_device_by_name - find a specific usb device in the system
+ * @name: the name of the device to find
+ *
+ * Returns a pointer to a struct usb_device if such a specified usb
+ * device is present in the system currently.  The usage count of the
+ * device will be incremented if a device is found.  Make sure to call
+ * usb_put_dev() when the caller is finished with the device.
+ *
+ * If a device with the specified bus id is not found, NULL is returned.
+ */
+struct usb_device *usb_find_device_by_name(const char *name)
+{
+	struct list_head *buslist;
+	struct usb_bus *bus;
+	struct usb_device *dev = NULL;
+
+	mutex_lock(&usb_bus_list_lock);
+	for (buslist = usb_bus_list.next;
+	     buslist != &usb_bus_list;
+	     buslist = buslist->next) {
+		bus = container_of(buslist, struct usb_bus, bus_list);
+		if (!bus->root_hub)
+			continue;
+		usb_lock_device(bus->root_hub);
+		dev = match_device_name(bus->root_hub, name);
+		usb_unlock_device(bus->root_hub);
+		if (dev)
+			goto exit;
+	}
+exit:
+	mutex_unlock(&usb_bus_list_lock);
+	return dev;
+}
+EXPORT_SYMBOL_GPL(usb_find_device_by_name);
+
 /**
  * usb_alloc_coherent - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
  * @dev: device the buffer will be used with
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 339be10..a5c37fd 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -756,7 +756,7 @@
 		"USB %x.%x started, EHCI %x.%02x%s\n",
 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
 		temp >> 8, temp & 0xff,
-		ignore_oc ? ", overcurrent ignored" : "");
+		(ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
 
 	ehci_writel(ehci, INTR_MASK,
 		    &ehci->regs->intr_enable); /* Turn On Interrupts */
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 77bbb23..c39ea4a 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -578,7 +578,7 @@
 	 * always set, seem to clear PORT_OCC and PORT_CSC when writing to
 	 * PORT_POWER; that's surprising, but maybe within-spec.
 	 */
-	if (!ignore_oc)
+	if (!ignore_oc && !ehci->ignore_oc)
 		mask = PORT_CSC | PORT_PEC | PORT_OCC;
 	else
 		mask = PORT_CSC | PORT_PEC;
@@ -803,7 +803,7 @@
 		if (temp & PORT_PEC)
 			status |= USB_PORT_STAT_C_ENABLE << 16;
 
-		if ((temp & PORT_OCC) && !ignore_oc){
+		if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
 			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
 
 			/*
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 0a5fda7..dcf60f5 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -147,6 +147,7 @@
 	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/
 	unsigned		has_synopsys_hc_bug:1; /* Synopsys HC */
 	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
+	unsigned		ignore_oc:1;
 
 	/* required for usb32 quirk */
 	#define OHCI_CTRL_HCFS          (3 << 6)
diff --git a/fs/file.c b/fs/file.c
index 4c6992d..9770a25 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -268,6 +268,7 @@
 	/* All good, so we try */
 	return expand_fdtable(files, nr);
 }
+EXPORT_SYMBOL_GPL(expand_files);
 
 static int count_open_files(struct fdtable *fdt)
 {
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 3005ec4..9572c26 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -112,6 +112,17 @@
 	dbg_fsbuild("scanned flash completely\n");
 	jffs2_dbg_dump_block_lists_nolock(c);
 
+	if (c->flags & (1 << 7)) {
+		printk("%s(): unlocking the mtd device... ", __func__);
+		if (c->mtd->unlock)
+			c->mtd->unlock(c->mtd, 0, c->mtd->size);
+		printk("done.\n");
+
+		printk("%s(): erasing all blocks after the end marker... ", __func__);
+		jffs2_erase_pending_blocks(c, -1);
+		printk("done.\n");
+	}
+
 	dbg_fsbuild("pass 1 starting\n");
 	c->flags |= JFFS2_SB_FLAG_BUILDING;
 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 28107ca..e3024ed 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -72,7 +72,7 @@
 		return ret;
 	if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size)))
 		return ret;
-	/* Turned wasted size into dirty, since we apparently 
+	/* Turned wasted size into dirty, since we apparently
 	   think it's recoverable now. */
 	jeb->dirty_size += jeb->wasted_size;
 	c->dirty_size += jeb->wasted_size;
@@ -147,8 +147,11 @@
 		/* reset summary info for next eraseblock scan */
 		jffs2_sum_reset_collected(s);
 
-		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
-						buf_size, s);
+		if (c->flags & (1 << 7))
+			ret = BLK_STATE_ALLFF;
+		else
+			ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+							buf_size, s);
 
 		if (ret < 0)
 			goto out;
@@ -403,7 +406,7 @@
 	if (!ref)
 		return -ENOMEM;
 
-	/* BEFORE jffs2_build_xattr_subsystem() called, 
+	/* BEFORE jffs2_build_xattr_subsystem() called,
 	 * and AFTER xattr_ref is marked as a dead xref,
 	 * ref->xid is used to store 32bit xid, xd is not used
 	 * ref->ino is used to store 32bit inode-number, ic is not used
@@ -476,7 +479,7 @@
 		struct jffs2_sum_marker *sm;
 		void *sumptr = NULL;
 		uint32_t sumlen;
-	      
+
 		if (!buf_size) {
 			/* XIP case. Just look, point at the summary if it's there */
 			sm = (void *)buf + c->sector_size - sizeof(*sm);
@@ -492,9 +495,9 @@
 				buf_len = sizeof(*sm);
 
 			/* Read as much as we want into the _end_ of the preallocated buffer */
-			err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, 
+			err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
 						  jeb->offset + c->sector_size - buf_len,
-						  buf_len);				
+						  buf_len);
 			if (err)
 				return err;
 
@@ -513,9 +516,9 @@
 				}
 				if (buf_len < sumlen) {
 					/* Need to read more so that the entire summary node is present */
-					err = jffs2_fill_scan_buf(c, sumptr, 
+					err = jffs2_fill_scan_buf(c, sumptr,
 								  jeb->offset + c->sector_size - sumlen,
-								  sumlen - buf_len);				
+								  sumlen - buf_len);
 					if (err)
 						return err;
 				}
@@ -528,7 +531,7 @@
 
 			if (buf_size && sumlen > buf_size)
 				kfree(sumptr);
-			/* If it returns with a real error, bail. 
+			/* If it returns with a real error, bail.
 			   If it returns positive, that's a block classification
 			   (i.e. BLK_STATE_xxx) so return that too.
 			   If it returns zero, fall through to full scan. */
@@ -549,6 +552,17 @@
 			return err;
 	}
 
+	if ((buf[0] == 0xde) &&
+		(buf[1] == 0xad) &&
+		(buf[2] == 0xc0) &&
+		(buf[3] == 0xde)) {
+		/* end of filesystem. erase everything after this point */
+		printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
+		c->flags |= (1 << 7);
+
+		return BLK_STATE_ALLFF;
+	}
+
 	/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
 	ofs = 0;
 	max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
@@ -674,7 +688,7 @@
 				scan_end = buf_len;
 				goto more_empty;
 			}
-			
+
 			/* See how much more there is to read in this eraseblock... */
 			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
 			if (!buf_len) {
@@ -910,7 +924,7 @@
 
 	D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
 		  jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size));
-	
+
 	/* mark_node_obsolete can add to wasted !! */
 	if (jeb->wasted_size) {
 		jeb->dirty_size += jeb->wasted_size;
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index b5e2e4c..6935a59 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -52,6 +52,27 @@
 #define LOAD_OFFSET 0
 #endif
 
+#ifndef SYMTAB_KEEP_STR
+#define SYMTAB_KEEP_STR *(__ksymtab_strings+*)
+#define SYMTAB_DISCARD_STR
+#else
+#define SYMTAB_DISCARD_STR *(__ksymtab_strings+*)
+#endif
+
+#ifndef SYMTAB_KEEP
+#define SYMTAB_KEEP *(SORT(___ksymtab+*))
+#define SYMTAB_DISCARD
+#else
+#define SYMTAB_DISCARD *(SORT(___ksymtab+*))
+#endif
+
+#ifndef SYMTAB_KEEP_GPL
+#define SYMTAB_KEEP_GPL *(SORT(___ksymtab_gpl+*))
+#define SYMTAB_DISCARD_GPL
+#else
+#define SYMTAB_DISCARD_GPL *(SORT(___ksymtab_gpl+*))
+#endif
+
 #ifndef SYMBOL_PREFIX
 #define VMLINUX_SYMBOL(sym) sym
 #else
@@ -275,14 +296,14 @@
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
-		*(SORT(___ksymtab+*))					\
+		SYMTAB_KEEP						\
 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
 	}								\
 									\
 	/* Kernel symbol table: GPL-only symbols */			\
 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
-		*(SORT(___ksymtab_gpl+*))				\
+		SYMTAB_KEEP_GPL						\
 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
 	}								\
 									\
@@ -344,7 +365,7 @@
 									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
-		*(__ksymtab_strings)					\
+		SYMTAB_KEEP_STR						\
 	}								\
 									\
 	/* __*init sections */						\
@@ -676,6 +697,9 @@
 	EXIT_TEXT							\
 	EXIT_DATA							\
 	EXIT_CALL							\
+	SYMTAB_DISCARD							\
+	SYMTAB_DISCARD_GPL						\
+	SYMTAB_DISCARD_STR						\
 	*(.discard)							\
 	*(.discard.*)							\
 	}
diff --git a/include/linux/crashlog.h b/include/linux/crashlog.h
new file mode 100644
index 0000000..11e98b3
--- /dev/null
+++ b/include/linux/crashlog.h
@@ -0,0 +1,12 @@
+#ifndef __CRASHLOG_H
+#define __CRASHLOG_H
+
+#ifdef CONFIG_CRASHLOG
+void __init crashlog_init_mem(struct bootmem_data *bdata);
+#else
+static inline void crashlog_init_mem(struct bootmem_data *bdata)
+{
+}
+#endif
+
+#endif
diff --git a/include/linux/decompress/unlzo_mm.h b/include/linux/decompress/unlzo_mm.h
new file mode 100644
index 0000000..08f9e70
--- /dev/null
+++ b/include/linux/decompress/unlzo_mm.h
@@ -0,0 +1,10 @@
+#ifndef UNLZO_MM_H
+#define UNLZO_MM_H
+
+#ifdef STATIC
+#define INIT
+#else
+#define INIT __init
+#endif
+
+#endif
diff --git a/include/linux/export.h b/include/linux/export.h
index 696c0f4..a2d8a34 100644
--- a/include/linux/export.h
+++ b/include/linux/export.h
@@ -45,12 +45,19 @@
 #define __CRC_SYMBOL(sym, sec)
 #endif
 
+#ifdef MODULE
+#define __EXPORT_SUFFIX(sym)
+#else
+#define __EXPORT_SUFFIX(sym) "+" #sym
+#endif
+
 /* For every exported symbol, place a struct in the __ksymtab section */
 #define __EXPORT_SYMBOL(sym, sec)				\
 	extern typeof(sym) sym;					\
 	__CRC_SYMBOL(sym, sec)					\
 	static const char __kstrtab_##sym[]			\
-	__attribute__((section("__ksymtab_strings"), aligned(1))) \
+	__attribute__((section("__ksymtab_strings"		\
+	  __EXPORT_SUFFIX(sym)), aligned(1)))			\
 	= MODULE_SYMBOL_PREFIX #sym;				\
 	static const struct kernel_symbol __ksymtab_##sym	\
 	__used							\
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index f379929..e06b393 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -29,6 +29,8 @@
 /* These ones are invisible by user level */
 #define PACKET_LOOPBACK		5		/* MC/BRD frame looped back */
 #define PACKET_FASTROUTE	6		/* Fastrouted frame	*/
+#define PACKET_MASK_ANY		0xffffffff	/* mask for packet type bits */
+
 
 /* Packet socket options */
 
@@ -50,6 +52,7 @@
 #define PACKET_TX_TIMESTAMP		16
 #define PACKET_TIMESTAMP		17
 #define PACKET_FANOUT			18
+#define PACKET_RECV_TYPE		19
 
 #define PACKET_FANOUT_HASH		0
 #define PACKET_FANOUT_LB		1
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index ad81e1c..6ef4b9d 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -31,6 +31,8 @@
 #define UEVENT_NUM_ENVP			32	/* number of env pointers */
 #define UEVENT_BUFFER_SIZE		2048	/* buffer for the variables */
 
+struct sk_buff;
+
 /* path to the userspace helper executed on an event */
 extern char uevent_helper[];
 
@@ -215,6 +217,10 @@
 
 int kobject_action_type(const char *buf, size_t count,
 			enum kobject_action *type);
+
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
+		     gfp_t allocation);
+
 #else
 static inline int kobject_uevent(struct kobject *kobj,
 				 enum kobject_action action)
@@ -231,6 +237,16 @@
 static inline int kobject_action_type(const char *buf, size_t count,
 				      enum kobject_action *type)
 { return -EINVAL; }
+
+void kfree_skb(struct sk_buff *);
+
+static inline int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
+				   gfp_t allocation)
+{
+	kfree_skb(skb);
+	return 0;
+}
+
 #endif
 
 #endif /* _KOBJECT_H_ */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 4baadd1..b880638 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -872,6 +872,7 @@
 
 int shmem_lock(struct file *file, int lock, struct user_struct *user);
 struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags);
+void shmem_set_file(struct vm_area_struct *vma, struct file *file);
 int shmem_zero_setup(struct vm_area_struct *);
 
 extern int can_do_mlock(void);
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 9f5b312..629401a 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -58,6 +58,10 @@
 	u_long priv;
 	u_char state;
 	struct erase_info *next;
+
+	u8 *erase_buf;
+	u32 erase_buf_ofs;
+	bool partial_start;
 };
 
 struct mtd_erase_region_info {
@@ -114,6 +118,7 @@
 
 struct module;	/* only needed for owner field in mtd_info */
 
+struct mtd_info;
 struct mtd_info {
 	u_char type;
 	uint32_t flags;
@@ -266,6 +271,9 @@
 	struct device dev;
 	int usecount;
 
+	int (*refresh_device)(struct mtd_info *mtd);
+	struct mtd_info *split;
+
 	/* If the driver is something smart, like UBI, it may need to maintain
 	 * its own reference counting. The below functions are only for driver.
 	 * The driver may register its callbacks. These callbacks are not
@@ -321,6 +329,7 @@
 			      int defnr_parts);
 #define mtd_device_register(master, parts, nr_parts)	\
 	mtd_device_parse_register(master, NULL, NULL, parts, nr_parts)
+extern int mtd_device_refresh(struct mtd_info *master);
 extern int mtd_device_unregister(struct mtd_info *master);
 extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
 extern int __get_mtd_device(struct mtd_info *mtd);
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index 2475228..8b2fecc 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -35,13 +35,16 @@
  * Note: writeable partitions require their size and offset be
  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
  */
+struct mtd_info;
 
+struct mtd_partition;
 struct mtd_partition {
 	char *name;			/* identifier string */
 	uint64_t size;			/* partition size */
 	uint64_t offset;		/* offset within the master MTD space */
 	uint32_t mask_flags;		/* master MTD flags to mask out for this partition */
 	struct nand_ecclayout *ecclayout;	/* out of band layout for this partition (NAND only) */
+	int (*refresh_partition)(struct mtd_info *);
 };
 
 #define MTDPART_OFS_RETAIN	(-3)
@@ -50,7 +53,6 @@
 #define MTDPART_SIZ_FULL	(0)
 
 
-struct mtd_info;
 struct device_node;
 
 /**
diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h
index 04e0181..41b00a5 100644
--- a/include/linux/mtd/physmap.h
+++ b/include/linux/mtd/physmap.h
@@ -17,6 +17,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
 
 struct map_info;
 struct platform_device;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index cb52340..ae451f8 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -142,7 +142,7 @@
  */
 
 #if defined(CONFIG_WLAN) || defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-# if defined(CONFIG_MAC80211_MESH)
+# if 1 || defined(CONFIG_MAC80211_MESH)
 #  define LL_MAX_HEADER 128
 # else
 #  define LL_MAX_HEADER 96
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 0ce91d5..feda699 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -2,12 +2,15 @@
 #define __NF_CONNTRACK_SIP_H__
 #ifdef __KERNEL__
 
+#include <linux/types.h>
+
 #define SIP_PORT	5060
 #define SIP_TIMEOUT	3600
 
 struct nf_ct_sip_master {
 	unsigned int	register_cseq;
 	unsigned int	invite_cseq;
+	__be16		forced_dport;
 };
 
 enum sip_expectation_classes {
diff --git a/include/linux/netfilter/xt_layer7.h b/include/linux/netfilter/xt_layer7.h
new file mode 100644
index 0000000..c38d3c4
--- /dev/null
+++ b/include/linux/netfilter/xt_layer7.h
@@ -0,0 +1,14 @@
+#ifndef _XT_LAYER7_H
+#define _XT_LAYER7_H
+
+#define MAX_PATTERN_LEN 8192
+#define MAX_PROTOCOL_LEN 256
+
+struct xt_layer7_info {
+    char protocol[MAX_PROTOCOL_LEN];
+    char pattern[MAX_PATTERN_LEN];
+    u_int8_t invert;
+    u_int8_t pkt;
+};
+
+#endif /* _XT_LAYER7_H */
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index db79231..061bb34 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -93,6 +93,7 @@
 #define IPT_F_FRAG		0x01	/* Set if rule is a fragment rule */
 #define IPT_F_GOTO		0x02	/* Set if jump is a goto */
 #define IPT_F_MASK		0x03	/* All possible flag bits mask. */
+#define IPT_F_NO_DEF_MATCH	0x80	/* Internal: no default match rules present */
 
 /* Values for "inv" field in struct ipt_ip. */
 #define IPT_INV_VIA_IN		0x01	/* Invert the sense of IN IFACE. */
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 7281d5a..8ee6a23 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -173,8 +173,37 @@
  *
  *	The only reason for this is efficiency, it is possible
  *	to change these parameters in compile time.
+ *
+ *	If you need to play with these values, use esfq instead.
  */
 
+/* ESFQ section */
+
+enum
+{
+        /* traditional */
+	TCA_SFQ_HASH_CLASSIC,
+	TCA_SFQ_HASH_DST,
+	TCA_SFQ_HASH_SRC,
+	TCA_SFQ_HASH_FWMARK,
+	/* conntrack */
+	TCA_SFQ_HASH_CTORIGDST,
+	TCA_SFQ_HASH_CTORIGSRC,
+	TCA_SFQ_HASH_CTREPLDST,
+	TCA_SFQ_HASH_CTREPLSRC,
+	TCA_SFQ_HASH_CTNATCHG,
+};
+
+struct tc_esfq_qopt
+{
+	unsigned	quantum;	/* Bytes per round allocated to flow */
+	int		perturb_period;	/* Period of hash perturbation */
+	__u32		limit;		/* Maximal packets in queue */
+	unsigned	divisor;	/* Hash divisor  */
+	unsigned	flows;		/* Maximal number of flows  */
+	unsigned	hash_kind;	/* Hash function to use for flow identification */
+};
+
 /* RED section */
 
 enum {
diff --git a/include/linux/stddef.h b/include/linux/stddef.h
index 6a40c76..5dab46c 100644
--- a/include/linux/stddef.h
+++ b/include/linux/stddef.h
@@ -16,6 +16,7 @@
 	false	= 0,
 	true	= 1
 };
+#endif /* __KERNEL__ */
 
 #undef offsetof
 #ifdef __compiler_offsetof
@@ -23,6 +24,5 @@
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif
-#endif /* __KERNEL__ */
 
 #endif
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 4269c3f..0ca88d7 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -531,6 +531,7 @@
 extern int usb_reset_device(struct usb_device *dev);
 extern void usb_queue_reset_device(struct usb_interface *dev);
 
+extern struct usb_device *usb_find_device_by_name(const char *name);
 
 /* USB autosuspend and autoresume */
 #ifdef CONFIG_USB_SUSPEND
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index 1a7e1d2..ec5aeaa 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -201,6 +201,7 @@
  * modes (see "struct mtd_write_req")
  */
 #define MEMWRITE		_IOWR('M', 24, struct mtd_write_req)
+#define MTDREFRESH		_IO('M', 50)
 
 /*
  * Obsolete legacy interface. Keep it in order not to break userspace
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index cbc6bb0..dbc0a0d 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -91,6 +91,12 @@
 extern void			addrconf_leave_solict(struct inet6_dev *idev,
 					const struct in6_addr *addr);
 
+extern int			(*ipv6_dev_get_saddr_hook)(struct net *net,
+						struct net_device *dev,
+						const struct in6_addr *daddr,
+						unsigned int srcprefs,
+						struct in6_addr *saddr);
+
 static inline unsigned long addrconf_timeout_fixup(u32 timeout,
 						    unsigned unit)
 {
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 8a2b0ae..0b6a3e8 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -134,6 +134,22 @@
 	struct net *ct_net;
 #endif
 
+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || \
+    defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
+	struct {
+		/*
+		 * e.g. "http". NULL before decision. "unknown" after decision
+		 * if no match.
+		 */
+		char *app_proto;
+		/*
+		 * application layer data so far. NULL after match decision.
+		 */
+		char *app_data;
+		unsigned int app_data_len;
+	} layer7;
+#endif
+
 	/* Storage reserved for other modules, must be the last member */
 	union nf_conntrack_proto proto;
 };
diff --git a/init/Kconfig b/init/Kconfig
index 43298f9..de390b3 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -891,6 +891,10 @@
 
 	  If unsure, say N.
 
+config CRASHLOG
+	bool "Crash logging"
+	depends on !NO_BOOTMEM && !HAVE_MEMBLOCK
+
 config BLK_DEV_INITRD
 	bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
 	depends on BROKEN || !FRV
diff --git a/init/main.c b/init/main.c
index cb08fea2..487c07e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -822,7 +822,7 @@
 
 	/* Open the /dev/console on the rootfs, this should never fail */
 	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
-		printk(KERN_WARNING "Warning: unable to open an initial console.\n");
+		printk(KERN_WARNING "Please be patient, while OpenWrt loads ...\n");
 
 	(void) sys_dup(0);
 	(void) sys_dup(0);
diff --git a/kernel/Makefile b/kernel/Makefile
index e898c5b..e1ac7e7 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -109,6 +109,7 @@
 obj-$(CONFIG_PADATA) += padata.o
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+obj-$(CONFIG_CRASHLOG) += crashlog.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/crashlog.c b/kernel/crashlog.c
new file mode 100644
index 0000000..00ea545
--- /dev/null
+++ b/kernel/crashlog.c
@@ -0,0 +1,171 @@
+/*
+ * Crash information logger
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Based on ramoops.c
+ *   Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/bootmem.h>
+#include <linux/debugfs.h>
+#include <linux/crashlog.h>
+#include <linux/kmsg_dump.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <asm/io.h>
+
+#define CRASHLOG_PAGES	4
+#define CRASHLOG_SIZE	(CRASHLOG_PAGES * PAGE_SIZE)
+#define CRASHLOG_MAGIC	0xa1eedead
+
+/*
+ * Start the log at 1M before the end of RAM, as some boot loaders like
+ * to use the end of the RAM for stack usage and other things
+ * If this fails, fall back to using the last part.
+ */
+#define CRASHLOG_OFFSET	(1024 * 1024)
+
+struct crashlog_data {
+	u32 magic;
+	u32 len;
+	u8 data[];
+};
+
+static struct debugfs_blob_wrapper crashlog_blob;
+static unsigned long crashlog_addr = 0;
+static struct crashlog_data *crashlog_buf;
+static struct kmsg_dumper dump;
+static bool first = true;
+
+extern struct list_head *crashlog_modules;
+
+void __init crashlog_init_mem(bootmem_data_t *bdata)
+{
+	unsigned long addr;
+
+	if (crashlog_addr)
+		return;
+
+	addr = PFN_PHYS(bdata->node_low_pfn) - CRASHLOG_OFFSET;
+	if (reserve_bootmem(addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) {
+		printk("Crashlog failed to allocate RAM at address 0x%lx\n", addr);
+		bdata->node_low_pfn -= CRASHLOG_PAGES;
+		addr = PFN_PHYS(bdata->node_low_pfn);
+	}
+	crashlog_addr = addr;
+}
+
+static void __init crashlog_copy(void)
+{
+	if (crashlog_buf->magic != CRASHLOG_MAGIC)
+		return;
+
+	if (!crashlog_buf->len || crashlog_buf->len >
+	    CRASHLOG_SIZE - sizeof(*crashlog_buf))
+		return;
+
+	crashlog_blob.size = crashlog_buf->len;
+	crashlog_blob.data = kmemdup(crashlog_buf->data,
+		crashlog_buf->len, GFP_KERNEL);
+
+	debugfs_create_blob("crashlog", 0700, NULL, &crashlog_blob);
+}
+
+static int get_maxlen(void)
+{
+	return CRASHLOG_SIZE - sizeof(*crashlog_buf) - crashlog_buf->len;
+}
+
+static void crashlog_printf(const char *fmt, ...)
+{
+	va_list args;
+	int len = get_maxlen();
+
+	if (!len)
+		return;
+
+	va_start(args, fmt);
+	crashlog_buf->len += vsnprintf(
+		&crashlog_buf->data[crashlog_buf->len],
+		len, fmt, args);
+	va_end(args);
+}
+
+static void crashlog_do_dump(struct kmsg_dumper *dumper,
+		enum kmsg_dump_reason reason, const char *s1, unsigned long l1,
+		const char *s2, unsigned long l2)
+{
+	unsigned long s1_start, s2_start;
+	unsigned long l1_cpy, l2_cpy;
+	struct timeval tv;
+	struct module *m;
+	char *buf;
+	int len;
+
+	if (!first)
+		crashlog_printf("\n===================================\n");
+
+	do_gettimeofday(&tv);
+	crashlog_printf("Time: %lu.%lu\n",
+		(long)tv.tv_sec, (long)tv.tv_usec);
+
+	if (first) {
+		crashlog_printf("Modules:");
+		list_for_each_entry(m, crashlog_modules, list) {
+			crashlog_printf("\t%s@%p+%x", m->name,
+			m->module_core, m->core_size,
+			m->module_init, m->init_size);
+		}
+		crashlog_printf("\n");
+		first = false;
+	}
+
+	buf = (char *)&crashlog_buf->data[crashlog_buf->len];
+	len = get_maxlen();
+
+	l2_cpy = min(l2, (unsigned long)len);
+	l1_cpy = min(l1, (unsigned long)len - l2_cpy);
+
+	s2_start = l2 - l2_cpy;
+	s1_start = l1 - l1_cpy;
+
+	memcpy(buf, s1 + s1_start, l1_cpy);
+	memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy);
+	crashlog_buf->len += l1_cpy + l2_cpy;
+}
+
+
+int __init crashlog_init_fs(void)
+{
+	if (!crashlog_addr)
+		return -ENOMEM;
+
+	crashlog_buf = ioremap(crashlog_addr, CRASHLOG_SIZE);
+
+	crashlog_copy();
+
+	crashlog_buf->magic = CRASHLOG_MAGIC;
+	crashlog_buf->len = 0;
+
+	dump.dump = crashlog_do_dump;
+	kmsg_dump_register(&dump);
+
+	return 0;
+}
+module_init(crashlog_init_fs);
diff --git a/kernel/exit.c b/kernel/exit.c
index 5a8a66e..0eca2ef 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -499,6 +499,7 @@
 
 	return files;
 }
+EXPORT_SYMBOL_GPL(get_files_struct);
 
 void put_files_struct(struct files_struct *files)
 {
@@ -520,6 +521,7 @@
 		rcu_read_unlock();
 	}
 }
+EXPORT_SYMBOL_GPL(put_files_struct);
 
 void reset_files_struct(struct files_struct *files)
 {
diff --git a/kernel/module.c b/kernel/module.c
index 6969ef0..424e00f 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -107,6 +107,9 @@
 #ifdef CONFIG_KGDB_KDB
 struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
 #endif /* CONFIG_KGDB_KDB */
+#ifdef CONFIG_CRASHLOG
+struct list_head *crashlog_modules = &modules;
+#endif
 
 
 /* Block module loading/unloading? */
diff --git a/kernel/sched.c b/kernel/sched.c
index 9cd8ca7..b16c3ac 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -5290,6 +5290,7 @@
 	return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) ||
 		capable(CAP_SYS_NICE));
 }
+EXPORT_SYMBOL_GPL(can_nice);
 
 #ifdef __ARCH_WANT_SYS_NICE
 
diff --git a/lib/Kconfig b/lib/Kconfig
index 32f3e5a..0a5d625 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -197,16 +197,16 @@
 # Textsearch support is select'ed if needed
 #
 config TEXTSEARCH
-	boolean
+	boolean	"Textsearch support"
 
 config TEXTSEARCH_KMP
-	tristate
+	tristate "Textsearch KMP"
 
 config TEXTSEARCH_BM
-	tristate
+	tristate "Textsearch BM"
 
 config TEXTSEARCH_FSM
-	tristate
+	tristate "Textsearch FSM"
 
 config BTREE
 	boolean
diff --git a/lib/decompress.c b/lib/decompress.c
index 3d766b7..af0c866 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -40,6 +40,7 @@
 	{ {037, 0236}, "gzip", gunzip },
 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
 	{ {0x5d, 0x00}, "lzma", unlzma },
+	{ {0x6d, 0x00}, "lzma-openwrt", unlzma },
 	{ {0xfd, 0x37}, "xz", unxz },
 	{ {0x89, 0x4c}, "lzo", unlzo },
 	{ {0, 0}, NULL, NULL }
diff --git a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c
index 5a7a2ad..09c4d85 100644
--- a/lib/decompress_unlzo.c
+++ b/lib/decompress_unlzo.c
@@ -38,6 +38,7 @@
 
 #include <linux/types.h>
 #include <linux/lzo.h>
+#include <linux/decompress/unlzo_mm.h>
 #include <linux/decompress/mm.h>
 
 #include <linux/compiler.h>
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 6d40244..df64823 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -50,6 +50,18 @@
 	[KOBJ_OFFLINE] =	"offline",
 };
 
+u64 uevent_next_seqnum(void)
+{
+	u64 seq;
+
+	mutex_lock(&uevent_sock_mutex);
+	seq = ++uevent_seqnum;
+	mutex_unlock(&uevent_sock_mutex);
+
+	return seq;
+}
+EXPORT_SYMBOL_GPL(uevent_next_seqnum);
+
 /**
  * kobject_action_type - translate action string to numeric type
  *
@@ -366,6 +378,43 @@
 EXPORT_SYMBOL_GPL(add_uevent_var);
 
 #if defined(CONFIG_NET)
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
+		     gfp_t allocation)
+{
+	struct uevent_sock *ue_sk;
+	int err = 0;
+
+	/* send netlink message */
+	mutex_lock(&uevent_sock_mutex);
+	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
+		struct sock *uevent_sock = ue_sk->sk;
+		struct sk_buff *skb2;
+
+		skb2 = skb_clone(skb, allocation);
+		if (!skb2)
+			break;
+
+		err = netlink_broadcast(uevent_sock, skb2, pid, group,
+					allocation);
+		if (err)
+			break;
+	}
+	mutex_unlock(&uevent_sock_mutex);
+
+	kfree_skb(skb);
+	return err;
+}
+#else
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
+		     gfp_t allocation)
+{
+	kfree_skb(skb);
+	return 0;
+}
+#endif
+EXPORT_SYMBOL_GPL(broadcast_uevent);
+
+#if defined(CONFIG_NET)
 static int uevent_net_init(struct net *net)
 {
 	struct uevent_sock *ue_sk;
diff --git a/mm/bootmem.c b/mm/bootmem.c
index b863822..d514f27 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -15,6 +15,7 @@
 #include <linux/export.h>
 #include <linux/kmemleak.h>
 #include <linux/range.h>
+#include <linux/crashlog.h>
 #include <linux/memblock.h>
 
 #include <asm/bug.h>
@@ -178,6 +179,7 @@
 	if (!bdata->node_bootmem_map)
 		return 0;
 
+	crashlog_init_mem(bdata);
 	start = bdata->node_min_pfn;
 	end = bdata->node_low_pfn;
 
diff --git a/mm/memory.c b/mm/memory.c
index 1b1ca17..8bb6f9a 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1393,6 +1393,7 @@
 	tlb_finish_mmu(&tlb, address, end);
 	return end;
 }
+EXPORT_SYMBOL_GPL(zap_page_range);
 
 /**
  * zap_vma_ptes - remove ptes mapping the vma
@@ -3068,6 +3069,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vmtruncate_range);
 
 /*
  * We enter with non-exclusive mmap_sem (to exclude vma changes,
diff --git a/mm/shmem.c b/mm/shmem.c
index 7a82174..90fbb87 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2492,6 +2492,16 @@
 
 /* common code */
 
+void shmem_set_file(struct vm_area_struct *vma, struct file *file)
+{
+	if (vma->vm_file)
+		fput(vma->vm_file);
+	vma->vm_file = file;
+	vma->vm_ops = &shmem_vm_ops;
+	vma->vm_flags |= VM_CAN_NONLINEAR;
+}
+EXPORT_SYMBOL_GPL(shmem_set_file);
+
 /**
  * shmem_file_setup - get an unlinked file living in tmpfs
  * @name: name for dentry (to be seen in /proc/<pid>/maps
@@ -2569,11 +2579,8 @@
 	if (IS_ERR(file))
 		return PTR_ERR(file);
 
-	if (vma->vm_file)
-		fput(vma->vm_file);
-	vma->vm_file = file;
-	vma->vm_ops = &shmem_vm_ops;
-	vma->vm_flags |= VM_CAN_NONLINEAR;
+	shmem_set_file(vma, file);
+
 	return 0;
 }
 
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index eeba3bb..626fd82 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1233,6 +1233,7 @@
 	vunmap_page_range(addr, end);
 	flush_tlb_kernel_range(addr, end);
 }
+EXPORT_SYMBOL_GPL(unmap_kernel_range);
 
 int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
 {
@@ -1370,6 +1371,7 @@
 	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
 				-1, GFP_KERNEL, __builtin_return_address(0));
 }
+EXPORT_SYMBOL_GPL(get_vm_area);
 
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
 				void *caller)
diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig
index 6dee7bf..9190ae4 100644
--- a/net/bridge/Kconfig
+++ b/net/bridge/Kconfig
@@ -6,7 +6,6 @@
 	tristate "802.1d Ethernet Bridging"
 	select LLC
 	select STP
-	depends on IPV6 || IPV6=n
 	---help---
 	  If you say Y here, then your Linux box will be able to act as an
 	  Ethernet bridge, which means that the different Ethernet segments it
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index e221f88..69e0c8f 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -110,7 +110,7 @@
 /* called with rcu_read_lock */
 void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0)
 {
-	if (should_deliver(to, skb)) {
+	if (should_deliver(to, skb) && !(to->flags & BR_ISOLATE_MODE)) {
 		if (skb0)
 			deliver_clone(to, skb, __br_forward);
 		else
@@ -165,7 +165,8 @@
 static void br_flood(struct net_bridge *br, struct sk_buff *skb,
 		     struct sk_buff *skb0,
 		     void (*__packet_hook)(const struct net_bridge_port *p,
-					   struct sk_buff *skb))
+					   struct sk_buff *skb),
+		     bool forward)
 {
 	struct net_bridge_port *p;
 	struct net_bridge_port *prev;
@@ -173,6 +174,9 @@
 	prev = NULL;
 
 	list_for_each_entry_rcu(p, &br->port_list, list) {
+		if (forward && (p->flags & BR_ISOLATE_MODE))
+			continue;
+
 		prev = maybe_deliver(prev, p, skb, __packet_hook);
 		if (IS_ERR(prev))
 			goto out;
@@ -196,14 +200,14 @@
 /* called with rcu_read_lock */
 void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
 {
-	br_flood(br, skb, NULL, __br_deliver);
+	br_flood(br, skb, NULL, __br_deliver, false);
 }
 
 /* called under bridge lock */
 void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
 		      struct sk_buff *skb2)
 {
-	br_flood(br, skb, skb2, __br_forward);
+	br_flood(br, skb, skb2, __br_forward, true);
 }
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 5a31731..988c300 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -65,7 +65,7 @@
 	    br_multicast_rcv(br, p, skb))
 		goto drop;
 
-	if (p->state == BR_STATE_LEARNING)
+	if ((p->state == BR_STATE_LEARNING) && skb->protocol != htons(ETH_P_PAE))
 		goto drop;
 
 	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
@@ -78,7 +78,11 @@
 
 	dst = NULL;
 
-	if (is_broadcast_ether_addr(dest))
+	if (skb->protocol == htons(ETH_P_PAE)) {
+		skb2 = skb;
+		/* Do not forward 802.1x/EAP frames */
+		skb = NULL;
+	} else if (is_broadcast_ether_addr(dest))
 		skb2 = skb;
 	else if (is_multicast_ether_addr(dest)) {
 		mdst = br_mdb_get(br, skb);
@@ -94,7 +98,8 @@
 			skb2 = skb;
 
 		br->dev->stats.multicast++;
-	} else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
+	} else if ((p->flags & BR_ISOLATE_MODE) ||
+		   ((dst = __br_fdb_get(br, dest)) && dst->is_local)) {
 		skb2 = skb;
 		/* Do not forward the packet since it's local. */
 		skb = NULL;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index b9bba8f..4d6fb62 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -135,6 +135,7 @@
 
 	unsigned long 			flags;
 #define BR_HAIRPIN_MODE		0x00000001
+#define BR_ISOLATE_MODE		0x00000002
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 	u32				multicast_startup_queries_sent;
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 6229b62..cde52fe 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -149,6 +149,22 @@
 static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
 		   show_hairpin_mode, store_hairpin_mode);
 
+static ssize_t show_isolate_mode(struct net_bridge_port *p, char *buf)
+{
+	int isolate_mode = (p->flags & BR_ISOLATE_MODE) ? 1 : 0;
+	return sprintf(buf, "%d\n", isolate_mode);
+}
+static ssize_t store_isolate_mode(struct net_bridge_port *p, unsigned long v)
+{
+	if (v)
+		p->flags |= BR_ISOLATE_MODE;
+	else
+		p->flags &= ~BR_ISOLATE_MODE;
+	return 0;
+}
+static BRPORT_ATTR(isolate_mode, S_IRUGO | S_IWUSR,
+		   show_isolate_mode, store_isolate_mode);
+
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
 {
@@ -181,6 +197,7 @@
 	&brport_attr_hold_timer,
 	&brport_attr_flush,
 	&brport_attr_hairpin_mode,
+	&brport_attr_isolate_mode,
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 	&brport_attr_multicast_router,
 #endif
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 24e556e..70a21fe 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -81,9 +81,14 @@
 
 #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
 
-	if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
+	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
+		return true;
+
+	if (FWINV(ipinfo->smsk.s_addr &&
+		  (ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
 		  IPT_INV_SRCIP) ||
-	    FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
+	    FWINV(ipinfo->dmsk.s_addr &&
+		  (ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
 		  IPT_INV_DSTIP)) {
 		dprintf("Source or dest mismatch.\n");
 
@@ -134,6 +139,29 @@
 	return true;
 }
 
+static void
+ip_checkdefault(struct ipt_ip *ip)
+{
+	static const char iface_mask[IFNAMSIZ] = {};
+
+	if (ip->invflags || ip->flags & IPT_F_FRAG)
+		return;
+
+	if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
+		return;
+
+	if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
+		return;
+
+	if (ip->smsk.s_addr || ip->dmsk.s_addr)
+		return;
+
+	if (ip->proto)
+		return;
+
+	ip->flags |= IPT_F_NO_DEF_MATCH;
+}
+
 static bool
 ip_checkentry(const struct ipt_ip *ip)
 {
@@ -284,6 +312,33 @@
 	return (void *)entry + entry->next_offset;
 }
 
+static bool
+ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
+{
+	struct xt_entry_target *t;
+	struct xt_standard_target *st;
+
+	if (e->target_offset != sizeof(struct ipt_entry))
+		return false;
+
+	if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
+		return false;
+
+	t = ipt_get_target(e);
+	if (t->u.kernel.target->target)
+		return false;
+
+	st = (struct xt_standard_target *) t;
+	if (st->verdict == XT_RETURN)
+		return false;
+
+	if (st->verdict >= 0)
+		return false;
+
+	*verdict = (unsigned)(-st->verdict) - 1;
+	return true;
+}
+
 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
 unsigned int
 ipt_do_table(struct sk_buff *skb,
@@ -308,6 +363,25 @@
 	ip = ip_hdr(skb);
 	indev = in ? in->name : nulldevname;
 	outdev = out ? out->name : nulldevname;
+
+	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
+	local_bh_disable();
+	addend = xt_write_recseq_begin();
+	private = table->private;
+	cpu        = smp_processor_id();
+	table_base = private->entries[cpu];
+	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
+	stackptr   = per_cpu_ptr(private->stackptr, cpu);
+	origptr    = *stackptr;
+
+	e = get_entry(table_base, private->hook_entry[hook]);
+	if (ipt_handle_default_rule(e, &verdict)) {
+		ADD_COUNTER(e->counters, skb->len, 1);
+		xt_write_recseq_end(addend);
+		local_bh_enable();
+		return verdict;
+	}
+
 	/* We handle fragments by dealing with the first fragment as
 	 * if it was a normal packet.  All other fragments are treated
 	 * normally, except that they will NEVER match rules that ask
@@ -322,18 +396,6 @@
 	acpar.family  = NFPROTO_IPV4;
 	acpar.hooknum = hook;
 
-	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
-	local_bh_disable();
-	addend = xt_write_recseq_begin();
-	private = table->private;
-	cpu        = smp_processor_id();
-	table_base = private->entries[cpu];
-	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
-	stackptr   = per_cpu_ptr(private->stackptr, cpu);
-	origptr    = *stackptr;
-
-	e = get_entry(table_base, private->hook_entry[hook]);
-
 	pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n",
 		 table->name, hook, origptr,
 		 get_entry(table_base, private->underflow[hook]));
@@ -561,7 +623,7 @@
 }
 
 static int
-check_entry(const struct ipt_entry *e, const char *name)
+check_entry(struct ipt_entry *e, const char *name)
 {
 	const struct xt_entry_target *t;
 
@@ -570,6 +632,8 @@
 		return -EINVAL;
 	}
 
+	ip_checkdefault(&e->ip);
+
 	if (e->target_offset + sizeof(struct xt_entry_target) >
 	    e->next_offset)
 		return -EINVAL;
@@ -931,6 +995,7 @@
 	const struct xt_table_info *private = table->private;
 	int ret = 0;
 	const void *loc_cpu_entry;
+	u8 flags;
 
 	counters = alloc_counters(table);
 	if (IS_ERR(counters))
@@ -962,6 +1027,14 @@
 			goto free_counters;
 		}
 
+		flags = e->ip.flags & IPT_F_MASK;
+		if (copy_to_user(userptr + off
+				 + offsetof(struct ipt_entry, ip.flags),
+				 &flags, sizeof(flags)) != 0) {
+			ret = -EFAULT;
+			goto free_counters;
+		}
+
 		for (i = sizeof(struct ipt_entry);
 		     i < e->target_offset;
 		     i += m->u.match_size) {
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 78844d9..d806690 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -73,6 +73,7 @@
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	struct nf_conn_help *help = nfct_help(ct);
 	char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
 	unsigned int buflen;
 	__be32 newaddr;
@@ -85,7 +86,8 @@
 	} else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip &&
 		   ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
 		newaddr = ct->tuplehash[!dir].tuple.src.u3.ip;
-		newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
+		newport = help->help.ct_sip_info.forced_dport ? :
+			  ct->tuplehash[!dir].tuple.src.u.udp.port;
 	} else
 		return 1;
 
@@ -121,6 +123,7 @@
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	struct nf_conn_help *help = nfct_help(ct);
 	unsigned int coff, matchoff, matchlen;
 	enum sip_header_types hdr;
 	union nf_inet_addr addr;
@@ -229,6 +232,20 @@
 	    !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
 		return NF_DROP;
 
+	/* Mangle destination port for Cisco phones, then fix up checksums */
+	if (dir == IP_CT_DIR_REPLY && help->help.ct_sip_info.forced_dport) {
+		struct udphdr *uh;
+
+		if (!skb_make_writable(skb, skb->len))
+			return NF_DROP;
+
+		uh = (struct udphdr *)(skb->data + ip_hdrlen(skb));
+		uh->dest = help->help.ct_sip_info.forced_dport;
+
+		if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, 0, 0, NULL, 0))
+			return NF_DROP;
+	}
+
 	return NF_ACCEPT;
 }
 
@@ -280,8 +297,10 @@
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	struct nf_conn_help *help = nfct_help(ct);
 	__be32 newip;
 	u_int16_t port;
+	__be16 srcport;
 	char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
 	unsigned buflen;
 
@@ -294,8 +313,9 @@
 	/* If the signalling port matches the connection's source port in the
 	 * original direction, try to use the destination port in the opposite
 	 * direction. */
-	if (exp->tuple.dst.u.udp.port ==
-	    ct->tuplehash[dir].tuple.src.u.udp.port)
+	srcport = help->help.ct_sip_info.forced_dport ? :
+		  ct->tuplehash[dir].tuple.src.u.udp.port;
+	if (exp->tuple.dst.u.udp.port == srcport)
 		port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
 	else
 		port = ntohs(exp->tuple.dst.u.udp.port);
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 686934a..049f35e 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -40,3 +40,4 @@
 obj-y += addrconf_core.o exthdrs_core.o
 
 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
+obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_stubs.o
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a5521c5..403a33a 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1111,7 +1111,7 @@
 	return ret;
 }
 
-int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
+static int __ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
 		       const struct in6_addr *daddr, unsigned int prefs,
 		       struct in6_addr *saddr)
 {
@@ -1236,7 +1236,6 @@
 	in6_ifa_put(hiscore->ifa);
 	return 0;
 }
-EXPORT_SYMBOL(ipv6_dev_get_saddr);
 
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
 		    unsigned char banned_flags)
@@ -4818,6 +4817,9 @@
 
 	ipv6_addr_label_rtnl_register();
 
+	BUG_ON(ipv6_dev_get_saddr_hook != NULL);
+	rcu_assign_pointer(ipv6_dev_get_saddr_hook, __ipv6_dev_get_saddr);
+
 	return 0;
 errout:
 	rtnl_af_unregister(&inet6_ops);
@@ -4836,6 +4838,9 @@
 	struct net_device *dev;
 	int i;
 
+	rcu_assign_pointer(ipv6_dev_get_saddr_hook, NULL);
+	synchronize_rcu();
+
 	unregister_netdevice_notifier(&ipv6_dev_notf);
 	unregister_pernet_subsys(&addrconf_ops);
 	ipv6_addr_label_cleanup();
diff --git a/net/ipv6/inet6_stubs.c b/net/ipv6/inet6_stubs.c
new file mode 100644
index 0000000..c9a90e7
--- /dev/null
+++ b/net/ipv6/inet6_stubs.c
@@ -0,0 +1,33 @@
+/*
+ *      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/export.h>
+#include <net/ipv6.h>
+
+int (*ipv6_dev_get_saddr_hook)(struct net *net, struct net_device *dev,
+			const struct in6_addr *daddr, unsigned int srcprefs,
+			struct in6_addr *saddr);
+
+EXPORT_SYMBOL(ipv6_dev_get_saddr_hook);
+
+int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
+			const struct in6_addr *daddr, unsigned int prefs,
+			struct in6_addr *saddr)
+{
+	int ret = -EADDRNOTAVAIL;
+	typeof(ipv6_dev_get_saddr_hook) dev_get_saddr;
+
+	rcu_read_lock();
+	dev_get_saddr = rcu_dereference(ipv6_dev_get_saddr_hook);
+
+	if (dev_get_saddr)
+		ret = dev_get_saddr(net, dst_dev, daddr, prefs, saddr);
+
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL(ipv6_dev_get_saddr);
+
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index d5597b7..b2e6f7e 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -163,7 +163,6 @@
 
 config NF_CONNTRACK_H323
 	tristate "H.323 protocol support"
-	depends on (IPV6 || IPV6=n)
 	depends on NETFILTER_ADVANCED
 	help
 	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most
@@ -609,7 +608,6 @@
 
 config NETFILTER_XT_TARGET_TCPMSS
 	tristate '"TCPMSS" target support'
-	depends on (IPV6 || IPV6=n)
 	default m if NETFILTER_ADVANCED=n
 	---help---
 	  This option adds a `TCPMSS' target, which allows you to alter the
@@ -832,6 +830,27 @@
 
 	  If unsure, say N.
 
+config NETFILTER_XT_MATCH_LAYER7
+	tristate '"layer7" match support'
+	depends on EXPERIMENTAL
+	depends on NETFILTER_XTABLES
+	depends on NETFILTER_ADVANCED
+	depends on NF_CONNTRACK
+	help
+	  Say Y if you want to be able to classify connections (and their
+	  packets) based on regular expression matching of their application
+	  layer data.   This is one way to classify applications such as
+	  peer-to-peer filesharing systems that do not always use the same
+	  port.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_LAYER7_DEBUG
+	bool 'Layer 7 debugging output'
+	depends on NETFILTER_XT_MATCH_LAYER7
+	help
+	  Say Y to get lots of debugging output.
+
 config NETFILTER_XT_MATCH_LENGTH
 	tristate '"length" match support'
 	depends on NETFILTER_ADVANCED
@@ -1018,6 +1037,12 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_LAYER7_DEBUG
+	bool 'Layer 7 debugging output'
+	depends on NETFILTER_XT_MATCH_LAYER7
+	help
+	  Say Y to get lots of debugging output.
+
 config NETFILTER_XT_MATCH_STATISTIC
 	tristate '"statistic" match support'
 	depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 1a02853..0427cbd 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -102,6 +102,7 @@
 obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_SOCKET) += xt_socket.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_LAYER7) += xt_layer7.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 1d15193..884e227 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -213,6 +213,14 @@
 	 * too. */
 	nf_ct_remove_expectations(ct);
 
+	#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
+	if(ct->layer7.app_proto)
+		kfree(ct->layer7.app_proto);
+	if(ct->layer7.app_data)
+	kfree(ct->layer7.app_data);
+	#endif
+
+
 	/* We overload first tuple to link into unconfirmed list. */
 	if (!nf_ct_is_confirmed(ct)) {
 		BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode));
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 8235b86..4c03e52 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -29,6 +29,9 @@
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 
+/* Do not check the TCP window for incoming packets  */
+static int nf_ct_tcp_no_window_check __read_mostly = 1;
+
 /* "Be conservative in what you do,
     be liberal in what you accept from others."
     If it's non-zero, we mark only out of window RST segments as INVALID. */
@@ -524,6 +527,9 @@
 	s16 receiver_offset;
 	bool res;
 
+	if (nf_ct_tcp_no_window_check)
+		return true;
+
 	/*
 	 * Get the required data from the packet.
 	 */
@@ -1321,6 +1327,13 @@
 		.proc_handler	= proc_dointvec,
 	},
 	{
+		.procname       = "nf_conntrack_tcp_no_window_check",
+		.data           = &nf_ct_tcp_no_window_check,
+		.maxlen         = sizeof(unsigned int),
+		.mode           = 0644,
+		.proc_handler   = proc_dointvec,
+	},
+	{
 		.procname       = "nf_conntrack_tcp_be_liberal",
 		.data           = &nf_ct_tcp_be_liberal,
 		.maxlen         = sizeof(unsigned int),
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 93faf6a..6a9c9aa 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1363,8 +1363,25 @@
 {
 	enum ip_conntrack_info ctinfo;
 	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	struct nf_conn_help *help = nfct_help(ct);
+	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	unsigned int matchoff, matchlen;
 	unsigned int cseq, i;
+	union nf_inet_addr addr;
+	__be16 port;
+
+	/* Many Cisco IP phones use a high source port for SIP requests, but
+	 * listen for the response on port 5060.  If we are the local
+	 * router for one of these phones, save the port number from the
+	 * Via: header so that nf_nat_sip can redirect the responses to
+	 * the correct port.
+	 */
+	if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
+				    SIP_HDR_VIA_UDP, NULL, &matchoff,
+				    &matchlen, &addr, &port) > 0 &&
+	    port != ct->tuplehash[dir].tuple.src.u.udp.port &&
+	    nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3))
+		help->help.ct_sip_info.forced_dport = port;
 
 	for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
 		const struct sip_handler *handler;
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 05e9feb..621e2da 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -239,6 +239,12 @@
 	if (ct_show_delta_time(s, ct))
 		goto release;
 
+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
+	if(ct->layer7.app_proto &&
+           seq_printf(s, "l7proto=%s ", ct->layer7.app_proto))
+		return -ENOSPC;
+#endif
+
 	if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
 		goto release;
 
diff --git a/net/netfilter/regexp/regexp.c b/net/netfilter/regexp/regexp.c
new file mode 100644
index 0000000..9006988
--- /dev/null
+++ b/net/netfilter/regexp/regexp.c
@@ -0,0 +1,1197 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ * @(#)regexp.c	1.3 of 18 April 87
+ *
+ *	Copyright (c) 1986 by University of Toronto.
+ *	Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *	Permission is granted to anyone to use this software for any
+ *	purpose on any computer system, and to redistribute it freely,
+ *	subject to the following restrictions:
+ *
+ *	1. The author is not responsible for the consequences of use of
+ *		this software, no matter how awful, even if they arise
+ *		from defects in it.
+ *
+ *	2. The origin of this software must not be misrepresented, either
+ *		by explicit claim or by omission.
+ *
+ *	3. Altered versions must be plainly marked as such, and must not
+ *		be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ *
+ * This code was modified by Ethan Sommer to work within the kernel
+ * (it now uses kmalloc etc..)
+ *
+ * Modified slightly by Matthew Strait to use more modern C.
+ */
+
+#include "regexp.h"
+#include "regmagic.h"
+
+/* added by ethan and matt.  Lets it work in both kernel and user space.
+(So iptables can use it, for instance.)  Yea, it goes both ways... */
+#if __KERNEL__
+  #define malloc(foo) kmalloc(foo,GFP_ATOMIC)
+#else
+  #define printk(format,args...) printf(format,##args)
+#endif
+
+void regerror(char * s)
+{
+        printk("<3>Regexp: %s\n", s);
+        /* NOTREACHED */
+}
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart	char that must begin a match; '\0' if none obvious
+ * reganch	is the match anchored (at beginning-of-line only)?
+ * regmust	string (pointer into program) that match must include, or NULL
+ * regmlen	length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.)  The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure:  the tail of the branch connects
+ * to the thing following the set of BRANCHes.)  The opcodes are:
+ */
+
+/* definition	number	opnd?	meaning */
+#define	END	0	/* no	End of program. */
+#define	BOL	1	/* no	Match "" at beginning of line. */
+#define	EOL	2	/* no	Match "" at end of line. */
+#define	ANY	3	/* no	Match any one character. */
+#define	ANYOF	4	/* str	Match any character in this string. */
+#define	ANYBUT	5	/* str	Match any character not in this string. */
+#define	BRANCH	6	/* node	Match this alternative, or the next... */
+#define	BACK	7	/* no	Match "", "next" ptr points backward. */
+#define	EXACTLY	8	/* str	Match this string. */
+#define	NOTHING	9	/* no	Match empty string. */
+#define	STAR	10	/* node	Match this (simple) thing 0 or more times. */
+#define	PLUS	11	/* node	Match this (simple) thing 1 or more times. */
+#define	OPEN	20	/* no	Mark this point in input as start of #n. */
+			/*	OPEN+1 is number 1, etc. */
+#define	CLOSE	30	/* no	Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH	The set of branches constituting a single choice are hooked
+ *		together with their "next" pointers, since precedence prevents
+ *		anything being concatenated to any individual branch.  The
+ *		"next" pointer of the last BRANCH in a choice points to the
+ *		thing following the whole choice.  This is also where the
+ *		final "next" pointer of each individual branch points; each
+ *		branch starts with the operand node of a BRANCH node.
+ *
+ * BACK		Normal "next" pointers all implicitly point forward; BACK
+ *		exists to make loop structures possible.
+ *
+ * STAR,PLUS	'?', and complex '*' and '+', are implemented as circular
+ *		BRANCH structures using BACK.  Simple cases (one character
+ *		per match) are implemented with STAR and PLUS for speed
+ *		and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE	...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define	OP(p)	(*(p))
+#define	NEXT(p)	(((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define	OPERAND(p)	((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define	UCHARAT(p)	((int)*(unsigned char *)(p))
+#else
+#define	UCHARAT(p)	((int)*(p)&CHARBITS)
+#endif
+
+#define	FAIL(m)	{ regerror(m); return(NULL); }
+#define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?')
+#define	META	"^$.[()|?+*\\"
+
+/*
+ * Flags to be passed up and down.
+ */
+#define	HASWIDTH	01	/* Known never to match null string. */
+#define	SIMPLE		02	/* Simple enough to be STAR/PLUS operand. */
+#define	SPSTART		04	/* Starts with * or +. */
+#define	WORST		0	/* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+struct match_globals {
+char *reginput;		/* String-input pointer. */
+char *regbol;		/* Beginning of input, for ^ check. */
+char **regstartp;	/* Pointer to startp array. */
+char **regendp;		/* Ditto for endp. */
+char *regparse;		/* Input-scan pointer. */
+int regnpar;		/* () count. */
+char regdummy;
+char *regcode;		/* Code-emit pointer; &regdummy = don't. */
+long regsize;		/* Code size. */
+};
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define	STATIC	static
+#endif
+STATIC char *reg(struct match_globals *g, int paren,int *flagp);
+STATIC char *regbranch(struct match_globals *g, int *flagp);
+STATIC char *regpiece(struct match_globals *g, int *flagp);
+STATIC char *regatom(struct match_globals *g, int *flagp);
+STATIC char *regnode(struct match_globals *g, char op);
+STATIC char *regnext(struct match_globals *g, char *p);
+STATIC void regc(struct match_globals *g, char b);
+STATIC void reginsert(struct match_globals *g, char op, char *opnd);
+STATIC void regtail(struct match_globals *g, char *p, char *val);
+STATIC void regoptail(struct match_globals *g, char *p, char *val);
+
+
+__kernel_size_t my_strcspn(const char *s1,const char *s2)
+{
+        char *scan1;
+        char *scan2;
+        int count;
+
+        count = 0;
+        for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) {
+                for (scan2 = (char *)s2; *scan2 != '\0';)       /* ++ moved down. */
+                        if (*scan1 == *scan2++)
+                                return(count);
+                count++;
+        }
+        return(count);
+}
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *
+regcomp(char *exp,int *patternsize)
+{
+	register regexp *r;
+	register char *scan;
+	register char *longest;
+	register int len;
+	int flags;
+	struct match_globals g;
+	
+	/* commented out by ethan
+	   extern char *malloc();
+	*/
+
+	if (exp == NULL)
+		FAIL("NULL argument");
+
+	/* First pass: determine size, legality. */
+	g.regparse = exp;
+	g.regnpar = 1;
+	g.regsize = 0L;
+	g.regcode = &g.regdummy;
+	regc(&g, MAGIC);
+	if (reg(&g, 0, &flags) == NULL)
+		return(NULL);
+
+	/* Small enough for pointer-storage convention? */
+	if (g.regsize >= 32767L)		/* Probably could be 65535L. */
+		FAIL("regexp too big");
+
+	/* Allocate space. */
+	*patternsize=sizeof(regexp) + (unsigned)g.regsize;
+	r = (regexp *)malloc(sizeof(regexp) + (unsigned)g.regsize);
+	if (r == NULL)
+		FAIL("out of space");
+
+	/* Second pass: emit code. */
+	g.regparse = exp;
+	g.regnpar = 1;
+	g.regcode = r->program;
+	regc(&g, MAGIC);
+	if (reg(&g, 0, &flags) == NULL)
+		return(NULL);
+
+	/* Dig out information for optimizations. */
+	r->regstart = '\0';	/* Worst-case defaults. */
+	r->reganch = 0;
+	r->regmust = NULL;
+	r->regmlen = 0;
+	scan = r->program+1;			/* First BRANCH. */
+	if (OP(regnext(&g, scan)) == END) {		/* Only one top-level choice. */
+		scan = OPERAND(scan);
+
+		/* Starting-point info. */
+		if (OP(scan) == EXACTLY)
+			r->regstart = *OPERAND(scan);
+		else if (OP(scan) == BOL)
+			r->reganch++;
+
+		/*
+		 * If there's something expensive in the r.e., find the
+		 * longest literal string that must appear and make it the
+		 * regmust.  Resolve ties in favor of later strings, since
+		 * the regstart check works with the beginning of the r.e.
+		 * and avoiding duplication strengthens checking.  Not a
+		 * strong reason, but sufficient in the absence of others.
+		 */
+		if (flags&SPSTART) {
+			longest = NULL;
+			len = 0;
+			for (; scan != NULL; scan = regnext(&g, scan))
+				if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+					longest = OPERAND(scan);
+					len = strlen(OPERAND(scan));
+				}
+			r->regmust = longest;
+			r->regmlen = len;
+		}
+	}
+
+	return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(struct match_globals *g, int paren, int *flagp /* Parenthesized? */ )
+{
+	register char *ret;
+	register char *br;
+	register char *ender;
+	register int parno = 0; /* 0 makes gcc happy */
+	int flags;
+
+	*flagp = HASWIDTH;	/* Tentatively. */
+
+	/* Make an OPEN node, if parenthesized. */
+	if (paren) {
+		if (g->regnpar >= NSUBEXP)
+			FAIL("too many ()");
+		parno = g->regnpar;
+		g->regnpar++;
+		ret = regnode(g, OPEN+parno);
+	} else
+		ret = NULL;
+
+	/* Pick up the branches, linking them together. */
+	br = regbranch(g, &flags);
+	if (br == NULL)
+		return(NULL);
+	if (ret != NULL)
+		regtail(g, ret, br);	/* OPEN -> first. */
+	else
+		ret = br;
+	if (!(flags&HASWIDTH))
+		*flagp &= ~HASWIDTH;
+	*flagp |= flags&SPSTART;
+	while (*g->regparse == '|') {
+		g->regparse++;
+		br = regbranch(g, &flags);
+		if (br == NULL)
+			return(NULL);
+		regtail(g, ret, br);	/* BRANCH -> BRANCH. */
+		if (!(flags&HASWIDTH))
+			*flagp &= ~HASWIDTH;
+		*flagp |= flags&SPSTART;
+	}
+
+	/* Make a closing node, and hook it on the end. */
+	ender = regnode(g, (paren) ? CLOSE+parno : END);	
+	regtail(g, ret, ender);
+
+	/* Hook the tails of the branches to the closing node. */
+	for (br = ret; br != NULL; br = regnext(g, br))
+		regoptail(g, br, ender);
+
+	/* Check for proper termination. */
+	if (paren && *g->regparse++ != ')') {
+		FAIL("unmatched ()");
+	} else if (!paren && *g->regparse != '\0') {
+		if (*g->regparse == ')') {
+			FAIL("unmatched ()");
+		} else
+			FAIL("junk on end");	/* "Can't happen". */
+		/* NOTREACHED */
+	}
+
+	return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch(struct match_globals *g, int *flagp)
+{
+	register char *ret;
+	register char *chain;
+	register char *latest;
+	int flags;
+
+	*flagp = WORST;		/* Tentatively. */
+
+	ret = regnode(g, BRANCH);
+	chain = NULL;
+	while (*g->regparse != '\0' && *g->regparse != '|' && *g->regparse != ')') {
+		latest = regpiece(g, &flags);
+		if (latest == NULL)
+			return(NULL);
+		*flagp |= flags&HASWIDTH;
+		if (chain == NULL)	/* First piece. */
+			*flagp |= flags&SPSTART;
+		else
+			regtail(g, chain, latest);
+		chain = latest;
+	}
+	if (chain == NULL)	/* Loop ran zero times. */
+		(void) regnode(g, NOTHING);
+
+	return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece(struct match_globals *g, int *flagp)
+{
+	register char *ret;
+	register char op;
+	register char *next;
+	int flags;
+
+	ret = regatom(g, &flags);
+	if (ret == NULL)
+		return(NULL);
+
+	op = *g->regparse;
+	if (!ISMULT(op)) {
+		*flagp = flags;
+		return(ret);
+	}
+
+	if (!(flags&HASWIDTH) && op != '?')
+		FAIL("*+ operand could be empty");
+	*flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+	if (op == '*' && (flags&SIMPLE))
+		reginsert(g, STAR, ret);
+	else if (op == '*') {
+		/* Emit x* as (x&|), where & means "self". */
+		reginsert(g, BRANCH, ret);			/* Either x */
+		regoptail(g, ret, regnode(g, BACK));		/* and loop */
+		regoptail(g, ret, ret);			/* back */
+		regtail(g, ret, regnode(g, BRANCH));		/* or */
+		regtail(g, ret, regnode(g, NOTHING));		/* null. */
+	} else if (op == '+' && (flags&SIMPLE))
+		reginsert(g, PLUS, ret);
+	else if (op == '+') {
+		/* Emit x+ as x(&|), where & means "self". */
+		next = regnode(g, BRANCH);			/* Either */
+		regtail(g, ret, next);
+		regtail(g, regnode(g, BACK), ret);		/* loop back */
+		regtail(g, next, regnode(g, BRANCH));		/* or */
+		regtail(g, ret, regnode(g, NOTHING));		/* null. */
+	} else if (op == '?') {
+		/* Emit x? as (x|) */
+		reginsert(g, BRANCH, ret);			/* Either x */
+		regtail(g, ret, regnode(g, BRANCH));		/* or */
+		next = regnode(g, NOTHING);		/* null. */
+		regtail(g, ret, next);
+		regoptail(g, ret, next);
+	}
+	g->regparse++;
+	if (ISMULT(*g->regparse))
+		FAIL("nested *?+");
+
+	return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *
+regatom(struct match_globals *g, int *flagp)
+{
+	register char *ret;
+	int flags;
+
+	*flagp = WORST;		/* Tentatively. */
+
+	switch (*g->regparse++) {
+	case '^':
+		ret = regnode(g, BOL);
+		break;
+	case '$':
+		ret = regnode(g, EOL);
+		break;
+	case '.':
+		ret = regnode(g, ANY);
+		*flagp |= HASWIDTH|SIMPLE;
+		break;
+	case '[': {
+			register int class;
+			register int classend;
+
+			if (*g->regparse == '^') {	/* Complement of range. */
+				ret = regnode(g, ANYBUT);
+				g->regparse++;
+			} else
+				ret = regnode(g, ANYOF);
+			if (*g->regparse == ']' || *g->regparse == '-')
+				regc(g, *g->regparse++);
+			while (*g->regparse != '\0' && *g->regparse != ']') {
+				if (*g->regparse == '-') {
+					g->regparse++;
+					if (*g->regparse == ']' || *g->regparse == '\0')
+						regc(g, '-');
+					else {
+						class = UCHARAT(g->regparse-2)+1;
+						classend = UCHARAT(g->regparse);
+						if (class > classend+1)
+							FAIL("invalid [] range");
+						for (; class <= classend; class++)
+							regc(g, class);
+						g->regparse++;
+					}
+				} else
+					regc(g, *g->regparse++);
+			}
+			regc(g, '\0');
+			if (*g->regparse != ']')
+				FAIL("unmatched []");
+			g->regparse++;
+			*flagp |= HASWIDTH|SIMPLE;
+		}
+		break;
+	case '(':
+		ret = reg(g, 1, &flags);
+		if (ret == NULL)
+			return(NULL);
+		*flagp |= flags&(HASWIDTH|SPSTART);
+		break;
+	case '\0':
+	case '|':
+	case ')':
+		FAIL("internal urp");	/* Supposed to be caught earlier. */
+		break;
+	case '?':
+	case '+':
+	case '*':
+		FAIL("?+* follows nothing");
+		break;
+	case '\\':
+		if (*g->regparse == '\0')
+			FAIL("trailing \\");
+		ret = regnode(g, EXACTLY);
+		regc(g, *g->regparse++);
+		regc(g, '\0');
+		*flagp |= HASWIDTH|SIMPLE;
+		break;
+	default: {
+			register int len;
+			register char ender;
+
+			g->regparse--;
+			len = my_strcspn((const char *)g->regparse, (const char *)META);
+			if (len <= 0)
+				FAIL("internal disaster");
+			ender = *(g->regparse+len);
+			if (len > 1 && ISMULT(ender))
+				len--;		/* Back off clear of ?+* operand. */
+			*flagp |= HASWIDTH;
+			if (len == 1)
+				*flagp |= SIMPLE;
+			ret = regnode(g, EXACTLY);
+			while (len > 0) {
+				regc(g, *g->regparse++);
+				len--;
+			}
+			regc(g, '\0');
+		}
+		break;
+	}
+
+	return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char *			/* Location. */
+regnode(struct match_globals *g, char op)
+{
+	register char *ret;
+	register char *ptr;
+
+	ret = g->regcode;
+	if (ret == &g->regdummy) {
+		g->regsize += 3;
+		return(ret);
+	}
+
+	ptr = ret;
+	*ptr++ = op;
+	*ptr++ = '\0';		/* Null "next" pointer. */
+	*ptr++ = '\0';
+	g->regcode = ptr;
+
+	return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc(struct match_globals *g, char b)
+{
+	if (g->regcode != &g->regdummy)
+		*g->regcode++ = b;
+	else
+		g->regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(struct match_globals *g, char op, char* opnd)
+{
+	register char *src;
+	register char *dst;
+	register char *place;
+
+	if (g->regcode == &g->regdummy) {
+		g->regsize += 3;
+		return;
+	}
+
+	src = g->regcode;
+	g->regcode += 3;
+	dst = g->regcode;
+	while (src > opnd)
+		*--dst = *--src;
+
+	place = opnd;		/* Op node, where operand used to be. */
+	*place++ = op;
+	*place++ = '\0';
+	*place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(struct match_globals *g, char *p, char *val)
+{
+	register char *scan;
+	register char *temp;
+	register int offset;
+
+	if (p == &g->regdummy)
+		return;
+
+	/* Find last node. */
+	scan = p;
+	for (;;) {
+		temp = regnext(g, scan);
+		if (temp == NULL)
+			break;
+		scan = temp;
+	}
+
+	if (OP(scan) == BACK)
+		offset = scan - val;
+	else
+		offset = val - scan;
+	*(scan+1) = (offset>>8)&0377;
+	*(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void
+regoptail(struct match_globals *g, char *p, char *val)
+{
+	/* "Operandless" and "op != BRANCH" are synonymous in practice. */
+	if (p == NULL || p == &g->regdummy || OP(p) != BRANCH)
+		return;
+	regtail(g, OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+
+/*
+ * Forwards.
+ */
+STATIC int regtry(struct match_globals *g, regexp *prog, char *string);
+STATIC int regmatch(struct match_globals *g, char *prog);
+STATIC int regrepeat(struct match_globals *g, char *p);
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+STATIC char *regprop(char *op);
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int
+regexec(regexp *prog, char *string)
+{
+	register char *s;
+	struct match_globals g;
+
+	/* Be paranoid... */
+	if (prog == NULL || string == NULL) {
+		printk("<3>Regexp: NULL parameter\n");
+		return(0);
+	}
+
+	/* Check validity of program. */
+	if (UCHARAT(prog->program) != MAGIC) {
+		printk("<3>Regexp: corrupted program\n");
+		return(0);
+	}
+
+	/* If there is a "must appear" string, look for it. */
+	if (prog->regmust != NULL) {
+		s = string;
+		while ((s = strchr(s, prog->regmust[0])) != NULL) {
+			if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+				break;	/* Found it. */
+			s++;
+		}
+		if (s == NULL)	/* Not present. */
+			return(0);
+	}
+
+	/* Mark beginning of line for ^ . */
+	g.regbol = string;
+
+	/* Simplest case:  anchored match need be tried only once. */
+	if (prog->reganch)
+		return(regtry(&g, prog, string));
+
+	/* Messy cases:  unanchored match. */
+	s = string;
+	if (prog->regstart != '\0')
+		/* We know what char it must start with. */
+		while ((s = strchr(s, prog->regstart)) != NULL) {
+			if (regtry(&g, prog, s))
+				return(1);
+			s++;
+		}
+	else
+		/* We don't -- general case. */
+		do {
+			if (regtry(&g, prog, s))
+				return(1);
+		} while (*s++ != '\0');
+
+	/* Failure. */
+	return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int			/* 0 failure, 1 success */
+regtry(struct match_globals *g, regexp *prog, char *string)
+{
+	register int i;
+	register char **sp;
+	register char **ep;
+
+	g->reginput = string;
+	g->regstartp = prog->startp;
+	g->regendp = prog->endp;
+
+	sp = prog->startp;
+	ep = prog->endp;
+	for (i = NSUBEXP; i > 0; i--) {
+		*sp++ = NULL;
+		*ep++ = NULL;
+	}
+	if (regmatch(g, prog->program + 1)) {
+		prog->startp[0] = string;
+		prog->endp[0] = g->reginput;
+		return(1);
+	} else
+		return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple:  check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly.  In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int			/* 0 failure, 1 success */
+regmatch(struct match_globals *g, char *prog)
+{
+	register char *scan = prog; /* Current node. */
+	char *next;		    /* Next node. */
+
+#ifdef DEBUG
+	if (scan != NULL && regnarrate)
+		fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+	while (scan != NULL) {
+#ifdef DEBUG
+		if (regnarrate)
+			fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+		next = regnext(g, scan);
+
+		switch (OP(scan)) {
+		case BOL:
+			if (g->reginput != g->regbol)
+				return(0);
+			break;
+		case EOL:
+			if (*g->reginput != '\0')
+				return(0);
+			break;
+		case ANY:
+			if (*g->reginput == '\0')
+				return(0);
+			g->reginput++;
+			break;
+		case EXACTLY: {
+				register int len;
+				register char *opnd;
+
+				opnd = OPERAND(scan);
+				/* Inline the first character, for speed. */
+				if (*opnd != *g->reginput)
+					return(0);
+				len = strlen(opnd);
+				if (len > 1 && strncmp(opnd, g->reginput, len) != 0)
+					return(0);
+				g->reginput += len;
+			}
+			break;
+		case ANYOF:
+			if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) == NULL)
+				return(0);
+			g->reginput++;
+			break;
+		case ANYBUT:
+			if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) != NULL)
+				return(0);
+			g->reginput++;
+			break;
+		case NOTHING:
+		case BACK:
+			break;
+		case OPEN+1:
+		case OPEN+2:
+		case OPEN+3:
+		case OPEN+4:
+		case OPEN+5:
+		case OPEN+6:
+		case OPEN+7:
+		case OPEN+8:
+		case OPEN+9: {
+				register int no;
+				register char *save;
+
+				no = OP(scan) - OPEN;
+				save = g->reginput;
+
+				if (regmatch(g, next)) {
+					/*
+					 * Don't set startp if some later
+					 * invocation of the same parentheses
+					 * already has.
+					 */
+					if (g->regstartp[no] == NULL)
+						g->regstartp[no] = save;
+					return(1);
+				} else
+					return(0);
+			}
+			break;
+		case CLOSE+1:
+		case CLOSE+2:
+		case CLOSE+3:
+		case CLOSE+4:
+		case CLOSE+5:
+		case CLOSE+6:
+		case CLOSE+7:
+		case CLOSE+8:
+		case CLOSE+9:
+			{
+				register int no;
+				register char *save;
+
+				no = OP(scan) - CLOSE;
+				save = g->reginput;
+
+				if (regmatch(g, next)) {
+					/*
+					 * Don't set endp if some later
+					 * invocation of the same parentheses
+					 * already has.
+					 */
+					if (g->regendp[no] == NULL)
+						g->regendp[no] = save;
+					return(1);
+				} else
+					return(0);
+			}
+			break;
+		case BRANCH: {
+				register char *save;
+
+				if (OP(next) != BRANCH)		/* No choice. */
+					next = OPERAND(scan);	/* Avoid recursion. */
+				else {
+					do {
+						save = g->reginput;
+						if (regmatch(g, OPERAND(scan)))
+							return(1);
+						g->reginput = save;
+						scan = regnext(g, scan);
+					} while (scan != NULL && OP(scan) == BRANCH);
+					return(0);
+					/* NOTREACHED */
+				}
+			}
+			break;
+		case STAR:
+		case PLUS: {
+				register char nextch;
+				register int no;
+				register char *save;
+				register int min;
+
+				/*
+				 * Lookahead to avoid useless match attempts
+				 * when we know what character comes next.
+				 */
+				nextch = '\0';
+				if (OP(next) == EXACTLY)
+					nextch = *OPERAND(next);
+				min = (OP(scan) == STAR) ? 0 : 1;
+				save = g->reginput;
+				no = regrepeat(g, OPERAND(scan));
+				while (no >= min) {
+					/* If it could work, try it. */
+					if (nextch == '\0' || *g->reginput == nextch)
+						if (regmatch(g, next))
+							return(1);
+					/* Couldn't or didn't -- back up. */
+					no--;
+					g->reginput = save + no;
+				}
+				return(0);
+			}
+			break;
+		case END:
+			return(1);	/* Success! */
+			break;
+		default:
+			printk("<3>Regexp: memory corruption\n");
+			return(0);
+			break;
+		}
+
+		scan = next;
+	}
+
+	/*
+	 * We get here only if there's trouble -- normally "case END" is
+	 * the terminating point.
+	 */
+	printk("<3>Regexp: corrupted pointers\n");
+	return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int
+regrepeat(struct match_globals *g, char *p)
+{
+	register int count = 0;
+	register char *scan;
+	register char *opnd;
+
+	scan = g->reginput;
+	opnd = OPERAND(p);
+	switch (OP(p)) {
+	case ANY:
+		count = strlen(scan);
+		scan += count;
+		break;
+	case EXACTLY:
+		while (*opnd == *scan) {
+			count++;
+			scan++;
+		}
+		break;
+	case ANYOF:
+		while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+			count++;
+			scan++;
+		}
+		break;
+	case ANYBUT:
+		while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+			count++;
+			scan++;
+		}
+		break;
+	default:		/* Oh dear.  Called inappropriately. */
+		printk("<3>Regexp: internal foulup\n");
+		count = 0;	/* Best compromise. */
+		break;
+	}
+	g->reginput = scan;
+
+	return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char*
+regnext(struct match_globals *g, char *p)
+{
+	register int offset;
+
+	if (p == &g->regdummy)
+		return(NULL);
+
+	offset = NEXT(p);
+	if (offset == 0)
+		return(NULL);
+
+	if (OP(p) == BACK)
+		return(p-offset);
+	else
+		return(p+offset);
+}
+
+#ifdef DEBUG
+
+STATIC char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void
+regdump(regexp *r)
+{
+	register char *s;
+	register char op = EXACTLY;	/* Arbitrary non-END op. */
+	register char *next;
+	/* extern char *strchr(); */
+
+
+	s = r->program + 1;
+	while (op != END) {	/* While that wasn't END last time... */
+		op = OP(s);
+		printf("%2d%s", s-r->program, regprop(s));	/* Where, what. */
+		next = regnext(s);
+		if (next == NULL)		/* Next ptr. */
+			printf("(0)");
+		else
+			printf("(%d)", (s-r->program)+(next-s));
+		s += 3;
+		if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+			/* Literal string, where present. */
+			while (*s != '\0') {
+				putchar(*s);
+				s++;
+			}
+			s++;
+		}
+		putchar('\n');
+	}
+
+	/* Header fields of interest. */
+	if (r->regstart != '\0')
+		printf("start `%c' ", r->regstart);
+	if (r->reganch)
+		printf("anchored ");
+	if (r->regmust != NULL)
+		printf("must have \"%s\"", r->regmust);
+	printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *
+regprop(char *op)
+{
+#define BUFLEN 50
+	register char *p;
+	static char buf[BUFLEN];
+
+	strcpy(buf, ":");
+
+	switch (OP(op)) {
+	case BOL:
+		p = "BOL";
+		break;
+	case EOL:
+		p = "EOL";
+		break;
+	case ANY:
+		p = "ANY";
+		break;
+	case ANYOF:
+		p = "ANYOF";
+		break;
+	case ANYBUT:
+		p = "ANYBUT";
+		break;
+	case BRANCH:
+		p = "BRANCH";
+		break;
+	case EXACTLY:
+		p = "EXACTLY";
+		break;
+	case NOTHING:
+		p = "NOTHING";
+		break;
+	case BACK:
+		p = "BACK";
+		break;
+	case END:
+		p = "END";
+		break;
+	case OPEN+1:
+	case OPEN+2:
+	case OPEN+3:
+	case OPEN+4:
+	case OPEN+5:
+	case OPEN+6:
+	case OPEN+7:
+	case OPEN+8:
+	case OPEN+9:
+		snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN);
+		p = NULL;
+		break;
+	case CLOSE+1:
+	case CLOSE+2:
+	case CLOSE+3:
+	case CLOSE+4:
+	case CLOSE+5:
+	case CLOSE+6:
+	case CLOSE+7:
+	case CLOSE+8:
+	case CLOSE+9:
+		snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+		p = NULL;
+		break;
+	case STAR:
+		p = "STAR";
+		break;
+	case PLUS:
+		p = "PLUS";
+		break;
+	default:
+		printk("<3>Regexp: corrupted opcode\n");
+		break;
+	}
+	if (p != NULL)
+		strncat(buf, p, BUFLEN-strlen(buf));
+	return(buf);
+}
+#endif
+
+
diff --git a/net/netfilter/regexp/regexp.h b/net/netfilter/regexp/regexp.h
new file mode 100644
index 0000000..a72eba7
--- /dev/null
+++ b/net/netfilter/regexp/regexp.h
@@ -0,0 +1,41 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+
+#ifndef REGEXP_H
+#define REGEXP_H
+
+
+/*
+http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h ,
+which contains a version of this library, says:
+
+ *
+ * NSUBEXP must be at least 10, and no greater than 117 or the parser
+ * will not work properly.
+ *
+
+However, it looks rather like this library is limited to 10.  If you think
+otherwise, let us know.
+*/
+
+#define NSUBEXP  10
+typedef struct regexp {
+	char *startp[NSUBEXP];
+	char *endp[NSUBEXP];
+	char regstart;		/* Internal use only. */
+	char reganch;		/* Internal use only. */
+	char *regmust;		/* Internal use only. */
+	int regmlen;		/* Internal use only. */
+	char program[1];	/* Unwarranted chumminess with compiler. */
+} regexp;
+
+regexp * regcomp(char *exp, int *patternsize);
+int regexec(regexp *prog, char *string);
+void regsub(regexp *prog, char *source, char *dest);
+void regerror(char *s);
+
+#endif
diff --git a/net/netfilter/regexp/regmagic.h b/net/netfilter/regexp/regmagic.h
new file mode 100644
index 0000000..5acf447
--- /dev/null
+++ b/net/netfilter/regexp/regmagic.h
@@ -0,0 +1,5 @@
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define	MAGIC	0234
diff --git a/net/netfilter/regexp/regsub.c b/net/netfilter/regexp/regsub.c
new file mode 100644
index 0000000..339631f
--- /dev/null
+++ b/net/netfilter/regexp/regsub.c
@@ -0,0 +1,95 @@
+/*
+ * regsub
+ * @(#)regsub.c	1.3 of 2 April 86
+ *
+ *	Copyright (c) 1986 by University of Toronto.
+ *	Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *	Permission is granted to anyone to use this software for any
+ *	purpose on any computer system, and to redistribute it freely,
+ *	subject to the following restrictions:
+ *
+ *	1. The author is not responsible for the consequences of use of
+ *		this software, no matter how awful, even if they arise
+ *		from defects in it.
+ *
+ *	2. The origin of this software must not be misrepresented, either
+ *		by explicit claim or by omission.
+ *
+ *	3. Altered versions must be plainly marked as such, and must not
+ *		be misrepresented as being the original software.
+ *
+ *
+ * This code was modified by Ethan Sommer to work within the kernel
+ * (it now uses kmalloc etc..)
+ *
+ */
+#include "regexp.h"
+#include "regmagic.h"
+#include <linux/string.h>
+
+
+#ifndef CHARBITS
+#define	UCHARAT(p)	((int)*(unsigned char *)(p))
+#else
+#define	UCHARAT(p)	((int)*(p)&CHARBITS)
+#endif
+
+#if 0
+//void regerror(char * s)
+//{
+//        printk("regexp(3): %s", s);
+//        /* NOTREACHED */
+//}
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+void
+regsub(regexp * prog, char * source, char * dest)
+{
+	register char *src;
+	register char *dst;
+	register char c;
+	register int no;
+	register int len;
+	
+	/* Not necessary and gcc doesn't like it -MLS */
+	/*extern char *strncpy();*/
+
+	if (prog == NULL || source == NULL || dest == NULL) {
+		regerror("NULL parm to regsub");
+		return;
+	}
+	if (UCHARAT(prog->program) != MAGIC) {
+		regerror("damaged regexp fed to regsub");
+		return;
+	}
+
+	src = source;
+	dst = dest;
+	while ((c = *src++) != '\0') {
+		if (c == '&')
+			no = 0;
+		else if (c == '\\' && '0' <= *src && *src <= '9')
+			no = *src++ - '0';
+		else
+			no = -1;
+
+		if (no < 0) {	/* Ordinary character. */
+			if (c == '\\' && (*src == '\\' || *src == '&'))
+				c = *src++;
+			*dst++ = c;
+		} else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+			len = prog->endp[no] - prog->startp[no];
+			(void) strncpy(dst, prog->startp[no], len);
+			dst += len;
+			if (len != 0 && *(dst-1) == '\0') {	/* strncpy hit NUL. */
+				regerror("damaged match string");
+				return;
+			}
+		}
+	}
+	*dst++ = '\0';
+}
diff --git a/net/netfilter/xt_layer7.c b/net/netfilter/xt_layer7.c
new file mode 100644
index 0000000..837fe2fd
--- /dev/null
+++ b/net/netfilter/xt_layer7.c
@@ -0,0 +1,700 @@
+/*
+  Kernel module to match application layer (OSI layer 7) data in connections.
+
+  http://l7-filter.sf.net
+
+  (C) 2003-2009 Matthew Strait and Ethan Sommer.
+
+  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.
+  http://www.gnu.org/licenses/gpl.txt
+
+  Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>,
+  xt_helper.c (C) 2002 Harald Welte and cls_layer7.c (C) 2003 Matthew Strait,
+  Ethan Sommer, Justin Levandoski.
+*/
+
+#include <linux/spinlock.h>
+#include <linux/version.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_acct.h>
+#endif
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_layer7.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+
+#include "regexp/regexp.c"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>");
+MODULE_DESCRIPTION("iptables application layer match module");
+MODULE_ALIAS("ipt_layer7");
+MODULE_VERSION("2.21");
+
+static int maxdatalen = 2048; // this is the default
+module_param(maxdatalen, int, 0444);
+MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter");
+#ifdef CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG
+	#define DPRINTK(format,args...) printk(format,##args)
+#else
+	#define DPRINTK(format,args...)
+#endif
+
+/* Number of packets whose data we look at.
+This can be modified through /proc/net/layer7_numpackets */
+static int num_packets = 10;
+
+static struct pattern_cache {
+	char * regex_string;
+	regexp * pattern;
+	struct pattern_cache * next;
+} * first_pattern_cache = NULL;
+
+DEFINE_SPINLOCK(l7_lock);
+
+static int total_acct_packets(struct nf_conn *ct)
+{
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26)
+	BUG_ON(ct == NULL);
+	return (ct->counters[IP_CT_DIR_ORIGINAL].packets + ct->counters[IP_CT_DIR_REPLY].packets);
+#else
+	struct nf_conn_counter *acct;
+
+	BUG_ON(ct == NULL);
+	acct = nf_conn_acct_find(ct);
+	if (!acct)
+		return 0;
+	return (acct[IP_CT_DIR_ORIGINAL].packets + acct[IP_CT_DIR_REPLY].packets);
+#endif
+}
+
+#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
+/* Converts an unfriendly string into a friendly one by
+replacing unprintables with periods and all whitespace with " ". */
+static char * friendly_print(unsigned char * s)
+{
+	char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC);
+	int i;
+
+	if(!f) {
+		if (net_ratelimit())
+			printk(KERN_ERR "layer7: out of memory in "
+					"friendly_print, bailing.\n");
+		return NULL;
+	}
+
+	for(i = 0; i < strlen(s); i++){
+		if(isprint(s[i]) && s[i] < 128)	f[i] = s[i];
+		else if(isspace(s[i]))		f[i] = ' ';
+		else 				f[i] = '.';
+	}
+	f[i] = '\0';
+	return f;
+}
+
+static char dec2hex(int i)
+{
+	switch (i) {
+		case 0 ... 9:
+			return (i + '0');
+			break;
+		case 10 ... 15:
+			return (i - 10 + 'a');
+			break;
+		default:
+			if (net_ratelimit())
+				printk("layer7: Problem in dec2hex\n");
+			return '\0';
+	}
+}
+
+static char * hex_print(unsigned char * s)
+{
+	char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC);
+	int i;
+
+	if(!g) {
+	       if (net_ratelimit())
+			printk(KERN_ERR "layer7: out of memory in hex_print, "
+					"bailing.\n");
+	       return NULL;
+	}
+
+	for(i = 0; i < strlen(s); i++) {
+		g[i*3    ] = dec2hex(s[i]/16);
+		g[i*3 + 1] = dec2hex(s[i]%16);
+		g[i*3 + 2] = ' ';
+	}
+	g[i*3] = '\0';
+
+	return g;
+}
+#endif // DEBUG
+
+/* Use instead of regcomp.  As we expect to be seeing the same regexps over and
+over again, it make sense to cache the results. */
+static regexp * compile_and_cache(const char * regex_string, 
+                                  const char * protocol)
+{
+	struct pattern_cache * node               = first_pattern_cache;
+	struct pattern_cache * last_pattern_cache = first_pattern_cache;
+	struct pattern_cache * tmp;
+	unsigned int len;
+
+	while (node != NULL) {
+		if (!strcmp(node->regex_string, regex_string))
+		return node->pattern;
+
+		last_pattern_cache = node;/* points at the last non-NULL node */
+		node = node->next;
+	}
+
+	/* If we reach the end of the list, then we have not yet cached
+	   the pattern for this regex. Let's do that now.
+	   Be paranoid about running out of memory to avoid list corruption. */
+	tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC);
+
+	if(!tmp) {
+		if (net_ratelimit())
+			printk(KERN_ERR "layer7: out of memory in "
+					"compile_and_cache, bailing.\n");
+		return NULL;
+	}
+
+	tmp->regex_string  = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC);
+	tmp->pattern       = kmalloc(sizeof(struct regexp),    GFP_ATOMIC);
+	tmp->next = NULL;
+
+	if(!tmp->regex_string || !tmp->pattern) {
+		if (net_ratelimit())
+			printk(KERN_ERR "layer7: out of memory in "
+					"compile_and_cache, bailing.\n");
+		kfree(tmp->regex_string);
+		kfree(tmp->pattern);
+		kfree(tmp);
+		return NULL;
+	}
+
+	/* Ok.  The new node is all ready now. */
+	node = tmp;
+
+	if(first_pattern_cache == NULL) /* list is empty */
+		first_pattern_cache = node; /* make node the beginning */
+	else
+		last_pattern_cache->next = node; /* attach node to the end */
+
+	/* copy the string and compile the regex */
+	len = strlen(regex_string);
+	DPRINTK("About to compile this: \"%s\"\n", regex_string);
+	node->pattern = regcomp((char *)regex_string, &len);
+	if ( !node->pattern ) {
+		if (net_ratelimit())
+			printk(KERN_ERR "layer7: Error compiling regexp "
+					"\"%s\" (%s)\n", 
+					regex_string, protocol);
+		/* pattern is now cached as NULL, so we won't try again. */
+	}
+
+	strcpy(node->regex_string, regex_string);
+	return node->pattern;
+}
+
+static int can_handle(const struct sk_buff *skb)
+{
+	if(!ip_hdr(skb)) /* not IP */
+		return 0;
+	if(ip_hdr(skb)->protocol != IPPROTO_TCP &&
+	   ip_hdr(skb)->protocol != IPPROTO_UDP &&
+	   ip_hdr(skb)->protocol != IPPROTO_ICMP)
+		return 0;
+	return 1;
+}
+
+/* Returns offset the into the skb->data that the application data starts */
+static int app_data_offset(const struct sk_buff *skb)
+{
+	/* In case we are ported somewhere (ebtables?) where ip_hdr(skb)
+	isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */
+	int ip_hl = 4*ip_hdr(skb)->ihl;
+
+	if( ip_hdr(skb)->protocol == IPPROTO_TCP ) {
+		/* 12 == offset into TCP header for the header length field.
+		Can't get this with skb->h.th->doff because the tcphdr
+		struct doesn't get set when routing (this is confirmed to be
+		true in Netfilter as well as QoS.) */
+		int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4);
+
+		return ip_hl + tcp_hl;
+	} else if( ip_hdr(skb)->protocol == IPPROTO_UDP  ) {
+		return ip_hl + 8; /* UDP header is always 8 bytes */
+	} else if( ip_hdr(skb)->protocol == IPPROTO_ICMP ) {
+		return ip_hl + 8; /* ICMP header is 8 bytes */
+	} else {
+		if (net_ratelimit())
+			printk(KERN_ERR "layer7: tried to handle unknown "
+					"protocol!\n");
+		return ip_hl + 8; /* something reasonable */
+	}
+}
+
+/* handles whether there's a match when we aren't appending data anymore */
+static int match_no_append(struct nf_conn * conntrack, 
+                           struct nf_conn * master_conntrack, 
+                           enum ip_conntrack_info ctinfo,
+                           enum ip_conntrack_info master_ctinfo,
+                           const struct xt_layer7_info * info)
+{
+	/* If we're in here, throw the app data away */
+	if(master_conntrack->layer7.app_data != NULL) {
+
+	#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
+		if(!master_conntrack->layer7.app_proto) {
+			char * f = 
+			  friendly_print(master_conntrack->layer7.app_data);
+			char * g = 
+			  hex_print(master_conntrack->layer7.app_data);
+			DPRINTK("\nl7-filter gave up after %d bytes "
+				"(%d packets):\n%s\n",
+				strlen(f), total_acct_packets(master_conntrack), f);
+			kfree(f);
+			DPRINTK("In hex: %s\n", g);
+			kfree(g);
+		}
+	#endif
+
+		kfree(master_conntrack->layer7.app_data);
+		master_conntrack->layer7.app_data = NULL; /* don't free again */
+	}
+
+	if(master_conntrack->layer7.app_proto){
+		/* Here child connections set their .app_proto (for /proc) */
+		if(!conntrack->layer7.app_proto) {
+			conntrack->layer7.app_proto = 
+			  kmalloc(strlen(master_conntrack->layer7.app_proto)+1, 
+			    GFP_ATOMIC);
+			if(!conntrack->layer7.app_proto){
+				if (net_ratelimit())
+					printk(KERN_ERR "layer7: out of memory "
+							"in match_no_append, "
+							"bailing.\n");
+				return 1;
+			}
+			strcpy(conntrack->layer7.app_proto, 
+				master_conntrack->layer7.app_proto);
+		}
+
+		return (!strcmp(master_conntrack->layer7.app_proto, 
+				info->protocol));
+	}
+	else {
+		/* If not classified, set to "unknown" to distinguish from
+		connections that are still being tested. */
+		master_conntrack->layer7.app_proto = 
+			kmalloc(strlen("unknown")+1, GFP_ATOMIC);
+		if(!master_conntrack->layer7.app_proto){
+			if (net_ratelimit())
+				printk(KERN_ERR "layer7: out of memory in "
+						"match_no_append, bailing.\n");
+			return 1;
+		}
+		strcpy(master_conntrack->layer7.app_proto, "unknown");
+		return 0;
+	}
+}
+
+/* add the new app data to the conntrack.  Return number of bytes added. */
+static int add_datastr(char *target, int offset, char *app_data, int len)
+{
+	int length = 0, i;
+	if (!target) return 0;
+
+	/* Strip nulls. Make everything lower case (our regex lib doesn't
+	do case insensitivity).  Add it to the end of the current data. */
+ 	for(i = 0; i < maxdatalen-offset-1 && i < len; i++) {
+		if(app_data[i] != '\0') {
+			/* the kernel version of tolower mungs 'upper ascii' */
+			target[length+offset] =
+				isascii(app_data[i])? 
+					tolower(app_data[i]) : app_data[i];
+			length++;
+		}
+	}
+	target[length+offset] = '\0';
+
+	return length;
+}
+
+/* add the new app data to the conntrack.  Return number of bytes added. */
+static int add_data(struct nf_conn * master_conntrack,
+                    char * app_data, int appdatalen)
+{
+	int length;
+
+	length = add_datastr(master_conntrack->layer7.app_data, master_conntrack->layer7.app_data_len, app_data, appdatalen);
+	master_conntrack->layer7.app_data_len += length;
+
+	return length;
+}
+
+/* taken from drivers/video/modedb.c */
+static int my_atoi(const char *s)
+{
+	int val = 0;
+
+	for (;; s++) {
+		switch (*s) {
+			case '0'...'9':
+			val = 10*val+(*s-'0');
+			break;
+		default:
+			return val;
+		}
+	}
+}
+
+/* write out num_packets to userland. */
+static int layer7_read_proc(char* page, char ** start, off_t off, int count,
+                            int* eof, void * data)
+{
+	if(num_packets > 99 && net_ratelimit())
+		printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n");
+
+	page[0] = num_packets/10 + '0';
+	page[1] = num_packets%10 + '0';
+	page[2] = '\n';
+	page[3] = '\0';
+
+	*eof=1;
+
+	return 3;
+}
+
+/* Read in num_packets from userland */
+static int layer7_write_proc(struct file* file, const char* buffer,
+                             unsigned long count, void *data)
+{
+	char * foo = kmalloc(count, GFP_ATOMIC);
+
+	if(!foo){
+		if (net_ratelimit())
+			printk(KERN_ERR "layer7: out of memory, bailing. "
+					"num_packets unchanged.\n");
+		return count;
+	}
+
+	if(copy_from_user(foo, buffer, count)) {
+		return -EFAULT;
+	}
+
+
+	num_packets = my_atoi(foo);
+	kfree (foo);
+
+	/* This has an arbitrary limit to make the math easier. I'm lazy.
+	But anyway, 99 is a LOT! If you want more, you're doing it wrong! */
+	if(num_packets > 99) {
+		printk(KERN_WARNING "layer7: num_packets can't be > 99.\n");
+		num_packets = 99;
+	} else if(num_packets < 1) {
+		printk(KERN_WARNING "layer7: num_packets can't be < 1.\n");
+		num_packets = 1;
+	}
+
+	return count;
+}
+
+static bool
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+match(const struct sk_buff *skbin, struct xt_action_param *par)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+match(const struct sk_buff *skbin, const struct xt_match_param *par)
+#else
+match(const struct sk_buff *skbin,
+      const struct net_device *in,
+      const struct net_device *out,
+      const struct xt_match *match,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      bool *hotdrop)
+#endif
+{
+	/* sidestep const without getting a compiler warning... */
+	struct sk_buff * skb = (struct sk_buff *)skbin; 
+
+	const struct xt_layer7_info * info = 
+	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+		par->matchinfo;
+	#else
+		matchinfo;
+	#endif
+
+	enum ip_conntrack_info master_ctinfo, ctinfo;
+	struct nf_conn *master_conntrack, *conntrack;
+	unsigned char *app_data, *tmp_data;
+	unsigned int pattern_result, appdatalen;
+	regexp * comppattern;
+
+	/* Be paranoid/incompetent - lock the entire match function. */
+	spin_lock_bh(&l7_lock);
+
+	if(!can_handle(skb)){
+		DPRINTK("layer7: This is some protocol I can't handle.\n");
+		spin_unlock_bh(&l7_lock);
+		return info->invert;
+	}
+
+	/* Treat parent & all its children together as one connection, except
+	for the purpose of setting conntrack->layer7.app_proto in the actual
+	connection. This makes /proc/net/ip_conntrack more satisfying. */
+	if(!(conntrack = nf_ct_get(skb, &ctinfo)) ||
+	   !(master_conntrack=nf_ct_get(skb,&master_ctinfo))){
+		DPRINTK("layer7: couldn't get conntrack.\n");
+		spin_unlock_bh(&l7_lock);
+		return info->invert;
+	}
+
+	/* Try to get a master conntrack (and its master etc) for FTP, etc. */
+	while (master_ct(master_conntrack) != NULL)
+		master_conntrack = master_ct(master_conntrack);
+
+	/* if we've classified it or seen too many packets */
+	if(!info->pkt && (total_acct_packets(master_conntrack) > num_packets ||
+	   master_conntrack->layer7.app_proto)) {
+
+		pattern_result = match_no_append(conntrack, master_conntrack, 
+						 ctinfo, master_ctinfo, info);
+
+		/* skb->cb[0] == seen. Don't do things twice if there are 
+		multiple l7 rules. I'm not sure that using cb for this purpose 
+		is correct, even though it says "put your private variables 
+		there". But it doesn't look like it is being used for anything
+		else in the skbs that make it here. */
+		skb->cb[0] = 1; /* marking it seen here's probably irrelevant */
+
+		spin_unlock_bh(&l7_lock);
+		return (pattern_result ^ info->invert);
+	}
+
+	if(skb_is_nonlinear(skb)){
+		if(skb_linearize(skb) != 0){
+			if (net_ratelimit())
+				printk(KERN_ERR "layer7: failed to linearize "
+						"packet, bailing.\n");
+			spin_unlock_bh(&l7_lock);
+			return info->invert;
+		}
+	}
+
+	/* now that the skb is linearized, it's safe to set these. */
+	app_data = skb->data + app_data_offset(skb);
+	appdatalen = skb_tail_pointer(skb) - app_data;
+
+	/* the return value gets checked later, when we're ready to use it */
+	comppattern = compile_and_cache(info->pattern, info->protocol);
+
+	if (info->pkt) {
+		tmp_data = kmalloc(maxdatalen, GFP_ATOMIC);
+		if(!tmp_data){
+			if (net_ratelimit())
+				printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
+			return info->invert;
+		}
+
+		tmp_data[0] = '\0';
+		add_datastr(tmp_data, 0, app_data, appdatalen);
+		pattern_result = ((comppattern && regexec(comppattern, tmp_data)) ? 1 : 0);
+
+		kfree(tmp_data);
+		tmp_data = NULL;
+		spin_unlock_bh(&l7_lock);
+
+		return (pattern_result ^ info->invert);
+	}
+
+	/* On the first packet of a connection, allocate space for app data */
+	if(total_acct_packets(master_conntrack) == 1 && !skb->cb[0] && 
+	   !master_conntrack->layer7.app_data){
+		master_conntrack->layer7.app_data = 
+			kmalloc(maxdatalen, GFP_ATOMIC);
+		if(!master_conntrack->layer7.app_data){
+			if (net_ratelimit())
+				printk(KERN_ERR "layer7: out of memory in "
+						"match, bailing.\n");
+			spin_unlock_bh(&l7_lock);
+			return info->invert;
+		}
+
+		master_conntrack->layer7.app_data[0] = '\0';
+	}
+
+	/* Can be here, but unallocated, if numpackets is increased near
+	the beginning of a connection */
+	if(master_conntrack->layer7.app_data == NULL){
+		spin_unlock_bh(&l7_lock);
+		return info->invert; /* unmatched */
+	}
+
+	if(!skb->cb[0]){
+		int newbytes;
+		newbytes = add_data(master_conntrack, app_data, appdatalen);
+
+		if(newbytes == 0) { /* didn't add any data */
+			skb->cb[0] = 1;
+			/* Didn't match before, not going to match now */
+			spin_unlock_bh(&l7_lock);
+			return info->invert;
+		}
+	}
+
+	/* If looking for "unknown", then never match.  "Unknown" means that
+	we've given up; we're still trying with these packets. */
+	if(!strcmp(info->protocol, "unknown")) {
+		pattern_result = 0;
+	/* If looking for "unset", then always match. "Unset" means that we
+	haven't yet classified the connection. */
+	} else if(!strcmp(info->protocol, "unset")) {
+		pattern_result = 2;
+		DPRINTK("layer7: matched unset: not yet classified "
+			"(%d/%d packets)\n",
+                        total_acct_packets(master_conntrack), num_packets);
+	/* If the regexp failed to compile, don't bother running it */
+	} else if(comppattern && 
+		  regexec(comppattern, master_conntrack->layer7.app_data)){
+		DPRINTK("layer7: matched %s\n", info->protocol);
+		pattern_result = 1;
+	} else pattern_result = 0;
+
+	if(pattern_result == 1) {
+		master_conntrack->layer7.app_proto = 
+			kmalloc(strlen(info->protocol)+1, GFP_ATOMIC);
+		if(!master_conntrack->layer7.app_proto){
+			if (net_ratelimit())
+				printk(KERN_ERR "layer7: out of memory in "
+						"match, bailing.\n");
+			spin_unlock_bh(&l7_lock);
+			return (pattern_result ^ info->invert);
+		}
+		strcpy(master_conntrack->layer7.app_proto, info->protocol);
+	} else if(pattern_result > 1) { /* cleanup from "unset" */
+		pattern_result = 1;
+	}
+
+	/* mark the packet seen */
+	skb->cb[0] = 1;
+
+	spin_unlock_bh(&l7_lock);
+	return (pattern_result ^ info->invert);
+}
+
+// load nf_conntrack_ipv4
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+static int
+#else
+static bool
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+check(const struct xt_mtchk_param *par)
+{
+        if (nf_ct_l3proto_try_module_get(par->match->family) < 0) {
+                printk(KERN_WARNING "can't load conntrack support for "
+                                    "proto=%d\n", par->match->family);
+#else
+check(const char *tablename, const void *inf,
+		 const struct xt_match *match, void *matchinfo,
+		 unsigned int hook_mask)
+{
+        if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+                printk(KERN_WARNING "can't load conntrack support for "
+                                    "proto=%d\n", match->family);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+		return -EINVAL;
+	}
+	return 0;
+#else
+                return 0;
+        }
+	return 1;
+#endif
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+	static void destroy(const struct xt_mtdtor_param *par)
+	{
+		nf_ct_l3proto_module_put(par->match->family);
+	}
+#else
+	static void destroy(const struct xt_match *match, void *matchinfo)
+	{
+		nf_ct_l3proto_module_put(match->family);
+	}
+#endif
+
+static struct xt_match xt_layer7_match[] __read_mostly = {
+{
+	.name		= "layer7",
+	.family		= AF_INET,
+	.checkentry	= check,
+	.match		= match,
+	.destroy	= destroy,
+	.matchsize	= sizeof(struct xt_layer7_info),
+	.me		= THIS_MODULE
+}
+};
+
+static void layer7_cleanup_proc(void)
+{
+	remove_proc_entry("layer7_numpackets", init_net.proc_net);
+}
+
+/* register the proc file */
+static void layer7_init_proc(void)
+{
+	struct proc_dir_entry* entry;
+	entry = create_proc_entry("layer7_numpackets", 0644, init_net.proc_net);
+	entry->read_proc = layer7_read_proc;
+	entry->write_proc = layer7_write_proc;
+}
+
+static int __init xt_layer7_init(void)
+{
+	need_conntrack();
+
+	layer7_init_proc();
+	if(maxdatalen < 1) {
+		printk(KERN_WARNING "layer7: maxdatalen can't be < 1, "
+			"using 1\n");
+		maxdatalen = 1;
+	}
+	/* This is not a hard limit.  It's just here to prevent people from
+	bringing their slow machines to a grinding halt. */
+	else if(maxdatalen > 65536) {
+		printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, "
+			"using 65536\n");
+		maxdatalen = 65536;
+	}
+	return xt_register_matches(xt_layer7_match,
+				   ARRAY_SIZE(xt_layer7_match));
+}
+
+static void __exit xt_layer7_fini(void)
+{
+	layer7_cleanup_proc();
+	xt_unregister_matches(xt_layer7_match, ARRAY_SIZE(xt_layer7_match));
+}
+
+module_init(xt_layer7_init);
+module_exit(xt_layer7_fini);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index d9d4970..80872e4 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -296,6 +296,7 @@
 	unsigned int		tp_loss:1;
 	unsigned int		tp_tstamp;
 	struct packet_type	prot_hook ____cacheline_aligned_in_smp;
+	unsigned int		pkt_type;
 };
 
 #define PACKET_FANOUT_MAX	256
@@ -1383,6 +1384,7 @@
 {
 	struct sock *sk;
 	struct sockaddr_pkt *spkt;
+	struct packet_sock *po;
 
 	/*
 	 *	When we registered the protocol we saved the socket in the data
@@ -1390,6 +1392,7 @@
 	 */
 
 	sk = pt->af_packet_priv;
+	po = pkt_sk(sk);
 
 	/*
 	 *	Yank back the headers [hope the device set this
@@ -1402,7 +1405,7 @@
 	 *	so that this procedure is noop.
 	 */
 
-	if (skb->pkt_type == PACKET_LOOPBACK)
+	if (!(po->pkt_type & (1 << skb->pkt_type)))
 		goto out;
 
 	if (!net_eq(dev_net(dev), sock_net(sk)))
@@ -1595,12 +1598,12 @@
 	int skb_len = skb->len;
 	unsigned int snaplen, res;
 
-	if (skb->pkt_type == PACKET_LOOPBACK)
-		goto drop;
-
 	sk = pt->af_packet_priv;
 	po = pkt_sk(sk);
 
+	if (!(po->pkt_type & (1 << skb->pkt_type)))
+		goto drop;
+
 	if (!net_eq(dev_net(dev), sock_net(sk)))
 		goto drop;
 
@@ -1719,12 +1722,12 @@
 	struct timespec ts;
 	struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
 
-	if (skb->pkt_type == PACKET_LOOPBACK)
-		goto drop;
-
 	sk = pt->af_packet_priv;
 	po = pkt_sk(sk);
 
+	if (!(po->pkt_type & (1 << skb->pkt_type)))
+		goto drop;
+
 	if (!net_eq(dev_net(dev), sock_net(sk)))
 		goto drop;
 
@@ -2590,6 +2593,7 @@
 	spin_lock_init(&po->bind_lock);
 	mutex_init(&po->pg_vec_lock);
 	po->prot_hook.func = packet_rcv;
+	po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
 
 	if (sock->type == SOCK_PACKET)
 		po->prot_hook.func = packet_rcv_spkt;
@@ -3187,6 +3191,16 @@
 
 		return fanout_add(sk, val & 0xffff, val >> 16);
 	}
+        case PACKET_RECV_TYPE:
+        {
+                unsigned int val;
+                if (optlen != sizeof(val))
+                        return -EINVAL;
+                if (copy_from_user(&val, optval, sizeof(val)))
+                        return -EFAULT;
+                po->pkt_type = val & ~PACKET_LOOPBACK;
+                return 0;
+        }
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -3257,6 +3271,13 @@
 
 		data = &val;
 		break;
+	case PACKET_RECV_TYPE:
+		if (len > sizeof(unsigned int))
+			len = sizeof(unsigned int);
+		val = po->pkt_type;
+
+		data = &val;
+		break;
 	case PACKET_VERSION:
 		if (len > sizeof(int))
 			len = sizeof(int);
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 2590e91..61a944a 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -148,6 +148,37 @@
 	  To compile this code as a module, choose M here: the
 	  module will be called sch_sfq.
 
+config NET_SCH_ESFQ
+	tristate "Enhanced Stochastic Fairness Queueing (ESFQ)"
+	---help---
+	  Say Y here if you want to use the Enhanced Stochastic Fairness
+	  Queueing (ESFQ) packet scheduling algorithm for some of your network
+	  devices or as a leaf discipline for a classful qdisc such as HTB or
+	  CBQ (see the top of <file:net/sched/sch_esfq.c> for details and
+	  references to the SFQ algorithm).
+
+	  This is an enchanced SFQ version which allows you to control some
+	  hardcoded values in the SFQ scheduler.
+
+	  ESFQ also adds control of the hash function used to identify packet
+	  flows. The original SFQ discipline hashes by connection; ESFQ add
+	  several other hashing methods, such as by src IP or by dst IP, which
+	  can be more fair to users in some networking situations.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called sch_esfq.
+
+config NET_SCH_ESFQ_NFCT
+	bool "Connection Tracking Hash Types"
+	depends on NET_SCH_ESFQ && NF_CONNTRACK
+	---help---
+	  Say Y here to enable support for hashing based on netfilter connection
+	  tracking information. This is useful for a router that is also using
+	  NAT to connect privately-addressed hosts to the Internet. If you want
+	  to provide fair distribution of upstream bandwidth, ESFQ must use
+	  connection tracking information, since all outgoing packets will share
+	  the same source address.
+
 config NET_SCH_TEQL
 	tristate "True Link Equalizer (TEQL)"
 	---help---
@@ -571,6 +602,19 @@
 	  To compile this code as a module, choose M here: the
 	  module will be called act_csum.
 
+config NET_ACT_CONNMARK
+        tristate "Connection Tracking Marking"
+        depends on NET_CLS_ACT
+        depends on NF_CONNTRACK
+	 depends on NF_CONNTRACK_MARK
+        ---help---
+	  Say Y here to restore the connmark from a scheduler action
+
+	  If unsure, say N.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called act_connmark.
+
 config NET_CLS_IND
 	bool "Incoming device classification"
 	depends on NET_CLS_U32 || NET_CLS_FW
diff --git a/net/sched/Makefile b/net/sched/Makefile
index dc5889c..4261c96 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -16,6 +16,7 @@
 obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
 obj-$(CONFIG_NET_ACT_SKBEDIT)	+= act_skbedit.o
 obj-$(CONFIG_NET_ACT_CSUM)	+= act_csum.o
+obj-$(CONFIG_NET_ACT_CONNMARK)	+= act_connmark.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)	+= sch_htb.o
@@ -26,6 +27,7 @@
 obj-$(CONFIG_NET_SCH_DSMARK)	+= sch_dsmark.o
 obj-$(CONFIG_NET_SCH_SFB)	+= sch_sfb.o
 obj-$(CONFIG_NET_SCH_SFQ)	+= sch_sfq.o
+obj-$(CONFIG_NET_SCH_ESFQ)	+= sch_esfq.o
 obj-$(CONFIG_NET_SCH_TBF)	+= sch_tbf.o
 obj-$(CONFIG_NET_SCH_TEQL)	+= sch_teql.o
 obj-$(CONFIG_NET_SCH_PRIO)	+= sch_prio.o
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
new file mode 100644
index 0000000..742a0f0
--- /dev/null
+++ b/net/sched/act_connmark.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/pkt_cls.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <net/act_api.h>
+
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+
+#define TCA_ACT_CONNMARK	20
+
+#define CONNMARK_TAB_MASK     3
+static struct tcf_common *tcf_connmark_ht[CONNMARK_TAB_MASK + 1];
+static u32 connmark_idx_gen;
+static DEFINE_RWLOCK(connmark_lock);
+
+static struct tcf_hashinfo connmark_hash_info = {
+	.htab	=	tcf_connmark_ht,
+	.hmask	=	CONNMARK_TAB_MASK,
+	.lock	=	&connmark_lock,
+};
+
+static int tcf_connmark(struct sk_buff *skb, struct tc_action *a,
+		       struct tcf_result *res)
+{
+	struct nf_conn *c;
+	enum ip_conntrack_info ctinfo;
+	int proto;
+	int r;
+
+	if (skb->protocol == htons(ETH_P_IP)) {
+		if (skb->len < sizeof(struct iphdr))
+			goto out;
+		proto = PF_INET;
+	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		if (skb->len < sizeof(struct ipv6hdr))
+			goto out;
+		proto = PF_INET6;
+	} else
+		goto out;
+
+	r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
+	if (r != NF_ACCEPT)
+		goto out;
+
+	c = nf_ct_get(skb, &ctinfo);
+	if (!c)
+		goto out;
+
+	skb->mark = c->mark;
+	nf_conntrack_put(skb->nfct);
+	skb->nfct = NULL;
+
+out:
+	return TC_ACT_PIPE;
+}
+
+static int tcf_connmark_init(struct nlattr *nla, struct nlattr *est,
+			 struct tc_action *a, int ovr, int bind)
+{
+	struct tcf_common *pc;
+
+	pc = tcf_hash_create(0, est, a, sizeof(*pc), bind,
+			     &connmark_idx_gen, &connmark_hash_info);
+	if (IS_ERR(pc))
+	    return PTR_ERR(pc);
+
+	tcf_hash_insert(pc, &connmark_hash_info);
+
+	return ACT_P_CREATED;
+}
+
+static inline int tcf_connmark_cleanup(struct tc_action *a, int bind)
+{
+	if (a->priv)
+		return tcf_hash_release(a->priv, bind, &connmark_hash_info);
+	return 0;
+}
+
+static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
+				int bind, int ref)
+{
+	return skb->len;
+}
+
+static struct tc_action_ops act_connmark_ops = {
+	.kind		=	"connmark",
+	.hinfo		=	&connmark_hash_info,
+	.type		=	TCA_ACT_CONNMARK,
+	.capab		=	TCA_CAP_NONE,
+	.owner		=	THIS_MODULE,
+	.act		=	tcf_connmark,
+	.dump		=	tcf_connmark_dump,
+	.cleanup	=	tcf_connmark_cleanup,
+	.init		=	tcf_connmark_init,
+	.walk		=	tcf_generic_walker,
+};
+
+MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
+MODULE_DESCRIPTION("Connection tracking mark restoring");
+MODULE_LICENSE("GPL");
+
+static int __init connmark_init_module(void)
+{
+	return tcf_register_action(&act_connmark_ops);
+}
+
+static void __exit connmark_cleanup_module(void)
+{
+	tcf_unregister_action(&act_connmark_ops);
+}
+
+module_init(connmark_init_module);
+module_exit(connmark_cleanup_module);
diff --git a/net/sched/sch_esfq.c b/net/sched/sch_esfq.c
new file mode 100644
index 0000000..6618a74
--- /dev/null
+++ b/net/sched/sch_esfq.c
@@ -0,0 +1,702 @@
+/*
+ * net/sched/sch_esfq.c	Extended Stochastic Fairness Queueing discipline.
+ *
+ *		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.
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Changes:	Alexander Atanasov, <alex@ssi.bg>
+ *		Added dynamic depth,limit,divisor,hash_kind options.
+ *		Added dst and src hashes.
+ *
+ * 		Alexander Clouter, <alex@digriz.org.uk>
+ *		Ported ESFQ to Linux 2.6.
+ *
+ * 		Corey Hickey, <bugfood-c@fatooh.org>
+ *		Maintenance of the Linux 2.6 port.
+ *		Added fwmark hash (thanks to Robert Kurjata).
+ *		Added usage of jhash.
+ *		Added conntrack support.
+ *		Added ctnatchg hash (thanks to Ben Pfountz).
+ */
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/netlink.h>
+#include <linux/ipv6.h>
+#include <net/route.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/jhash.h>
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+#include <net/netfilter/nf_conntrack.h>
+#endif
+
+/*	Stochastic Fairness Queuing algorithm.
+	For more comments look at sch_sfq.c.
+	The difference is that you can change limit, depth,
+	hash table size and choose alternate hash types.
+
+	classic:	same as in sch_sfq.c
+	dst:		destination IP address
+	src:		source IP address
+	fwmark:		netfilter mark value
+	ctorigdst:	original destination IP address
+	ctorigsrc:	original source IP address
+	ctrepldst:	reply destination IP address
+	ctreplsrc:	reply source IP
+
+*/
+
+#define ESFQ_HEAD 0
+#define ESFQ_TAIL 1
+
+/* This type should contain at least SFQ_DEPTH*2 values */
+typedef unsigned int esfq_index;
+
+struct esfq_head
+{
+	esfq_index	next;
+	esfq_index	prev;
+};
+
+struct esfq_sched_data
+{
+/* Parameters */
+	int		perturb_period;
+	unsigned	quantum;	/* Allotment per round: MUST BE >= MTU */
+	int		limit;
+	unsigned	depth;
+	unsigned	hash_divisor;
+	unsigned	hash_kind;
+/* Variables */
+	struct timer_list perturb_timer;
+	int		perturbation;
+	esfq_index	tail;		/* Index of current slot in round */
+	esfq_index	max_depth;	/* Maximal depth */
+
+	esfq_index	*ht;			/* Hash table */
+	esfq_index	*next;			/* Active slots link */
+	short		*allot;			/* Current allotment per slot */
+	unsigned short	*hash;			/* Hash value indexed by slots */
+	struct sk_buff_head	*qs;		/* Slot queue */
+	struct esfq_head	*dep;		/* Linked list of slots, indexed by depth */
+};
+
+/* This contains the info we will hash. */
+struct esfq_packet_info
+{
+	u32	proto;		/* protocol or port */
+	u32	src;		/* source from packet header */
+	u32	dst;		/* destination from packet header */
+	u32	ctorigsrc;	/* original source from conntrack */
+	u32	ctorigdst;	/* original destination from conntrack */
+	u32	ctreplsrc;	/* reply source from conntrack */
+	u32	ctrepldst;	/* reply destination from conntrack */
+	u32	mark;		/* netfilter mark (fwmark) */
+};
+
+static __inline__ unsigned esfq_jhash_1word(struct esfq_sched_data *q,u32 a)
+{
+	return jhash_1word(a, q->perturbation) & (q->hash_divisor-1);
+}
+
+static __inline__ unsigned esfq_jhash_2words(struct esfq_sched_data *q, u32 a, u32 b)
+{
+	return jhash_2words(a, b, q->perturbation) & (q->hash_divisor-1);
+}
+
+static __inline__ unsigned esfq_jhash_3words(struct esfq_sched_data *q, u32 a, u32 b, u32 c)
+{
+	return jhash_3words(a, b, c, q->perturbation) & (q->hash_divisor-1);
+}
+
+static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb)
+{
+	struct esfq_packet_info info;
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+#endif
+
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_IP):
+	{
+		struct iphdr *iph = ip_hdr(skb);
+		info.dst = iph->daddr;
+		info.src = iph->saddr;
+		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
+		    (iph->protocol == IPPROTO_TCP ||
+		     iph->protocol == IPPROTO_UDP ||
+		     iph->protocol == IPPROTO_SCTP ||
+		     iph->protocol == IPPROTO_DCCP ||
+		     iph->protocol == IPPROTO_ESP))
+			info.proto = *(((u32*)iph) + iph->ihl);
+		else
+			info.proto = iph->protocol;
+		break;
+	}
+	case __constant_htons(ETH_P_IPV6):
+	{
+		struct ipv6hdr *iph = ipv6_hdr(skb);
+		/* Hash ipv6 addresses into a u32. This isn't ideal,
+		 * but the code is simple. */
+		info.dst = jhash2(iph->daddr.s6_addr32, 4, q->perturbation);
+		info.src = jhash2(iph->saddr.s6_addr32, 4, q->perturbation);
+		if (iph->nexthdr == IPPROTO_TCP ||
+		    iph->nexthdr == IPPROTO_UDP ||
+		    iph->nexthdr == IPPROTO_SCTP ||
+		    iph->nexthdr == IPPROTO_DCCP ||
+		    iph->nexthdr == IPPROTO_ESP)
+			info.proto = *(u32*)&iph[1];
+		else
+			info.proto = iph->nexthdr;
+		break;
+	}
+	default:
+		info.dst   = (u32)(unsigned long)skb_dst(skb);
+		info.src   = (u32)(unsigned long)skb->sk;
+		info.proto = skb->protocol;
+	}
+
+	info.mark = skb->mark;
+
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+	/* defaults if there is no conntrack info */
+	info.ctorigsrc = info.src;
+	info.ctorigdst = info.dst;
+	info.ctreplsrc = info.dst;
+	info.ctrepldst = info.src;
+	/* collect conntrack info */
+	if (ct && ct != &nf_conntrack_untracked) {
+		if (skb->protocol == __constant_htons(ETH_P_IP)) {
+			info.ctorigsrc = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
+			info.ctorigdst = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip;
+			info.ctreplsrc = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip;
+			info.ctrepldst = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
+		}
+		else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+			/* Again, hash ipv6 addresses into a single u32. */
+			info.ctorigsrc = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6, 4, q->perturbation);
+			info.ctorigdst = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip6, 4, q->perturbation);
+			info.ctreplsrc = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6, 4, q->perturbation);
+			info.ctrepldst = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6, 4, q->perturbation);
+		}
+
+	}
+#endif
+
+	switch(q->hash_kind) {
+	case TCA_SFQ_HASH_CLASSIC:
+		return esfq_jhash_3words(q, info.dst, info.src, info.proto);
+	case TCA_SFQ_HASH_DST:
+		return esfq_jhash_1word(q, info.dst);
+	case TCA_SFQ_HASH_SRC:
+		return esfq_jhash_1word(q, info.src);
+	case TCA_SFQ_HASH_FWMARK:
+		return esfq_jhash_1word(q, info.mark);
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+	case TCA_SFQ_HASH_CTORIGDST:
+		return esfq_jhash_1word(q, info.ctorigdst);
+	case TCA_SFQ_HASH_CTORIGSRC:
+		return esfq_jhash_1word(q, info.ctorigsrc);
+	case TCA_SFQ_HASH_CTREPLDST:
+		return esfq_jhash_1word(q, info.ctrepldst);
+	case TCA_SFQ_HASH_CTREPLSRC:
+		return esfq_jhash_1word(q, info.ctreplsrc);
+	case TCA_SFQ_HASH_CTNATCHG:
+	{
+		if (info.ctorigdst == info.ctreplsrc)
+			return esfq_jhash_1word(q, info.ctorigsrc);
+		return esfq_jhash_1word(q, info.ctreplsrc);
+	}
+#endif
+	default:
+		if (net_ratelimit())
+			printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n");
+	}
+	return esfq_jhash_3words(q, info.dst, info.src, info.proto);
+}
+
+static inline void esfq_link(struct esfq_sched_data *q, esfq_index x)
+{
+	esfq_index p, n;
+	int d = q->qs[x].qlen + q->depth;
+
+	p = d;
+	n = q->dep[d].next;
+	q->dep[x].next = n;
+	q->dep[x].prev = p;
+	q->dep[p].next = q->dep[n].prev = x;
+}
+
+static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x)
+{
+	esfq_index p, n;
+
+	n = q->dep[x].next;
+	p = q->dep[x].prev;
+	q->dep[p].next = n;
+	q->dep[n].prev = p;
+
+	if (n == p && q->max_depth == q->qs[x].qlen + 1)
+		q->max_depth--;
+
+	esfq_link(q, x);
+}
+
+static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x)
+{
+	esfq_index p, n;
+	int d;
+
+	n = q->dep[x].next;
+	p = q->dep[x].prev;
+	q->dep[p].next = n;
+	q->dep[n].prev = p;
+	d = q->qs[x].qlen;
+	if (q->max_depth < d)
+		q->max_depth = d;
+
+	esfq_link(q, x);
+}
+
+static unsigned int esfq_drop(struct Qdisc *sch)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	esfq_index d = q->max_depth;
+	struct sk_buff *skb;
+	unsigned int len;
+
+	/* Queue is full! Find the longest slot and
+	   drop a packet from it */
+
+	if (d > 1) {
+		esfq_index x = q->dep[d+q->depth].next;
+		skb = q->qs[x].prev;
+		len = skb->len;
+		__skb_unlink(skb, &q->qs[x]);
+		kfree_skb(skb);
+		esfq_dec(q, x);
+		sch->q.qlen--;
+		sch->qstats.drops++;
+		sch->qstats.backlog -= len;
+		return len;
+	}
+
+	if (d == 1) {
+		/* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */
+		d = q->next[q->tail];
+		q->next[q->tail] = q->next[d];
+		q->allot[q->next[d]] += q->quantum;
+		skb = q->qs[d].prev;
+		len = skb->len;
+		__skb_unlink(skb, &q->qs[d]);
+		kfree_skb(skb);
+		esfq_dec(q, d);
+		sch->q.qlen--;
+		q->ht[q->hash[d]] = q->depth;
+		sch->qstats.drops++;
+		sch->qstats.backlog -= len;
+		return len;
+	}
+
+	return 0;
+}
+
+static void esfq_q_enqueue(struct sk_buff *skb, struct esfq_sched_data *q, unsigned int end)
+{
+	unsigned hash = esfq_hash(q, skb);
+	unsigned depth = q->depth;
+	esfq_index x;
+
+	x = q->ht[hash];
+	if (x == depth) {
+		q->ht[hash] = x = q->dep[depth].next;
+		q->hash[x] = hash;
+	}
+
+	if (end == ESFQ_TAIL)
+		__skb_queue_tail(&q->qs[x], skb);
+	else
+		__skb_queue_head(&q->qs[x], skb);
+
+	esfq_inc(q, x);
+	if (q->qs[x].qlen == 1) {		/* The flow is new */
+		if (q->tail == depth) {	/* It is the first flow */
+			q->tail = x;
+			q->next[x] = x;
+			q->allot[x] = q->quantum;
+		} else {
+			q->next[x] = q->next[q->tail];
+			q->next[q->tail] = x;
+			q->tail = x;
+		}
+	}
+}
+
+static int esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	esfq_q_enqueue(skb, q, ESFQ_TAIL);
+	sch->qstats.backlog += skb->len;
+	if (++sch->q.qlen < q->limit-1) {
+		sch->bstats.bytes += skb->len;
+		sch->bstats.packets++;
+		return 0;
+	}
+
+	sch->qstats.drops++;
+	esfq_drop(sch);
+	return NET_XMIT_CN;
+}
+
+static struct sk_buff *esfq_peek(struct Qdisc* sch)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	esfq_index a;
+
+	/* No active slots */
+	if (q->tail == q->depth)
+		return NULL;
+
+	a = q->next[q->tail];
+	return skb_peek(&q->qs[a]);
+}
+
+static struct sk_buff *esfq_q_dequeue(struct esfq_sched_data *q)
+{
+	struct sk_buff *skb;
+	unsigned depth = q->depth;
+	esfq_index a, old_a;
+
+	/* No active slots */
+	if (q->tail == depth)
+		return NULL;
+
+	a = old_a = q->next[q->tail];
+
+	/* Grab packet */
+	skb = __skb_dequeue(&q->qs[a]);
+	esfq_dec(q, a);
+
+	/* Is the slot empty? */
+	if (q->qs[a].qlen == 0) {
+		q->ht[q->hash[a]] = depth;
+		a = q->next[a];
+		if (a == old_a) {
+			q->tail = depth;
+			return skb;
+		}
+		q->next[q->tail] = a;
+		q->allot[a] += q->quantum;
+	} else if ((q->allot[a] -= skb->len) <= 0) {
+		q->tail = a;
+		a = q->next[a];
+		q->allot[a] += q->quantum;
+	}
+
+	return skb;
+}
+
+static struct sk_buff *esfq_dequeue(struct Qdisc* sch)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	struct sk_buff *skb;
+
+	skb = esfq_q_dequeue(q);
+	if (skb == NULL)
+		return NULL;
+	sch->q.qlen--;
+	sch->qstats.backlog -= skb->len;
+	return skb;
+}
+
+static void esfq_q_destroy(struct esfq_sched_data *q)
+{
+	del_timer(&q->perturb_timer);
+	if(q->ht)
+		kfree(q->ht);
+	if(q->dep)
+		kfree(q->dep);
+	if(q->next)
+		kfree(q->next);
+	if(q->allot)
+		kfree(q->allot);
+	if(q->hash)
+		kfree(q->hash);
+	if(q->qs)
+		kfree(q->qs);
+}
+
+static void esfq_destroy(struct Qdisc *sch)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	esfq_q_destroy(q);
+}
+
+
+static void esfq_reset(struct Qdisc* sch)
+{
+	struct sk_buff *skb;
+
+	while ((skb = esfq_dequeue(sch)) != NULL)
+		kfree_skb(skb);
+}
+
+static void esfq_perturbation(unsigned long arg)
+{
+	struct Qdisc *sch = (struct Qdisc*)arg;
+	struct esfq_sched_data *q = qdisc_priv(sch);
+
+	q->perturbation = net_random()&0x1F;
+
+	if (q->perturb_period) {
+		q->perturb_timer.expires = jiffies + q->perturb_period;
+		add_timer(&q->perturb_timer);
+	}
+}
+
+static unsigned int esfq_check_hash(unsigned int kind)
+{
+	switch (kind) {
+	case TCA_SFQ_HASH_CTORIGDST:
+	case TCA_SFQ_HASH_CTORIGSRC:
+	case TCA_SFQ_HASH_CTREPLDST:
+	case TCA_SFQ_HASH_CTREPLSRC:
+	case TCA_SFQ_HASH_CTNATCHG:
+#ifndef CONFIG_NET_SCH_ESFQ_NFCT
+	{
+		if (net_ratelimit())
+			printk(KERN_WARNING "ESFQ: Conntrack hash types disabled in kernel config. Falling back to classic.\n");
+		return TCA_SFQ_HASH_CLASSIC;
+	}
+#endif
+	case TCA_SFQ_HASH_CLASSIC:
+	case TCA_SFQ_HASH_DST:
+	case TCA_SFQ_HASH_SRC:
+	case TCA_SFQ_HASH_FWMARK:
+		return kind;
+	default:
+	{
+		if (net_ratelimit())
+			printk(KERN_WARNING "ESFQ: Unknown hash type. Falling back to classic.\n");
+		return TCA_SFQ_HASH_CLASSIC;
+	}
+	}
+}
+
+static int esfq_q_init(struct esfq_sched_data *q, struct nlattr *opt)
+{
+	struct tc_esfq_qopt *ctl = nla_data(opt);
+	esfq_index p = ~0U/2;
+	int i;
+
+	if (opt && opt->nla_len < nla_attr_size(sizeof(*ctl)))
+		return -EINVAL;
+
+	q->perturbation = 0;
+	q->hash_kind = TCA_SFQ_HASH_CLASSIC;
+	q->max_depth = 0;
+	if (opt == NULL) {
+		q->perturb_period = 0;
+		q->hash_divisor = 1024;
+		q->tail = q->limit = q->depth = 128;
+
+	} else {
+		struct tc_esfq_qopt *ctl = nla_data(opt);
+		if (ctl->quantum)
+			q->quantum = ctl->quantum;
+		q->perturb_period = ctl->perturb_period*HZ;
+		q->hash_divisor = ctl->divisor ? : 1024;
+		q->tail = q->limit = q->depth = ctl->flows ? : 128;
+
+		if ( q->depth > p - 1 )
+			return -EINVAL;
+
+		if (ctl->limit)
+			q->limit = min_t(u32, ctl->limit, q->depth);
+
+		if (ctl->hash_kind) {
+			q->hash_kind = esfq_check_hash(ctl->hash_kind);
+		}
+	}
+
+	q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL);
+	if (!q->ht)
+		goto err_case;
+	q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL);
+	if (!q->dep)
+		goto err_case;
+	q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL);
+	if (!q->next)
+		goto err_case;
+	q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL);
+	if (!q->allot)
+		goto err_case;
+	q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL);
+	if (!q->hash)
+		goto err_case;
+	q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL);
+	if (!q->qs)
+		goto err_case;
+
+	for (i=0; i< q->hash_divisor; i++)
+		q->ht[i] = q->depth;
+	for (i=0; i<q->depth; i++) {
+		skb_queue_head_init(&q->qs[i]);
+		q->dep[i+q->depth].next = i+q->depth;
+		q->dep[i+q->depth].prev = i+q->depth;
+	}
+
+	for (i=0; i<q->depth; i++)
+		esfq_link(q, i);
+	return 0;
+err_case:
+	esfq_q_destroy(q);
+	return -ENOBUFS;
+}
+
+static int esfq_init(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	int err;
+
+	q->quantum = psched_mtu(qdisc_dev(sch)); /* default */
+	if ((err = esfq_q_init(q, opt)))
+		return err;
+
+	init_timer(&q->perturb_timer);
+	q->perturb_timer.data = (unsigned long)sch;
+	q->perturb_timer.function = esfq_perturbation;
+	if (q->perturb_period) {
+		q->perturb_timer.expires = jiffies + q->perturb_period;
+		add_timer(&q->perturb_timer);
+	}
+
+	return 0;
+}
+
+static int esfq_change(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	struct esfq_sched_data new;
+	struct sk_buff *skb;
+	int err;
+
+	/* set up new queue */
+	memset(&new, 0, sizeof(struct esfq_sched_data));
+	new.quantum = psched_mtu(qdisc_dev(sch)); /* default */
+	if ((err = esfq_q_init(&new, opt)))
+		return err;
+
+	/* copy all packets from the old queue to the new queue */
+	sch_tree_lock(sch);
+	while ((skb = esfq_q_dequeue(q)) != NULL)
+		esfq_q_enqueue(skb, &new, ESFQ_TAIL);
+
+	/* clean up the old queue */
+	esfq_q_destroy(q);
+
+	/* copy elements of the new queue into the old queue */
+	q->perturb_period = new.perturb_period;
+	q->quantum        = new.quantum;
+	q->limit          = new.limit;
+	q->depth          = new.depth;
+	q->hash_divisor   = new.hash_divisor;
+	q->hash_kind      = new.hash_kind;
+	q->tail           = new.tail;
+	q->max_depth      = new.max_depth;
+	q->ht    = new.ht;
+	q->dep   = new.dep;
+	q->next  = new.next;
+	q->allot = new.allot;
+	q->hash  = new.hash;
+	q->qs    = new.qs;
+
+	/* finish up */
+	if (q->perturb_period) {
+		q->perturb_timer.expires = jiffies + q->perturb_period;
+		add_timer(&q->perturb_timer);
+	} else {
+		q->perturbation = 0;
+	}
+	sch_tree_unlock(sch);
+	return 0;
+}
+
+static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct esfq_sched_data *q = qdisc_priv(sch);
+	unsigned char *b = skb_tail_pointer(skb);
+	struct tc_esfq_qopt opt;
+
+	opt.quantum = q->quantum;
+	opt.perturb_period = q->perturb_period/HZ;
+
+	opt.limit = q->limit;
+	opt.divisor = q->hash_divisor;
+	opt.flows = q->depth;
+	opt.hash_kind = q->hash_kind;
+
+	NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+
+	return skb->len;
+
+nla_put_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+static struct Qdisc_ops esfq_qdisc_ops =
+{
+	.next		=	NULL,
+	.cl_ops		=	NULL,
+	.id		=	"esfq",
+	.priv_size	=	sizeof(struct esfq_sched_data),
+	.enqueue	=	esfq_enqueue,
+	.dequeue	=	esfq_dequeue,
+	.peek		=	esfq_peek,
+	.drop		=	esfq_drop,
+	.init		=	esfq_init,
+	.reset		=	esfq_reset,
+	.destroy	=	esfq_destroy,
+	.change		=	esfq_change,
+	.dump		=	esfq_dump,
+	.owner		=	THIS_MODULE,
+};
+
+static int __init esfq_module_init(void)
+{
+	return register_qdisc(&esfq_qdisc_ops);
+}
+static void __exit esfq_module_exit(void)
+{
+	unregister_qdisc(&esfq_qdisc_ops);
+}
+module_init(esfq_module_init)
+module_exit(esfq_module_exit)
+MODULE_LICENSE("GPL");
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 1f1ef70..e6dd593 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,5 +1,5 @@
 config WIRELESS_EXT
-	bool
+	bool "Wireless extensions"
 
 config WEXT_CORE
 	def_bool y
@@ -11,10 +11,10 @@
 	depends on WEXT_CORE
 
 config WEXT_SPY
-	bool
+	bool "WEXT_SPY"
 
 config WEXT_PRIV
-	bool
+	bool "WEXT_PRIV"
 
 config CFG80211
 	tristate "cfg80211 - wireless configuration API"
@@ -142,13 +142,13 @@
 	  you want this built into your kernel.
 
 config LIB80211_CRYPT_WEP
-	tristate
+	tristate "LIB80211_CRYPT_WEP"
 
 config LIB80211_CRYPT_CCMP
-	tristate
+	tristate "LIB80211_CRYPT_CCMP"
 
 config LIB80211_CRYPT_TKIP
-	tristate
+	tristate "LIB80211_CRYPT_TKIP"
 
 config LIB80211_DEBUG
 	bool "lib80211 debugging messages"
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 5d986d9..973325c 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -296,7 +296,7 @@
 
 quiet_cmd_lzma = LZMA    $@
 cmd_lzma = (cat $(filter-out FORCE,$^) | \
-	lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+	lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
 	(rm -f $@ ; false)
 
 quiet_cmd_lzo = LZO     $@
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index b482f16..59ffa51 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -226,7 +226,7 @@
 output="/dev/stdout"
 output_file=""
 is_cpio_compressed=
-compr="gzip -n -9 -f"
+compr="gzip -n -9 -f -"
 
 arg="$1"
 case "$arg" in
@@ -240,9 +240,9 @@
 		output_file="$1"
 		cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
 		output=${cpio_list}
-		echo "$output_file" | grep -q "\.gz$" && compr="gzip -n -9 -f"
-		echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f"
-		echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f"
+		echo "$output_file" | grep -q "\.gz$" && compr="gzip -n -9 -f -"
+		echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f -"
+		echo "$output_file" | grep -q "\.lzma$" && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
 		echo "$output_file" | grep -q "\.xz$" && \
 				compr="xz --check=crc32 --lzma2=dict=1MiB"
 		echo "$output_file" | grep -q "\.lzo$" && compr="lzop -9 -f"
@@ -303,7 +303,7 @@
 	if [ "${is_cpio_compressed}" = "compressed" ]; then
 		cat ${cpio_tfile} > ${output_file}
 	else
-		(cat ${cpio_tfile} | ${compr}  - > ${output_file}) \
+		(cat ${cpio_tfile} | ${compr} > ${output_file}) \
 		|| (rm -f ${output_file} ; false)
 	fi
 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 487ac6f..95ca1f3 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -22,6 +22,35 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#ifdef __APPLE__
+/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */
+void *memmem (const void *haystack, size_t haystack_len,
+                          const void *needle,  size_t needle_len)
+{
+  const char *begin;
+  const char *const last_possible
+    = (const char *) haystack + haystack_len - needle_len;
+
+  if (needle_len == 0)
+    /* The first occurrence of the empty string is deemed to occur at
+       the beginning of the string.  */
+    return (void *) haystack;
+
+  /* Sanity check, otherwise the loop might search through the whole
+     memory.  */
+  if (__builtin_expect (haystack_len < needle_len, 0))
+    return NULL;
+
+  for (begin = (const char *) haystack; begin <= last_possible; ++begin)
+    if (begin[0] == ((const char *) needle)[0] &&
+        !memcmp ((const void *) &begin[1],
+                 (const void *) ((const char *) needle + 1),
+                 needle_len - 1))
+      return (void *) begin;
+
+  return NULL;
+}
+#endif
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 914833d..d127f25 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -123,6 +123,9 @@
 # we really need to do so. (Do not call gcc as part of make mrproper)
 HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
                     -DLOCALE
+ifeq ($(shell uname -s),Darwin)
+HOST_LOADLIBES  += -lncurses
+endif
 
 # ===========================================================================
 # Shared Makefile for the various kconfig executables:
diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c
index 639bca7..d20b17e 100644
--- a/scripts/mod/mk_elfconfig.c
+++ b/scripts/mod/mk_elfconfig.c
@@ -1,7 +1,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifndef __APPLE__
 #include <elf.h>
+#else
+#include "../../../../../tools/sstrip/include/elf.h"
+#endif
 
 int
 main(int argc, char **argv)
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 51207e4..9c67fb3 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -7,7 +7,11 @@
 #include <sys/mman.h>
 #include <fcntl.h>
 #include <unistd.h>
+#if !(defined(__APPLE__) || defined(__CYGWIN__))
 #include <elf.h>
+#else
+#include "../../../../../tools/sstrip/include/elf.h"
+#endif
 
 #include "elfconfig.h"
 
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 4d40384..ebdad63 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -168,7 +168,7 @@
 	# annotated or signed tagged state (as git describe only
 	# looks at signed or annotated tags - git tag -a/-s) and
 	# LOCALVERSION= is not specified
-	if test "${LOCALVERSION+set}" != "set"; then
+	if test "${CONFIG_LOCALVERSION+set}" != "set"; then
 		scm=$(scm_version --short)
 		res="$res${scm:++}"
 	fi