+++ /dev/null
-Platforms will now have to supply a function dma_device_is_coherent which
-returns if a particular device participates in the coherence domain. For
-most platforms this function will always return 0 or 1.
-
-Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
---- linux.old/arch/mips/Kconfig 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/arch/mips/Kconfig 2007-02-09 20:26:45.367388152 +0100
-@@ -571,8 +571,6 @@
- select ARC
- select ARC32
- select BOOT_ELF32
-- select OWN_DMA
-- select DMA_IP32
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select R5000_CPU_SCACHE
-@@ -835,9 +833,6 @@
- config DMA_NEED_PCI_MAP_STATE
- bool
-
--config OWN_DMA
-- bool
--
- config EARLY_PRINTK
- bool
-
-diff -urN linux.old/arch/mips/mm/dma-coherent.c linux.dev/arch/mips/mm/dma-coherent.c
---- linux.old/arch/mips/mm/dma-coherent.c 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/arch/mips/mm/dma-coherent.c 1970-01-01 01:00:00.000000000 +0100
-@@ -1,254 +0,0 @@
--/*
-- * This file is subject to the terms and conditions of the GNU General Public
-- * License. See the file "COPYING" in the main directory of this archive
-- * for more details.
-- *
-- * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
-- * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org>
-- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
-- */
--#include <linux/types.h>
--#include <linux/dma-mapping.h>
--#include <linux/mm.h>
--#include <linux/module.h>
--#include <linux/string.h>
--
--#include <asm/cache.h>
--#include <asm/io.h>
--
--void *dma_alloc_noncoherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
--{
-- void *ret;
-- /* ignore region specifiers */
-- gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
--
-- if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-- gfp |= GFP_DMA;
-- ret = (void *) __get_free_pages(gfp, get_order(size));
--
-- if (ret != NULL) {
-- memset(ret, 0, size);
-- *dma_handle = virt_to_phys(ret);
-- }
--
-- return ret;
--}
--
--EXPORT_SYMBOL(dma_alloc_noncoherent);
--
--void *dma_alloc_coherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
-- __attribute__((alias("dma_alloc_noncoherent")));
--
--EXPORT_SYMBOL(dma_alloc_coherent);
--
--void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle)
--{
-- unsigned long addr = (unsigned long) vaddr;
--
-- free_pages(addr, get_order(size));
--}
--
--EXPORT_SYMBOL(dma_free_noncoherent);
--
--void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent")));
--
--EXPORT_SYMBOL(dma_free_coherent);
--
--dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--
-- return __pa(ptr);
--}
--
--EXPORT_SYMBOL(dma_map_single);
--
--void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_unmap_single);
--
--int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- for (i = 0; i < nents; i++, sg++) {
-- sg->dma_address = (dma_addr_t)page_to_phys(sg->page) + sg->offset;
-- }
--
-- return nents;
--}
--
--EXPORT_SYMBOL(dma_map_sg);
--
--dma_addr_t dma_map_page(struct device *dev, struct page *page,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--
-- return page_to_phys(page) + offset;
--}
--
--EXPORT_SYMBOL(dma_map_page);
--
--void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_unmap_page);
--
--void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_unmap_sg);
--
--void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-- size_t size, enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_cpu);
--
--void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-- size_t size, enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_device);
--
--void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
--
--void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_device);
--
--void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_cpu);
--
--void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_device);
--
--int dma_mapping_error(dma_addr_t dma_addr)
--{
-- return 0;
--}
--
--EXPORT_SYMBOL(dma_mapping_error);
--
--int dma_supported(struct device *dev, u64 mask)
--{
-- /*
-- * we fall back to GFP_DMA when the mask isn't all 1s,
-- * so we can't guarantee allocations that must be
-- * within a tighter range than GFP_DMA..
-- */
-- if (mask < 0x00ffffff)
-- return 0;
--
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_supported);
--
--int dma_is_consistent(dma_addr_t dma_addr)
--{
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_is_consistent);
--
--void dma_cache_sync(void *vaddr, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_cache_sync);
--
--/* The DAC routines are a PCIism.. */
--
--#ifdef CONFIG_PCI
--
--#include <linux/pci.h>
--
--dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
-- struct page *page, unsigned long offset, int direction)
--{
-- return (dma64_addr_t)page_to_phys(page) + offset;
--}
--
--EXPORT_SYMBOL(pci_dac_page_to_dma);
--
--struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
-- dma64_addr_t dma_addr)
--{
-- return mem_map + (dma_addr >> PAGE_SHIFT);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_to_page);
--
--unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
-- dma64_addr_t dma_addr)
--{
-- return dma_addr & ~PAGE_MASK;
--}
--
--EXPORT_SYMBOL(pci_dac_dma_to_offset);
--
--void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
-- dma64_addr_t dma_addr, size_t len, int direction)
--{
-- BUG_ON(direction == PCI_DMA_NONE);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
--
--void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
-- dma64_addr_t dma_addr, size_t len, int direction)
--{
-- BUG_ON(direction == PCI_DMA_NONE);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
--
--#endif /* CONFIG_PCI */
-diff -urN linux.old/arch/mips/mm/dma-default.c linux.dev/arch/mips/mm/dma-default.c
---- linux.old/arch/mips/mm/dma-default.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/mm/dma-default.c 2007-02-09 20:26:48.671885792 +0100
-@@ -0,0 +1,363 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
-+ * Copyright (C) 2000, 2001, 06 Ralf Baechle <ralf@linux-mips.org>
-+ * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+
-+#include <asm/cache.h>
-+#include <asm/io.h>
-+
-+#include <dma-coherence.h>
-+
-+/*
-+ * Warning on the terminology - Linux calls an uncached area coherent;
-+ * MIPS terminology calls memory areas with hardware maintained coherency
-+ * coherent.
-+ */
-+
-+static inline int cpu_is_noncoherent_r10000(struct device *dev)
-+{
-+ return !plat_device_is_coherent(dev) &&
-+ (current_cpu_data.cputype == CPU_R10000 &&
-+ current_cpu_data.cputype == CPU_R12000);
-+}
-+
-+void *dma_alloc_noncoherent(struct device *dev, size_t size,
-+ dma_addr_t * dma_handle, gfp_t gfp)
-+{
-+ void *ret;
-+
-+ /* ignore region specifiers */
-+ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-+
-+ if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-+ gfp |= GFP_DMA;
-+ ret = (void *) __get_free_pages(gfp, get_order(size));
-+
-+ if (ret != NULL) {
-+ memset(ret, 0, size);
-+ *dma_handle = plat_map_dma_mem(dev, ret, size);
-+ }
-+
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL(dma_alloc_noncoherent);
-+
-+void *dma_alloc_coherent(struct device *dev, size_t size,
-+ dma_addr_t * dma_handle, gfp_t gfp)
-+{
-+ void *ret;
-+
-+ /* ignore region specifiers */
-+ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-+
-+ if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-+ gfp |= GFP_DMA;
-+ ret = (void *) __get_free_pages(gfp, get_order(size));
-+
-+ if (ret) {
-+ memset(ret, 0, size);
-+ *dma_handle = plat_map_dma_mem(dev, ret, size);
-+
-+ if (!plat_device_is_coherent(dev)) {
-+ dma_cache_wback_inv((unsigned long) ret, size);
-+ ret = UNCAC_ADDR(ret);
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+EXPORT_SYMBOL(dma_alloc_coherent);
-+
-+void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-+ dma_addr_t dma_handle)
-+{
-+ free_pages((unsigned long) vaddr, get_order(size));
-+}
-+
-+EXPORT_SYMBOL(dma_free_noncoherent);
-+
-+void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-+ dma_addr_t dma_handle)
-+{
-+ unsigned long addr = (unsigned long) vaddr;
-+
-+ if (!plat_device_is_coherent(dev))
-+ addr = CAC_ADDR(addr);
-+
-+ free_pages(addr, get_order(size));
-+}
-+
-+EXPORT_SYMBOL(dma_free_coherent);
-+
-+static inline void __dma_sync(unsigned long addr, size_t size,
-+ enum dma_data_direction direction)
-+{
-+ switch (direction) {
-+ case DMA_TO_DEVICE:
-+ dma_cache_wback(addr, size);
-+ break;
-+
-+ case DMA_FROM_DEVICE:
-+ dma_cache_inv(addr, size);
-+ break;
-+
-+ case DMA_BIDIRECTIONAL:
-+ dma_cache_wback_inv(addr, size);
-+ break;
-+
-+ default:
-+ BUG();
-+ }
-+}
-+
-+dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-+ enum dma_data_direction direction)
-+{
-+ unsigned long addr = (unsigned long) ptr;
-+
-+ if (!plat_device_is_coherent(dev))
-+ __dma_sync(addr, size, direction);
-+
-+ return plat_map_dma_mem(dev, ptr, size);
-+}
-+
-+EXPORT_SYMBOL(dma_map_single);
-+
-+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-+ enum dma_data_direction direction)
-+{
-+ if (cpu_is_noncoherent_r10000(dev))
-+ __dma_sync(plat_dma_addr_to_phys(dma_addr) + PAGE_OFFSET, size,
-+ direction);
-+
-+ plat_unmap_dma_mem(dma_addr);
-+}
-+
-+EXPORT_SYMBOL(dma_unmap_single);
-+
-+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-+ enum dma_data_direction direction)
-+{
-+ int i;
-+
-+ BUG_ON(direction == DMA_NONE);
-+
-+ for (i = 0; i < nents; i++, sg++) {
-+ unsigned long addr;
-+
-+ addr = (unsigned long) page_address(sg->page);
-+ if (!plat_device_is_coherent(dev) && addr)
-+ __dma_sync(addr + sg->offset, sg->length, direction);
-+ sg->dma_address = plat_map_dma_mem_page(dev, sg->page) +
-+ sg->offset;
-+ }
-+
-+ return nents;
-+}
-+
-+EXPORT_SYMBOL(dma_map_sg);
-+
-+dma_addr_t dma_map_page(struct device *dev, struct page *page,
-+ unsigned long offset, size_t size, enum dma_data_direction direction)
-+{
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (!plat_device_is_coherent(dev)) {
-+ unsigned long addr;
-+
-+ addr = (unsigned long) page_address(page) + offset;
-+ dma_cache_wback_inv(addr, size);
-+ }
-+
-+ return plat_map_dma_mem_page(dev, page) + offset;
-+}
-+
-+EXPORT_SYMBOL(dma_map_page);
-+
-+void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-+ enum dma_data_direction direction)
-+{
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) {
-+ unsigned long addr;
-+
-+ addr = plat_dma_addr_to_phys(dma_address);
-+ dma_cache_wback_inv(addr, size);
-+ }
-+
-+ plat_unmap_dma_mem(dma_address);
-+}
-+
-+EXPORT_SYMBOL(dma_unmap_page);
-+
-+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-+ enum dma_data_direction direction)
-+{
-+ unsigned long addr;
-+ int i;
-+
-+ BUG_ON(direction == DMA_NONE);
-+
-+ for (i = 0; i < nhwentries; i++, sg++) {
-+ if (!plat_device_is_coherent(dev) &&
-+ direction != DMA_TO_DEVICE) {
-+ addr = (unsigned long) page_address(sg->page);
-+ if (addr)
-+ __dma_sync(addr + sg->offset, sg->length,
-+ direction);
-+ }
-+ plat_unmap_dma_mem(sg->dma_address);
-+ }
-+}
-+
-+EXPORT_SYMBOL(dma_unmap_sg);
-+
-+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-+ size_t size, enum dma_data_direction direction)
-+{
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (cpu_is_noncoherent_r10000(dev)) {
-+ unsigned long addr;
-+
-+ addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle);
-+ __dma_sync(addr, size, direction);
-+ }
-+}
-+
-+EXPORT_SYMBOL(dma_sync_single_for_cpu);
-+
-+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-+ size_t size, enum dma_data_direction direction)
-+{
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (cpu_is_noncoherent_r10000(dev)) {
-+ unsigned long addr;
-+
-+ addr = plat_dma_addr_to_phys(dma_handle);
-+ __dma_sync(addr, size, direction);
-+ }
-+}
-+
-+EXPORT_SYMBOL(dma_sync_single_for_device);
-+
-+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-+ unsigned long offset, size_t size, enum dma_data_direction direction)
-+{
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (cpu_is_noncoherent_r10000(dev)) {
-+ unsigned long addr;
-+
-+ addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle);
-+ __dma_sync(addr + offset, size, direction);
-+ }
-+}
-+
-+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-+
-+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-+ unsigned long offset, size_t size, enum dma_data_direction direction)
-+{
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (cpu_is_noncoherent_r10000(dev)) {
-+ unsigned long addr;
-+
-+ addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle);
-+ __dma_sync(addr + offset, size, direction);
-+ }
-+}
-+
-+EXPORT_SYMBOL(dma_sync_single_range_for_device);
-+
-+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-+ enum dma_data_direction direction)
-+{
-+ int i;
-+
-+ BUG_ON(direction == DMA_NONE);
-+
-+ /* Make sure that gcc doesn't leave the empty loop body. */
-+ for (i = 0; i < nelems; i++, sg++) {
-+ if (!plat_device_is_coherent(dev))
-+ __dma_sync((unsigned long)page_address(sg->page),
-+ sg->length, direction);
-+ plat_unmap_dma_mem(sg->dma_address);
-+ }
-+}
-+
-+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
-+
-+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-+ enum dma_data_direction direction)
-+{
-+ int i;
-+
-+ BUG_ON(direction == DMA_NONE);
-+
-+ /* Make sure that gcc doesn't leave the empty loop body. */
-+ for (i = 0; i < nelems; i++, sg++) {
-+ if (!plat_device_is_coherent(dev))
-+ __dma_sync((unsigned long)page_address(sg->page),
-+ sg->length, direction);
-+ plat_unmap_dma_mem(sg->dma_address);
-+ }
-+}
-+
-+EXPORT_SYMBOL(dma_sync_sg_for_device);
-+
-+int dma_mapping_error(dma_addr_t dma_addr)
-+{
-+ return 0;
-+}
-+
-+EXPORT_SYMBOL(dma_mapping_error);
-+
-+int dma_supported(struct device *dev, u64 mask)
-+{
-+ /*
-+ * we fall back to GFP_DMA when the mask isn't all 1s,
-+ * so we can't guarantee allocations that must be
-+ * within a tighter range than GFP_DMA..
-+ */
-+ if (mask < 0x00ffffff)
-+ return 0;
-+
-+ return 1;
-+}
-+
-+EXPORT_SYMBOL(dma_supported);
-+
-+int dma_is_consistent(dma_addr_t dma_addr)
-+{
-+ return plat_device_is_coherent(NULL);
-+}
-+
-+EXPORT_SYMBOL(dma_is_consistent);
-+
-+void dma_cache_sync(void *vaddr, size_t size,
-+ enum dma_data_direction direction)
-+{
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (!plat_device_is_coherent(NULL))
-+ dma_cache_wback_inv((unsigned long)vaddr, size);
-+}
-+
-+EXPORT_SYMBOL(dma_cache_sync);
-diff -urN linux.old/arch/mips/mm/dma-ip27.c linux.dev/arch/mips/mm/dma-ip27.c
---- linux.old/arch/mips/mm/dma-ip27.c 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/arch/mips/mm/dma-ip27.c 1970-01-01 01:00:00.000000000 +0100
-@@ -1,257 +0,0 @@
--/*
-- * This file is subject to the terms and conditions of the GNU General Public
-- * License. See the file "COPYING" in the main directory of this archive
-- * for more details.
-- *
-- * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
-- * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org>
-- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
-- */
--#include <linux/types.h>
--#include <linux/mm.h>
--#include <linux/module.h>
--#include <linux/string.h>
--#include <linux/pci.h>
--
--#include <asm/cache.h>
--#include <asm/pci/bridge.h>
--
--#define pdev_to_baddr(pdev, addr) \
-- (BRIDGE_CONTROLLER(pdev->bus)->baddr + (addr))
--#define dev_to_baddr(dev, addr) \
-- pdev_to_baddr(to_pci_dev(dev), (addr))
--
--void *dma_alloc_noncoherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
--{
-- void *ret;
--
-- /* ignore region specifiers */
-- gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
--
-- if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-- gfp |= GFP_DMA;
-- ret = (void *) __get_free_pages(gfp, get_order(size));
--
-- if (ret != NULL) {
-- memset(ret, 0, size);
-- *dma_handle = dev_to_baddr(dev, virt_to_phys(ret));
-- }
--
-- return ret;
--}
--
--EXPORT_SYMBOL(dma_alloc_noncoherent);
--
--void *dma_alloc_coherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
-- __attribute__((alias("dma_alloc_noncoherent")));
--
--EXPORT_SYMBOL(dma_alloc_coherent);
--
--void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle)
--{
-- unsigned long addr = (unsigned long) vaddr;
--
-- free_pages(addr, get_order(size));
--}
--
--EXPORT_SYMBOL(dma_free_noncoherent);
--
--void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent")));
--
--EXPORT_SYMBOL(dma_free_coherent);
--
--dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--
-- return dev_to_baddr(dev, __pa(ptr));
--}
--
--EXPORT_SYMBOL(dma_map_single);
--
--void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_unmap_single);
--
--int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- for (i = 0; i < nents; i++, sg++) {
-- sg->dma_address = (dma_addr_t) dev_to_baddr(dev,
-- page_to_phys(sg->page) + sg->offset);
-- }
--
-- return nents;
--}
--
--EXPORT_SYMBOL(dma_map_sg);
--
--dma_addr_t dma_map_page(struct device *dev, struct page *page,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--
-- return dev_to_baddr(dev, page_to_phys(page) + offset);
--}
--
--EXPORT_SYMBOL(dma_map_page);
--
--void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_unmap_page);
--
--void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_unmap_sg);
--
--void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_cpu);
--
--void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_device);
--
--void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
--
--void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_device);
--
--void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_cpu);
--
--void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_device);
--
--int dma_mapping_error(dma_addr_t dma_addr)
--{
-- return 0;
--}
--
--EXPORT_SYMBOL(dma_mapping_error);
--
--int dma_supported(struct device *dev, u64 mask)
--{
-- /*
-- * we fall back to GFP_DMA when the mask isn't all 1s,
-- * so we can't guarantee allocations that must be
-- * within a tighter range than GFP_DMA..
-- */
-- if (mask < 0x00ffffff)
-- return 0;
--
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_supported);
--
--int dma_is_consistent(dma_addr_t dma_addr)
--{
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_is_consistent);
--
--void dma_cache_sync(void *vaddr, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--}
--
--EXPORT_SYMBOL(dma_cache_sync);
--
--dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
-- struct page *page, unsigned long offset, int direction)
--{
-- dma64_addr_t addr = page_to_phys(page) + offset;
--
-- return (dma64_addr_t) pdev_to_baddr(pdev, addr);
--}
--
--EXPORT_SYMBOL(pci_dac_page_to_dma);
--
--struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
-- dma64_addr_t dma_addr)
--{
-- struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus);
--
-- return pfn_to_page((dma_addr - bc->baddr) >> PAGE_SHIFT);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_to_page);
--
--unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
-- dma64_addr_t dma_addr)
--{
-- return dma_addr & ~PAGE_MASK;
--}
--
--EXPORT_SYMBOL(pci_dac_dma_to_offset);
--
--void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
-- dma64_addr_t dma_addr, size_t len, int direction)
--{
-- BUG_ON(direction == PCI_DMA_NONE);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
--
--void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
-- dma64_addr_t dma_addr, size_t len, int direction)
--{
-- BUG_ON(direction == PCI_DMA_NONE);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
-diff -urN linux.old/arch/mips/mm/dma-ip32.c linux.dev/arch/mips/mm/dma-ip32.c
---- linux.old/arch/mips/mm/dma-ip32.c 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/arch/mips/mm/dma-ip32.c 1970-01-01 01:00:00.000000000 +0100
-@@ -1,382 +0,0 @@
--/*
-- * This file is subject to the terms and conditions of the GNU General Public
-- * License. See the file "COPYING" in the main directory of this archive
-- * for more details.
-- *
-- * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
-- * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org>
-- * Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
-- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
-- * IP32 changes by Ilya.
-- */
--#include <linux/types.h>
--#include <linux/mm.h>
--#include <linux/module.h>
--#include <linux/string.h>
--#include <linux/dma-mapping.h>
--
--#include <asm/cache.h>
--#include <asm/io.h>
--#include <asm/ip32/crime.h>
--
--/*
-- * Warning on the terminology - Linux calls an uncached area coherent;
-- * MIPS terminology calls memory areas with hardware maintained coherency
-- * coherent.
-- */
--
--/*
-- * Few notes.
-- * 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M
-- * 2. PCI sees memory as one big chunk @0x0 (or we could use 0x40000000 for native-endian)
-- * 3. All other devices see memory as one big chunk at 0x40000000
-- * 4. Non-PCI devices will pass NULL as struct device*
-- * Thus we translate differently, depending on device.
-- */
--
--#define RAM_OFFSET_MASK 0x3fffffff
--
--void *dma_alloc_noncoherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
--{
-- void *ret;
-- /* ignore region specifiers */
-- gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
--
-- if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-- gfp |= GFP_DMA;
-- ret = (void *) __get_free_pages(gfp, get_order(size));
--
-- if (ret != NULL) {
-- unsigned long addr = virt_to_phys(ret)&RAM_OFFSET_MASK;
-- memset(ret, 0, size);
-- if(dev==NULL)
-- addr+= CRIME_HI_MEM_BASE;
-- *dma_handle = addr;
-- }
--
-- return ret;
--}
--
--EXPORT_SYMBOL(dma_alloc_noncoherent);
--
--void *dma_alloc_coherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
--{
-- void *ret;
--
-- ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
-- if (ret) {
-- dma_cache_wback_inv((unsigned long) ret, size);
-- ret = UNCAC_ADDR(ret);
-- }
--
-- return ret;
--}
--
--EXPORT_SYMBOL(dma_alloc_coherent);
--
--void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle)
--{
-- free_pages((unsigned long) vaddr, get_order(size));
--}
--
--EXPORT_SYMBOL(dma_free_noncoherent);
--
--void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle)
--{
-- unsigned long addr = (unsigned long) vaddr;
--
-- addr = CAC_ADDR(addr);
-- free_pages(addr, get_order(size));
--}
--
--EXPORT_SYMBOL(dma_free_coherent);
--
--static inline void __dma_sync(unsigned long addr, size_t size,
-- enum dma_data_direction direction)
--{
-- switch (direction) {
-- case DMA_TO_DEVICE:
-- dma_cache_wback(addr, size);
-- break;
--
-- case DMA_FROM_DEVICE:
-- dma_cache_inv(addr, size);
-- break;
--
-- case DMA_BIDIRECTIONAL:
-- dma_cache_wback_inv(addr, size);
-- break;
--
-- default:
-- BUG();
-- }
--}
--
--dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-- enum dma_data_direction direction)
--{
-- unsigned long addr = (unsigned long) ptr;
--
-- switch (direction) {
-- case DMA_TO_DEVICE:
-- dma_cache_wback(addr, size);
-- break;
--
-- case DMA_FROM_DEVICE:
-- dma_cache_inv(addr, size);
-- break;
--
-- case DMA_BIDIRECTIONAL:
-- dma_cache_wback_inv(addr, size);
-- break;
--
-- default:
-- BUG();
-- }
--
-- addr = virt_to_phys(ptr)&RAM_OFFSET_MASK;
-- if(dev == NULL)
-- addr+=CRIME_HI_MEM_BASE;
-- return (dma_addr_t)addr;
--}
--
--EXPORT_SYMBOL(dma_map_single);
--
--void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-- enum dma_data_direction direction)
--{
-- switch (direction) {
-- case DMA_TO_DEVICE:
-- break;
--
-- case DMA_FROM_DEVICE:
-- break;
--
-- case DMA_BIDIRECTIONAL:
-- break;
--
-- default:
-- BUG();
-- }
--}
--
--EXPORT_SYMBOL(dma_unmap_single);
--
--int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- for (i = 0; i < nents; i++, sg++) {
-- unsigned long addr;
--
-- addr = (unsigned long) page_address(sg->page)+sg->offset;
-- if (addr)
-- __dma_sync(addr, sg->length, direction);
-- addr = __pa(addr)&RAM_OFFSET_MASK;
-- if(dev == NULL)
-- addr += CRIME_HI_MEM_BASE;
-- sg->dma_address = (dma_addr_t)addr;
-- }
--
-- return nents;
--}
--
--EXPORT_SYMBOL(dma_map_sg);
--
--dma_addr_t dma_map_page(struct device *dev, struct page *page,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- addr = (unsigned long) page_address(page) + offset;
-- dma_cache_wback_inv(addr, size);
-- addr = __pa(addr)&RAM_OFFSET_MASK;
-- if(dev == NULL)
-- addr += CRIME_HI_MEM_BASE;
--
-- return (dma_addr_t)addr;
--}
--
--EXPORT_SYMBOL(dma_map_page);
--
--void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--
-- if (direction != DMA_TO_DEVICE) {
-- unsigned long addr;
--
-- dma_address&=RAM_OFFSET_MASK;
-- addr = dma_address + PAGE_OFFSET;
-- if(dma_address>=256*1024*1024)
-- addr+=CRIME_HI_MEM_BASE;
-- dma_cache_wback_inv(addr, size);
-- }
--}
--
--EXPORT_SYMBOL(dma_unmap_page);
--
--void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-- enum dma_data_direction direction)
--{
-- unsigned long addr;
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- if (direction == DMA_TO_DEVICE)
-- return;
--
-- for (i = 0; i < nhwentries; i++, sg++) {
-- addr = (unsigned long) page_address(sg->page);
-- if (!addr)
-- continue;
-- dma_cache_wback_inv(addr + sg->offset, sg->length);
-- }
--}
--
--EXPORT_SYMBOL(dma_unmap_sg);
--
--void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-- size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- dma_handle&=RAM_OFFSET_MASK;
-- addr = dma_handle + PAGE_OFFSET;
-- if(dma_handle>=256*1024*1024)
-- addr+=CRIME_HI_MEM_BASE;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_cpu);
--
--void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-- size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- dma_handle&=RAM_OFFSET_MASK;
-- addr = dma_handle + PAGE_OFFSET;
-- if(dma_handle>=256*1024*1024)
-- addr+=CRIME_HI_MEM_BASE;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_device);
--
--void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- dma_handle&=RAM_OFFSET_MASK;
-- addr = dma_handle + offset + PAGE_OFFSET;
-- if(dma_handle>=256*1024*1024)
-- addr+=CRIME_HI_MEM_BASE;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
--
--void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- dma_handle&=RAM_OFFSET_MASK;
-- addr = dma_handle + offset + PAGE_OFFSET;
-- if(dma_handle>=256*1024*1024)
-- addr+=CRIME_HI_MEM_BASE;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_device);
--
--void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- /* Make sure that gcc doesn't leave the empty loop body. */
-- for (i = 0; i < nelems; i++, sg++)
-- __dma_sync((unsigned long)page_address(sg->page),
-- sg->length, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_cpu);
--
--void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- /* Make sure that gcc doesn't leave the empty loop body. */
-- for (i = 0; i < nelems; i++, sg++)
-- __dma_sync((unsigned long)page_address(sg->page),
-- sg->length, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_device);
--
--int dma_mapping_error(dma_addr_t dma_addr)
--{
-- return 0;
--}
--
--EXPORT_SYMBOL(dma_mapping_error);
--
--int dma_supported(struct device *dev, u64 mask)
--{
-- /*
-- * we fall back to GFP_DMA when the mask isn't all 1s,
-- * so we can't guarantee allocations that must be
-- * within a tighter range than GFP_DMA..
-- */
-- if (mask < 0x00ffffff)
-- return 0;
--
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_supported);
--
--int dma_is_consistent(dma_addr_t dma_addr)
--{
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_is_consistent);
--
--void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction direction)
--{
-- if (direction == DMA_NONE)
-- return;
--
-- dma_cache_wback_inv((unsigned long)vaddr, size);
--}
--
--EXPORT_SYMBOL(dma_cache_sync);
--
-diff -urN linux.old/arch/mips/mm/dma-noncoherent.c linux.dev/arch/mips/mm/dma-noncoherent.c
---- linux.old/arch/mips/mm/dma-noncoherent.c 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/arch/mips/mm/dma-noncoherent.c 1970-01-01 01:00:00.000000000 +0100
-@@ -1,369 +0,0 @@
--/*
-- * This file is subject to the terms and conditions of the GNU General Public
-- * License. See the file "COPYING" in the main directory of this archive
-- * for more details.
-- *
-- * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
-- * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org>
-- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
-- */
--#include <linux/types.h>
--#include <linux/mm.h>
--#include <linux/module.h>
--#include <linux/string.h>
--#include <linux/dma-mapping.h>
--
--#include <asm/cache.h>
--#include <asm/io.h>
--
--/*
-- * Warning on the terminology - Linux calls an uncached area coherent;
-- * MIPS terminology calls memory areas with hardware maintained coherency
-- * coherent.
-- */
--
--void *dma_alloc_noncoherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
--{
-- void *ret;
-- /* ignore region specifiers */
-- gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
--
-- if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
-- gfp |= GFP_DMA;
-- ret = (void *) __get_free_pages(gfp, get_order(size));
--
-- if (ret != NULL) {
-- memset(ret, 0, size);
-- *dma_handle = virt_to_phys(ret);
-- }
--
-- return ret;
--}
--
--EXPORT_SYMBOL(dma_alloc_noncoherent);
--
--void *dma_alloc_coherent(struct device *dev, size_t size,
-- dma_addr_t * dma_handle, gfp_t gfp)
--{
-- void *ret;
--
-- ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
-- if (ret) {
-- dma_cache_wback_inv((unsigned long) ret, size);
-- ret = UNCAC_ADDR(ret);
-- }
--
-- return ret;
--}
--
--EXPORT_SYMBOL(dma_alloc_coherent);
--
--void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle)
--{
-- free_pages((unsigned long) vaddr, get_order(size));
--}
--
--EXPORT_SYMBOL(dma_free_noncoherent);
--
--void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-- dma_addr_t dma_handle)
--{
-- unsigned long addr = (unsigned long) vaddr;
--
-- addr = CAC_ADDR(addr);
-- free_pages(addr, get_order(size));
--}
--
--EXPORT_SYMBOL(dma_free_coherent);
--
--static inline void __dma_sync(unsigned long addr, size_t size,
-- enum dma_data_direction direction)
--{
-- switch (direction) {
-- case DMA_TO_DEVICE:
-- dma_cache_wback(addr, size);
-- break;
--
-- case DMA_FROM_DEVICE:
-- dma_cache_inv(addr, size);
-- break;
--
-- case DMA_BIDIRECTIONAL:
-- dma_cache_wback_inv(addr, size);
-- break;
--
-- default:
-- BUG();
-- }
--}
--
--dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-- enum dma_data_direction direction)
--{
-- unsigned long addr = (unsigned long) ptr;
--
-- __dma_sync(addr, size, direction);
--
-- return virt_to_phys(ptr);
--}
--
--EXPORT_SYMBOL(dma_map_single);
--
--void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-- enum dma_data_direction direction)
--{
-- unsigned long addr;
-- addr = dma_addr + PAGE_OFFSET;
--
-- //__dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_unmap_single);
--
--int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- for (i = 0; i < nents; i++, sg++) {
-- unsigned long addr;
--
-- addr = (unsigned long) page_address(sg->page);
-- if (addr) {
-- __dma_sync(addr + sg->offset, sg->length, direction);
-- sg->dma_address = (dma_addr_t)page_to_phys(sg->page)
-- + sg->offset;
-- }
-- }
--
-- return nents;
--}
--
--EXPORT_SYMBOL(dma_map_sg);
--
--dma_addr_t dma_map_page(struct device *dev, struct page *page,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- addr = (unsigned long) page_address(page) + offset;
-- dma_cache_wback_inv(addr, size);
--
-- return page_to_phys(page) + offset;
--}
--
--EXPORT_SYMBOL(dma_map_page);
--
--void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-- enum dma_data_direction direction)
--{
-- BUG_ON(direction == DMA_NONE);
--
-- if (direction != DMA_TO_DEVICE) {
-- unsigned long addr;
--
-- addr = dma_address + PAGE_OFFSET;
-- dma_cache_wback_inv(addr, size);
-- }
--}
--
--EXPORT_SYMBOL(dma_unmap_page);
--
--void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-- enum dma_data_direction direction)
--{
-- unsigned long addr;
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- if (direction == DMA_TO_DEVICE)
-- return;
--
-- for (i = 0; i < nhwentries; i++, sg++) {
-- addr = (unsigned long) page_address(sg->page);
-- if (addr)
-- __dma_sync(addr + sg->offset, sg->length, direction);
-- }
--}
--
--EXPORT_SYMBOL(dma_unmap_sg);
--
--void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-- size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- addr = dma_handle + PAGE_OFFSET;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_cpu);
--
--void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-- size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- addr = dma_handle + PAGE_OFFSET;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_for_device);
--
--void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- addr = dma_handle + offset + PAGE_OFFSET;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
--
--void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-- unsigned long offset, size_t size, enum dma_data_direction direction)
--{
-- unsigned long addr;
--
-- BUG_ON(direction == DMA_NONE);
--
-- addr = dma_handle + offset + PAGE_OFFSET;
-- __dma_sync(addr, size, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_single_range_for_device);
--
--void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- /* Make sure that gcc doesn't leave the empty loop body. */
-- for (i = 0; i < nelems; i++, sg++)
-- __dma_sync((unsigned long)page_address(sg->page),
-- sg->length, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_cpu);
--
--void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-- enum dma_data_direction direction)
--{
-- int i;
--
-- BUG_ON(direction == DMA_NONE);
--
-- /* Make sure that gcc doesn't leave the empty loop body. */
-- for (i = 0; i < nelems; i++, sg++)
-- __dma_sync((unsigned long)page_address(sg->page),
-- sg->length, direction);
--}
--
--EXPORT_SYMBOL(dma_sync_sg_for_device);
--
--int dma_mapping_error(dma_addr_t dma_addr)
--{
-- return 0;
--}
--
--EXPORT_SYMBOL(dma_mapping_error);
--
--int dma_supported(struct device *dev, u64 mask)
--{
-- /*
-- * we fall back to GFP_DMA when the mask isn't all 1s,
-- * so we can't guarantee allocations that must be
-- * within a tighter range than GFP_DMA..
-- */
-- if (mask < 0x00ffffff)
-- return 0;
--
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_supported);
--
--int dma_is_consistent(dma_addr_t dma_addr)
--{
-- return 1;
--}
--
--EXPORT_SYMBOL(dma_is_consistent);
--
--void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction direction)
--{
-- if (direction == DMA_NONE)
-- return;
--
-- dma_cache_wback_inv((unsigned long)vaddr, size);
--}
--
--EXPORT_SYMBOL(dma_cache_sync);
--
--/* The DAC routines are a PCIism.. */
--
--#ifdef CONFIG_PCI
--
--#include <linux/pci.h>
--
--dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
-- struct page *page, unsigned long offset, int direction)
--{
-- return (dma64_addr_t)page_to_phys(page) + offset;
--}
--
--EXPORT_SYMBOL(pci_dac_page_to_dma);
--
--struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
-- dma64_addr_t dma_addr)
--{
-- return mem_map + (dma_addr >> PAGE_SHIFT);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_to_page);
--
--unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
-- dma64_addr_t dma_addr)
--{
-- return dma_addr & ~PAGE_MASK;
--}
--
--EXPORT_SYMBOL(pci_dac_dma_to_offset);
--
--void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
-- dma64_addr_t dma_addr, size_t len, int direction)
--{
-- BUG_ON(direction == PCI_DMA_NONE);
--
-- dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
--
--void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
-- dma64_addr_t dma_addr, size_t len, int direction)
--{
-- BUG_ON(direction == PCI_DMA_NONE);
--
-- dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
--}
--
--EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
--
--#endif /* CONFIG_PCI */
-diff -urN linux.old/arch/mips/mm/Makefile linux.dev/arch/mips/mm/Makefile
---- linux.old/arch/mips/mm/Makefile 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/arch/mips/mm/Makefile 2007-02-09 20:26:45.376386784 +0100
-@@ -2,8 +2,8 @@
- # Makefile for the Linux/MIPS-specific parts of the memory manager.
- #
-
--obj-y += cache.o extable.o fault.o init.o pgtable.o \
-- tlbex.o tlbex-fault.o
-+obj-y += cache.o dma-default.o extable.o fault.o \
-+ init.o pgtable.o tlbex.o tlbex-fault.o
-
- obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o
- obj-$(CONFIG_64BIT) += pgtable-64.o
-@@ -32,14 +32,4 @@
- obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
- obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
-
--#
--# Choose one DMA coherency model
--#
--ifndef CONFIG_OWN_DMA
--obj-$(CONFIG_DMA_COHERENT) += dma-coherent.o
--obj-$(CONFIG_DMA_NONCOHERENT) += dma-noncoherent.o
--endif
--obj-$(CONFIG_DMA_IP27) += dma-ip27.o
--obj-$(CONFIG_DMA_IP32) += dma-ip32.o
--
- EXTRA_AFLAGS := $(CFLAGS)
-diff -urN linux.old/arch/mips/pci/Makefile linux.dev/arch/mips/pci/Makefile
---- linux.old/arch/mips/pci/Makefile 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/arch/mips/pci/Makefile 2007-02-09 20:26:50.961537712 +0100
-@@ -2,7 +2,7 @@
- # Makefile for the PCI specific kernel interface routines under Linux.
- #
-
--obj-y += pci.o
-+obj-y += pci.o pci-dac.o
-
- #
- # PCI bus host bridge specific code
-diff -urN linux.old/arch/mips/pci/pci-dac.c linux.dev/arch/mips/pci/pci-dac.c
---- linux.old/arch/mips/pci/pci-dac.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/arch/mips/pci/pci-dac.c 2007-02-09 20:26:50.961537712 +0100
-@@ -0,0 +1,79 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
-+ * Copyright (C) 2000, 2001, 06 Ralf Baechle <ralf@linux-mips.org>
-+ * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+
-+#include <asm/cache.h>
-+#include <asm/io.h>
-+
-+#include <dma-coherence.h>
-+
-+#include <linux/pci.h>
-+
-+dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
-+ struct page *page, unsigned long offset, int direction)
-+{
-+ struct device *dev = &pdev->dev;
-+
-+ BUG_ON(direction == DMA_NONE);
-+
-+ if (!plat_device_is_coherent(dev)) {
-+ unsigned long addr;
-+
-+ addr = (unsigned long) page_address(page) + offset;
-+ dma_cache_wback_inv(addr, PAGE_SIZE);
-+ }
-+
-+ return plat_map_dma_mem_page(dev, page) + offset;
-+}
-+
-+EXPORT_SYMBOL(pci_dac_page_to_dma);
-+
-+struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
-+ dma64_addr_t dma_addr)
-+{
-+ return pfn_to_page(plat_dma_addr_to_phys(dma_addr) >> PAGE_SHIFT);
-+}
-+
-+EXPORT_SYMBOL(pci_dac_dma_to_page);
-+
-+unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
-+ dma64_addr_t dma_addr)
-+{
-+ return dma_addr & ~PAGE_MASK;
-+}
-+
-+EXPORT_SYMBOL(pci_dac_dma_to_offset);
-+
-+void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
-+ dma64_addr_t dma_addr, size_t len, int direction)
-+{
-+ BUG_ON(direction == PCI_DMA_NONE);
-+
-+ if (!plat_device_is_coherent(&pdev->dev))
-+ dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
-+}
-+
-+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
-+
-+void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
-+ dma64_addr_t dma_addr, size_t len, int direction)
-+{
-+ BUG_ON(direction == PCI_DMA_NONE);
-+
-+ if (!plat_device_is_coherent(&pdev->dev))
-+ dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
-+}
-+
-+EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
-diff -urN linux.old/include/asm-mips/mach-generic/dma-coherence.h linux.dev/include/asm-mips/mach-generic/dma-coherence.h
---- linux.old/include/asm-mips/mach-generic/dma-coherence.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/include/asm-mips/mach-generic/dma-coherence.h 2007-02-09 20:26:50.962537560 +0100
-@@ -0,0 +1,43 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2006 Ralf Baechle <ralf@linux-mips.org>
-+ *
-+ */
-+#ifndef __ASM_MACH_GENERIC_DMA_COHERENCE_H
-+#define __ASM_MACH_GENERIC_DMA_COHERENCE_H
-+
-+struct device;
-+
-+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
-+{
-+ return virt_to_phys(addr);
-+}
-+
-+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
-+{
-+ return page_to_phys(page);
-+}
-+
-+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
-+{
-+ return dma_addr;
-+}
-+
-+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
-+{
-+}
-+
-+static inline int plat_device_is_coherent(struct device *dev)
-+{
-+#ifdef CONFIG_DMA_COHERENT
-+ return 1;
-+#endif
-+#ifdef CONFIG_DMA_NONCOHERENT
-+ return 0;
-+#endif
-+}
-+
-+#endif /* __ASM_MACH_GENERIC_DMA_COHERENCE_H */
-diff -urN linux.old/include/asm-mips/mach-generic/kmalloc.h linux.dev/include/asm-mips/mach-generic/kmalloc.h
---- linux.old/include/asm-mips/mach-generic/kmalloc.h 2007-01-10 20:10:37.000000000 +0100
-+++ linux.dev/include/asm-mips/mach-generic/kmalloc.h 2007-02-09 20:26:50.962537560 +0100
-@@ -5,6 +5,7 @@
- #ifndef CONFIG_DMA_COHERENT
- /*
- * Total overkill for most systems but need as a safe default.
-+ * Set this one if any device in the system might do non-coherent DMA.
- */
- #define ARCH_KMALLOC_MINALIGN 128
- #endif
-diff -urN linux.old/include/asm-mips/mach-ip27/dma-coherence.h linux.dev/include/asm-mips/mach-ip27/dma-coherence.h
---- linux.old/include/asm-mips/mach-ip27/dma-coherence.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/include/asm-mips/mach-ip27/dma-coherence.h 2007-02-09 20:26:50.962537560 +0100
-@@ -0,0 +1,49 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2006 Ralf Baechle <ralf@linux-mips.org>
-+ *
-+ */
-+#ifndef __ASM_MACH_IP27_DMA_COHERENCE_H
-+#define __ASM_MACH_IP27_DMA_COHERENCE_H
-+
-+#include <asm/pci/bridge.h>
-+
-+#define pdev_to_baddr(pdev, addr) \
-+ (BRIDGE_CONTROLLER(pdev->bus)->baddr + (addr))
-+#define dev_to_baddr(dev, addr) \
-+ pdev_to_baddr(to_pci_dev(dev), (addr))
-+
-+struct device;
-+
-+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
-+{
-+ dma_addr_t pa = dev_to_baddr(dev, virt_to_phys(addr));
-+
-+ return pa;
-+}
-+
-+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
-+{
-+ dma_addr_t pa = dev_to_baddr(dev, page_to_phys(page));
-+
-+ return pa;
-+}
-+
-+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
-+{
-+ return dma_addr & (0xffUL << 56);
-+}
-+
-+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
-+{
-+}
-+
-+static inline int plat_device_is_coherent(struct device *dev)
-+{
-+ return 1; /* IP27 non-cohernet mode is unsupported */
-+}
-+
-+#endif /* __ASM_MACH_IP27_DMA_COHERENCE_H */
-diff -urN linux.old/include/asm-mips/mach-ip32/dma-coherence.h linux.dev/include/asm-mips/mach-ip32/dma-coherence.h
---- linux.old/include/asm-mips/mach-ip32/dma-coherence.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/include/asm-mips/mach-ip32/dma-coherence.h 2007-02-09 20:26:50.963537408 +0100
-@@ -0,0 +1,71 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2006 Ralf Baechle <ralf@linux-mips.org>
-+ *
-+ */
-+#ifndef __ASM_MACH_IP35_DMA_COHERENCE_H
-+#define __ASM_MACH_IP35_DMA_COHERENCE_H
-+
-+#include <asm/ip32/crime.h>
-+
-+struct device;
-+
-+/*
-+ * Few notes.
-+ * 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M
-+ * 2. PCI sees memory as one big chunk @0x0 (or we could use 0x40000000 for
-+ * native-endian)
-+ * 3. All other devices see memory as one big chunk at 0x40000000
-+ * 4. Non-PCI devices will pass NULL as struct device*
-+ *
-+ * Thus we translate differently, depending on device.
-+ */
-+
-+#define RAM_OFFSET_MASK 0x3fffffffUL
-+
-+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
-+{
-+ dma_addr_t pa = virt_to_phys(addr) & RAM_OFFSET_MASK;
-+
-+ if (dev == NULL)
-+ pa += CRIME_HI_MEM_BASE;
-+
-+ return pa;
-+}
-+
-+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
-+{
-+ dma_addr_t pa;
-+
-+ pa = page_to_phys(page) & RAM_OFFSET_MASK;
-+
-+ if (dev == NULL)
-+ pa += CRIME_HI_MEM_BASE;
-+
-+ return pa;
-+}
-+
-+/* This is almost certainly wrong but it's what dma-ip32.c used to use */
-+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
-+{
-+ unsigned long addr = dma_addr & RAM_OFFSET_MASK;
-+
-+ if (dma_addr >= 256*1024*1024)
-+ addr += CRIME_HI_MEM_BASE;
-+
-+ return addr;
-+}
-+
-+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
-+{
-+}
-+
-+static inline int plat_device_is_coherent(struct device *dev)
-+{
-+ return 0; /* IP32 is non-cohernet */
-+}
-+
-+#endif /* __ASM_MACH_IP35_DMA_COHERENCE_H */
-diff -urN linux.old/include/asm-mips/mach-jazz/dma-coherence.h linux.dev/include/asm-mips/mach-jazz/dma-coherence.h
---- linux.old/include/asm-mips/mach-jazz/dma-coherence.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux.dev/include/asm-mips/mach-jazz/dma-coherence.h 2007-02-09 20:26:50.963537408 +0100
-@@ -0,0 +1,40 @@
-+/*
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file "COPYING" in the main directory of this archive
-+ * for more details.
-+ *
-+ * Copyright (C) 2006 Ralf Baechle <ralf@linux-mips.org>
-+ */
-+#ifndef __ASM_MACH_JAZZ_DMA_COHERENCE_H
-+#define __ASM_MACH_JAZZ_DMA_COHERENCE_H
-+
-+#include <asm/jazzdma.h>
-+
-+struct device;
-+
-+static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
-+{
-+ return vdma_alloc(virt_to_phys(addr), size);
-+}
-+
-+static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
-+{
-+ return vdma_alloc(page_to_phys(page), PAGE_SIZE);
-+}
-+
-+static unsigned long plat_dma_addr_to_phys(dma_addr_t dma_addr)
-+{
-+ return vdma_log2phys(dma_addr);
-+}
-+
-+static void plat_unmap_dma_mem(dma_addr_t dma_addr)
-+{
-+ vdma_free(dma_addr);
-+}
-+
-+static inline int plat_device_is_coherent(struct device *dev)
-+{
-+ return 0;
-+}
-+
-+#endif /* __ASM_MACH_JAZZ_DMA_COHERENCE_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set.h 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,489 @@
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set.h 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,498 @@
+#ifndef _IP_SET_H
+#define _IP_SET_H
+
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
++#if 0
++#define IP_SET_DEBUG
++#endif
++
+/*
+ * A sockopt of such quality has hardly ever been seen before on the open
+ * market! This little beauty, hardly ever used: above 64, so it's
+ * - in order to "deal with" backward compatibility, renamed to ipset
+ */
+
-+/*
-+ * Used so that the kernel module and ipset-binary can match their versions
++/*
++ * Used so that the kernel module and ipset-binary can match their versions
+ */
+#define IP_SET_PROTOCOL_VERSION 2
+
+ *
+ * The representation works in HOST byte order, because most set types
+ * will perform arithmetic operations and compare operations.
-+ *
++ *
+ * For now the type is an uint32_t.
+ *
+ * Make sure to ONLY use the functions when translating and parsing
+#define IPSET_MATCH_INV 0x04 /* Inverse matching */
+
+/*
-+ * Set types (flavours)
++ * Set features
+ */
-+#define IPSET_TYPE_IP 0 /* IP address type of set */
-+#define IPSET_TYPE_PORT 1 /* Port type of set */
++#define IPSET_TYPE_IP 0x01 /* IP address type of set */
++#define IPSET_TYPE_PORT 0x02 /* Port type of set */
++#define IPSET_DATA_SINGLE 0x04 /* Single data storage */
++#define IPSET_DATA_DOUBLE 0x08 /* Double data storage */
+
+/* Reserved keywords */
+#define IPSET_TOKEN_DEFAULT ":default:"
+ * 200-299: list, save, restore
+ */
+
-+/* Single shot operations:
-+ * version, create, destroy, flush, rename and swap
++/* Single shot operations:
++ * version, create, destroy, flush, rename and swap
+ *
+ * Sets are identified by name.
+ */
+ unsigned version;
+};
+
-+/* Double shots operations:
++/* Double shots operations:
+ * add, del, test, bind and unbind.
+ *
+ * First we query the kernel to get the index and type of the target set,
+};
+
+#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
-+/* Uses ip_set_req_bind, with type speficic addage
++/* Uses ip_set_req_bind, with type speficic addage
+ * index = 0 means unbinding for all sets */
+
+#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
+#define IP_SET_OP_LIST 0x00000203
+struct ip_set_req_list {
+ IP_SET_REQ_BYINDEX;
-+ /* sets number of struct ip_set_list in reply */
++ /* sets number of struct ip_set_list in reply */
+};
+
+struct ip_set_list {
+/* The restore operation */
+#define IP_SET_OP_RESTORE 0x00000205
+/* Uses ip_set_req_setnames followed by ip_set_restore structures
-+ * plus a marker ip_set_restore, followed by ip_set_hash_save
++ * plus a marker ip_set_restore, followed by ip_set_hash_save
+ * structures.
+ */
+struct ip_set_restore {
+ * return 0 if not in set, 1 if in set.
+ */
+ int (*testip_kernel) (struct ip_set *set,
-+ const struct sk_buff * skb,
-+ u_int32_t flags,
-+ ip_set_ip_t *ip);
++ const struct sk_buff * skb,
++ ip_set_ip_t *ip,
++ const u_int32_t *flags,
++ unsigned char index);
+
+ /* test for IP in set (userspace: ipset -T set IP)
+ * return 0 if not in set, 1 if in set.
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address was not already in the set, 0 is returned.
+ */
-+ int (*addip) (struct ip_set *set,
++ int (*addip) (struct ip_set *set,
+ const void *data, size_t size,
+ ip_set_ip_t *ip);
+
+ * If the address was not already in the set, 0 is returned.
+ */
+ int (*addip_kernel) (struct ip_set *set,
-+ const struct sk_buff * skb,
-+ u_int32_t flags,
-+ ip_set_ip_t *ip);
++ const struct sk_buff * skb,
++ ip_set_ip_t *ip,
++ const u_int32_t *flags,
++ unsigned char index);
+
+ /* remove IP from set (userspace: ipset -D set --entry x)
+ * Return -EEXIST if the address is NOT in the set,
+ * and -ERANGE if the address lies outside the set bounds.
+ * If the address really was in the set, 0 is returned.
+ */
-+ int (*delip) (struct ip_set *set,
++ int (*delip) (struct ip_set *set,
+ const void *data, size_t size,
+ ip_set_ip_t *ip);
+
+ * If the address really was in the set, 0 is returned.
+ */
+ int (*delip_kernel) (struct ip_set *set,
-+ const struct sk_buff * skb,
-+ u_int32_t flags,
-+ ip_set_ip_t *ip);
++ const struct sk_buff * skb,
++ ip_set_ip_t *ip,
++ const u_int32_t *flags,
++ unsigned char index);
+
+ /* new set creation - allocated type specific items
+ */
+ /* Listing: Get the header
+ *
+ * Fill in the information in "data".
-+ * This function is always run after list_header_size() under a
-+ * writelock on the set. Therefor is the length of "data" always
-+ * correct.
++ * This function is always run after list_header_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
+ */
-+ void (*list_header) (const struct ip_set *set,
++ void (*list_header) (const struct ip_set *set,
+ void *data);
+
+ /* Listing: Get the size for the set members
+ /* Listing: Get the set members
+ *
+ * Fill in the information in "data".
-+ * This function is always run after list_member_size() under a
-+ * writelock on the set. Therefor is the length of "data" always
-+ * correct.
++ * This function is always run after list_member_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
+ */
+ void (*list_members) (const struct ip_set *set,
+ void *data);
+
+ char typename[IP_SET_MAXNAMELEN];
-+ char typecode;
++ unsigned char features;
+ int protocol_version;
+
+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+#endif /*_IP_SET_H*/
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_iphash.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_iphash.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_iphash.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_iphash.h 2007-05-14 11:44:19.000000000 +0200
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_iphash.h 2007-05-23 23:04:36.000000000 +0200
@@ -0,0 +1,30 @@
+#ifndef __IP_SET_IPHASH_H
+#define __IP_SET_IPHASH_H
+
+struct ip_set_iphash {
+ ip_set_ip_t *members; /* the iphash proper */
-+ uint32_t initval; /* initval for jhash_1word */
-+ uint32_t prime; /* prime for double hashing */
++ uint32_t elements; /* number of elements */
+ uint32_t hashsize; /* hash size */
+ uint16_t probes; /* max number of probes */
+ uint16_t resize; /* resize factor in percent */
+ ip_set_ip_t netmask; /* netmask */
++ void *initval[0]; /* initvals for jhash_1word */
+};
+
+struct ip_set_req_iphash_create {
+#endif /* __IP_SET_IPHASH_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_ipmap.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_ipmap.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_ipmap.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_ipmap.h 2007-05-14 11:44:19.000000000 +0200
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_ipmap.h 2007-05-23 23:04:36.000000000 +0200
@@ -0,0 +1,56 @@
+#ifndef __IP_SET_IPMAP_H
+#define __IP_SET_IPMAP_H
+ ip_set_ip_t last_ip; /* host byte order, included in range */
+ ip_set_ip_t netmask; /* subnet netmask */
+ ip_set_ip_t sizeid; /* size of set in IPs */
-+ u_int16_t hosts; /* number of hosts in a subnet */
++ ip_set_ip_t hosts; /* number of hosts in a subnet */
+};
+
+struct ip_set_req_ipmap_create {
+{
+ unsigned int bits = 32;
+ ip_set_ip_t maskaddr;
-+
++
+ if (mask == 0xFFFFFFFF)
+ return bits;
-+
++
+ maskaddr = 0xFFFFFFFE;
+ while (--bits >= 0 && maskaddr != mask)
+ maskaddr <<= 1;
-+
++
+ return bits;
+}
+
+range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
+{
+ ip_set_ip_t mask = 0xFFFFFFFE;
-+
++
+ *bits = 32;
+ while (--(*bits) >= 0 && mask && (to & mask) != from)
+ mask <<= 1;
-+
++
+ return mask;
+}
-+
++
+#endif /* __IP_SET_IPMAP_H */
+diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_ipporthash.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_ipporthash.h
+--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_ipporthash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_ipporthash.h 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,34 @@
++#ifndef __IP_SET_IPPORTHASH_H
++#define __IP_SET_IPPORTHASH_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "ipporthash"
++#define MAX_RANGE 0x0000FFFF
++#define INVALID_PORT (MAX_RANGE + 1)
++
++struct ip_set_ipporthash {
++ ip_set_ip_t *members; /* the ipporthash proper */
++ uint32_t elements; /* number of elements */
++ uint32_t hashsize; /* hash size */
++ uint16_t probes; /* max number of probes */
++ uint16_t resize; /* resize factor in percent */
++ ip_set_ip_t first_ip; /* host byte order, included in range */
++ ip_set_ip_t last_ip; /* host byte order, included in range */
++ void *initval[0]; /* initvals for jhash_1word */
++};
++
++struct ip_set_req_ipporthash_create {
++ uint32_t hashsize;
++ uint16_t probes;
++ uint16_t resize;
++ ip_set_ip_t from;
++ ip_set_ip_t to;
++};
++
++struct ip_set_req_ipporthash {
++ ip_set_ip_t ip;
++ ip_set_ip_t port;
++};
++
++#endif /* __IP_SET_IPPORTHASH_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_iptree.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_iptree.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_iptree.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_iptree.h 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,39 @@
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_iptree.h 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,40 @@
+#ifndef __IP_SET_IPTREE_H
+#define __IP_SET_IPTREE_H
+
+#define MAX_RANGE 0x0000FFFF
+
+struct ip_set_iptreed {
-+ unsigned long expires[255]; /* x.x.x.ADDR */
++ unsigned long expires[256]; /* x.x.x.ADDR */
+};
+
+struct ip_set_iptreec {
-+ struct ip_set_iptreed *tree[255]; /* x.x.ADDR.* */
++ struct ip_set_iptreed *tree[256]; /* x.x.ADDR.* */
+};
+
+struct ip_set_iptreeb {
-+ struct ip_set_iptreec *tree[255]; /* x.ADDR.*.* */
++ struct ip_set_iptreec *tree[256]; /* x.ADDR.*.* */
+};
+
+struct ip_set_iptree {
+ unsigned int timeout;
+ unsigned int gc_interval;
+#ifdef __KERNEL__
++ uint32_t elements; /* number of elements */
+ struct timer_list gc;
-+ struct ip_set_iptreeb *tree[255]; /* ADDR.*.*.* */
++ struct ip_set_iptreeb *tree[256]; /* ADDR.*.*.* */
+#endif
+};
+
+#endif /* __IP_SET_IPTREE_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_jhash.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_jhash.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_jhash.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_jhash.h 2007-05-14 11:44:19.000000000 +0200
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_jhash.h 2007-05-23 23:04:36.000000000 +0200
@@ -0,0 +1,148 @@
+#ifndef _LINUX_IPSET_JHASH_H
+#define _LINUX_IPSET_JHASH_H
+#endif /* _LINUX_IPSET_JHASH_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_macipmap.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_macipmap.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_macipmap.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_macipmap.h 2007-05-14 11:44:19.000000000 +0200
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_macipmap.h 2007-05-23 23:04:36.000000000 +0200
@@ -0,0 +1,38 @@
+#ifndef __IP_SET_MACIPMAP_H
+#define __IP_SET_MACIPMAP_H
+#endif /* __IP_SET_MACIPMAP_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_malloc.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_malloc.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_malloc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_malloc.h 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,42 @@
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_malloc.h 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,116 @@
+#ifndef _IP_SET_MALLOC_H
+#define _IP_SET_MALLOC_H
+
+#undef CACHE
+}
+
-+static inline void * ip_set_malloc_atomic(size_t bytes)
-+{
-+ if (bytes > max_malloc_size)
-+ return __vmalloc(bytes, GFP_ATOMIC, PAGE_KERNEL);
-+ else
-+ return kmalloc(bytes, GFP_ATOMIC);
-+}
-+
+static inline void * ip_set_malloc(size_t bytes)
+{
+ if (bytes > max_malloc_size)
+ kfree(data);
+}
+
++struct harray {
++ size_t max_elements;
++ void *arrays[0];
++};
++
++static inline void *
++harray_malloc(size_t hashsize, size_t typesize, int flags)
++{
++ struct harray *harray;
++ size_t max_elements, size, i, j;
++
++ if (!max_malloc_size)
++ init_max_malloc_size();
++
++ if (typesize > max_malloc_size)
++ return NULL;
++
++ max_elements = max_malloc_size/typesize;
++ size = hashsize/max_elements;
++ if (hashsize % max_elements)
++ size++;
++
++ /* Last pointer signals end of arrays */
++ harray = kmalloc(sizeof(struct harray) + (size + 1) * sizeof(void *),
++ flags);
++
++ if (!harray)
++ return NULL;
++
++ for (i = 0; i < size - 1; i++) {
++ harray->arrays[i] = kmalloc(max_elements * typesize, flags);
++ if (!harray->arrays[i])
++ goto undo;
++ memset(harray->arrays[i], 0, max_elements * typesize);
++ }
++ harray->arrays[i] = kmalloc((hashsize - i * max_elements) * typesize,
++ flags);
++ if (!harray->arrays[i])
++ goto undo;
++ memset(harray->arrays[i], 0, (hashsize - i * max_elements) * typesize);
++
++ harray->max_elements = max_elements;
++ harray->arrays[size] = NULL;
++
++ return (void *)harray;
++
++ undo:
++ for (j = 0; j < i; j++) {
++ kfree(harray->arrays[j]);
++ }
++ kfree(harray);
++ return NULL;
++}
++
++static inline void harray_free(void *h)
++{
++ struct harray *harray = (struct harray *) h;
++ size_t i;
++
++ for (i = 0; harray->arrays[i] != NULL; i++)
++ kfree(harray->arrays[i]);
++ kfree(harray);
++}
++
++static inline void harray_flush(void *h, size_t hashsize, size_t typesize)
++{
++ struct harray *harray = (struct harray *) h;
++ size_t i;
++
++ for (i = 0; harray->arrays[i+1] != NULL; i++)
++ memset(harray->arrays[i], 0, harray->max_elements * typesize);
++ memset(harray->arrays[i], 0,
++ (hashsize - i * harray->max_elements) * typesize);
++}
++
++#define HARRAY_ELEM(h, type, which) \
++({ \
++ struct harray *__h = (struct harray *)(h); \
++ ((type)((__h)->arrays[(which)/(__h)->max_elements]) \
++ + (which)%(__h)->max_elements); \
++})
++
+#endif /* __KERNEL__ */
+
+#endif /*_IP_SET_MALLOC_H*/
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_nethash.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_nethash.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_nethash.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_nethash.h 2007-05-14 11:44:19.000000000 +0200
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_nethash.h 2007-05-23 23:04:36.000000000 +0200
@@ -0,0 +1,55 @@
+#ifndef __IP_SET_NETHASH_H
+#define __IP_SET_NETHASH_H
+
+struct ip_set_nethash {
+ ip_set_ip_t *members; /* the nethash proper */
-+ uint32_t initval; /* initval for jhash_1word */
-+ uint32_t prime; /* prime for double hashing */
++ uint32_t elements; /* number of elements */
+ uint32_t hashsize; /* hash size */
+ uint16_t probes; /* max number of probes */
+ uint16_t resize; /* resize factor in percent */
+ unsigned char cidr[30]; /* CIDR sizes */
++ void *initval[0]; /* initvals for jhash_1word */
+};
+
+struct ip_set_req_nethash_create {
+
+static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
+
-+static inline ip_set_ip_t
++static inline ip_set_ip_t
+pack(ip_set_ip_t ip, unsigned char cidr)
+{
+ ip_set_ip_t addr, *paddr = &addr;
+ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
+#endif
+ n = cidr / 8;
-+ t = cidr % 8;
++ t = cidr % 8;
+ a = &((unsigned char *)paddr)[n];
+ *a = *a /(1 << (8 - t)) + shifts[t];
+#ifdef __KERNEL__
+#endif /* __IP_SET_NETHASH_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_portmap.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_portmap.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_portmap.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_portmap.h 2007-05-14 11:44:19.000000000 +0200
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_portmap.h 2007-05-23 23:04:36.000000000 +0200
@@ -0,0 +1,25 @@
+#ifndef __IP_SET_PORTMAP_H
+#define __IP_SET_PORTMAP_H
+};
+
+#endif /* __IP_SET_PORTMAP_H */
-diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_prime.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_prime.h
---- linux-2.6.21.1/include/linux/netfilter_ipv4/ip_set_prime.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ip_set_prime.h 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,34 @@
-+#ifndef __IP_SET_PRIME_H
-+#define __IP_SET_PRIME_H
-+
-+static inline unsigned make_prime_bound(unsigned nr)
-+{
-+ unsigned long long nr64 = nr;
-+ unsigned long long x = 1;
-+ nr = 1;
-+ while (x <= nr64) { x <<= 2; nr <<= 1; }
-+ return nr;
-+}
-+
-+static inline int make_prime_check(unsigned nr)
-+{
-+ unsigned x = 3;
-+ unsigned b = make_prime_bound(nr);
-+ while (x <= b) {
-+ if (0 == (nr % x)) return 0;
-+ x += 2;
-+ }
-+ return 1;
-+}
-+
-+static unsigned make_prime(unsigned nr)
-+{
-+ if (0 == (nr & 1)) nr--;
-+ while (nr > 1) {
-+ if (make_prime_check(nr)) return nr;
-+ nr -= 2;
-+ }
-+ return 2;
-+}
-+
-+#endif /* __IP_SET_PRIME_H */
diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/ipt_set.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ipt_set.h
--- linux-2.6.21.1/include/linux/netfilter_ipv4/ipt_set.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ipt_set.h 2007-05-14 11:44:19.000000000 +0200
++++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/ipt_set.h 2007-05-23 23:04:36.000000000 +0200
@@ -0,0 +1,21 @@
+#ifndef _IPT_SET_H
+#define _IPT_SET_H
+};
+
+#endif /*_IPT_SET_H*/
-diff -Nur linux-2.6.21.1/include/linux/netfilter_ipv4/listhelp.h linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/listhelp.h
---- linux-2.6.21.1/include/linux/netfilter_ipv4/listhelp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/include/linux/netfilter_ipv4/listhelp.h 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,123 @@
-+#ifndef _LISTHELP_H
-+#define _LISTHELP_H
-+#include <linux/list.h>
-+
-+/* Header to do more comprehensive job than linux/list.h; assume list
-+ is first entry in structure. */
-+
-+/* Return pointer to first true entry, if any, or NULL. A macro
-+ required to allow inlining of cmpfn. */
-+#define LIST_FIND(head, cmpfn, type, args...) \
-+({ \
-+ const struct list_head *__i, *__j = NULL; \
-+ \
-+ ASSERT_READ_LOCK(head); \
-+ list_for_each(__i, (head)) \
-+ if (cmpfn((const type)__i , ## args)) { \
-+ __j = __i; \
-+ break; \
-+ } \
-+ (type)__j; \
-+})
-+
-+#define LIST_FIND_W(head, cmpfn, type, args...) \
-+({ \
-+ const struct list_head *__i, *__j = NULL; \
-+ \
-+ ASSERT_WRITE_LOCK(head); \
-+ list_for_each(__i, (head)) \
-+ if (cmpfn((type)__i , ## args)) { \
-+ __j = __i; \
-+ break; \
-+ } \
-+ (type)__j; \
-+})
-+
-+/* Just like LIST_FIND but we search backwards */
-+#define LIST_FIND_B(head, cmpfn, type, args...) \
-+({ \
-+ const struct list_head *__i, *__j = NULL; \
-+ \
-+ ASSERT_READ_LOCK(head); \
-+ list_for_each_prev(__i, (head)) \
-+ if (cmpfn((const type)__i , ## args)) { \
-+ __j = __i; \
-+ break; \
-+ } \
-+ (type)__j; \
-+})
-+
-+static inline int
-+__list_cmp_same(const void *p1, const void *p2) { return p1 == p2; }
-+
-+/* Is this entry in the list? */
-+static inline int
-+list_inlist(struct list_head *head, const void *entry)
-+{
-+ return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL;
-+}
-+
-+/* Delete from list. */
-+#ifdef CONFIG_NETFILTER_DEBUG
-+#define LIST_DELETE(head, oldentry) \
-+do { \
-+ ASSERT_WRITE_LOCK(head); \
-+ if (!list_inlist(head, oldentry)) \
-+ printk("LIST_DELETE: %s:%u `%s'(%p) not in %s.\n", \
-+ __FILE__, __LINE__, #oldentry, oldentry, #head); \
-+ else list_del((struct list_head *)oldentry); \
-+} while(0)
-+#else
-+#define LIST_DELETE(head, oldentry) list_del((struct list_head *)oldentry)
-+#endif
-+
-+/* Append. */
-+static inline void
-+list_append(struct list_head *head, void *new)
-+{
-+ ASSERT_WRITE_LOCK(head);
-+ list_add((new), (head)->prev);
-+}
-+
-+/* Prepend. */
-+static inline void
-+list_prepend(struct list_head *head, void *new)
-+{
-+ ASSERT_WRITE_LOCK(head);
-+ list_add(new, head);
-+}
-+
-+/* Insert according to ordering function; insert before first true. */
-+#define LIST_INSERT(head, new, cmpfn) \
-+do { \
-+ struct list_head *__i; \
-+ ASSERT_WRITE_LOCK(head); \
-+ list_for_each(__i, (head)) \
-+ if ((new), (typeof (new))__i) \
-+ break; \
-+ list_add((struct list_head *)(new), __i->prev); \
-+} while(0)
-+
-+/* If the field after the list_head is a nul-terminated string, you
-+ can use these functions. */
-+static inline int __list_cmp_name(const void *i, const char *name)
-+{
-+ return strcmp(name, i+sizeof(struct list_head)) == 0;
-+}
-+
-+/* Returns false if same name already in list, otherwise does insert. */
-+static inline int
-+list_named_insert(struct list_head *head, void *new)
-+{
-+ if (LIST_FIND(head, __list_cmp_name, void *,
-+ new + sizeof(struct list_head)))
-+ return 0;
-+ list_prepend(head, new);
-+ return 1;
-+}
-+
-+/* Find this named element in the list. */
-+#define list_named_find(head, name) \
-+LIST_FIND(head, __list_cmp_name, void *, name)
-+
-+#endif /*_LISTHELP_H*/
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set.c
--- linux-2.6.21.1/net/ipv4/netfilter/ip_set.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,1989 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,2001 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module for IP set management */
+
-+#include <linux/autoconf.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++#include <linux/config.h>
++#endif
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+
-+#define ASSERT_READ_LOCK(x) /* dont use that */
++#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
-+#include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+
+static struct list_head set_type_list; /* all registered sets */
+
+/*
+ * Sets are identified either by the index in ip_set_list or by id.
-+ * The id never changes and is used to find a key in the hash.
-+ * The index may change by swapping and used at all other places
++ * The id never changes and is used to find a key in the hash.
++ * The index may change by swapping and used at all other places
+ * (set/SET netfilter modules, binding value, etc.)
+ *
+ * Userspace requests are serialized by ip_set_mutex and sets can
-+ * be deleted only from userspace. Therefore ip_set_list locking
++ * be deleted only from userspace. Therefore ip_set_list locking
+ * must obey the following rules:
+ *
+ * - kernel requests: read and write locking mandatory
+ * Binding routines
+ */
+
-+static inline int
-+ip_hash_cmp(const struct ip_set_hash *set_hash,
-+ ip_set_id_t id, ip_set_ip_t ip)
++static inline struct ip_set_hash *
++__ip_set_find(u_int32_t key, ip_set_id_t id, ip_set_ip_t ip)
+{
-+ return set_hash->id == id && set_hash->ip == ip;
++ struct ip_set_hash *set_hash;
++
++ list_for_each_entry(set_hash, &ip_set_hash[key], list)
++ if (set_hash->id == id && set_hash->ip == ip)
++ return set_hash;
++
++ return NULL;
+}
+
+static ip_set_id_t
+ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip)
+{
-+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
+
+ ASSERT_READ_LOCK(&ip_set_lock);
+ IP_SET_ASSERT(ip_set_list[id]);
-+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
-+
-+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
-+ struct ip_set_hash *, id, ip);
-+
-+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++
++ set_hash = __ip_set_find(key, id, ip);
++
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip),
+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
+
+ return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID);
+}
+
-+static inline void
++static inline void
+__set_hash_del(struct ip_set_hash *set_hash)
+{
+ ASSERT_WRITE_LOCK(&ip_set_lock);
-+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
+
+ __ip_set_put(set_hash->binding);
+ list_del(&set_hash->list);
+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
-+
++
+ IP_SET_ASSERT(ip_set_list[id]);
-+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
+ write_lock_bh(&ip_set_lock);
-+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
-+ struct ip_set_hash *, id, ip);
++ set_hash = __ip_set_find(key, id, ip);
+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip),
+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
+ return 0;
+}
+
-+static int
++static int
+ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding)
+{
+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
+ % ip_set_bindings_hash_size;
+ struct ip_set_hash *set_hash;
+ int ret = 0;
-+
++
+ IP_SET_ASSERT(ip_set_list[id]);
+ IP_SET_ASSERT(ip_set_list[binding]);
-+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
+ HIPQUAD(ip), ip_set_list[binding]->name);
+ write_lock_bh(&ip_set_lock);
-+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
-+ struct ip_set_hash *, id, ip);
++ set_hash = __ip_set_find(key, id, ip);
+ if (!set_hash) {
-+ set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_KERNEL);
++ set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_ATOMIC);
+ if (!set_hash) {
+ ret = -ENOMEM;
+ goto unlock;
+ INIT_LIST_HEAD(&set_hash->list);
+ set_hash->id = id;
+ set_hash->ip = ip;
-+ list_add(&ip_set_hash[key], &set_hash->list);
++ list_add(&set_hash->list, &ip_set_hash[key]);
+ } else {
-+ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
+ DP("overwrite binding: %s",
+ ip_set_list[set_hash->binding]->name);
+ __ip_set_put(set_hash->binding);
+ }
+ set_hash->binding = binding;
+ __ip_set_get(set_hash->binding);
++ DP("stored: key %u, id %u (%s), ip %u.%u.%u.%u, binding %u (%s)",
++ key, id, ip_set_list[id]->name,
++ HIPQUAD(ip), binding, ip_set_list[binding]->name);
+ unlock:
+ write_unlock_bh(&ip_set_lock);
+ return ret;
+{
+ struct ip_set *set;
+ ip_set_ip_t ip;
-+ int res, i = 0;
-+
++ int res;
++ unsigned char i = 0;
++
+ IP_SET_ASSERT(flags[i]);
+ read_lock_bh(&ip_set_lock);
+ do {
+ IP_SET_ASSERT(set);
+ DP("set %s, index %u", set->name, index);
+ read_lock_bh(&set->lock);
-+ res = set->type->testip_kernel(set, skb, flags[i], &ip);
++ res = set->type->testip_kernel(set, skb, &ip, flags, i++);
+ read_unlock_bh(&set->lock);
-+ } while (res > 0
-+ && flags[++i]
++ i += !!(set->type->features & IPSET_DATA_DOUBLE);
++ } while (res > 0
++ && flags[i]
+ && follow_bindings(index, set, ip));
+ read_unlock_bh(&ip_set_lock);
+
+{
+ struct ip_set *set;
+ ip_set_ip_t ip;
-+ int res, i= 0;
++ int res;
++ unsigned char i = 0;
+
+ IP_SET_ASSERT(flags[i]);
+ retry:
+ IP_SET_ASSERT(set);
+ DP("set %s, index %u", set->name, index);
+ write_lock_bh(&set->lock);
-+ res = set->type->addip_kernel(set, skb, flags[i], &ip);
++ res = set->type->addip_kernel(set, skb, &ip, flags, i++);
+ write_unlock_bh(&set->lock);
++ i += !!(set->type->features & IPSET_DATA_DOUBLE);
+ } while ((res == 0 || res == -EEXIST)
-+ && flags[++i]
++ && flags[i]
+ && follow_bindings(index, set, ip));
+ read_unlock_bh(&ip_set_lock);
+
+{
+ struct ip_set *set;
+ ip_set_ip_t ip;
-+ int res, i = 0;
++ int res;
++ unsigned char i = 0;
+
+ IP_SET_ASSERT(flags[i]);
+ read_lock_bh(&ip_set_lock);
+ IP_SET_ASSERT(set);
+ DP("set %s, index %u", set->name, index);
+ write_lock_bh(&set->lock);
-+ res = set->type->delip_kernel(set, skb, flags[i], &ip);
++ res = set->type->delip_kernel(set, skb, &ip, flags, i++);
+ write_unlock_bh(&set->lock);
++ i += !!(set->type->features & IPSET_DATA_DOUBLE);
+ } while ((res == 0 || res == -EEXIST)
-+ && flags[++i]
++ && flags[i]
+ && follow_bindings(index, set, ip));
+ read_unlock_bh(&ip_set_lock);
+}
+
+/* Register and deregister settype */
+
-+static inline int
-+set_type_equal(const struct ip_set_type *set_type, const char *str2)
-+{
-+ return !strncmp(set_type->typename, str2, IP_SET_MAXNAMELEN - 1);
-+}
-+
+static inline struct ip_set_type *
+find_set_type(const char *name)
+{
-+ return LIST_FIND(&set_type_list,
-+ set_type_equal,
-+ struct ip_set_type *,
-+ name);
++ struct ip_set_type *set_type;
++
++ list_for_each_entry(set_type, &set_type_list, list)
++ if (!strncmp(set_type->typename, name, IP_SET_MAXNAMELEN - 1))
++ return set_type;
++ return NULL;
+}
+
-+int
++int
+ip_set_register_set_type(struct ip_set_type *set_type)
+{
+ int ret = 0;
-+
++
+ if (set_type->protocol_version != IP_SET_PROTOCOL_VERSION) {
+ ip_set_printk("'%s' uses wrong protocol version %u (want %u)",
+ set_type->typename,
+ write_lock_bh(&ip_set_lock);
+ if (find_set_type(set_type->typename)) {
+ /* Duplicate! */
-+ ip_set_printk("'%s' already registered!",
++ ip_set_printk("'%s' already registered!",
+ set_type->typename);
+ ret = -EINVAL;
+ goto unlock;
+ ret = -EFAULT;
+ goto unlock;
+ }
-+ list_append(&set_type_list, set_type);
++ list_add(&set_type->list, &set_type_list);
+ DP("'%s' registered.", set_type->typename);
+ unlock:
+ write_unlock_bh(&ip_set_lock);
+ set_type->typename);
+ goto unlock;
+ }
-+ LIST_DELETE(&set_type_list, set_type);
++ list_del(&set_type->list);
+ module_put(THIS_MODULE);
+ DP("'%s' unregistered.", set_type->typename);
+ unlock:
+ip_set_get_byname(const char *name)
+{
+ ip_set_id_t i, index = IP_SET_INVALID_ID;
-+
++
+ down(&ip_set_app_mutex);
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+
+ if (index >= ip_set_max)
+ return IP_SET_INVALID_ID;
-+
++
+ if (ip_set_list[index])
+ __ip_set_get(index);
+ else
+ index = IP_SET_INVALID_ID;
-+
++
+ up(&ip_set_app_mutex);
+ return index;
+}
+ip_set_find_byname(const char *name)
+{
+ ip_set_id_t i, index = IP_SET_INVALID_ID;
-+
++
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && strcmp(ip_set_list[i]->name, name) == 0) {
+{
+ if (index >= ip_set_max || ip_set_list[index] == NULL)
+ index = IP_SET_INVALID_ID;
-+
++
+ return index;
+}
+
+ struct ip_set *set = ip_set_list[index];
+ ip_set_ip_t ip;
+ int res;
-+
++
+ IP_SET_ASSERT(set);
+ do {
+ write_lock_bh(&set->lock);
+ struct ip_set *set = ip_set_list[index];
+ ip_set_ip_t ip;
+ int res;
-+
++
+ IP_SET_ASSERT(set);
+ write_lock_bh(&set->lock);
+ res = set->type->delip(set,
+ IP_SET_ASSERT(set);
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
-+
++
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of a set */
+ char *binding_name;
-+
++
+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
+ return -EINVAL;
+
-+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ binding = ip_set_find_byname(binding_name);
+ &ip);
+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
-+
++
+ if (res >= 0)
+ res = ip_set_hash_add(set->id, ip, binding);
+
+ DP("");
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
-+
++
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
-+
++
+ DP("%u %s", index, req_bind->binding);
+ if (index == IP_SET_INVALID_ID) {
+ /* unbind :all: */
+ DP("unreachable reached!");
+ return -EINVAL;
+ }
-+
++
+ set = ip_set_list[index];
+ IP_SET_ASSERT(set);
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
-+
++
+ write_lock_bh(&ip_set_lock);
+ /* Sets in hash values are referenced */
+ __ip_set_put(set->binding);
+ write_unlock_bh(&ip_set_lock);
+ return 0;
+ }
-+
++
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_bind),
+ size - sizeof(struct ip_set_req_bind),
+ IP_SET_ASSERT(set);
+ if (size < sizeof(struct ip_set_req_bind))
+ return -EINVAL;
-+
++
+ req_bind = (struct ip_set_req_bind *) data;
+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
+ /* Default binding of set */
+ char *binding_name;
-+
++
+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
+ return -EINVAL;
+
-+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
+
+ binding = ip_set_find_byname(binding_name);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
-+
++
+ res = (set->binding == binding) ? -EEXIST : 0;
+
+ return res;
+ binding = ip_set_find_byname(req_bind->binding);
+ if (binding == IP_SET_INVALID_ID)
+ return -ENOENT;
-+
-+
++
++
+ res = __ip_set_testip(set,
+ data + sizeof(struct ip_set_req_bind),
+ size - sizeof(struct ip_set_req_bind),
+ &ip);
+ DP("set %s, ip: %u.%u.%u.%u, binding %s",
+ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
-+
++
+ if (res >= 0)
+ res = (ip_set_find_in_hash(set->id, ip) == binding)
+ ? -EEXIST : 0;
+find_set_type_rlock(const char *typename)
+{
+ struct ip_set_type *type;
-+
++
+ read_lock_bh(&ip_set_lock);
+ type = find_set_type(typename);
+ if (type == NULL)
+ /* No free slot remained */
+ return -ERANGE;
+ /* Check that index is usable as id (swapping) */
-+ check:
++ check:
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
+ && ip_set_list[i]->id == *id) {
+ size_t size)
+{
+ struct ip_set *set;
-+ ip_set_id_t index, id;
++ ip_set_id_t index = 0, id;
+ int res = 0;
+
+ DP("setname: %s, typename: %s, id: %u", name, typename, restore);
+
+ /*
+ * Here, we have a valid, constructed set. &ip_set_lock again,
-+ * find free id/index and check that it is not already in
++ * find free id/index and check that it is not already in
+ * ip_set_list.
+ */
+ write_lock_bh(&ip_set_lock);
+ res = -ERANGE;
+ goto cleanup;
+ }
-+
++
+ /*
+ * Finally! Add our shiny new set to the list, and be done.
+ */
+ ip_set_list[index] = set;
+ write_unlock_bh(&ip_set_lock);
+ return res;
-+
++
+ cleanup:
+ write_unlock_bh(&ip_set_lock);
+ set->type->destroy(set);
+ ip_set_destroy_set(index);
+ } else {
+ for (i = 0; i < ip_set_max; i++) {
-+ if (ip_set_list[i] != NULL
++ if (ip_set_list[i] != NULL
+ && (atomic_read(&ip_set_list[i]->ref)))
+ return -EBUSY;
+ }
+ write_unlock_bh(&set->lock);
+}
+
-+/*
++/*
+ * Flush data in a set - or in all sets
+ */
+static int
+ write_lock_bh(&ip_set_lock);
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] != NULL
-+ && strncmp(ip_set_list[i]->name,
++ && strncmp(ip_set_list[i]->name,
+ name,
+ IP_SET_MAXNAMELEN - 1) == 0) {
+ res = -EEXIST;
+ u_int32_t from_ref;
+
+ DP("set: %s to %s", from->name, to->name);
-+ /* Type can't be changed. Artifical restriction. */
-+ if (from->type->typecode != to->type->typecode)
++ /* Features must not change. Artifical restriction. */
++ if (from->type->features != to->type->features)
+ return -ENOEXEC;
+
-+ /* No magic here: ref munging protected by the mutex */
++ /* No magic here: ref munging protected by the mutex */
+ write_lock_bh(&ip_set_lock);
+ strncpy(from_name, from->name, IP_SET_MAXNAMELEN);
+ from_ref = atomic_read(&from->ref);
+ atomic_set(&from->ref, atomic_read(&to->ref));
+ strncpy(to->name, from_name, IP_SET_MAXNAMELEN);
+ atomic_set(&to->ref, from_ref);
-+
++
+ ip_set_list[from_index] = to;
+ ip_set_list[to_index] = from;
-+
++
+ write_unlock_bh(&ip_set_lock);
+ return 0;
+}
+ ip_set_id_t id, void *data, int *used)
+{
+ if (set_hash->id == id) {
-+ struct ip_set_hash_list *hash_list =
++ struct ip_set_hash_list *hash_list =
+ (struct ip_set_hash_list *)(data + *used);
+
+ hash_list->ip = set_hash->ip;
+
+ /* Fill in set spefific bindings data */
+ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used);
-+
++
+ return 0;
+
+ unlock_set:
+ *used += sizeof(struct ip_set_save);
+
+ set = ip_set_list[index];
-+ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
++ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
+ data, data + *used);
+
+ read_lock_bh(&set->lock);
+ set->type->list_header(set, data + *used);
+ *used += set_save->header_size;
+
-+ DP("set header filled: %s, used: %u %p %p", set->name, *used,
-+ data, data + *used);
++ DP("set header filled: %s, used: %u(%u) %p %p", set->name, *used,
++ set_save->header_size, data, data + *used);
+ /* Get and ensure set specific members size */
+ set_save->members_size = set->type->list_members_size(set);
+ if (*used + set_save->members_size > len)
+ set->type->list_members(set, data + *used);
+ *used += set_save->members_size;
+ read_unlock_bh(&set->lock);
-+ DP("set members filled: %s, used: %u %p %p", set->name, *used,
-+ data, data + *used);
++ DP("set members filled: %s, used: %u(%u) %p %p", set->name, *used,
++ set_save->members_size, data, data + *used);
+ return 0;
+
+ unlock_set:
+{
+ if (*res == 0
+ && (id == IP_SET_INVALID_ID || set_hash->id == id)) {
-+ struct ip_set_hash_save *hash_save =
++ struct ip_set_hash_save *hash_save =
+ (struct ip_set_hash_save *)(data + *used);
+ /* Ensure bindings size */
+ if (*used + sizeof(struct ip_set_hash_save) > len) {
+ /* Marker */
+ set_save = (struct ip_set_save *) (data + *used);
+ set_save->index = IP_SET_INVALID_ID;
++ set_save->header_size = 0;
++ set_save->members_size = 0;
+ *used += sizeof(struct ip_set_save);
+
+ DP("marker added used %u, len %u", *used, len);
+ index = ip_set_list[index]->id;
+ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res);
+
-+ return res;
++ return res;
+}
+
+/*
+ /* Loop to restore sets */
+ while (1) {
+ line++;
-+
++
+ DP("%u %u %u", used, sizeof(struct ip_set_restore), len);
+ /* Get and ensure header size */
+ if (used + sizeof(struct ip_set_restore) > len)
+ used += sizeof(struct ip_set_restore);
+
+ /* Ensure data size */
-+ if (used
-+ + set_restore->header_size
++ if (used
++ + set_restore->header_size
+ + set_restore->members_size > len)
+ return line;
+
+ line--;
+ goto bindings;
+ }
-+
++
+ /* Try to create the set */
+ DP("restore %s %s", set_restore->name, set_restore->typename);
+ res = ip_set_create(set_restore->name,
+ set_restore->index,
+ data + used,
+ set_restore->header_size);
-+
++
+ if (res != 0)
+ return line;
+ used += set_restore->header_size;
+ res = __ip_set_addip(index,
+ data + used + members_size,
+ set->type->reqsize);
-+ if (!(res == 0 || res == -EEXIST))
++ if (!(res == 0 || res == -EEXIST))
+ return line;
+ members_size += set->type->reqsize;
+ }
+ set_restore->members_size, members_size);
+ if (members_size != set_restore->members_size)
+ return line++;
-+ used += set_restore->members_size;
++ used += set_restore->members_size;
+ }
-+
++
+ bindings:
+ /* Loop to restore bindings */
+ while (used < len) {
+ line++;
+
-+ DP("restore binding, line %u", line);
++ DP("restore binding, line %u", line);
+ /* Get and ensure size */
+ if (used + sizeof(struct ip_set_hash_save) > len)
+ return line;
+ hash_save = (struct ip_set_hash_save *) (data + used);
+ used += sizeof(struct ip_set_hash_save);
-+
++
+ /* hash_save->id is used to store the index */
+ index = ip_set_find_byindex(hash_save->id);
+ DP("restore binding index %u, id %u, %u -> %u",
-+ index, hash_save->id, hash_save->ip, hash_save->binding);
++ index, hash_save->id, hash_save->ip, hash_save->binding);
+ if (index != hash_save->id)
+ return line;
-+
++ if (ip_set_find_byindex(hash_save->binding) == IP_SET_INVALID_ID) {
++ DP("corrupt binding set index %u", hash_save->binding);
++ return line;
++ }
+ set = ip_set_list[hash_save->id];
+ /* Null valued IP means default binding */
+ if (hash_save->ip)
-+ res = ip_set_hash_add(set->id,
++ res = ip_set_hash_add(set->id,
+ hash_save->ip,
+ hash_save->binding);
+ else {
+ }
+ if (used != len)
+ return line;
-+
-+ return 0;
++
++ return 0;
+}
+
+static int
+
+ op = (unsigned *)data;
+ DP("op=%x", *op);
-+
++
+ if (*op < IP_SET_OP_VERSION) {
+ /* Check the version at the beginning of operations */
+ struct ip_set_req_version *req_version =
+ case IP_SET_OP_CREATE:{
+ struct ip_set_req_create *req_create
+ = (struct ip_set_req_create *) data;
-+
-+ if (len <= sizeof(struct ip_set_req_create)) {
-+ ip_set_printk("short CREATE data (want >%zu, got %u)",
++
++ if (len < sizeof(struct ip_set_req_create)) {
++ ip_set_printk("short CREATE data (want >=%zu, got %u)",
+ sizeof(struct ip_set_req_create), len);
+ res = -EINVAL;
+ goto done;
+ case IP_SET_OP_DESTROY:{
+ struct ip_set_req_std *req_destroy
+ = (struct ip_set_req_std *) data;
-+
++
+ if (len != sizeof(struct ip_set_req_std)) {
+ ip_set_printk("invalid DESTROY data (want %zu, got %u)",
+ sizeof(struct ip_set_req_std), len);
+ goto done;
+ }
+ }
-+
++
+ res = ip_set_destroy(index);
+ goto done;
+ }
+
+ req_rename->name[IP_SET_MAXNAMELEN - 1] = '\0';
+ req_rename->typename[IP_SET_MAXNAMELEN - 1] = '\0';
-+
++
+ index = ip_set_find_byname(req_rename->name);
+ if (index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ res = ip_set_swap(index, to_index);
+ goto done;
+ }
-+ default:
++ default:
+ break; /* Set identified by id */
+ }
-+
++
+ /* There we may have add/del/test/bind/unbind/test_bind operations */
+ if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) {
+ res = -EBADMSG;
+ req_adt = (struct ip_set_req_adt *) data;
+
+ /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */
-+ if (!(*op == IP_SET_OP_UNBIND_SET
++ if (!(*op == IP_SET_OP_UNBIND_SET
+ && req_adt->index == IP_SET_INVALID_ID)) {
+ index = ip_set_find_byindex(req_adt->index);
+ if (index == IP_SET_INVALID_ID) {
+ return res;
+}
+
-+static int
++static int
+ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
+{
+ int res = 0;
+ req_max_sets->set.index = IP_SET_INVALID_ID;
+ } else {
+ req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
-+ req_max_sets->set.index =
++ req_max_sets->set.index =
+ ip_set_find_byname(req_max_sets->set.name);
+ if (req_max_sets->set.index == IP_SET_INVALID_ID) {
+ res = -ENOENT;
+ }
+ goto copy;
+ }
-+ case IP_SET_OP_LIST_SIZE:
++ case IP_SET_OP_LIST_SIZE:
+ case IP_SET_OP_SAVE_SIZE: {
+ struct ip_set_req_setnames *req_setnames
+ = (struct ip_set_req_setnames *) data;
+ for (i = 0; i < ip_set_max; i++) {
+ if (ip_set_list[i] == NULL)
+ continue;
-+ name_list = (struct ip_set_name_list *)
++ name_list = (struct ip_set_name_list *)
+ (data + used);
+ used += sizeof(struct ip_set_name_list);
+ if (used > copylen) {
+ req_setnames->size += sizeof(struct ip_set_list)
+ + set->type->header_size
+ + set->type->list_members_size(set);
-+ FOREACH_HASH_DO(__set_hash_bindings_size_list,
-+ i, &req_setnames->size);
++ /* Sets are identified by id in the hash */
++ FOREACH_HASH_DO(__set_hash_bindings_size_list,
++ set->id, &req_setnames->size);
+ break;
+ }
+ case IP_SET_OP_SAVE_SIZE: {
+ + set->type->header_size
+ + set->type->list_members_size(set);
+ FOREACH_HASH_DO(__set_hash_bindings_size_save,
-+ i, &req_setnames->size);
++ set->id, &req_setnames->size);
+ break;
+ }
+ default:
+ }
+ if (res == 0)
+ res = ip_set_save_bindings(index, data, &used, *len);
-+
++
+ if (res != 0)
+ goto done;
+ else if (copylen != used) {
+ && ip_set_list[index]
+ ? ip_set_list[index]->name
+ : ":all:", copylen);
-+ if (res == 0)
-+ res = copy_to_user(user, data, copylen);
-+ else
-+ copy_to_user(user, data, copylen);
-+
++ res = copy_to_user(user, data, copylen);
++
+ done:
+ up(&ip_set_app_mutex);
+ vfree(data);
+module_exit(fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_iphash.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_iphash.c
--- linux-2.6.21.1/net/ipv4/netfilter/ip_set_iphash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_iphash.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,379 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_iphash.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,413 @@
+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an ip hash set */
+#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set_iphash.h>
+#include <linux/netfilter_ipv4/ip_set_jhash.h>
-+#include <linux/netfilter_ipv4/ip_set_prime.h>
+
-+static inline __u32
-+jhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
-+{
-+ return jhash_1word(ip, map->initval);
-+}
++static int limit = MAX_RANGE;
+
+static inline __u32
-+randhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
++jhash_ip(const struct ip_set_iphash *map, uint16_t i, ip_set_ip_t ip)
+{
-+ return (1 + ip % map->prime);
++ return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
+}
+
+static inline __u32
+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
-+ __u32 jhash, randhash, id;
++ __u32 id;
+ u_int16_t i;
++ ip_set_ip_t *elem;
+
+ *hash_ip = ip & map->netmask;
-+ jhash = jhash_ip(map, *hash_ip);
-+ randhash = randhash_ip(map, *hash_ip);
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
-+
++
+ for (i = 0; i < map->probes; i++) {
-+ id = (jhash + i * randhash) % map->hashsize;
++ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ DP("hash key: %u", id);
-+ if (map->members[id] == *hash_ip)
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
++ if (*elem == *hash_ip)
+ return id;
+ /* No shortcut at testing - there can be deleted
+ * entries. */
+static inline int
+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
-+ return (hash_id(set, ip, hash_ip) != UINT_MAX);
++ return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
+}
+
+static int
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_iphash *req =
++ struct ip_set_req_iphash *req =
+ (struct ip_set_req_iphash *) data;
+
+ if (size != sizeof(struct ip_set_req_iphash)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __testip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static inline int
+__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
-+ __u32 jhash, randhash, probe;
++ __u32 probe;
+ u_int16_t i;
++ ip_set_ip_t *elem;
++
++ if (!ip || map->elements > limit)
++ return -ERANGE;
+
+ *hash_ip = ip & map->netmask;
-+ jhash = jhash_ip(map, *hash_ip);
-+ randhash = randhash_ip(map, *hash_ip);
-+
++
+ for (i = 0; i < map->probes; i++) {
-+ probe = (jhash + i * randhash) % map->hashsize;
-+ if (map->members[probe] == *hash_ip)
++ probe = jhash_ip(map, i, *hash_ip) % map->hashsize;
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
++ if (*elem == *hash_ip)
+ return -EEXIST;
-+ if (!map->members[probe]) {
-+ map->members[probe] = *hash_ip;
++ if (!*elem) {
++ *elem = *hash_ip;
++ map->elements++;
+ return 0;
+ }
+ }
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_iphash *req =
++ struct ip_set_req_iphash *req =
+ (struct ip_set_req_iphash *) data;
+
+ if (size != sizeof(struct ip_set_req_iphash)) {
+}
+
+static int
-+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++addip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __addip((struct ip_set_iphash *) set->data,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static int retry(struct ip_set *set)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
-+ ip_set_ip_t hash_ip, *members;
-+ u_int32_t i, hashsize;
-+ unsigned newbytes;
++ ip_set_ip_t hash_ip, *elem;
++ void *members;
++ u_int32_t i, hashsize = map->hashsize;
+ int res;
-+ struct ip_set_iphash tmp = {
-+ .hashsize = map->hashsize,
-+ .probes = map->probes,
-+ .resize = map->resize,
-+ .netmask = map->netmask,
-+ };
-+
++ struct ip_set_iphash *tmp;
++
+ if (map->resize == 0)
+ return -ERANGE;
+
+ again:
+ res = 0;
-+
-+ /* Calculate new parameters */
-+ get_random_bytes(&tmp.initval, 4);
-+ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
-+ if (hashsize == tmp.hashsize)
++
++ /* Calculate new hash size */
++ hashsize += (hashsize * map->resize)/100;
++ if (hashsize == map->hashsize)
+ hashsize++;
-+ tmp.prime = make_prime(hashsize);
-+
++
+ ip_set_printk("rehashing of set %s triggered: "
+ "hashsize grows from %u to %u",
-+ set->name, tmp.hashsize, hashsize);
-+ tmp.hashsize = hashsize;
++ set->name, map->hashsize, hashsize);
+
-+ newbytes = hashsize * sizeof(ip_set_ip_t);
-+ tmp.members = ip_set_malloc_atomic(newbytes);
-+ if (!tmp.members) {
-+ DP("out of memory for %d bytes", newbytes);
++ tmp = kmalloc(sizeof(struct ip_set_iphash)
++ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
++ if (!tmp) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_iphash)
++ + map->probes * sizeof(uint32_t));
+ return -ENOMEM;
+ }
-+ memset(tmp.members, 0, newbytes);
-+
++ tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
++ if (!tmp->members) {
++ DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
++ kfree(tmp);
++ return -ENOMEM;
++ }
++ tmp->hashsize = hashsize;
++ tmp->elements = 0;
++ tmp->probes = map->probes;
++ tmp->resize = map->resize;
++ tmp->netmask = map->netmask;
++ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
++
+ write_lock_bh(&set->lock);
+ map = (struct ip_set_iphash *) set->data; /* Play safe */
+ for (i = 0; i < map->hashsize && res == 0; i++) {
-+ if (map->members[i])
-+ res = __addip(&tmp, map->members[i], &hash_ip);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ if (*elem)
++ res = __addip(tmp, *elem, &hash_ip);
+ }
+ if (res) {
+ /* Failure, try again */
+ write_unlock_bh(&set->lock);
-+ ip_set_free(tmp.members, newbytes);
++ harray_free(tmp->members);
++ kfree(tmp);
+ goto again;
+ }
-+
++
+ /* Success at resizing! */
+ members = map->members;
-+ hashsize = map->hashsize;
+
-+ map->initval = tmp.initval;
-+ map->prime = tmp.prime;
-+ map->hashsize = tmp.hashsize;
-+ map->members = tmp.members;
++ map->hashsize = tmp->hashsize;
++ map->members = tmp->members;
+ write_unlock_bh(&set->lock);
+
-+ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
++ harray_free(members);
++ kfree(tmp);
+
+ return 0;
+}
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
-+ ip_set_ip_t id = hash_id(set, ip, hash_ip);
++ ip_set_ip_t id, *elem;
++
++ if (!ip)
++ return -ERANGE;
+
++ id = hash_id(set, ip, hash_ip);
+ if (id == UINT_MAX)
+ return -EEXIST;
++
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
++ *elem = 0;
++ map->elements--;
+
-+ map->members[id] = 0;
+ return 0;
+}
+
+}
+
+static int
-+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++delip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __delip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static int create(struct ip_set *set, const void *data, size_t size)
+{
-+ unsigned newbytes;
+ struct ip_set_req_iphash_create *req =
+ (struct ip_set_req_iphash_create *) data;
+ struct ip_set_iphash *map;
++ uint16_t i;
+
+ if (size != sizeof(struct ip_set_req_iphash_create)) {
+ ip_set_printk("data length wrong (want %zu, have %zu)",
+ return -ENOEXEC;
+ }
+
-+ map = kmalloc(sizeof(struct ip_set_iphash), GFP_KERNEL);
++ if (req->probes < 1) {
++ ip_set_printk("probes too small");
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_iphash)
++ + req->probes * sizeof(uint32_t), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
-+ sizeof(struct ip_set_iphash));
++ sizeof(struct ip_set_iphash)
++ + req->probes * sizeof(uint32_t));
+ return -ENOMEM;
+ }
-+ get_random_bytes(&map->initval, 4);
-+ map->prime = make_prime(req->hashsize);
++ for (i = 0; i < req->probes; i++)
++ get_random_bytes(((uint32_t *) map->initval)+i, 4);
++ map->elements = 0;
+ map->hashsize = req->hashsize;
+ map->probes = req->probes;
+ map->resize = req->resize;
+ map->netmask = req->netmask;
-+ newbytes = map->hashsize * sizeof(ip_set_ip_t);
-+ map->members = ip_set_malloc(newbytes);
++ map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
+ if (!map->members) {
-+ DP("out of memory for %d bytes", newbytes);
++ DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
+ kfree(map);
+ return -ENOMEM;
+ }
-+ memset(map->members, 0, newbytes);
+
+ set->data = map;
+ return 0;
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
+
-+ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
++ harray_free(map->members);
+ kfree(map);
+
+ set->data = NULL;
+static void flush(struct ip_set *set)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
-+ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
++ harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
++ map->elements = 0;
+}
+
+static void list_header(const struct ip_set *set, void *data)
+static void list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
-+ int bytes = map->hashsize * sizeof(ip_set_ip_t);
++ ip_set_ip_t i, *elem;
+
-+ memcpy(data, map->members, bytes);
++ for (i = 0; i < map->hashsize; i++) {
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ ((ip_set_ip_t *)data)[i] = *elem;
++ }
+}
+
+static struct ip_set_type ip_set_iphash = {
+ .typename = SETTYPE_NAME,
-+ .typecode = IPSET_TYPE_IP,
++ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("iphash type of IP sets");
++module_param(limit, int, 0600);
++MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
+
+static int __init init(void)
+{
-+ init_max_malloc_size();
+ return ip_set_register_set_type(&ip_set_iphash);
+}
+
+module_exit(fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_ipmap.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_ipmap.c
--- linux-2.6.21.1/net/ipv4/netfilter/ip_set_ipmap.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_ipmap.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,313 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_ipmap.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,327 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the single bitmap type */
+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
-+
++
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
+
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_ipmap *req =
++ struct ip_set_req_ipmap *req =
+ (struct ip_set_req_ipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_ipmap)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++testip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
-+ u_int32_t flags,
-+ ip_set_ip_t *hash_ip)
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ int res;
-+
++
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
-+ flags & IPSET_SRC ? "SRC" : "DST",
++ flags[index] & IPSET_SRC ? "SRC" : "DST",
+ NIPQUAD(skb->nh.iph->saddr),
+ NIPQUAD(skb->nh.iph->daddr));
+
+ res = __testip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+ return (res < 0 ? 0 : res);
+}
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_ipmap *req =
++ struct ip_set_req_ipmap *req =
+ (struct ip_set_req_ipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_ipmap)) {
+}
+
+static int
-+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++addip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __addip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
-+static inline int
++static inline int
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
+ if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
+ return -EEXIST;
-+
++
+ return 0;
+}
+
+}
+
+static int
-+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++delip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __delip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+ return -ENOEXEC;
+ }
+
-+ if (req->to - req->from > MAX_RANGE) {
-+ ip_set_printk("range too big (max %d addresses)",
-+ MAX_RANGE);
-+ return -ENOEXEC;
-+ }
-+
+ map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
+ } else {
+ unsigned int mask_bits, netmask_bits;
+ ip_set_ip_t mask;
-+
++
+ map->first_ip &= map->netmask; /* Should we better bark? */
-+
++
+ mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
+ netmask_bits = mask_to_bits(map->netmask);
-+
-+ if (!mask || netmask_bits <= mask_bits)
++
++ if ((!mask && (map->first_ip || map->last_ip != 0xFFFFFFFF))
++ || netmask_bits <= mask_bits)
+ return -ENOEXEC;
+
++ DP("mask_bits %u, netmask_bits %u",
++ mask_bits, netmask_bits);
+ map->hosts = 2 << (32 - netmask_bits - 1);
+ map->sizeid = 2 << (netmask_bits - mask_bits - 1);
+ }
++ if (map->sizeid > MAX_RANGE + 1) {
++ ip_set_printk("range too big (max %d addresses)",
++ MAX_RANGE+1);
++ kfree(map);
++ return -ENOEXEC;
++ }
++ DP("hosts %u, sizeid %u", map->hosts, map->sizeid);
+ newbytes = bitmap_bytes(0, map->sizeid - 1);
+ map->members = kmalloc(newbytes, GFP_KERNEL);
+ if (!map->members) {
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
-+
++
+ set->data = map;
+ return 0;
+}
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
-+
++
+ kfree(map->members);
+ kfree(map);
-+
++
+ set->data = NULL;
+}
+
+
+static struct ip_set_type ip_set_ipmap = {
+ .typename = SETTYPE_NAME,
-+ .typecode = IPSET_TYPE_IP,
++ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+
+module_init(init);
+module_exit(fini);
-diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_iptree.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_iptree.c
---- linux-2.6.21.1/net/ipv4/netfilter/ip_set_iptree.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_iptree.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,510 @@
-+/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_ipporthash.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_ipporthash.c
+--- linux-2.6.21.1/net/ipv4/netfilter/ip_set_ipporthash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_ipporthash.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,535 @@
++/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
-+/* Kernel module implementing an IP set type: the iptree type */
++/* Kernel module implementing an ip+port hash set */
+
+#include <linux/module.h>
+#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
+#include <linux/skbuff.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++#include <linux/random.h>
+
-+#include <linux/netfilter_ipv4/ip_set_iptree.h>
++#include <net/ip.h>
+
-+/* Garbage collection interval in seconds: */
-+#define IPTREE_GC_TIME 5*60
-+/* Sleep so many milliseconds before trying again
-+ * to delete the gc timer at destroying a set */
-+#define IPTREE_DESTROY_SLEEP 100
++#include <linux/netfilter_ipv4/ip_set_malloc.h>
++#include <linux/netfilter_ipv4/ip_set_ipporthash.h>
++#include <linux/netfilter_ipv4/ip_set_jhash.h>
+
-+static kmem_cache_t *branch_cachep;
-+static kmem_cache_t *leaf_cachep;
++static int limit = MAX_RANGE;
+
-+#define ABCD(a,b,c,d,addrp) do { \
-+ a = ((unsigned char *)addrp)[3]; \
-+ b = ((unsigned char *)addrp)[2]; \
-+ c = ((unsigned char *)addrp)[1]; \
-+ d = ((unsigned char *)addrp)[0]; \
-+} while (0)
++/* We must handle non-linear skbs */
++static inline ip_set_ip_t
++get_port(const struct sk_buff *skb, u_int32_t flags)
++{
++ struct iphdr *iph = skb->nh.iph;
++ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
+
-+#define TESTIP_WALK(map, elem, branch) do { \
-+ if ((map)->tree[elem]) { \
-+ branch = (map)->tree[elem]; \
++ switch (iph->protocol) {
++ case IPPROTO_TCP: {
++ struct tcphdr tcph;
++
++ /* See comments at tcp_match in ip_tables.c */
++ if (offset)
++ return INVALID_PORT;
++
++ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
++ /* No choice either */
++ return INVALID_PORT;
++
++ return ntohs(flags & IPSET_SRC ?
++ tcph.source : tcph.dest);
++ }
++ case IPPROTO_UDP: {
++ struct udphdr udph;
++
++ if (offset)
++ return INVALID_PORT;
++
++ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
++ /* No choice either */
++ return INVALID_PORT;
++
++ return ntohs(flags & IPSET_SRC ?
++ udph.source : udph.dest);
++ }
++ default:
++ return INVALID_PORT;
++ }
++}
++
++static inline __u32
++jhash_ip(const struct ip_set_ipporthash *map, uint16_t i, ip_set_ip_t ip)
++{
++ return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
++}
++
++#define HASH_IP(map, ip, port) (port + ((ip - ((map)->first_ip)) << 16))
++
++static inline __u32
++hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipporthash *map =
++ (struct ip_set_ipporthash *) set->data;
++ __u32 id;
++ u_int16_t i;
++ ip_set_ip_t *elem;
++
++ *hash_ip = HASH_IP(map, ip, port);
++ DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
++
++ for (i = 0; i < map->probes; i++) {
++ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
++ DP("hash key: %u", id);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
++ if (*elem == *hash_ip)
++ return id;
++ /* No shortcut at testing - there can be deleted
++ * entries. */
++ }
++ return UINT_MAX;
++}
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ return (hash_id(set, ip, port, hash_ip) != UINT_MAX);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipporthash *req =
++ (struct ip_set_req_ipporthash *) data;
++
++ if (size != sizeof(struct ip_set_req_ipporthash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipporthash),
++ size);
++ return -EINVAL;
++ }
++ return __testip(set, req->ip, req->port, hash_ip);
++}
++
++static int
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
++{
++ ip_set_ip_t port;
++
++ if (flags[index+1] == 0)
++ return -EINVAL;
++
++ port = get_port(skb, flags[index+1]);
++
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags[index] & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++ DP("flag %s port %u",
++ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
++ port);
++ if (port == INVALID_PORT)
++ return 0;
++
++ return __testip(set,
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ port,
++ hash_ip);
++}
++
++static inline int
++__add_haship(struct ip_set_ipporthash *map, ip_set_ip_t hash_ip)
++{
++ __u32 probe;
++ u_int16_t i;
++ ip_set_ip_t *elem;
++
++ for (i = 0; i < map->probes; i++) {
++ probe = jhash_ip(map, i, hash_ip) % map->hashsize;
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
++ if (*elem == hash_ip)
++ return -EEXIST;
++ if (!*elem) {
++ *elem = hash_ip;
++ map->elements++;
++ return 0;
++ }
++ }
++ /* Trigger rehashing */
++ return -EAGAIN;
++}
++
++static inline int
++__addip(struct ip_set_ipporthash *map, ip_set_ip_t ip, ip_set_ip_t port,
++ ip_set_ip_t *hash_ip)
++{
++ if (map->elements > limit)
++ return -ERANGE;
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = HASH_IP(map, ip, port);
++
++ return __add_haship(map, *hash_ip);
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipporthash *req =
++ (struct ip_set_req_ipporthash *) data;
++
++ if (size != sizeof(struct ip_set_req_ipporthash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipporthash),
++ size);
++ return -EINVAL;
++ }
++ return __addip((struct ip_set_ipporthash *) set->data,
++ req->ip, req->port, hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
++{
++ ip_set_ip_t port;
++
++ if (flags[index+1] == 0)
++ return -EINVAL;
++
++ port = get_port(skb, flags[index+1]);
++
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags[index] & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++ DP("flag %s port %u",
++ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
++ port);
++ if (port == INVALID_PORT)
++ return -EINVAL;
++
++ return __addip((struct ip_set_ipporthash *) set->data,
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ port,
++ hash_ip);
++}
++
++static int retry(struct ip_set *set)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++ ip_set_ip_t *elem;
++ void *members;
++ u_int32_t i, hashsize = map->hashsize;
++ int res;
++ struct ip_set_ipporthash *tmp;
++
++ if (map->resize == 0)
++ return -ERANGE;
++
++ again:
++ res = 0;
++
++ /* Calculate new hash size */
++ hashsize += (hashsize * map->resize)/100;
++ if (hashsize == map->hashsize)
++ hashsize++;
++
++ ip_set_printk("rehashing of set %s triggered: "
++ "hashsize grows from %u to %u",
++ set->name, map->hashsize, hashsize);
++
++ tmp = kmalloc(sizeof(struct ip_set_ipporthash)
++ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
++ if (!tmp) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_ipporthash)
++ + map->probes * sizeof(uint32_t));
++ return -ENOMEM;
++ }
++ tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
++ if (!tmp->members) {
++ DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
++ kfree(tmp);
++ return -ENOMEM;
++ }
++ tmp->hashsize = hashsize;
++ tmp->elements = 0;
++ tmp->probes = map->probes;
++ tmp->resize = map->resize;
++ tmp->first_ip = map->first_ip;
++ tmp->last_ip = map->last_ip;
++ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
++
++ write_lock_bh(&set->lock);
++ map = (struct ip_set_ipporthash *) set->data; /* Play safe */
++ for (i = 0; i < map->hashsize && res == 0; i++) {
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ if (*elem)
++ res = __add_haship(tmp, *elem);
++ }
++ if (res) {
++ /* Failure, try again */
++ write_unlock_bh(&set->lock);
++ harray_free(tmp->members);
++ kfree(tmp);
++ goto again;
++ }
++
++ /* Success at resizing! */
++ members = map->members;
++
++ map->hashsize = tmp->hashsize;
++ map->members = tmp->members;
++ write_unlock_bh(&set->lock);
++
++ harray_free(members);
++ kfree(tmp);
++
++ return 0;
++}
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++ ip_set_ip_t id;
++ ip_set_ip_t *elem;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ id = hash_id(set, ip, port, hash_ip);
++
++ if (id == UINT_MAX)
++ return -EEXIST;
++
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
++ *elem = 0;
++ map->elements--;
++
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipporthash *req =
++ (struct ip_set_req_ipporthash *) data;
++
++ if (size != sizeof(struct ip_set_req_ipporthash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipporthash),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, req->port, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
++{
++ ip_set_ip_t port;
++
++ if (flags[index+1] == 0)
++ return -EINVAL;
++
++ port = get_port(skb, flags[index+1]);
++
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags[index] & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++ DP("flag %s port %u",
++ flags[index+1] & IPSET_SRC ? "SRC" : "DST",
++ port);
++ if (port == INVALID_PORT)
++ return -EINVAL;
++
++ return __delip(set,
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ port,
++ hash_ip);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ struct ip_set_req_ipporthash_create *req =
++ (struct ip_set_req_ipporthash_create *) data;
++ struct ip_set_ipporthash *map;
++ uint16_t i;
++
++ if (size != sizeof(struct ip_set_req_ipporthash_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipporthash_create),
++ size);
++ return -EINVAL;
++ }
++
++ if (req->hashsize < 1) {
++ ip_set_printk("hashsize too small");
++ return -ENOEXEC;
++ }
++
++ if (req->probes < 1) {
++ ip_set_printk("probes too small");
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_ipporthash)
++ + req->probes * sizeof(uint32_t), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_ipporthash)
++ + req->probes * sizeof(uint32_t));
++ return -ENOMEM;
++ }
++ for (i = 0; i < req->probes; i++)
++ get_random_bytes(((uint32_t *) map->initval)+i, 4);
++ map->elements = 0;
++ map->hashsize = req->hashsize;
++ map->probes = req->probes;
++ map->resize = req->resize;
++ map->first_ip = req->from;
++ map->last_ip = req->to;
++ map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
++ if (!map->members) {
++ DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
++ kfree(map);
++ return -ENOMEM;
++ }
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++
++ harray_free(map->members);
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++ harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
++ map->elements = 0;
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++ struct ip_set_req_ipporthash_create *header =
++ (struct ip_set_req_ipporthash_create *) data;
++
++ header->hashsize = map->hashsize;
++ header->probes = map->probes;
++ header->resize = map->resize;
++ header->from = map->first_ip;
++ header->to = map->last_ip;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++
++ return (map->hashsize * sizeof(ip_set_ip_t));
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_ipporthash *map = (struct ip_set_ipporthash *) set->data;
++ ip_set_ip_t i, *elem;
++
++ for (i = 0; i < map->hashsize; i++) {
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ ((ip_set_ip_t *)data)[i] = *elem;
++ }
++}
++
++static struct ip_set_type ip_set_ipporthash = {
++ .typename = SETTYPE_NAME,
++ .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_ipporthash),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .retry = &retry,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_ipporthash_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("ipporthash type of IP sets");
++module_param(limit, int, 0600);
++MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_ipporthash);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_ipporthash);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_iptree.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_iptree.c
+--- linux-2.6.21.1/net/ipv4/netfilter/ip_set_iptree.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_iptree.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,565 @@
++/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an IP set type: the iptree type */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/spinlock.h>
++
++/* Backward compatibility */
++#ifndef __nocast
++#define __nocast
++#endif
++
++#include <linux/netfilter_ipv4/ip_set_iptree.h>
++
++static int limit = MAX_RANGE;
++
++/* Garbage collection interval in seconds: */
++#define IPTREE_GC_TIME 5*60
++/* Sleep so many milliseconds before trying again
++ * to delete the gc timer at destroying/flushing a set */
++#define IPTREE_DESTROY_SLEEP 100
++
++static struct kmem_cache *branch_cachep;
++static struct kmem_cache *leaf_cachep;
++
++#define ABCD(a,b,c,d,addrp) do { \
++ a = ((unsigned char *)addrp)[3]; \
++ b = ((unsigned char *)addrp)[2]; \
++ c = ((unsigned char *)addrp)[1]; \
++ d = ((unsigned char *)addrp)[0]; \
++} while (0)
++
++#define TESTIP_WALK(map, elem, branch) do { \
++ if ((map)->tree[elem]) { \
++ branch = (map)->tree[elem]; \
+ } else \
+ return 0; \
+} while (0)
+ struct ip_set_iptreed *dtree;
+ unsigned char a,b,c,d;
+
++ if (!ip)
++ return -ERANGE;
++
+ *hash_ip = ip;
+ ABCD(a, b, c, d, hash_ip);
+ DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_iptree *req =
++ struct ip_set_req_iptree *req =
+ (struct ip_set_req_iptree *) data;
+
+ if (size != sizeof(struct ip_set_req_iptree)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set,
++testip_kernel(struct ip_set *set,
+ const struct sk_buff *skb,
-+ u_int32_t flags,
-+ ip_set_ip_t *hash_ip)
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ int res;
-+
++
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
-+ flags & IPSET_SRC ? "SRC" : "DST",
++ flags[index] & IPSET_SRC ? "SRC" : "DST",
+ NIPQUAD(skb->nh.iph->saddr),
+ NIPQUAD(skb->nh.iph->daddr));
+
+ res = __testip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+ return (res < 0 ? 0 : res);
+}
+
-+#define ADDIP_WALK(map, elem, branch, type, cachep) do { \
++#define ADDIP_WALK(map, elem, branch, type, cachep, flags) do { \
+ if ((map)->tree[elem]) { \
+ DP("found %u", elem); \
+ branch = (map)->tree[elem]; \
+ } else { \
+ branch = (type *) \
-+ kmem_cache_alloc(cachep, GFP_KERNEL); \
++ kmem_cache_alloc(cachep, flags); \
+ if (branch == NULL) \
+ return -ENOMEM; \
+ memset(branch, 0, sizeof(*branch)); \
+ (map)->tree[elem] = branch; \
+ DP("alloc %u", elem); \
+ } \
-+} while (0)
++} while (0)
+
+static inline int
+__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
-+ ip_set_ip_t *hash_ip)
++ ip_set_ip_t *hash_ip,
++ unsigned int __nocast flags)
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+ struct ip_set_iptreeb *btree;
+ struct ip_set_iptreed *dtree;
+ unsigned char a,b,c,d;
+ int ret = 0;
-+
++
++ if (!ip || map->elements > limit)
++ /* We could call the garbage collector
++ * but it's probably overkill */
++ return -ERANGE;
++
+ *hash_ip = ip;
+ ABCD(a, b, c, d, hash_ip);
+ DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
-+ ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep);
-+ ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep);
-+ ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep);
++ ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep, flags);
++ ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep, flags);
++ ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep, flags);
+ if (dtree->expires[d]
+ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
+ ret = -EEXIST;
+ dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
++ /* Lottery */
++ if (dtree->expires[d] == 0)
++ dtree->expires[d] = 1;
+ DP("%u %lu", d, dtree->expires[d]);
++ if (ret == 0)
++ map->elements++;
+ return ret;
+}
+
+ ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
-+ struct ip_set_req_iptree *req =
++ struct ip_set_req_iptree *req =
+ (struct ip_set_req_iptree *) data;
+
+ if (size != sizeof(struct ip_set_req_iptree)) {
+ DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout);
+ return __addip(set, req->ip,
+ req->timeout ? req->timeout : map->timeout,
-+ hash_ip);
++ hash_ip,
++ GFP_ATOMIC);
+}
+
+static int
-+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++addip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+
+ return __addip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ map->timeout,
-+ hash_ip);
++ hash_ip,
++ GFP_ATOMIC);
+}
+
+#define DELIP_WALK(map, elem, branch) do { \
+ return -EEXIST; \
+} while (0)
+
-+static inline int
++static inline int
+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+ struct ip_set_iptreec *ctree;
+ struct ip_set_iptreed *dtree;
+ unsigned char a,b,c,d;
-+
++
++ if (!ip)
++ return -ERANGE;
++
+ *hash_ip = ip;
+ ABCD(a, b, c, d, hash_ip);
+ DELIP_WALK(map, a, btree);
+
+ if (dtree->expires[d]) {
+ dtree->expires[d] = 0;
++ map->elements--;
+ return 0;
+ }
+ return -EEXIST;
+}
+
+static int
-+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++delip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __delip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+#define LOOP_WALK_BEGIN(map, i, branch) \
-+ for (i = 0; i < 255; i++) { \
++ for (i = 0; i < 256; i++) { \
+ if (!(map)->tree[i]) \
+ continue; \
+ branch = (map)->tree[i]
+ struct ip_set_iptreeb *btree;
+ struct ip_set_iptreec *ctree;
+ struct ip_set_iptreed *dtree;
-+ unsigned char a,b,c,d;
++ unsigned int a,b,c,d;
+ unsigned char i,j,k;
+
+ i = j = k = 0;
+ LOOP_WALK_BEGIN(map, a, btree);
+ LOOP_WALK_BEGIN(btree, b, ctree);
+ LOOP_WALK_BEGIN(ctree, c, dtree);
-+ for (d = 0; d < 255; d++) {
++ for (d = 0; d < 256; d++) {
+ if (dtree->expires[d]) {
+ DP("gc: %u %u %u %u: expires %lu jiffies %lu",
+ a, b, c, d,
+ dtree->expires[d], jiffies);
+ if (map->timeout
-+ && time_before(dtree->expires[d], jiffies))
++ && time_before(dtree->expires[d], jiffies)) {
+ dtree->expires[d] = 0;
-+ else
++ map->elements--;
++ } else
+ k = 1;
+ }
+ }
+ }
+ LOOP_WALK_END;
+ write_unlock_bh(&set->lock);
++
++ map->gc.expires = jiffies + map->gc_interval * HZ;
++ add_timer(&map->gc);
++}
+
++static inline void init_gc_timer(struct ip_set *set)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++
++ /* Even if there is no timeout for the entries,
++ * we still have to call gc because delete
++ * do not clean up empty branches */
++ map->gc_interval = IPTREE_GC_TIME;
++ init_timer(&map->gc);
++ map->gc.data = (unsigned long) set;
++ map->gc.function = ip_tree_gc;
+ map->gc.expires = jiffies + map->gc_interval * HZ;
+ add_timer(&map->gc);
+}
+ }
+ memset(map, 0, sizeof(*map));
+ map->timeout = req->timeout;
++ map->elements = 0;
+ set->data = map;
+
-+ /* If there is no timeout for the entries,
-+ * we still have to call gc because delete
-+ * do not clean up empty branches */
-+ map->gc_interval = IPTREE_GC_TIME;
-+ init_timer(&map->gc);
-+ map->gc.data = (unsigned long) set;
-+ map->gc.function = ip_tree_gc;
-+ map->gc.expires = jiffies + map->gc_interval * HZ;
-+ add_timer(&map->gc);
++ init_gc_timer(set);
+
+ return 0;
+}
+ LOOP_WALK_END;
+ kmem_cache_free(branch_cachep, btree);
+ LOOP_WALK_END;
++ map->elements = 0;
+}
+
+static void destroy(struct ip_set *set)
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+
++ /* gc might be running */
+ while (!del_timer(&map->gc))
+ msleep(IPTREE_DESTROY_SLEEP);
+ __flush(map);
+{
+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
+ unsigned int timeout = map->timeout;
-+
++
++ /* gc might be running */
++ while (!del_timer(&map->gc))
++ msleep(IPTREE_DESTROY_SLEEP);
+ __flush(map);
+ memset(map, 0, sizeof(*map));
+ map->timeout = timeout;
++
++ init_gc_timer(set);
+}
+
+static void list_header(const struct ip_set *set, void *data)
+ struct ip_set_iptreeb *btree;
+ struct ip_set_iptreec *ctree;
+ struct ip_set_iptreed *dtree;
-+ unsigned char a,b,c,d;
++ unsigned int a,b,c,d;
+ unsigned int count = 0;
+
+ LOOP_WALK_BEGIN(map, a, btree);
+ LOOP_WALK_BEGIN(btree, b, ctree);
+ LOOP_WALK_BEGIN(ctree, c, dtree);
-+ for (d = 0; d < 255; d++) {
++ for (d = 0; d < 256; d++) {
+ if (dtree->expires[d]
+ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
+ count++;
+ struct ip_set_iptreeb *btree;
+ struct ip_set_iptreec *ctree;
+ struct ip_set_iptreed *dtree;
-+ unsigned char a,b,c,d;
++ unsigned int a,b,c,d;
+ size_t offset = 0;
+ struct ip_set_req_iptree *entry;
+
+ LOOP_WALK_BEGIN(map, a, btree);
+ LOOP_WALK_BEGIN(btree, b, ctree);
+ LOOP_WALK_BEGIN(ctree, c, dtree);
-+ for (d = 0; d < 255; d++) {
++ for (d = 0; d < 256; d++) {
+ if (dtree->expires[d]
+ && (!map->timeout || time_after(dtree->expires[d], jiffies))) {
+ entry = (struct ip_set_req_iptree *)(data + offset);
+ entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
-+ entry->timeout = !map->timeout ? 0
++ entry->timeout = !map->timeout ? 0
+ : (dtree->expires[d] - jiffies)/HZ;
+ offset += sizeof(struct ip_set_req_iptree);
+ }
+
+static struct ip_set_type ip_set_iptree = {
+ .typename = SETTYPE_NAME,
-+ .typecode = IPSET_TYPE_IP,
++ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("iptree type of IP sets");
++module_param(limit, int, 0600);
++MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
+
+static int __init init(void)
+{
+ int ret;
-+
++
+ branch_cachep = kmem_cache_create("ip_set_iptreeb",
+ sizeof(struct ip_set_iptreeb),
+ 0, 0, NULL, NULL);
+ goto out;
+
+ kmem_cache_destroy(leaf_cachep);
-+ free_branch:
++ free_branch:
+ kmem_cache_destroy(branch_cachep);
+ out:
+ return ret;
+module_exit(fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_macipmap.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_macipmap.c
--- linux-2.6.21.1/net/ipv4/netfilter/ip_set_macipmap.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_macipmap.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,338 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_macipmap.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,353 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the macipmap type */
+testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map = (struct ip_set_macipmap *) set->data;
-+ struct ip_set_macip *table = (struct ip_set_macip *) map->members;
++ struct ip_set_macip *table = (struct ip_set_macip *) map->members;
+ struct ip_set_req_macipmap *req = (struct ip_set_req_macipmap *) data;
+
+ if (size != sizeof(struct ip_set_req_macipmap)) {
+
+ *hash_ip = req->ip;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
-+ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
++ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
+ if (test_bit(IPSET_MACIP_ISSET,
+ (void *) &table[req->ip - map->first_ip].flags)) {
+ return (memcmp(req->ethernet,
+}
+
+static int
-+testip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+ struct ip_set_macip *table =
+ (struct ip_set_macip *) map->members;
+ ip_set_ip_t ip;
-+
-+ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr);
++
++ ip = ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
-+ flags & IPSET_SRC ? "SRC" : "DST",
++ flags[index] & IPSET_SRC ? "SRC" : "DST",
+ NIPQUAD(skb->nh.iph->saddr),
+ NIPQUAD(skb->nh.iph->daddr));
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return 0;
+
-+ *hash_ip = ip;
++ *hash_ip = ip;
+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
-+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
+ if (test_bit(IPSET_MACIP_ISSET,
+ (void *) &table[ip - map->first_ip].flags)) {
+ /* Is mac pointer valid?
+
+/* returns 0 on success */
+static inline int
-+__addip(struct ip_set *set,
++__addip(struct ip_set *set,
+ ip_set_ip_t ip, unsigned char *ethernet, ip_set_ip_t *hash_ip)
+{
+ struct ip_set_macipmap *map =
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
-+ if (test_and_set_bit(IPSET_MACIP_ISSET,
++ if (test_and_set_bit(IPSET_MACIP_ISSET,
+ (void *) &table[ip - map->first_ip].flags))
+ return -EEXIST;
+
+}
+
+static int
-+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++addip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ ip_set_ip_t ip;
-+
-+ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr);
++
++ ip = ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
+
+ if (!(skb->mac.raw >= skb->head
+ && (skb->mac.raw + ETH_HLEN) <= skb->data))
+
+ if (ip < map->first_ip || ip > map->last_ip)
+ return -ERANGE;
-+ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
++ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
+ (void *)&table[ip - map->first_ip].flags))
+ return -EEXIST;
+
+}
+
+static int
-+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++delip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __delip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big (max %d addresses)",
-+ MAX_RANGE);
++ MAX_RANGE+1);
+ return -ENOEXEC;
+ }
+
+ map->last_ip = req->to;
+ newbytes = members_size(map->first_ip, map->last_ip);
+ map->members = ip_set_malloc(newbytes);
++ DP("members: %u %p", newbytes, map->members);
+ if (!map->members) {
+ DP("out of memory for %d bytes", newbytes);
+ kfree(map);
+ return -ENOMEM;
+ }
+ memset(map->members, 0, newbytes);
-+
++
+ set->data = map;
+ return 0;
+}
+ struct ip_set_macipmap *map =
+ (struct ip_set_macipmap *) set->data;
+
++ DP("%u", members_size(map->first_ip, map->last_ip));
+ return members_size(map->first_ip, map->last_ip);
+}
+
+
+ int bytes = members_size(map->first_ip, map->last_ip);
+
++ DP("members: %u %p", bytes, map->members);
+ memcpy(data, map->members, bytes);
+}
+
+static struct ip_set_type ip_set_macipmap = {
+ .typename = SETTYPE_NAME,
-+ .typecode = IPSET_TYPE_IP,
++ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+module_exit(fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_nethash.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_nethash.c
--- linux-2.6.21.1/net/ipv4/netfilter/ip_set_nethash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_nethash.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,449 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_nethash.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,481 @@
+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing a cidr nethash set */
+#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set_nethash.h>
+#include <linux/netfilter_ipv4/ip_set_jhash.h>
-+#include <linux/netfilter_ipv4/ip_set_prime.h>
+
-+static inline __u32
-+jhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
-+{
-+ return jhash_1word(ip, map->initval);
-+}
++static int limit = MAX_RANGE;
+
+static inline __u32
-+randhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
++jhash_ip(const struct ip_set_nethash *map, uint16_t i, ip_set_ip_t ip)
+{
-+ return (1 + ip % map->prime);
++ return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
+}
+
+static inline __u32
+ unsigned char cidr,
+ ip_set_ip_t *hash_ip)
+{
-+ __u32 jhash, randhash, id;
++ __u32 id;
+ u_int16_t i;
++ ip_set_ip_t *elem;
+
+ *hash_ip = pack(ip, cidr);
-+ jhash = jhash_ip(map, *hash_ip);
-+ randhash = randhash_ip(map, *hash_ip);
-+
++
+ for (i = 0; i < map->probes; i++) {
-+ id = (jhash + i * randhash) % map->hashsize;
++ id = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ DP("hash key: %u", id);
-+ if (map->members[id] == *hash_ip)
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
++ if (*elem == *hash_ip)
+ return id;
+ }
+ return UINT_MAX;
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+
-+ return (hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
++ return (ip && hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
+}
+
+static inline int
+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+{
-+ return (hash_id(set, ip, hash_ip) != UINT_MAX);
++ return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
+}
+
+static int
+testip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_nethash *req =
++ struct ip_set_req_nethash *req =
+ (struct ip_set_req_nethash *) data;
+
+ if (size != sizeof(struct ip_set_req_nethash)) {
+}
+
+static int
-+testip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ return __testip(set,
-+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr),
++ ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
+ hash_ip);
+}
+
+static inline int
+__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
+{
-+ __u32 jhash, randhash, probe;
++ __u32 probe;
+ u_int16_t i;
-+
-+ jhash = jhash_ip(map, ip);
-+ randhash = randhash_ip(map, ip);
-+
++ ip_set_ip_t *elem;
++
+ for (i = 0; i < map->probes; i++) {
-+ probe = (jhash + i * randhash) % map->hashsize;
-+ if (map->members[probe] == ip)
++ probe = jhash_ip(map, i, ip) % map->hashsize;
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
++ if (*elem == ip)
+ return -EEXIST;
-+ if (!map->members[probe]) {
-+ map->members[probe] = ip;
++ if (!*elem) {
++ *elem = ip;
++ map->elements++;
+ return 0;
+ }
+ }
+__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
+ ip_set_ip_t *hash_ip)
+{
++ if (!ip || map->elements > limit)
++ return -ERANGE;
++
+ *hash_ip = pack(ip, cidr);
+ DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
-+
++
+ return __addip_base(map, *hash_ip);
+}
+
+{
+ unsigned char next;
+ int i;
-+
++
+ for (i = 0; i < 30 && map->cidr[i]; i++) {
+ if (map->cidr[i] == cidr) {
+ return;
+addip(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_ip)
+{
-+ struct ip_set_req_nethash *req =
++ struct ip_set_req_nethash *req =
+ (struct ip_set_req_nethash *) data;
+ int ret;
+
+ size);
+ return -EINVAL;
+ }
-+ ret = __addip((struct ip_set_nethash *) set->data,
++ ret = __addip((struct ip_set_nethash *) set->data,
+ req->ip, req->cidr, hash_ip);
-+
++
+ if (ret == 0)
+ update_cidr_sizes((struct ip_set_nethash *) set->data,
+ req->cidr);
-+
++
+ return ret;
+}
+
+static int
-+addip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++addip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ int ret = -ERANGE;
-+ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr);
-+
++ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
+ if (map->cidr[0])
+ ret = __addip(map, ip, map->cidr[0], hash_ip);
-+
++
+ return ret;
+}
+
+static int retry(struct ip_set *set)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
-+ ip_set_ip_t *members;
-+ u_int32_t i, hashsize;
-+ unsigned newbytes;
++ ip_set_ip_t *elem;
++ void *members;
++ u_int32_t i, hashsize = map->hashsize;
+ int res;
-+ struct ip_set_nethash tmp = {
-+ .hashsize = map->hashsize,
-+ .probes = map->probes,
-+ .resize = map->resize
-+ };
-+
++ struct ip_set_nethash *tmp;
++
+ if (map->resize == 0)
+ return -ERANGE;
+
-+ memcpy(tmp.cidr, map->cidr, 30 * sizeof(unsigned char));
+ again:
+ res = 0;
-+
++
+ /* Calculate new parameters */
-+ get_random_bytes(&tmp.initval, 4);
-+ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
-+ if (hashsize == tmp.hashsize)
++ hashsize += (hashsize * map->resize)/100;
++ if (hashsize == map->hashsize)
+ hashsize++;
-+ tmp.prime = make_prime(hashsize);
-+
++
+ ip_set_printk("rehashing of set %s triggered: "
+ "hashsize grows from %u to %u",
-+ set->name, tmp.hashsize, hashsize);
-+ tmp.hashsize = hashsize;
++ set->name, map->hashsize, hashsize);
+
-+ newbytes = hashsize * sizeof(ip_set_ip_t);
-+ tmp.members = ip_set_malloc_atomic(newbytes);
-+ if (!tmp.members) {
-+ DP("out of memory for %d bytes", newbytes);
++ tmp = kmalloc(sizeof(struct ip_set_nethash)
++ + map->probes * sizeof(uint32_t), GFP_ATOMIC);
++ if (!tmp) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_nethash)
++ + map->probes * sizeof(uint32_t));
+ return -ENOMEM;
+ }
-+ memset(tmp.members, 0, newbytes);
-+
++ tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
++ if (!tmp->members) {
++ DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
++ kfree(tmp);
++ return -ENOMEM;
++ }
++ tmp->hashsize = hashsize;
++ tmp->elements = 0;
++ tmp->probes = map->probes;
++ tmp->resize = map->resize;
++ memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
++ memcpy(tmp->cidr, map->cidr, 30 * sizeof(unsigned char));
++
+ write_lock_bh(&set->lock);
+ map = (struct ip_set_nethash *) set->data; /* Play safe */
+ for (i = 0; i < map->hashsize && res == 0; i++) {
-+ if (map->members[i])
-+ res = __addip_base(&tmp, map->members[i]);
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ if (*elem)
++ res = __addip_base(tmp, *elem);
+ }
+ if (res) {
+ /* Failure, try again */
+ write_unlock_bh(&set->lock);
-+ ip_set_free(tmp.members, newbytes);
++ harray_free(tmp->members);
++ kfree(tmp);
+ goto again;
+ }
-+
++
+ /* Success at resizing! */
+ members = map->members;
-+ hashsize = map->hashsize;
-+
-+ map->initval = tmp.initval;
-+ map->prime = tmp.prime;
-+ map->hashsize = tmp.hashsize;
-+ map->members = tmp.members;
++
++ map->hashsize = tmp->hashsize;
++ map->members = tmp->members;
+ write_unlock_bh(&set->lock);
+
-+ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
++ harray_free(members);
++ kfree(tmp);
+
+ return 0;
+}
+__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
+ ip_set_ip_t *hash_ip)
+{
-+ ip_set_ip_t id = hash_id_cidr(map, ip, cidr, hash_ip);
++ ip_set_ip_t id, *elem;
+
++ if (!ip)
++ return -ERANGE;
++
++ id = hash_id_cidr(map, ip, cidr, hash_ip);
+ if (id == UINT_MAX)
+ return -EEXIST;
-+
-+ map->members[id] = 0;
++
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
++ *elem = 0;
++ map->elements--;
+ return 0;
+}
+
+ size);
+ return -EINVAL;
+ }
-+ /* TODO: no garbage collection in map->cidr */
-+ return __delip((struct ip_set_nethash *) set->data,
++ /* TODO: no garbage collection in map->cidr */
++ return __delip((struct ip_set_nethash *) set->data,
+ req->ip, req->cidr, hash_ip);
+}
+
+static int
-+delip_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_ip)
++delip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_ip,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+ int ret = -ERANGE;
-+ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
-+ : skb->nh.iph->daddr);
-+
++ ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
++ ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
+ if (map->cidr[0])
+ ret = __delip(map, ip, map->cidr[0], hash_ip);
-+
++
+ return ret;
+}
+
+static int create(struct ip_set *set, const void *data, size_t size)
+{
-+ unsigned newbytes;
+ struct ip_set_req_nethash_create *req =
+ (struct ip_set_req_nethash_create *) data;
+ struct ip_set_nethash *map;
++ uint16_t i;
+
+ if (size != sizeof(struct ip_set_req_nethash_create)) {
+ ip_set_printk("data length wrong (want %zu, have %zu)",
+ ip_set_printk("hashsize too small");
+ return -ENOEXEC;
+ }
++ if (req->probes < 1) {
++ ip_set_printk("probes too small");
++ return -ENOEXEC;
++ }
+
-+ map = kmalloc(sizeof(struct ip_set_nethash), GFP_KERNEL);
++ map = kmalloc(sizeof(struct ip_set_nethash)
++ + req->probes * sizeof(uint32_t), GFP_KERNEL);
+ if (!map) {
+ DP("out of memory for %d bytes",
-+ sizeof(struct ip_set_nethash));
++ sizeof(struct ip_set_nethash)
++ + req->probes * sizeof(uint32_t));
+ return -ENOMEM;
+ }
-+ get_random_bytes(&map->initval, 4);
-+ map->prime = make_prime(req->hashsize);
++ for (i = 0; i < req->probes; i++)
++ get_random_bytes(((uint32_t *) map->initval)+i, 4);
++ map->elements = 0;
+ map->hashsize = req->hashsize;
+ map->probes = req->probes;
+ map->resize = req->resize;
+ memset(map->cidr, 0, 30 * sizeof(unsigned char));
-+ newbytes = map->hashsize * sizeof(ip_set_ip_t);
-+ map->members = ip_set_malloc(newbytes);
++ map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
+ if (!map->members) {
-+ DP("out of memory for %d bytes", newbytes);
++ DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
+ kfree(map);
+ return -ENOMEM;
+ }
-+ memset(map->members, 0, newbytes);
-+
++
+ set->data = map;
+ return 0;
+}
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
+
-+ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
++ harray_free(map->members);
+ kfree(map);
+
+ set->data = NULL;
+static void flush(struct ip_set *set)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
-+ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
++ harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
+ memset(map->cidr, 0, 30 * sizeof(unsigned char));
++ map->elements = 0;
+}
+
+static void list_header(const struct ip_set *set, void *data)
+static void list_members(const struct ip_set *set, void *data)
+{
+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
-+ int bytes = map->hashsize * sizeof(ip_set_ip_t);
++ ip_set_ip_t i, *elem;
+
-+ memcpy(data, map->members, bytes);
++ for (i = 0; i < map->hashsize; i++) {
++ elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
++ ((ip_set_ip_t *)data)[i] = *elem;
++ }
+}
+
+static struct ip_set_type ip_set_nethash = {
+ .typename = SETTYPE_NAME,
-+ .typecode = IPSET_TYPE_IP,
++ .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("nethash type of IP sets");
++module_param(limit, int, 0600);
++MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
+
+static int __init init(void)
+{
+module_exit(fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ip_set_portmap.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_portmap.c
--- linux-2.6.21.1/net/ipv4/netfilter/ip_set_portmap.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_portmap.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,325 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ip_set_portmap.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,334 @@
+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing a port set type as a bitmap */
+ switch (iph->protocol) {
+ case IPPROTO_TCP: {
+ struct tcphdr tcph;
-+
++
+ /* See comments at tcp_match in ip_tables.c */
+ if (offset)
+ return INVALID_PORT;
+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
+ /* No choice either */
+ return INVALID_PORT;
-+
++
+ return ntohs(flags & IPSET_SRC ?
+ tcph.source : tcph.dest);
+ }
+ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
+ /* No choice either */
+ return INVALID_PORT;
-+
++
+ return ntohs(flags & IPSET_SRC ?
+ udph.source : udph.dest);
+ }
+
+ if (port < map->first_port || port > map->last_port)
+ return -ERANGE;
-+
++
+ *hash_port = port;
+ DP("set: %s, port:%u, %u", set->name, port, *hash_port);
+ return !!test_bit(port - map->first_port, map->members);
+testport(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_port)
+{
-+ struct ip_set_req_portmap *req =
++ struct ip_set_req_portmap *req =
+ (struct ip_set_req_portmap *) data;
+
+ if (size != sizeof(struct ip_set_req_portmap)) {
+}
+
+static int
-+testport_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_port)
++testport_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_port,
++ const u_int32_t *flags,
++ unsigned char index)
+{
+ int res;
-+ ip_set_ip_t port = get_port(skb, flags);
++ ip_set_ip_t port = get_port(skb, flags[index]);
+
-+ DP("flag %s port %u", flags & IPSET_SRC ? "SRC" : "DST", port);
++ DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
+ if (port == INVALID_PORT)
-+ return 0;
++ return 0;
+
+ res = __testport(set, port, hash_port);
-+
++
+ return (res < 0 ? 0 : res);
+}
+
+ return -ERANGE;
+ if (test_and_set_bit(port - map->first_port, map->members))
+ return -EEXIST;
-+
++
+ *hash_port = port;
+ DP("port %u", port);
+ return 0;
+addport(struct ip_set *set, const void *data, size_t size,
+ ip_set_ip_t *hash_port)
+{
-+ struct ip_set_req_portmap *req =
++ struct ip_set_req_portmap *req =
+ (struct ip_set_req_portmap *) data;
+
+ if (size != sizeof(struct ip_set_req_portmap)) {
+}
+
+static int
-+addport_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_port)
-+{
-+ ip_set_ip_t port = get_port(skb, flags);
-+
++addport_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_port,
++ const u_int32_t *flags,
++ unsigned char index)
++{
++ ip_set_ip_t port = get_port(skb, flags[index]);
++
+ if (port == INVALID_PORT)
+ return -EINVAL;
+
+ return -ERANGE;
+ if (!test_and_clear_bit(port - map->first_port, map->members))
+ return -EEXIST;
-+
++
+ *hash_port = port;
+ DP("port %u", port);
+ return 0;
+}
+
+static int
-+delport_kernel(struct ip_set *set, const struct sk_buff *skb,
-+ u_int32_t flags, ip_set_ip_t *hash_port)
-+{
-+ ip_set_ip_t port = get_port(skb, flags);
-+
++delport_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ ip_set_ip_t *hash_port,
++ const u_int32_t *flags,
++ unsigned char index)
++{
++ ip_set_ip_t port = get_port(skb, flags[index]);
++
+ if (port == INVALID_PORT)
+ return -EINVAL;
+
+
+ if (req->to - req->from > MAX_RANGE) {
+ ip_set_printk("range too big (max %d ports)",
-+ MAX_RANGE);
++ MAX_RANGE+1);
+ return -ENOEXEC;
+ }
+
+
+static struct ip_set_type ip_set_portmap = {
+ .typename = SETTYPE_NAME,
-+ .typecode = IPSET_TYPE_PORT,
++ .features = IPSET_TYPE_PORT | IPSET_DATA_SINGLE,
+ .protocol_version = IP_SET_PROTOCOL_VERSION,
+ .create = &create,
+ .destroy = &destroy,
+module_exit(fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ipt_set.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_set.c
--- linux-2.6.21.1/net/ipv4/netfilter/ipt_set.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_set.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,105 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_set.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,142 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* Kernel module to match an IP set. */
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
++#include <linux/version.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+match_set(const struct ipt_set_info *info,
+ const struct sk_buff *skb,
+ int inv)
-+{
++{
+ if (ip_set_testip_kernel(info->index, skb, info->flags))
+ inv = !inv;
+ return inv;
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
+ const struct xt_match *match,
++#endif
+ const void *matchinfo,
-+ int offset,
-+ unsigned int protoff,
-+ int *hotdrop)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
++ int offset, unsigned int protoff, int *hotdrop)
++#else
++ int offset, int *hotdrop)
++#endif
+{
+ const struct ipt_set_info_match *info = matchinfo;
-+
++
+ return match_set(&info->match_set,
+ skb,
+ info->match_set.flags[0] & IPSET_MATCH_INV);
+
+static int
+checkentry(const char *tablename,
-+ const void *ip,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
++ const void *inf,
++#else
++ const struct ipt_ip *ip,
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
+ const struct xt_match *match,
++#endif
+ void *matchinfo,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ unsigned int matchsize,
++#endif
+ unsigned int hook_mask)
+{
-+ struct ipt_set_info_match *info =
++ struct ipt_set_info_match *info =
+ (struct ipt_set_info_match *) matchinfo;
+ ip_set_id_t index;
+
-+ index = ip_set_get_byindex(info->match_set.index);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
++ ip_set_printk("invalid matchsize %d", matchsize);
++ return 0;
++ }
++#endif
+
++ index = ip_set_get_byindex(info->match_set.index);
++
+ if (index == IP_SET_INVALID_ID) {
+ ip_set_printk("Cannot find set indentified by id %u to match",
+ info->match_set.index);
+ return 1;
+}
+
-+static void destroy(const struct xt_match *match, void *matchinfo)
++static void destroy(
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_match *match,
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ void *matchinfo, unsigned int matchsize)
++#else
++ void *matchinfo)
++#endif
+{
+ struct ipt_set_info_match *info = matchinfo;
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
++ ip_set_printk("invalid matchsize %d", matchsize);
++ return;
++ }
++#endif
+ ip_set_put(info->match_set.index);
+}
+
+static struct ipt_match set_match = {
+ .name = "set",
+ .match = &match,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
+ .matchsize = sizeof(struct ipt_set_info_match),
++#endif
+ .checkentry = &checkentry,
+ .destroy = &destroy,
+ .me = THIS_MODULE
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("iptables IP set match module");
+
-+static int __init init(void)
++static int __init ipt_ipset_init(void)
+{
-+ return ipt_register_match(&set_match);
++ return xt_register_match(&set_match);
+}
+
-+static void __exit fini(void)
++static void __exit ipt_ipset_fini(void)
+{
-+ ipt_unregister_match(&set_match);
++ xt_unregister_match(&set_match);
+}
+
-+module_init(init);
-+module_exit(fini);
++module_init(ipt_ipset_init);
++module_exit(ipt_ipset_fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/ipt_SET.c linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_SET.c
--- linux-2.6.21.1/net/ipv4/netfilter/ipt_SET.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_SET.c 2007-05-14 11:44:19.000000000 +0200
-@@ -0,0 +1,120 @@
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/ipt_SET.c 2007-05-23 23:04:36.000000000 +0200
+@@ -0,0 +1,160 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ * Patrick Schaaf <bof@bof.de>
+ * Martin Josefsson <gandalf@wlug.westbo.se>
+ *
+ * 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.
++ * published by the Free Software Foundation.
+ */
+
+/* ipt_SET.c - netfilter target to manipulate IP sets */
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/inetdevice.h>
++#include <linux/version.h>
+#include <net/protocol.h>
+#include <net/checksum.h>
+#include <linux/netfilter_ipv4.h>
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
+ const struct xt_target *target,
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ const void *targinfo,
++ void *userinfo)
++#else
+ const void *targinfo)
++#endif
+{
+ const struct ipt_set_info_target *info = targinfo;
-+
++
+ if (info->add_set.index != IP_SET_INVALID_ID)
+ ip_set_addip_kernel(info->add_set.index,
+ *pskb,
+
+static int
+checkentry(const char *tablename,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+ const void *e,
++#else
++ const struct ipt_entry *e,
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
+ const struct xt_target *target,
++#endif
+ void *targinfo,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ unsigned int targinfosize,
++#endif
+ unsigned int hook_mask)
+{
-+ struct ipt_set_info_target *info =
++ struct ipt_set_info_target *info =
+ (struct ipt_set_info_target *) targinfo;
+ ip_set_id_t index;
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ if (targinfosize != IPT_ALIGN(sizeof(*info))) {
++ DP("bad target info size %u", targinfosize);
++ return 0;
++ }
++#endif
++
+ if (info->add_set.index != IP_SET_INVALID_ID) {
+ index = ip_set_get_byindex(info->add_set.index);
+ if (index == IP_SET_INVALID_ID) {
+ return 1;
+}
+
-+static void destroy(const struct xt_target *target, void *targetinfo)
++static void destroy(
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
++ const struct xt_target *target,
++#endif
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ void *targetinfo, unsigned int targetsize)
++#else
++ void *targetinfo)
++#endif
+{
+ struct ipt_set_info_target *info = targetinfo;
+
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++ if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
++ ip_set_printk("invalid targetsize %d", targetsize);
++ return;
++ }
++#endif
+ if (info->add_set.index != IP_SET_INVALID_ID)
+ ip_set_put(info->add_set.index);
+ if (info->del_set.index != IP_SET_INVALID_ID)
+static struct ipt_target SET_target = {
+ .name = "SET",
+ .target = target,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
+ .targetsize = sizeof(struct ipt_set_info_target),
++#endif
+ .checkentry = checkentry,
+ .destroy = destroy,
+ .me = THIS_MODULE
+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
+MODULE_DESCRIPTION("iptables IP set target module");
+
-+static int __init init(void)
++static int __init ipt_SET_init(void)
+{
+ return xt_register_target(&SET_target);
+}
+
-+static void __exit fini(void)
++static void __exit ipt_SET_fini(void)
+{
-+ ipt_unregister_target(&SET_target);
++ xt_unregister_target(&SET_target);
+}
+
-+module_init(init);
-+module_exit(fini);
++module_init(ipt_SET_init);
++module_exit(ipt_SET_fini);
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/Kconfig linux-2.6.21.1-owrt/net/ipv4/netfilter/Kconfig
---- linux-2.6.21.1/net/ipv4/netfilter/Kconfig 2007-05-14 11:24:57.000000000 +0200
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/Kconfig 2007-05-14 11:44:19.000000000 +0200
-@@ -681,5 +681,106 @@
- Allows altering the ARP packet payload: source and destination
- hardware and network addresses.
+--- linux-2.6.21.1/net/ipv4/netfilter/Kconfig 2007-05-23 20:34:11.000000000 +0200
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/Kconfig 2007-05-23 23:04:36.000000000 +0200
+@@ -674,5 +674,114 @@
+ Documentation/modules.txt. The module will be called ipt_ROUTE.o.
+ If unsure, say `N'.
+config IP_NF_SET
+ tristate "IP set support"
+ range 2 65534
+ depends on IP_NF_SET
+ help
-+ You can define here default value of the maximum number
++ You can define here default value of the maximum number
+ of IP sets for the kernel.
+
+ The value can be overriden by the 'max_sets' module
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config IP_NF_SET_IPPORTHASH
++ tristate "ipporthash set support"
++ depends on IP_NF_SET
++ help
++ This option adds the ipporthash set type support.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+config IP_NF_SET_IPTREE
+ tristate "iptree set support"
+ depends on IP_NF_SET
endmenu
diff -Nur linux-2.6.21.1/net/ipv4/netfilter/Makefile linux-2.6.21.1-owrt/net/ipv4/netfilter/Makefile
---- linux-2.6.21.1/net/ipv4/netfilter/Makefile 2007-05-14 11:24:57.000000000 +0200
-+++ linux-2.6.21.1-owrt/net/ipv4/netfilter/Makefile 2007-05-14 11:47:22.000000000 +0200
-@@ -83,6 +83,7 @@
- obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
-
- # matches
+--- linux-2.6.21.1/net/ipv4/netfilter/Makefile 2007-05-23 20:34:11.000000000 +0200
++++ linux-2.6.21.1-owrt/net/ipv4/netfilter/Makefile 2007-05-23 23:04:36.000000000 +0200
+@@ -90,6 +90,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
- obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
- obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
- obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
-@@ -107,6 +108,16 @@
+ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
+
+ # targets
+@@ -106,6 +107,17 @@
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
+obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o
+obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o
+obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o
++obj-$(CONFIG_IP_NF_SET_IPPORTHASH) += ip_set_ipporthash.o
+obj-$(CONFIG_IP_NF_SET_IPTREE) += ip_set_iptree.o
# generic ARP tables