[
  {
    "path": "020-mips-hz1000.patch",
    "content": "--- include/asm-mips/param_orig.h\t2010-02-23 12:45:58.000000000 +0100\n+++ include/asm-mips/param.h\t2010-02-23 12:00:31.000000000 +0100\n@@ -41,7 +41,7 @@\n    counter is increasing.  This value is independent from the external value\n    and can be changed in order to suit the hardware and application\n    requirements.  */\n-#  define HZ 100\n+#  define HZ 1000\n #  define hz_to_std(a) (a)\n \n #endif /* Not a DECstation  */\n"
  },
  {
    "path": "Makefile",
    "content": "# $Id: Makefile 11689 2012-08-12 21:07:34Z luigi $\n#\n# Top level makefile for building ipfw/dummynet (kernel and userspace).\n# You can run it manually or also under the Planetlab build.\n# Planetlab wants also the 'install' target.\n#\n# To build on system with non standard Kernel sources or userland files,\n# you should run this with\n#\n#\tmake KERNELPATH=/path/to/linux-2.x.y.z USRDIR=/path/to/usr\n#\n# We assume that $(USRDIR) contains include/ and lib/ used to build userland.\n#\n\ninclude Makefile.inc\n\nDATE ?= $(shell date +%Y%m%d)\nSNAPSHOT_NAME=$(DATE)-ipfw3.tgz\nBINDIST=$(DATE)-dummynet-linux.tgz\nWINDIST=$(DATE)-dummynet-windows.zip\n\nDISTFILES= Makefile Makefile.inc README binary* ipfw kipfw *.h sys\n\n.PHONY: ipfw kipfw\n\n###########################################\n#  windows x86 and x64 specific variables #\n###########################################\n#  DRIVE must be the hard drive letter where DDK is installed\n#  DDKDIR must be the path to the DDK root directory, without drive letter\n#  TARGETOS (x64 only) must be one of the following:\n#  wnet   -> windows server 2003\n#  wlh    -> windows vista and windows server 2008\n#  win7   -> windows 7\n#  future version must be added here\nDRIVE ?= C:\nDDKDIR ?= /WinDDK/7600.16385.1\nDDK = $(DRIVE)$(DDKDIR)\nTARGETOS=win7\n\nexport WIN64\nexport DDK\nexport DRIVE\nexport DDKDIR\n\n_all: all\n\nclean distclean:\n\t-@(cd ipfw && $(MAKE) $(@) )\n\t-@rm -rf kipfw-mod binary64/[A-hj-z]*\n\nall: kipfw ipfw\n\t@# -- windows only\nifeq ($(OSARCH),Windows)\t# copy files\nifeq ($(WIN64),)\n\t-@ cp ipfw/ipfw.exe kipfw-mod/$(OBJDIR)/ipfw.sys binary/\n\t-@ cp kipfw/*.inf binary/\nelse\n\t-@ cp binary/* kipfw/*.inf binary64/\n\t-@ cp ipfw/ipfw.exe kipfw-mod/objchk_win7_amd64/amd64/ipfw.sys binary64/\nendif\t# WIN64\nendif\t# Windows\n\nwin64:\n\t$(MAKE) WIN64=1\n\n# kipfw-src prepares the sources for the kernel part.\n# The windows files (passthru etc.) are modified version of the\n# examples found in the $(DDK)/src/network/ndis/passthru/driver/\n# They can be re-created using the 'ndis-glue' target\n# # We need a sed trick to remove newlines from the patchfile.\n\nndis-glue:\n\t-@mkdir -p kipfw-mod\n\tcp $(DDK)/src/network/ndis/passthru/driver/*.[ch] kipfw-mod\n\t(cd kipfw-mod; for i in  `find . -type f`; do sed -i.tmp \"s/$$(printf '\\r')//g\" $$i; done )\n\tcat kipfw/win-passthru.diff | sed \"s/$$(printf '\\r')//g\" | (cd kipfw-mod; patch )\n\nkipfw-src:\n\t-@rm -rf kipfw-mod\n\t-@mkdir -p kipfw-mod\n\t-@cp -Rp kipfw/* kipfw-mod\n\t-@cp `find sys -name \\*.c` kipfw-mod\n\t-@(cd kipfw-mod && $(MAKE) include_e)\nifeq ($(OSARCH),Windows)\n\tmake ndis-glue\nendif\n\nsnapshot:\n\t$(MAKE) distclean\n\t(tar cvzhf /tmp/$(SNAPSHOT_NAME) -s':^:ipfw3-2012/:' $(DISTFILES) )\n\nbindist:\n\t$(MAKE) clean\n\t$(MAKE) all\n\ttar cvzf /tmp/$(BINDIST) ipfw/ipfw ipfw/ipfw.8 kipfw-mod/ipfw_mod.ko\n\nwindist:\n\t$(MAKE) clean\n\t-$(MAKE) all\n\t-rm /tmp/$(WINDIST)\n\tzip -r /tmp/$(WINDIST) binary -x \\*.svn\\*\n\n\nipfw:\n\t@(cd ipfw && $(MAKE) $(@) )\n\nkipfw: kipfw-src\nifeq ($(WIN64),)\t# linux or windows 32 bit\n\t@(cd kipfw-mod && $(MAKE) $(@) )\nelse\t#--- windows 64 bit, we use build.exe and nmake\n\trm -f kipfw-mod/Makefile\n\tmkdir kipfw-mod/tmpbuild\t\t# check mysetenv.sh\n\tbash kipfw/mysetenv.sh $(DRIVE) $(DDKDIR) $(TARGETOS)\nendif\n\nopenwrt_release:\n\t# create a temporary directory\n\t$(eval TMPDIR := $(shell mktemp -d -p /tmp/ ipfw3_openwrt_XXXXX))\n\t# create the source destination directory\n\t$(eval IPFWDIR := ipfw3-$(DATE))\n\t$(eval DSTDIR := $(TMPDIR)/$(IPFWDIR))\n\tmkdir $(DSTDIR)\n\t# copy the package, clean objects and svn info\n\tcp -r ./ipfw ./kipfw-mod glue.h Makefile ./configuration README $(DSTDIR)\n\t(cd $(DSTDIR); make -s distclean; find . -name .svn | xargs rm -rf)\n\t(cd $(TMPDIR); tar czf $(IPFWDIR).tar.gz $(IPFWDIR))\n\n\t# create the port files in /tmp/ipfw3-port\n\t$(eval PORTDIR := $(TMPDIR)/ipfw3)\n\tmkdir -p $(PORTDIR)/patches\n\t# generate the Makefile, PKG_VERSION and PKG_MD5SUM\n\tmd5sum $(DSTDIR).tar.gz | cut -d ' ' -f 1 > $(TMPDIR)/md5sum\n\tcat ./OPENWRT/Makefile | \\\n\t\tsed s/PKG_VERSION:=/PKG_VERSION:=$(DATE)/ | \\\n\t\tsed s/PKG_MD5SUM:=/PKG_MD5SUM:=`cat $(TMPDIR)/md5sum`/ \\\n\t\t> $(PORTDIR)/Makefile\n\n\t@echo \"\"\n\t@echo \"The openwrt port is in $(TMPDIR)/ipfw3-port\"\n\t@echo \"The source file should be copied to the public server:\"\n\t@echo \"scp $(DSTDIR).tar.gz marta@info.iet.unipi.it:~marta/public_html/dummynet\"\n\t@echo \"after this the temporary directory $(TMPDIR) can be removed.\"\n\ninstall:\n\ndiff:\n\t-@(diff -upr $(BSD_HEAD)/sbin/ipfw ipfw)\n\t-@(diff -upr $(BSD_HEAD)/sys sys)\n\n"
  },
  {
    "path": "Makefile.inc",
    "content": "# $Id$\n# GNU makefile header for ipfw/kipfw building\nBSD_HEAD ?= ~/FreeBSD/head\nOSARCH := $(shell uname)\nOSARCH := $(findstring $(OSARCH),FreeBSD Linux Darwin)\nifeq ($(OSARCH),)\n    OSARCH := Windows\nendif\nOBJDIR=mia\n\nKSRC ?= /lib/modules/$(shell uname -r)/build\nifneq ($V,1) # no echo\n    MSG=@echo\n    HIDE=@\nelse\n    MSG=@\\#\n    HIDE=\nendif\n\n.c.o:\n\t$(MSG) \"   CC $<\"\n\t$(HIDE) $(CC) $(CFLAGS) -c $< -o $@\n\n"
  },
  {
    "path": "Makefile.openwrt",
    "content": "# Makefile to build the package in openwrt.\n# goes into package/network/utils/ipfw3/Makefile\n#\n# Edit IPFW_DIR to point to the directory with the sources for ipfw\n\nIPFW_DIR := $(TOPDIR)/../qemu-misc/ipfw3\n\ninclude $(TOPDIR)/rules.mk\ninclude $(INCLUDE_DIR)/kernel.mk\n\nPKG_NAME:=ipfw3\nPKG_RELEASE:=1\n\n# MV is undefined, we use it in the internal Makefiles\nMV ?= mv\n\ninclude $(INCLUDE_DIR)/package.mk\n\n#Stuff depending on kernel version\n$(warning --- openwrt kernel version $(KERNEL) linux dir $(LINUX_DIR) -------)\n\nifeq ($(KERNEL),2.4)\n    VERS:=openwrt\n    CFLAGS_WRT:=-DSYSCTL_NODE -DEMULATE_SYSCTL\n    IPFW_MOD:=ipfw_mod.o\n    IPFW_SRC_DIR:=SUBDIRS\nelse\n    #VERS:=2.6\n    IPFW_MOD:=ipfw_mod.ko\n    IPFW_SRC_DIR:=M\nendif\n\ndefine Package/ipfw3\n  SECTION:=utils\n  CATEGORY:=Utilities\n  TITLE := /sbin/ipfw\n  DEPENDS := +libc +libgcc\n  FILES := $(PKG_BUILD_DIR)/ipfw/ipfw\n  $(warning --- build dir is $(PKG_BUILD_DIR) ---)\nendef\n\ndefine Package/ipfw3/description\n  Control program for ipfw and dummynet\nendef\n\n# XXX not entirely clear why the install entry for userland works,\n# given that /sbin/ipfw is in KernelPackage/ipfw3\n\ndefine Package/ipfw3/install\n\t$(INSTALL_DIR) $(1) /sbin\nendef\n\n# Description for the package.\n# The names KernelPackage/ipfw3 must match the arguments to the\n# call $(eval $(call KernelPackage,ipfw3)) used to build it\n\ndefine KernelPackage/ipfw3\n  SUBMENU:=Other modules\n  TITLE:= IPFW and dummynet\n  # FILES is what makes up the module, both kernel and userland\n  # It must be in the KernelPackage section XXX\n  FILES := $(PKG_BUILD_DIR)/kipfw-mod/$(IPFW_MOD)\n  # AUTOLOAD:=$(call AutoLoad,80,ipfw_mod)\nendef\n\ndefine KernelPackage/kmod-ipfw3/description\n  ipfw and dummynet kernel module\nendef\n\n# Standard entries for the openwrt builds: Build/Prepare and Build/Compile\n# Remember that commands must start with a tab\n\n# 'prepare' instructions for both kernel and userland\n# We copy the entire subtree, then build include_e/ which\n# contains empty headers used by the kernel sources.\ndefine Build/Prepare\n  # $(warning --- Preparing ipfw sources ---)\n\tmkdir -p $(PKG_BUILD_DIR)\n\t$(CP) -Rp $(IPFW_DIR)/* $(PKG_BUILD_DIR)/\n\t# The kernel sources are spread in multiple places,\n\t# so we put everything in kipfw-mod\n\tmkdir -p $(PKG_BUILD_DIR)/kipfw-mod\n\tcp -Rp $(IPFW_DIR)/kipfw/* $(PKG_BUILD_DIR)/kipfw-mod\n\tcp `find $(IPFW_DIR)/sys -name \\*.c` $(PKG_BUILD_DIR)/kipfw-mod\n\t# we do not need cross parameters\n\t(cd $(PKG_BUILD_DIR)/ipfw && $(MAKE) include_e )\n\t(cd $(PKG_BUILD_DIR)/kipfw-mod && $(MAKE) include_e )\nendef\n\ndefine Build/Compile\n\t# XXX check whether we need all linux_dir etc.\n\t$(warning --- compile the user part for ipfw/openwrt ---)\n\t$(MAKE) -C $(PKG_BUILD_DIR)/ipfw \\\n\t\tLINUX_DIR=$(LINUX_DIR) \\\n\t\t$(TARGET_CONFIGURE_OPTS) \\\n\t\tCFLAGS=\"$(TARGET_CFLAGS) $(CFLAGS_WRT) -I./include_e -I./include -include ../glue.h -DNO_ALTQ -D__BSD_VISIBLE\" \\\n\t\t_VER=$(VERS) all\n\t$(warning --- compile the kernel part for ipfw/openwrt ---)\n\t$(MAKE) -C \"$(LINUX_DIR)\" \\\n\t\tCROSS_COMPILE=\"$(TARGET_CROSS)\" \\\n\t\tLINUX_DIR=$(LINUX_DIR) \\\n\t\tKERNELPATH=$(LINUX_DIR) \\\n\t\tARCH=\"$(LINUX_KARCH)\" \\\n\t\t$(IPFW_SRC_DIR)=\"$(PKG_BUILD_DIR)/kipfw-mod\" \\\n\t\tIPFW3_ROOT=\"$(PKG_BUILD_DIR)\" \\\n\t\t_VER=$(VERS) modules\n\t$(warning +++ done compile the kernel part for ipfw/openwrt ---)\nendef\n\n\n$(eval $(call BuildPackage,ipfw3))\n$(eval $(call KernelPackage,ipfw3))\n"
  },
  {
    "path": "NOTES",
    "content": "#\n# $Id: NOTES 6552 2010-06-15 11:24:59Z svn_panicucci $\n#\n\n---------------------------------------------------------------------\n---  DEVELOPER NOTES ------------------------------------------------\n\nBoth the client and the kernel code use almost unmodified sources\nfrom FreeBSD (just a very small number of sections #ifdef'ed out\nfor features not relevant or not implemented).\n\nIn both cases we provide two set of headers:\n - one set is made of empty files, automatically generated, to replace\n   FreeBSD headers not available or conflicting on the ported platforms.\n - one set is made of custom files, sometimes copied verbatim\n   from FreeBSD, sometimes containing only the minimal set of\n   macros/ struct/ prototypes required by the port.\n\nAdditionally, we have a small set of .c files providing functions not\navailable in the port platforms, and hooks for the sockopt/packet\ndata.\n\n\nTODO 20100205:\n+ use an appropriate identifier instead of LINUX24\n+ find the discharging module hook, in order to force a queue flush\n+ better matching on interface names (case insensitive etc ?)\n+ match by interface address\n+ verify path\n+ send keepalives (20100301 marta: implemented)\n+ pullup of data in external buffers\n+ O_TAG\n+ O_DIVERT\n+ O_TEE\n+ O_SETFIB\n+ kmem_cache_alloc \n\nTODO (OpenWRT) 20090622\n+ add a module compilation for 2.6\n\nTODO (FreeBSD, general)\n+ New features related to the forthcoming IPv6 are missing, as the IPv6\nsupport for lookup tables that currently support IPv4 addresses only.\nOne of the goal of this project is to add the tables feature to the\nIPv6 protocol.\n\n+ The current code implements rules listing requests as a single\nrequest returning both static and dynamic rules as a whole block. This\noperation requires a lock to be held for the time needed to get the\nfull list of rules, regardless of the requested rules.  I propose to\nbreak up the rule request in two parts, for static and dynamic rules, in\norder to avoid to lock the whole struct for a subset of rules required.\n\n+ At last, due to improvement and contribution to the code, the tool\nsignificantly grown over the time with new functionalities and features,\nleaving the general view aside. An example of this will be the use of\ndispatching table instead some very long switch case, making the resulting\ncode more readable and hopefully a faster execution.\n\n+ XXX can't find the ipfw_* indirection...\n\nDETAILED PORTING INFO\n\n--- ipfw (userland) on linux ---\n\nThe port is relatively trivial. Communication with the kernel occurs\nthrough a raw socket using [gs]etsockopt(), and all is needed is the\navailability of ip_fw.h and ip_dummynet.h headers to describe the\nrelevant data structures.\n\n--- kernel ipfw on linux ---\n\nSources are mostly unmodified, except for commenting out\nunsupported features (tables, in-kernel nat...).\nThe port requires a rather large number of empty headers.\nOther porting issues are in ipfw2_mod.c\n\n--- build as an Openwrt package\n\n------ WINDOWS PORT ------\n\nWe started from the wipfw port available at [WIPFW] , but\nmost of the port is done from scratch using the most recent\nversion of ipfw+dummynet from HEAD/RELENG_7 as of March 2009\n\n# WIPFW: wipfw.sourceforge.net\n#binary:\nhttp://downloads.sourceforge.net/wipfw/wipfw-0.3.2b.zip?use_mirror=mesh\nhttp://downloads.sourceforge.net/wipfw/wipfw-0.2.8-source.zip\n\n--- DEVELOPMENT TOOLS:\n\nAt least initially, to build the code you need a pc with\nwindows installed and the [WINDDK] from the microsoft site.\nOther tools like the new WDK should work as well.\n\nThe 'standard' way used by WDK/WINDDK is to run a 'build'\nscript which in turn calls nmake and then the microsoft\ncompiler [CL] and linker [LINK]. See the documentation for\ncommand line switches for these tools, they are similar but\nnot the same as the equivalent gcc switches. In particular,\na / is often used to replace - though both forms are accepted.\n\nThe steps to do in order to launch the build environment follows:\n\n + download winddk from microsoft.com \n + install \n + run the Free Build Enviroment from:\n\n\tStart -> All Program -> WINDDK ->\n\t[NT|XP|2000] -> Free Build Environment\n\n + change dir to .src and type `build' in command line\n\nFor our purposes, however, it is much more convenient to use\ncygwin [CYGWIN] and invoke CL and LINK using gmake\n\nA debugging tools is:\n\thttp://technet.microsoft.com/en-us/sysinternals/bb896647.aspx\nit simply display the kernel-mode debug output.\nUse the DbgPrint() function, that is something similar to printk().\nCan be lauched with dbgview.exe.\n\nAfter a succesfully compilation and link, you can launch the program\nin user space simply executing the binary file, while for the kernel\nspace you need to do the following steps:\n\ncp ipfw.sys /cygdrive/c/WINDOWS/system32/drivers/\nipfw install_drv System32\\DRIVERS\\ip_fw.sys\nnet start ip_fw\n\n\n=======\n--- ARCHITECTURE ---\n\nThe main part of the userland program mostly work as the\nunix equivalent, the only issue is to provide empty\nheader files to replace those not available in Windows,\nand include the winsock2 headers to access some network\nrelated functions and headers.\n\nCommunication with the kernel module does not use a raw IP socket\nas in the unix version. Instead, we inherit the same method\nused in ipfw -- a replacement for socket() creates a handle\nto access the control structure, and setsockopt/getsockopt\nreplacements are also used to communicate with the kernel\nside. This is implemented in win32.c\n\nIn order to load the module and activate it, we also use\nthe same technique suggested in wipfw -- the main() is\nextended (with a wrapper) so that it can handle additional\ncommands to install/control/deinstall the service and\ncall the appropriate actions. See svcmain.c for details.\n\n--- PORTING ISSUES:\n\nMost of the unix hierarchy of headers is not available so we\nhave to replicate them.\n\ngcc attributes are also not present.\n\nC99 types are not present, remapped in <sys/cdefs.h>\nAlso, we don't have C99 initializers which sometimes gives trouble.\n\n--- USEFUL LINKS:\n\n[WIPFW]\n\thttp://wipfw.sourceforge.net/\n\n[WINDDK]\n\thttp://www.microsoft.com/whdc/devtools/ddk/default.mspx\n\n[CL]\n\thttp://msdn.microsoft.com/en-us/library/610ecb4h.aspx\n\tcommand line syntax\n\n[CYGWIN]\n\thttp://www.cygwin.com/setup.exe\nWindows Driver Kit\nhttp://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx\n\nDebug Symbols for WinXP SP3\nhttp://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx#d\n\nDbgView\nhttp://technet.microsoft.com/en-us/sysinternals/bb896647.aspx\n\nCygwin\nhttp://www.cygwin.com/\n(installazione pacchetti di default + categoria devel)\n\nWinrar (il WDK e' distribuito in un file .iso)\nhttp://www.rarlab.com/download.htm\n\nputtycyg (terminale per cygwin)\nhttp://code.google.com/p/puttycyg/\n\nTortoise SVN\nhttp://tortoisesvn.net/downloads\n\nEditPlus\nhttp://www.editplus.com/\n\n---------------------------------------------------------------------\n--- OPEN ISSUES/TODO ------------------------------------------------\n\n- Fix the build on OpenWRT for linux 2.6\n  [Forum: https://forum.openwrt.org/viewtopic.php?id=24990]\n- Compilation on 2.6 OpenWRT (target is MIPS Artheros 71xx) gives compilation\n  errors; [Send updates to: https://forum.openwrt.org/viewtopic.php?id=24990]\n- Windows stack corruption [a tricky bug in dummynet]\n- Windows ipv6 port [RE: Windows port of ipv6 in ipfw+dummynet]\n\nNOTE:\n- To allow compilation on OpenWRT with kernel 2.6 only the Makefile.opewrt\n  is modified to guess the kernel version (2.4/2.6)\n- ipfw3 Makefile is not modified.\n- Also compile on bigendian, but not tested yet...\n- Little changes in source code.\n\n"
  },
  {
    "path": "README",
    "content": "#\n# $Id: README 11691 2012-08-12 21:32:37Z luigi $\n#\n\nThis directory contains a port of ipfw and dummynet to Linux and Windows.\nThis version of ipfw and dummynet is called \"ipfw3\" as it is the\nthird major rewrite of the code.  The source code here comes straight\nfrom FreeBSD (roughly the version in HEAD as of February 2010),\nplus some glue code and headers written from scratch.  Unless\nspecified otherwise, all the code here is under a BSD license.\n\nSpecific build instructions are below, and in general produce\n\n\ta kernel module,\tipfw_mod.ko (ipfw.sys on windows)\n\ta userland program,\t/sbin/ipfw (ipfw.exe on windows)\n\nwhich you need to install on your system.\n\nCREDITS:\n    Luigi Rizzo (main design and development)\n    Marta Carbone (Linux and Planetlab ports)\n    Riccardo Panicucci (modular scheduler support)\n    Francesco Magno (Windows port)\n    Fabio Checconi (the QFQ scheduler)\n    Funding from Universita` di Pisa (NETOS project),\n\tEuropean Commission (ONELAB2 project)\n\tACM SIGCOMM (Sigcomm Community Projects Award, April 2012)\n    \n------ INSTALL/REMOVE INSTRUCTIONS ------\n\nLinux\n    INSTALL:\n\t# Do the following as root\n\tinsmod ./dummynet2/ipfw_mod.ko\n\tcp ipfw/ipfw /usr/local/sbin\n    REMOVE:\n\trmmod ipfw_mod.ko\n\nOpenWRT\n    INSTALL:\t# use the correct name for your system\n\topkg install  kmod-ipfw3_2.4.35.4-brcm-2.4-1_mipsel.ipk #install\n\tls -l ls -l /lib/modules/2.4.35.4/ipfw*     # check\n\tinsmod /lib/modules/2.4.35.4/ipfw_mod.o     # load the module\n\t/lib/modules/2.4.35.4/ipfw show             # launch the userspace tool\n    REMOVE:\n\trmmod ipfw_mod.o                            # remove the module\n\nWindows:\n    A pre-built version is in binary/ and binary64/ directories.\n\n    INSTALL THE NDIS DRIVER\n\t- open the configuration panel for the network card in use\n\t  (right click on the icon on the SYSTRAY, or go to\n\t  Control Panel -> Network and select one card)\n\t- click on Properties->Install->Service->Add\n\t- click on 'Driver Disk' and select 'netipfw.inf' in this folder\n\t- select 'ipfw+dummynet' which is the only service you should see\n\t- click accept on the warnings for the installation of an unsigned\n\t  driver (roughly twice per existing network card)\n\n\tNow you are ready to use the emulator. To configure it, open a 'cmd'\n\twindow (REMEMBER to run it as Administrator)\n\tand you can use the ipfw command from the command line.\n\tOtherwise click on the 'TESTME.bat' which is a batch program that\n\truns various tests.\n\tREMEMBER: you need to run ipfw as administrator.\n\n    REMOVE:\n\t- select a network card as above.\n\t- click on Properties\n\t- select 'ipfw+dummynet'\n\t- click on 'Remove'\n\n\n------ BUILD INSTRUCTIONS ------\n\n+ Windows 32 bit and 64 bit (XP, Windows7)\n\n    To build your own version of the package you need:\n\t- cygwin, http://www.cygwin.com/ with base packages, make,\n\t  c compiler, possibly an editor and subversion.\n\t  This is used to build the userspace control program, ipfw.exe\n\n\t- Microsoft Windows Driver Kit Version 7.1.0, available from\n\t    http://www.microsoft.com/en-us/download/details.aspx?id=11800\n\t    (ISO image, GRMWDK_EN_7600_1.ISO)\n\t  This is used to build the kernel module.\n\n\t- optionally, DbgView if you want to see diagnostics coming from\n\t  the kernel module. You can find it at\n\n\t    http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx\n\n    Check the Makefile in the root directory to make sure that the WDK is\n    installed in the place indicated by DRIVE and DDKDIR variables\n    (otherwise pass the correct values to the Makefile).\n    Open a shell from cygwin, move to this directory, and run \"make\" for\n    the 32-bit version, \"make win64\" for the 64 bit version.\n    This will produce in the binary/ or binary64/ directory the\n    following files:\n\tipfw.exe (you also need cygwin1.dll)\n\tipfw.sys (an NDIS intermediate filter driver)\n\tnetipfw.inf and netipfw_m.inf (installer files)\n\n    Cross compilation of the userland side under FreeBSD is possible with\n\tgmake TCC=`pwd`/tcc-0.9.25-bsd/win32 CC=`pwd`/tcc-0.9.25-bsd/win32/bin/wintcc\n    (wintcc is a custom version of tcc which produces Windows code)\n\n    NOTE: the 64-bit version is compiled as a 32-bit executable for userspace,\n\twith appropriate changes to produce 64-bit pointers.\n\tThe kernel module is built using the MSC 'build' utility instead\n\tof 'make'. THE MODULE IS NOT SIGNED.\n    IMPORTANT: Windows 64-bit will not load unsigned kernel modules unless\n\tyou boot with 'F8' and disable checks for signed modules.\n\n***** Linux 2.6 and above ******\n\n\tmake [KSRC=/path/to/linux USRDIR=/path/to/usr]\n\n    where the two variables are optional an point to the linux kernel\n    sources and the /usr directory. Defaults are USRDIR=/usr and\n    KSRC=/lib/modules/`uname -r`/build \t--- XXX check ?\n\n    NOTE: make sure CONFIG_NETFILTER is enabled in the kernel\n    configuration file. You need the ncurses devel library,\n    that can be installed according your distro with:\n\tapt-get install ncurses-dev\t# for debian based distro\n\tyum -y install ncurses-dev\t# for fedora based distro\n    You can enable CONFIG_NETFILTER by doing:\n    \n\t\"(cd ${KSRC}; make menuconfig)\"\n\n    and enabling the option listed below:\n\n        Networking --->\n\t    Networking options  --->\n              [*] Network packet filtering framework (Netfilter)\n\n    If you have not yet compiled your kernel source, you need to\n    prepare the build environment:\n\n\t(cd $(KSRC); make oldconfig; make prepare; make scripts)\n\n***** Linux 2.4.x *****\n\n    Almost as above, with an additional VER=2.4\n\n\tmake VER=2.4 KSRC=...\n\n    For 2.4, if KSRC is not specified then we use\n    \tKSRC ?= /usr/src/`uname -r`/build\n\n    You need to follow the same instruction for the 2.6 kernel, enabling\n    netfilter in the kernel options:\n\n    Networking options  --->\n      [*] Network packet filtering (replaces ipchains)\n\n***** Openwrt package *****\n\n    (Tested with kamikaze_8.09.1 and Linux 2.4)\n\n    + Download and extract the OpenWrt package, e.g.\n\n\twget http://downloads.openwrt.org/kamikaze/8.09.1/kamikaze_8.09.1_source.tar.bz2\n\ttar xvjf kamikaze_8.09.1_source.tar.bz2\n\n    + move to the directory with the OpenWrt sources (the one that\n      contains Config.in, rules.mk ...)\n\n\tcd kamikaze_8.09.1\n\n    + Optional: Add support for 1ms resolution.\n\n\tBy default OpenWRT kernel is compiled with HZ=100; this implies\n        that all timeouts are rounded to 10ms, too coarse for dummynet.\n        The file 020-mips-hz1000.patch contains a kernel patch to build\n\ta kernel with HZ=1000 (i.e. 1ms resolution) as in Linux/FreeBSD.\n        To apply this patch, go in the kernel source directory and\n        patch the kernel\n\n\t\tcd build_dir/linux-brcm-2.4/linux-2.4.35.4\n\t\tcat $IPFW3_SOURCES/020-mips-hz1000.patch | patch -p0\n\n\twhere IPFW3_SOURCES contains the ipfw3 source code.\n\tNow, the next kernel recompilation will use the right HZ value\n\n    + Optional: to be sure that the tools are working, make a first\n      build as follows:\n\n\t- run \"make menuconfig\" and set the correct target device,\n\t  drivers, and so on;\n\t- run \"make\" to do the build\n\n    + Add ipfw3 to the openwrt package, as follows:\n\n      - copy the code from this directory to the place used for the build:\n\n\t\tcp -Rp /path_to_ipfw3 ../ipfw3; \n\n\tIf you want, you can fetch a newer version from the web\n\t(cd ..; rm -rf ipfw3; \\\n\twget http://info.iet.unipi.it/~luigi/dummynet/ipfw3-latest.tgz;\\\n\ttar xvzf ipfw3-latest.tgz)\n\n      - run the following commands:\n\t(mkdir package/ipfw3; \\\n\tcp ../ipfw3/Makefile.openwrt package/ipfw3/Makefile)\n\n\tto create the package/ipfw3 directory in the OpenWrt source\n\tdirectory, and copy Makefile.openwrt to package/ipfw3/Makefile ;\n\n      - if necessary, edit package/ipfw3/Makefile and set IPFW_DIR to point to\n\tthe directory ipfw3, which contains the sources;\n\n      - run \"make menuconfig\" and select kmod-ipfw3 as a module <M> in\n\t    Kernel Modules -> Other modules -> kmod-ipfw3 \n\n      - run \"make\" to build the package, \"make V=99\" for verbose build.\n\n      - to modify the code, assuming you are in directory \"kamikaze_8.09.1\"\n\t\n\t(cd ../ipfw3 && vi ...the files you are interested in )\n\trm -rf build_dir/linux-brcm-2.4/kmod-ipfw3\n\tmake package/ipfw3/compile V=99\n\n    The resulting package is located in bin/packages/mipsel/kmod-ipfw3*,\n    upload the file and install on the target system, as follows:\n\n    opkg install  kmod-ipfw3_2.4.35.4-brcm-2.4-1_mipsel.ipk #install\n    ls -l ls -l /lib/modules/2.4.35.4/ipfw*     # check\n    insmod /lib/modules/2.4.35.4/ipfw_mod.o     # load the module\n    /lib/modules/2.4.35.4/ipfw show             # launch the userspace tool\n    rmmod ipfw_mod.o                            # remove the module\n\n***** PLANETLAB BUILD (within a slice) *****\nThese instruction can be used by PlanetLab developers to compile\nthe dummynet module on a node. To install the module on the node\nusers need root access in root context.  PlanetLab users that want\nto use the dummynet package should ask to PlanetLab support for\nnodes with dummynet emulation capabilities.\n\n    Follow the instructions below. You can just cut&paste\n\n\t# install the various tools if not available\n\tsudo yum -y install subversion rpm-build rpm-devel m4 redhat-rpm-config make gcc\n\t# new build installation requires the gnupg package\n\tsudo yum -y install gnupg\n\t# the linux kernel and the ipfw source can be fetched by git\n\tsudo yum -y install git\n\n\t# create and move to a work directory\n\tmkdir -p test\n\t# extract a planetlab distribution to directory XYZ\n\t(cd test; git clone git://git.onelab.eu/build ./XYZ)\n\t# download the specfiles and do some patching.\n\t# Results are into SPEC/ (takes 5 minutes)\n\t(cd test/XYZ; make stage1=true PLDISTRO=onelab)\n\t# Building the slice code is fast, the root code takes longer\n\t# as it needs to rebuild the whole kernel\n\t(cd test/XYZ; sudo make ipfwslice PLDISTRO=onelab)\n\t(cd test/XYZ; sudo make ipfwroot PLDISTRO=onelab)\n\n    The kernel dependency phase is a bit time consuming, but does not\n    need to be redone if we are changing the ipfw sources only.\n    To clean up the code do\n\t(cd test/XYZ; sudo make ipfwroot-clean ipfwslice-clean)\n    then after you have updated the repository again\n\t(cd test/XYZ; sudo make ipfwslice ipfwroot)\n\n--- References\n[1] https://svn.planet-lab.org/wiki/VserverCentos\n[2] http://wiki.linux-vserver.org/Installation_on_CentOS\n[3] http://mirror.centos.org/centos/5/isos/\n[4] More information are in /build/README* files \n"
  },
  {
    "path": "binary/README.txt",
    "content": "This directory contains the binaries to install and use IPFW and\r\nDUMMYNET on a Windows Machine. The kernel part is an NDIS module,\r\nwhereas the user interface is a command line program.\r\n\r\n1. INSTALL THE NDIS DRIVER\r\n\r\n- open the configuration panel for the network card in use\r\n  (either right click on the icon on the SYSTRAY, or go to\r\n  Control Panel -> Network and select one card)\r\n\r\n- click on Properties->Install->Service->Add\r\n- click on 'Driver Disk' and select 'netipfw.inf' in this folder\r\n- select 'ipfw+dummynet' which is the only service you should see\r\n- click accept on the warnings for the installation of an unknown\r\n  driver (roughly twice per existing network card)\r\n\r\nNow you are ready to use the emulator. To configure it, open a 'cmd'\r\nwindow and you can use the ipfw command from the command line.\r\nOtherwise click on the 'TESTME.bat' which is a batch program that\r\nruns various tests.\r\n\r\n2. UNINSTALL THE DRIVER\r\n\r\n- select a network card as above.\r\n- click on Properties\r\n- select 'ipfw+dummynet'\r\n- click on 'Remove'\r\n"
  },
  {
    "path": "binary/netipfw.inf",
    "content": "; version section\r\n[Version]\r\nSignature  = \"$Windows NT$\"\r\nClass      = NetService\r\nClassGUID  = {4D36E974-E325-11CE-BFC1-08002BE10318}\r\nProvider   = %Unipi%\r\nDriverVer  = 26/02/2010,3.0.0.1\r\n\r\n; manufacturer section\r\n[Manufacturer]\r\n%Unipi% = UNIPI,NTx86,NTamd64\r\n\r\n; control flags section\r\n; optional, unused in netipfw.inf inf, used in netipfw_m.inf\r\n[ControlFlags]\r\n\r\n; models section\r\n[UNIPI] ; Win2k\r\n%Desc% = Ipfw.ndi, unipi_ipfw\r\n[UNIPI.NTx86] ;For WinXP and later\r\n%Desc% = Ipfw.ndi, unipi_ipfw\r\n[UNIPI.NTamd64] ;For x64\r\n%Desc% = Ipfw.ndi, unipi_ipfw\r\n\r\n; ddinstall section\r\n[Ipfw.ndi]\r\nAddReg          = Ipfw.ndi.AddReg, Ipfw.AddReg\r\nCharacteristics = 0x4410 ;  NCF_FILTER | NCF_NDIS_PROTOCOL !--Filter Specific--!!\r\nCopyFiles       = Ipfw.Files.Sys\r\nCopyInf         = netipfw_m.inf\r\n\r\n; remove section\r\n[Ipfw.ndi.Remove]\r\nDelFiles = Ipfw.Files.Sys\r\n\r\n;ddinstall.services section\r\n[Ipfw.ndi.Services]\r\nAddService = Ipfw,,Ipfw.AddService\r\n\r\n[Ipfw.AddService]\r\nDisplayName    = %ServiceDesc%\r\nServiceType    = 1 ;SERVICE_KERNEL_DRIVER\r\nStartType      = 3 ;SERVICE_DEMAND_START\r\nErrorControl   = 1 ;SERVICE_ERROR_NORMAL\r\nServiceBinary  = %12%\\ipfw.sys\r\nAddReg         = Ipfw.AddService.AddReg\r\n\r\n[Ipfw.AddService.AddReg]\r\n\r\n;file copy related sections\r\n[SourceDisksNames]\r\n1=%DiskDescription%,\"\",,\r\n\r\n[SourceDisksFiles]\r\nipfw.sys=1\r\n\r\n[DestinationDirs]\r\nDefaultDestDir = 12\r\nIpfw.Files.Sys   = 12   ; %windir%\\System32\\drivers\r\n\r\n; ddinstall->copyfiles points here\r\n[Ipfw.Files.Sys]\r\nipfw.sys,,,2\r\n\r\n; ddinstall->addreg points here\r\n[Ipfw.ndi.AddReg]\r\nHKR, Ndi,            HelpText,            , %HELP% ; this is displayed at the bottom of the General page of the Connection Properties dialog box\r\nHKR, Ndi,            FilterClass,         , failover\r\nHKR, Ndi,            FilterDeviceInfId,   , unipi_ipfwmp\r\nHKR, Ndi,            Service,             , Ipfw\r\nHKR, Ndi\\Interfaces, UpperRange,          , noupper\r\nHKR, Ndi\\Interfaces, LowerRange,          , nolower\r\nHKR, Ndi\\Interfaces, FilterMediaTypes,    , \"ethernet, tokenring, fddi, wan\"\r\n\r\n;strings section\r\n[Strings]\r\nUnipi = \"Unipi\"\r\nDiskDescription = \"Ipfw Driver Disk\"\r\nDesc = \"ipfw+dummynet\"\r\nHELP = \"This is ipfw and dummynet network emulator, developed by unipi.it\"\r\nServiceDesc = \"ipfw service\"\r\n"
  },
  {
    "path": "binary/netipfw_m.inf",
    "content": "; version section\r\n[Version]\r\nSignature  = \"$Windows NT$\"\r\nClass      = Net\r\nClassGUID  = {4D36E972-E325-11CE-BFC1-08002BE10318}\r\nProvider   = %Unipi%\r\nDriverVer  = 26/02/2010,3.0.0.1\r\n\r\n; control flags section\r\n; optional, unused in netipfw.inf inf, used in netipfw_m.inf\r\n[ControlFlags]\r\nExcludeFromSelect = unipi_ipfwmp\r\n\r\n; destinationdirs section, optional\r\n[DestinationDirs]\r\nDefaultDestDir=12\r\n; No files to copy \r\n\r\n; manufacturer section\r\n[Manufacturer]\r\n%Unipi% = UNIPI,NTx86,NTamd64\r\n\r\n; models section\r\n[UNIPI] ; Win2k\r\n%Desc% = IpfwMP.ndi, unipi_ipfwmp\r\n[UNIPI.NTx86] ;For WinXP and later\r\n%Desc% = IpfwMP.ndi, unipi_ipfwmp\r\n[UNIPI.NTamd64] ;For x64\r\n%Desc% = IpfwMP.ndi, unipi_ipfwmp\r\n\r\n; ddinstall section\r\n[IpfwMP.ndi]\r\nAddReg  = IpfwMP.ndi.AddReg\r\nCharacteristics = 0x29 ;NCF_NOT_USER_REMOVABLE | NCF_VIRTUAL | NCF_HIDDEN\r\n\r\n; ddinstall->addreg points here\r\n[IpfwMP.ndi.AddReg]\r\nHKR, Ndi, Service,  0,  IpfwMP\r\n\r\n;ddinstall.services section\r\n[IpfwMP.ndi.Services]\r\nAddService = IpfwMP,0x2, IpfwMP.AddService\r\n\r\n[IpfwMP.AddService]\r\nServiceType    = 1 ;SERVICE_KERNEL_DRIVER\r\nStartType      = 3 ;SERVICE_DEMAND_START\r\nErrorControl   = 1 ;SERVICE_ERROR_NORMAL\r\nServiceBinary  = %12%\\ipfw.sys\r\nAddReg         = IpfwMP.AddService.AddReg\r\n\r\n[IpfwMP.AddService.AddReg]\r\n; None\r\n\r\n[Strings]\r\nUnipi = \"Unipi\"\r\nDesc = \"Ipfw Miniport\""
  },
  {
    "path": "binary/testme.bat",
    "content": "@echo on\r\n@set CYGWIN=nodosfilewarning\r\n\r\n@ipfw -q flush\r\n@ipfw -q pipe flush\r\n@echo ######################################################################\r\n@echo ## Setting delay to 100ms for both incoming and outgoing ip packets ##\r\n@echo ## and sending 4 echo request to Google                             ##\r\n@echo ######################################################################\r\nipfw pipe 3 config delay 100ms\r\nipfw add pipe 3 ip from any to any\r\nipfw pipe show\r\nping -n 4 www.google.it\r\n\r\n@echo ##############################################\r\n@echo ## Raising delay to 300ms and pinging again ##\r\n@echo ##############################################\r\nipfw pipe 3 config delay 300ms\r\nipfw pipe show\r\nping -n 4 www.google.com\r\n\r\n@echo ##################################\r\n@echo ## Shaping bandwidth to 500kbps ##\r\n@echo ##################################\r\nipfw pipe 3 config bw 500Kbit/s\r\nipfw pipe show\r\nwget http://info.iet.unipi.it/~luigi/1m\r\n@del 1m\r\n\r\n@echo ###################################\r\n@echo ## Lowering bandwidth to 250kbps ##\r\n@echo ###################################\r\nipfw pipe 3 config bw 250Kbit/s\r\nipfw pipe show\r\nwget http://info.iet.unipi.it/~luigi/1m\r\n@del 1m\r\n\r\n@echo ###################################################################\r\n@echo ## Simulating 50 percent packet loss and sending 15 echo request ##\r\n@echo ###################################################################\r\n@ipfw -q flush\r\n@ipfw -q pipe flush\r\nipfw add prob 0.5 deny proto icmp in\r\nping -n 15 -w 300 www.google.it\r\n@ipfw -q flush\r\n\r\n@echo ##############################\r\n@echo ## Showing SYSCTL variables ##\r\n@echo ##############################\r\nipfw sysctl -a\r\n\r\n@echo #############################################\r\n@echo ## Inserting rules to test command parsing ##\r\n@echo #############################################\r\n@echo -- dropping all packets of a specific protocol --\r\nipfw add deny proto icmp\r\n@echo -- dropping packets of all protocols except a specific one --\r\nipfw add deny not proto tcp\r\n@echo -- dropping all packets from IP x to IP y --\r\nipfw add deny src-ip 1.2.3.4 dst-ip 5.6.7.8\r\n@echo -- dropping all ssh outgoing connections --\r\nipfw add deny out dst-port 22\r\n@echo -- allowing already opened browser connections --\r\n@echo -- but preventing new ones from being opened   --\r\nipfw add deny out proto tcp dst-port 80 tcpflags syn\r\n@echo -- another way to do the same thing --\r\nipfw add allow out proto tcp dst-port 80 established\r\nipfw add deny out proto tcp dst-port 80 setup\r\n@echo -- checking what rules have been inserted --\r\nipfw -c show\r\n@ipfw -q flush\r\n\r\n@echo #################\r\n@echo ## Cleaning up ##\r\n@echo #################\r\nipfw -q flush\r\nipfw -q pipe flush\r\n\r\npause\r\n"
  },
  {
    "path": "configuration/README",
    "content": "This directorty contains some ipfw configurations and a scripts \nto safely change the firewall rules.\n\nThe firewall configuration comes from the FreeBSD initial script.\nThe change_rules_linux.sh allows to change the ipfw rules and\nin case os a misconfiguration which prevents to reach the remote\nhost, to restore the old ruleset.\n\nTo configure the firewall behavior, edit the ipfw.conf file and \nexecute the ./change_rules_linux.sh script.\n\nThe ipfw program executable should be located in /sbin (XXX)\n\nXXX seems we use something which is not compatible with dash\n"
  },
  {
    "path": "configuration/change_rules.sh",
    "content": "#!/bin/sh\n#\n# Copyright (c) 2000 Alexandre Peixoto\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n# 1. Redistributions of source code must retain the above copyright\n#    notice, this list of conditions and the following disclaimer.\n# 2. Redistributions in binary form must reproduce the above copyright\n#    notice, this list of conditions and the following disclaimer in the\n#    documentation and/or other materials provided with the distribution.\n#\n# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n# SUCH DAMAGE.\n#\n# $FreeBSD: src/share/examples/ipfw/change_rules.sh,v 1.6 2003/09/07 07:52:56 jmg Exp $\n\n# Change ipfw(8) rules with safety guarantees for remote operation\n#\n# Invoke this script to edit ${firewall_script}. It will call ${EDITOR},\n# or vi(1) if the environment variable is not set, for you to edit\n# ${firewall_script}, ask for confirmation, and then run\n# ${firewall_script}. You can then examine the output of ipfw list and\n# confirm whether you want the new version or not.\n#\n# If no answer is received in 30 seconds, the previous\n# ${firewall_script} is run, restoring the old rules (this assumes ipfw\n# flush is present in it).\n#\n# If the new rules are confirmed, they'll replace ${firewall_script} and\n# the previous ones will be copied to ${firewall_script}.{date}. Mail\n# will also be sent to root with a unified diff of the rule change.\n#\n# Unapproved rules are kept in ${firewall_script}.new, and you are\n# offered the option of changing them instead of the present rules when\n# you call this script.\n#\n# This script could be improved by using version control\n# software.\n\n# XXX on linux /etc/rc.conf defines:\n# firewall_type and firewall_script\n\nif [ -r /etc/defaults/rc.conf ]; then\n\t. /etc/defaults/rc.conf\n\tsource_rc_confs\nelif [ -r /etc/rc.conf ]; then\n\t. /etc/rc.conf\nfi\n\nEDITOR=${EDITOR:-/usr/bin/vi}\nPAGER=${PAGER:-/usr/bin/more}\n\n# on linux the default mktemp invocation behavior\n# is different, we should change the temporary file creation\ntempfoo=`basename $0`\n#TMPFILE=`mktemp -t ${tempfoo}` || exit 1\nTMPFILE=`mktemp -t ${tempfoo}.XXXXX` || exit 1\n\nget_yes_no() {\n\twhile true\n\tdo\n\t\techo -n \"$1 (Y/N) ? \" \n\t\tread -t 30 a\n\t\tif [ $? != 0 ]; then\n\t\t\ta=\"No\";\n\t\t        return;\n\t\tfi\n\t\tcase $a in\n\t\t\t[Yy]) a=\"Yes\";\n\t\t\t      return;;\n\t\t\t[Nn]) a=\"No\";\n\t\t\t      return;;\n\t\t\t*);;\n\t\tesac\n\tdone\n}\n\nrestore_rules() {\n\tnohup sh ${firewall_script} </dev/null >/dev/null 2>&1\n\trm ${TMPFILE}\n\texit 1\n}\n\ncase \"${firewall_type}\" in\n[Cc][Ll][Ii][Ee][Nn][Tt]|\\\n[Cc][Ll][Oo][Ss][Ee][Dd]|\\\n[Oo][Pp][Ee][Nn]|\\\n[Ss][Ii][Mm][Pp][Ll][Ee]|\\\n[Uu][Nn][Kk][Nn][Oo][Ww][Nn])\n\tedit_file=\"${firewall_script}\"\n\trules_edit=no\n\t;;\n*)\n\tif [ -r \"${firewall_type}\" ]; then\n\t\tedit_file=\"${firewall_type}\"\n\t\trules_edit=yes\n\tfi\n\t;;\nesac\n\nif [ -f ${edit_file}.new ]; then\n\tget_yes_no \"A new rules file already exists, do you want to use it\"\n\t[ $a = 'No' ] && cp ${edit_file} ${edit_file}.new\nelse \n\tcp ${edit_file} ${edit_file}.new\nfi\n\ntrap restore_rules SIGHUP\n\n${EDITOR} ${edit_file}.new\n\nget_yes_no \"Do you want to install the new rules\"\n\n[ $a = 'No' ] && exit 1\n\ncat <<!\nThe rules will be changed now. If the message 'Type y to keep the new\nrules' does not appear on the screen or the y key is not pressed in 30\nseconds, the original rules will be restored.\nThe TCP/IP connections might be broken during the change. If so, restore\nthe ssh/telnet connection being used.\n!\n\nif [ ${rules_edit} = yes ]; then\n\tnohup sh ${firewall_script} ${firewall_type}.new \\\n\t    < /dev/null > ${TMPFILE} 2>&1\nelse\n\tnohup sh ${firewall_script}.new \\\n\t    < /dev/null > ${TMPFILE} 2>&1\nfi\nsleep 2;\nget_yes_no \"Would you like to see the resulting new rules\"\n[ $a = 'Yes' ] && ${PAGER} ${TMPFILE}\nget_yes_no \"Type y to keep the new rules\"\n[ $a != 'Yes' ] && restore_rules\n\nDATE=`date \"+%Y%m%d%H%M\"`\ncp ${edit_file} ${edit_file}.$DATE\nmv ${edit_file}.new ${edit_file} \ncat <<!\nThe new rules are now installed. The previous rules have been preserved in\nthe file ${edit_file}.$DATE\n!\ndiff -F \"^# .*[A-Za-z]\" -u ${edit_file}.$DATE ${edit_file} \\\n    | mail -s \"`hostname` Firewall rule change\" root\nrm ${TMPFILE}\nexit 0\n"
  },
  {
    "path": "configuration/change_rules_linux.sh",
    "content": "#!/bin/sh\n#\n# marta\n# linux wrapper for the FreeBSD change rules program\n# This file load the linux configuration and calls the\n# original change rules program\n\nif [ -r ./ipfw.conf ]; then\n\t. ./ipfw.conf\nfi\n\n. ./change_rules.sh\n"
  },
  {
    "path": "configuration/ipfw.conf",
    "content": "# ipfw and dummynet configuration file for linux\n# XXX TO BE TESTED ON LINUX\n\n# The firewall_type variable is used to configure the firewall behavior.\n# A detailed description on how a following type works is in rc.firewall\n#\n#   open        - will allow anyone in\n#   client      - will try to protect just this machine\n#   simple      - will try to protect a whole network\n#   closed      - totally disables IP services except via lo0 interface\n#   workstation - will try to protect just this machine using statefull\n#                 firewalling. See below for rc.conf variables used\n#   UNKNOWN     - disables the loading of firewall rules.\n#   filename    - will load the rules in the given filename (full path required)\n\n# firewall_type=open\n\n# The following file is an example on how to use a filename to define a firewall\n# and how to configure a simple dummynet pipe to ... XXX shape traffic... etc...\nfirewall_type=/home/marta/SVN/ports-luigi/dummynet-branches/ipfw3/configuration/ipfw.rules\n\n# Environment variables expected by the change rules script\nEDITOR=/usr/bin/vi\nPAGER=/bin/more\n\n# The following variable should point to the rc.firewall script\n# XXX TEST\n#firewall_script=`echo \"please edit the firewall_script variable in ipfw.conf\"`;\nfirewall_script=\"/home/marta/SVN/ports-luigi/dummynet-branches/ipfw3/configuration/rc.firewall\"\n"
  },
  {
    "path": "configuration/ipfw.rules",
    "content": "# This is a simple configuration file\n# add dummynet pipes and a firewall section\n\n# flush all rules ...\n# flush\n\n# dummynet configuration\n\n# firewall configuration\nadd 1 allow all from any to any\n# ...\nadd 65000 deny all from any to any\n"
  },
  {
    "path": "configuration/rc.firewall",
    "content": "#!/bin/sh -\n# Copyright (c) 1996  Poul-Henning Kamp\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n# 1. Redistributions of source code must retain the above copyright\n#    notice, this list of conditions and the following disclaimer.\n# 2. Redistributions in binary form must reproduce the above copyright\n#    notice, this list of conditions and the following disclaimer in the\n#    documentation and/or other materials provided with the distribution.\n#\n# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n# SUCH DAMAGE.\n#\n# $FreeBSD: src/etc/rc.firewall,v 1.52.4.1 2008/01/29 00:22:32 dougb Exp $\n#\n\n#\n# Setup system for ipfw(4) firewall service.\n#\n\n# Suck in the configuration variables.\nif [ -z \"${source_rc_confs_defined}\" ]; then\n\tif [ -r /etc/defaults/rc.conf ]; then\n\t\t. /etc/defaults/rc.conf\n\t\tsource_rc_confs\n\telif [ -r /etc/rc.conf ]; then\n\t\t. /etc/rc.conf\n\tfi\nfi\n\n############\n# Define the firewall type in /etc/rc.conf.  Valid values are:\n#   open        - will allow anyone in\n#   client      - will try to protect just this machine\n#   simple      - will try to protect a whole network\n#   closed      - totally disables IP services except via lo0 interface\n#   workstation - will try to protect just this machine using statefull\n#\t\t  firewalling. See below for rc.conf variables used\n#   UNKNOWN     - disables the loading of firewall rules.\n#   filename    - will load the rules in the given filename (full path required)\n#\n# For ``client'' and ``simple'' the entries below should be customized\n# appropriately.\n\n############\n#\n# If you don't know enough about packet filtering, we suggest that you\n# take time to read this book:\n#\n#\tBuilding Internet Firewalls, 2nd Edition\n#\tBrent Chapman and Elizabeth Zwicky\n#\n#\tO'Reilly & Associates, Inc\n#\tISBN 1-56592-871-7\n#\thttp://www.ora.com/\n#\thttp://www.oreilly.com/catalog/fire2/\n#\n# For a more advanced treatment of Internet Security read:\n#\n#\tFirewalls and Internet Security: Repelling the Wily Hacker, 2nd Edition\n#\tWilliam R. Cheswick, Steven M. Bellowin, Aviel D. Rubin\n#\n#\tAddison-Wesley / Prentice Hall\n#\tISBN 0-201-63466-X\n#\thttp://www.pearsonhighered.com/\n#\thttp://www.pearsonhighered.com/educator/academic/product/0,3110,020163466X,00.html\n#\n\nsetup_loopback () {\n\t############\n\t# Only in rare cases do you want to change these rules\n\t#\n\t${fwcmd} add 100 pass all from any to any via lo0\n\t${fwcmd} add 200 deny all from any to 127.0.0.0/8\n\t${fwcmd} add 300 deny ip from 127.0.0.0/8 to any\n}\n\nif [ -n \"${1}\" ]; then\n\tfirewall_type=\"${1}\"\nfi\n\n############\n# Set quiet mode if requested\n#\ncase ${firewall_quiet} in\n[Yy][Ee][Ss])\n\tfwcmd=\"/sbin/ipfw -q\"\n\t;;\n*)\n\tfwcmd=\"/sbin/ipfw\"\n\t;;\nesac\n\n############\n# Flush out the list before we begin.\n#\n${fwcmd} -f flush\n\nsetup_loopback\n\n############\n# Network Address Translation.  All packets are passed to natd(8)\n# before they encounter your remaining rules.  The firewall rules\n# will then be run again on each packet after translation by natd\n# starting at the rule number following the divert rule.\n#\n# For ``simple'' firewall type the divert rule should be put to a\n# different place to not interfere with address-checking rules.\n#\ncase ${firewall_type} in\n[Oo][Pp][Ee][Nn]|[Cc][Ll][Ii][Ee][Nn][Tt])\n\tcase ${natd_enable} in\n\t[Yy][Ee][Ss])\n\t\tif [ -n \"${natd_interface}\" ]; then\n\t\t\t${fwcmd} add 50 divert natd ip4 from any to any via ${natd_interface}\n\t\tfi\n\t\t;;\n\tesac\n\tcase ${firewall_nat_enable} in\n\t[Yy][Ee][Ss])\n\t\tif [ -n \"${firewall_nat_interface}\" ]; then\n\t\t\t${fwcmd} nat 123 config if ${firewall_nat_interface} log\n\t\t\t${fwcmd} add 50 nat 123 ip4 from any to any via ${firewall_nat_interface}\n\t\tfi\n\t\t;;\n\tesac\nesac\n\n############\n# If you just configured ipfw in the kernel as a tool to solve network\n# problems or you just want to disallow some particular kinds of traffic\n# then you will want to change the default policy to open.  You can also\n# do this as your only action by setting the firewall_type to ``open''.\n#\n# ${fwcmd} add 65000 pass all from any to any\n\n\n# Prototype setups.\n#\ncase ${firewall_type} in\n[Oo][Pp][Ee][Nn])\n\t${fwcmd} add 65000 pass all from any to any\n\t;;\n\n[Cc][Ll][Ii][Ee][Nn][Tt])\n\t############\n\t# This is a prototype setup that will protect your system somewhat\n\t# against people from outside your own network.\n\t############\n\n\t# set these to your network and netmask and ip\n\tnet=\"192.0.2.0\"\n\tmask=\"255.255.255.0\"\n\tip=\"192.0.2.1\"\n\n\t# Allow any traffic to or from my own net.\n\t${fwcmd} add pass all from ${ip} to ${net}:${mask}\n\t${fwcmd} add pass all from ${net}:${mask} to ${ip}\n\n\t# Allow TCP through if setup succeeded\n\t${fwcmd} add pass tcp from any to any established\n\n\t# Allow IP fragments to pass through\n\t${fwcmd} add pass all from any to any frag\n\n\t# Allow setup of incoming email\n\t${fwcmd} add pass tcp from any to me 25 setup\n\n\t# Allow setup of outgoing TCP connections only\n\t${fwcmd} add pass tcp from me to any setup\n\n\t# Disallow setup of all other TCP connections\n\t${fwcmd} add deny tcp from any to any setup\n\n\t# Allow DNS queries out in the world\n\t${fwcmd} add pass udp from me to any 53 keep-state\n\n\t# Allow NTP queries out in the world\n\t${fwcmd} add pass udp from me to any 123 keep-state\n\n\t# Everything else is denied by default, unless the\n\t# IPFIREWALL_DEFAULT_TO_ACCEPT option is set in your kernel\n\t# config file.\n\t;;\n\n[Ss][Ii][Mm][Pp][Ll][Ee])\n\t############\n\t# This is a prototype setup for a simple firewall.  Configure this\n\t# machine as a DNS and NTP server, and point all the machines\n\t# on the inside at this machine for those services.\n\t############\n\n\t# set these to your outside interface network and netmask and ip\n\toif=\"ed0\"\n\tonet=\"192.0.2.0\"\n\tomask=\"255.255.255.240\"\n\toip=\"192.0.2.1\"\n\n\t# set these to your inside interface network and netmask and ip\n\tiif=\"ed1\"\n\tinet=\"192.0.2.16\"\n\timask=\"255.255.255.240\"\n\tiip=\"192.0.2.17\"\n\n\t# Stop spoofing\n\t${fwcmd} add deny all from ${inet}:${imask} to any in via ${oif}\n\t${fwcmd} add deny all from ${onet}:${omask} to any in via ${iif}\n\n\t# Stop RFC1918 nets on the outside interface\n\t${fwcmd} add deny all from any to 10.0.0.0/8 via ${oif}\n\t${fwcmd} add deny all from any to 172.16.0.0/12 via ${oif}\n\t${fwcmd} add deny all from any to 192.168.0.0/16 via ${oif}\n\n\t# Stop draft-manning-dsua-03.txt (1 May 2000) nets (includes RESERVED-1,\n\t# DHCP auto-configuration, NET-TEST, MULTICAST (class D), and class E)\n\t# on the outside interface\n\t${fwcmd} add deny all from any to 0.0.0.0/8 via ${oif}\n\t${fwcmd} add deny all from any to 169.254.0.0/16 via ${oif}\n\t${fwcmd} add deny all from any to 192.0.2.0/24 via ${oif}\n\t${fwcmd} add deny all from any to 224.0.0.0/4 via ${oif}\n\t${fwcmd} add deny all from any to 240.0.0.0/4 via ${oif}\n\n\t# Network Address Translation.  This rule is placed here deliberately\n\t# so that it does not interfere with the surrounding address-checking\n\t# rules.  If for example one of your internal LAN machines had its IP\n\t# address set to 192.0.2.1 then an incoming packet for it after being\n\t# translated by natd(8) would match the `deny' rule above.  Similarly\n\t# an outgoing packet originated from it before being translated would\n\t# match the `deny' rule below.\n\tcase ${natd_enable} in\n\t[Yy][Ee][Ss])\n\t\tif [ -n \"${natd_interface}\" ]; then\n\t\t\t${fwcmd} add divert natd all from any to any via ${natd_interface}\n\t\tfi\n\t\t;;\n\tesac\n\n\t# Stop RFC1918 nets on the outside interface\n\t${fwcmd} add deny all from 10.0.0.0/8 to any via ${oif}\n\t${fwcmd} add deny all from 172.16.0.0/12 to any via ${oif}\n\t${fwcmd} add deny all from 192.168.0.0/16 to any via ${oif}\n\n\t# Stop draft-manning-dsua-03.txt (1 May 2000) nets (includes RESERVED-1,\n\t# DHCP auto-configuration, NET-TEST, MULTICAST (class D), and class E)\n\t# on the outside interface\n\t${fwcmd} add deny all from 0.0.0.0/8 to any via ${oif}\n\t${fwcmd} add deny all from 169.254.0.0/16 to any via ${oif}\n\t${fwcmd} add deny all from 192.0.2.0/24 to any via ${oif}\n\t${fwcmd} add deny all from 224.0.0.0/4 to any via ${oif}\n\t${fwcmd} add deny all from 240.0.0.0/4 to any via ${oif}\n\n\t# Allow TCP through if setup succeeded\n\t${fwcmd} add pass tcp from any to any established\n\n\t# Allow IP fragments to pass through\n\t${fwcmd} add pass all from any to any frag\n\n\t# Allow setup of incoming email\n\t${fwcmd} add pass tcp from any to ${oip} 25 setup\n\n\t# Allow access to our DNS\n\t${fwcmd} add pass tcp from any to ${oip} 53 setup\n\t${fwcmd} add pass udp from any to ${oip} 53\n\t${fwcmd} add pass udp from ${oip} 53 to any\n\n\t# Allow access to our WWW\n\t${fwcmd} add pass tcp from any to ${oip} 80 setup\n\n\t# Reject&Log all setup of incoming connections from the outside\n\t${fwcmd} add deny log tcp from any to any in via ${oif} setup\n\n\t# Allow setup of any other TCP connection\n\t${fwcmd} add pass tcp from any to any setup\n\n\t# Allow DNS queries out in the world\n\t${fwcmd} add pass udp from ${oip} to any 53 keep-state\n\n\t# Allow NTP queries out in the world\n\t${fwcmd} add pass udp from ${oip} to any 123 keep-state\n\n\t# Everything else is denied by default, unless the\n\t# IPFIREWALL_DEFAULT_TO_ACCEPT option is set in your kernel\n\t# config file.\n\t;;\n\n[Ww][Oo][Rr][Kk][Ss][Tt][Aa][Tt][Ii][Oo][Nn])\n\t# Configuration:\n\t#  firewall_myservices:\t\tList of TCP ports on which this host\n\t#\t\t\t \t offers services.\n\t#  firewall_allowservices:\tList of IPs which has access to\n\t#\t\t\t\t $firewall_myservices.\n\t#  firewall_trusted:\t\tList of IPs which has full access \n\t#\t\t\t\t to this host. Be very carefull \n\t#\t\t\t\t when setting this. This option can\n\t#\t\t\t\t seriously degrade the level of \n\t#\t\t\t\t protection provided by the firewall.\n\t#  firewall_logdeny:\t\tBoolean (YES/NO) specifying if the\n\t#\t\t\t\t default denied packets should be\n\t#\t\t\t\t logged (in /var/log/security).\n\t#  firewall_nologports:\t\tList of TCP/UDP ports for which\n\t#\t\t\t\t denied incomming packets are not\n\t#\t\t\t\t logged.\n\t\n\t# Allow packets for which a state has been built.\n\t${fwcmd} add check-state\n\n\t# For services permitted below.\n\t${fwcmd} add pass tcp  from me to any established\n\n\t# Allow any connection out, adding state for each.\n\t${fwcmd} add pass tcp  from me to any setup keep-state\n\t${fwcmd} add pass udp  from me to any       keep-state\n\t${fwcmd} add pass icmp from me to any       keep-state\n\n\t# Allow DHCP.\n\t${fwcmd} add pass udp  from 0.0.0.0 68 to 255.255.255.255 67 out\n\t${fwcmd} add pass udp  from any 67     to me 68 in\n\t${fwcmd} add pass udp  from any 67     to 255.255.255.255 68 in\n\t# Some servers will ping the IP while trying to decide if it's \n\t# still in use.\n\t${fwcmd} add pass icmp from any to any icmptype 8\n\n\t# Allow \"mandatory\" ICMP in.\n\t${fwcmd} add pass icmp from any to any icmptype 3,4,11\n\t\n\t# Add permits for this workstations published services below\n\t# Only IPs and nets in firewall_allowservices is allowed in.\n\t# If you really wish to let anyone use services on your \n\t# workstation, then set \"firewall_allowservices='any'\" in /etc/rc.conf\n\t#\n\t# Note: We don't use keep-state as that would allow DoS of\n\t#       our statetable. \n\t#       You can add 'keep-state' to the lines for slightly\n\t#       better performance if you fell that DoS of your\n\t#       workstation won't be a problem.\n\t#\n\tfor i in ${firewall_allowservices} ; do\n\t  for j in ${firewall_myservices} ; do\n\t    ${fwcmd} add pass tcp from $i to me $j\n\t  done\n\tdone\n\n\t# Allow all connections from trusted IPs.\n\t# Playing with the content of firewall_trusted could seriously\n\t# degrade the level of protection provided by the firewall.\n\tfor i in ${firewall_trusted} ; do\n\t  ${fwcmd} add pass ip from $i to me\n\tdone\n\t\n\t${fwcmd} add 65000 count ip from any to any\n\n\t# Drop packets to ports where we don't want logging\n\tfor i in ${firewall_nologports} ; do\n\t  ${fwcmd} add deny { tcp or udp } from any to any $i in\n\tdone\n\n\t# Broadcasts and muticasts\n\t${fwcmd} add deny ip  from any to 255.255.255.255\n\t${fwcmd} add deny ip  from any to 224.0.0.0/24 in\t# XXX\n\n\t# Noise from routers\n\t${fwcmd} add deny udp from any to any 520 in\n\n\t# Noise from webbrowsing.\n\t# The statefull filter is a bit agressive, and will cause some\n\t#  connection teardowns to be logged.\n\t${fwcmd} add deny tcp from any 80,443 to any 1024-65535 in\n\n\t# Deny and (if wanted) log the rest unconditionally.\n\tlog=\"\"\n\tif [ ${firewall_logdeny:-x} = \"YES\" -o ${firewall_logdeny:-x} = \"yes\" ] ; then\n\t  log=\"log logamount 500\"\t# The default of 100 is too low.\n\t  sysctl net.inet.ip.fw.verbose=1 >/dev/null\n\tfi\n\t${fwcmd} add deny $log ip from any to any\n\t;;\n\n[Cc][Ll][Oo][Ss][Ee][Dd])\n\t${fwcmd} add 65000 deny ip from any to any\n\t;;\n[Uu][Nn][Kk][Nn][Oo][Ww][Nn])\n\t;;\n*)\n\tif [ -r \"${firewall_type}\" ]; then\n\t\t${fwcmd} ${firewall_flags} ${firewall_type}\n\tfi\n\t;;\nesac\n"
  },
  {
    "path": "glue.h",
    "content": "/*\n * Copyright (c) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n/*\n * $Id: glue.h 12501 2014-01-10 01:09:14Z luigi $\n *\n * glue code to adapt the FreeBSD version to linux and windows,\n * userland and kernel.\n * This is included before any other headers, so we do not have\n * a chance to override any #define that should appear in other\n * headers.\n * First handle headers for userland and kernel. Then common code\n * (including headers that require a specific order of inclusion),\n * then the user- and kernel- specific parts.\n */\n \n#if defined __FreeBSD__\n#define _GLUE_H\n#endif /* __FreeBSD__ */\n#ifndef _GLUE_H\n#define\t_GLUE_H\n\n\n/*\n * common definitions to allow portability\n */\n#ifndef __FBSDID\n#define __FBSDID(x)\n#endif  /* FBSDID */\n\n#ifndef KERNEL_MODULE\t/* Userland headers */\n\n#if defined(__CYGWIN32__) || defined(__CYGWIN__)\n#if !defined(_WIN32)                                   \n#define _WIN32                                                                  \n#endif                                                                          \n#endif                                                                          \n\n#if defined(TCC) && defined(_WIN32)\n#include <tcc_glue.h>\n#endif /* TCC */\n\n#include <stdint.h>\t/* linux needs it in addition to sys/types.h */\n#include <sys/types.h>\t/* for size_t */\n#include <sys/ioctl.h>\n#include <time.h>\n#include <errno.h>\n#ifdef __linux__\n#include <netinet/ether.h>\t/* linux only 20111031 */\n#endif\n\n#else /* KERNEL_MODULE, kernel headers */\n\n#define\tINET\t\t# want inet support\n#ifdef __linux__\n\n#include <linux/version.h>\n\n#define ifnet\t\tnet_device\t/* remap */\n#define\t_KERNEL\t\t# make kernel structure visible\n#define\tKLD_MODULE\t# add the module glue\n\n#include <linux/stddef.h>\t/* linux kernel */\n#include <linux/types.h>\t/* linux kernel */\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)\t// or 2.4.x\n#include <linux/linkage.h>\t/* linux/msg.h require this */\n#include <linux/netdevice.h>\t/* just MAX_ADDR_LEN 8 on 2.4 32 on 2.6, also brings in byteorder */\n#endif\n\n/* on 2.6.22, msg.h requires spinlock_types.h */\n/* XXX spinlock_type.h was introduced in 2.6.14 */\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13) && \\\n\tLINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)\n#include <linux/spinlock_types.h>\n#endif\n/* XXX m_type define conflict with include/sys/mbuf.h,\n * so early include msg.h (to be solved)\n*/\n#include <linux/msg.h>\t\n\n#include <linux/list.h>\n#include <linux/in.h>\t\t/* struct in_addr */\n#include <linux/in6.h>\t\t/* struct in6_addr */\n#include <linux/icmp.h>\n/*\n * LIST_HEAD in queue.h conflict with linux/list.h\n * some previous linux include need list.h definition\n */\n#undef LIST_HEAD\n\n#define\tIF_NAMESIZE\t(16)\ntypedef\tuint32_t\tin_addr_t;\n\n#define printf(fmt, arg...) printk(KERN_ERR fmt, ##arg)\n#endif\t/* __linux__ */\n\n#endif /* KERNEL_MODULE end of kernel headers */\n\n\n/*\n * Part 2: common userland and kernel definitions\n */\n\n#ifndef ETHER_ADDR_LEN\n#define ETHER_ADDR_LEN (6+0)       /* length of an Ethernet address */\n#endif\n\n#define ICMP6_DST_UNREACH_NOROUTE       0       /* no route to destination */\n#define ICMP6_DST_UNREACH_ADMIN         1       /* administratively prohibited */\n#define ICMP6_DST_UNREACH_ADDR          3       /* address unreachable */\n#define ICMP6_DST_UNREACH_NOPORT        4       /* port unreachable */\n\n/*\n * linux: sysctl are mapped into /sys/module/ipfw_mod parameters\n * windows: they are emulated via get/setsockopt\n */\n#define CTLFLAG_RD\t\t1\n#define CTLFLAG_RDTUN\t1\n#define CTLFLAG_RW\t\t2\n#define CTLFLAG_SECURE3\t0 // unsupported\n#define CTLFLAG_VNET    0\t/* unsupported */\n\n/* if needed, queue.h must be included here after list.h */\n\n/*\n * struct thread is used in linux and windows kernel.\n * In windows, we need to emulate the sockopt interface\n * so also the userland needs to have the struct sockopt defined.\n * In order to achieve 64 bit compatibility, padding has been inserted.\n */\nstruct thread {\n        void *sopt_td;\n        void *td_ucred;\n};\n\nenum sopt_dir { SOPT_GET, SOPT_SET };\n\nstruct  sockopt {\n        enum    sopt_dir sopt_dir; /* is this a get or a set? */\n        int     sopt_level;     /* second arg of [gs]etsockopt */\n        int     sopt_name;      /* third arg of [gs]etsockopt */\n#ifdef _X64EMU\n\t\tvoid* pad1;\n\t\tvoid* pad2;\n#endif\n\t\tvoid   *sopt_val;       /* fourth arg of [gs]etsockopt */\n\t\tsize_t  sopt_valsize;   /* (almost) fifth arg of [gs]etsockopt */\n#ifdef _X64EMU\n\t\tvoid* pad3;\n\t\tvoid* pad4;\n#endif\n\t\tstruct  thread *sopt_td; /* calling thread or null if kernel */\n};\n\n\n#define INET_ADDRSTRLEN\t\t(16)\t/* missing in netinet/in.h */\n\n/*\n * List of values used for set/getsockopt options.\n * The base value on FreeBSD is defined as a macro,\n * if not available we will use our own enum.\n * The TABLE_BASE value is used in the kernel.\n */\n#ifndef IP_FW_TABLE_ADD\n#define _IPFW_SOCKOPT_BASE\t100\t/* 40 on freebsd */\nenum ipfw_msg_type {\n\tIP_FW_TABLE_ADD\t\t= _IPFW_SOCKOPT_BASE,\n\tIP_FW_TABLE_DEL,\n\tIP_FW_TABLE_FLUSH,\n\tIP_FW_TABLE_GETSIZE,\n\tIP_FW_TABLE_LIST,\n\tIP_FW_DYN_GET,\t\t/* new addition */\n\n\t/* IP_FW3 and IP_DUMMYNET3 are the new API */\n\tIP_FW3\t\t\t= _IPFW_SOCKOPT_BASE + 8,\n\tIP_DUMMYNET3,\n\n\tIP_FW_ADD\t\t= _IPFW_SOCKOPT_BASE + 10,\n\tIP_FW_DEL,\n\tIP_FW_FLUSH,\n\tIP_FW_ZERO,\n\tIP_FW_GET,\n\tIP_FW_RESETLOG,\n\n\tIP_FW_NAT_CFG,\n\tIP_FW_NAT_DEL,\n\tIP_FW_NAT_GET_CONFIG,\n\tIP_FW_NAT_GET_LOG,\n\n\tIP_DUMMYNET_CONFIGURE,\n\tIP_DUMMYNET_DEL\t,\n\tIP_DUMMYNET_FLUSH,\n\t/* 63 is missing */\n\tIP_DUMMYNET_GET\t\t= _IPFW_SOCKOPT_BASE + 24,\n\t_IPFW_SOCKOPT_END\n};\n#endif /* IP_FW_TABLE_ADD */\n\n/*\n * Part 3: userland stuff\n */\n\n#ifndef KERNEL_MODULE\n\n/*\n * internal names in struct in6_addr (netinet/in6.h) differ,\n * so we remap the FreeBSD names to the platform-specific ones.\n */\n#ifndef _WIN32\n#define __u6_addr\tin6_u\n#define __u6_addr32\tu6_addr32\n#define in6_u __in6_u\t/* missing type for ipv6 (linux 2.6.28) */\n#else\t/* _WIN32 uses different naming */\n#define __u6_addr\t__u6\n#define __u6_addr32\t__s6_addr32\n#endif\t/* _WIN32 */\n\n/* missing in linux netinet/ip.h */\n#define IPTOS_ECN_ECT0\t0x02    /* ECN-capable transport (0) */\n#define IPTOS_ECN_CE\t0x03    /* congestion experienced */\n\n/* defined in freebsd netinet/icmp6.h */\n#define ICMP6_MAXTYPE\t201\n\n/* on freebsd sys/socket.h pf specific */\n#define NET_RT_IFLIST\t3               /* survey interface list */\n\n#if defined(__linux__) || defined(__CYGWIN32__) || defined(__CYGWIN__)\n/* on freebsd net/if.h XXX used */\nstruct if_data {\n\t/* ... */\n        u_long ifi_mtu;\t/* maximum transmission unit */\n};\n\n/*\n * Message format for use in obtaining information about interfaces\n * from getkerninfo and the routing socket.\n * This is used in nat.c\n */\nstruct if_msghdr {\n        u_short ifm_msglen;     /* to skip over unknown messages */\n        u_char  ifm_version;    /* future binary compatibility */\n        u_char  ifm_type;       /* message type */\n        int     ifm_addrs;      /* like rtm_addrs */\n        int     ifm_flags;      /* value of if_flags */\n        u_short ifm_index;      /* index for associated ifp */\n        struct  if_data ifm_data;/* stats and other ifdata */\n};\n\n/*\n * Message format for use in obtaining information about interface\n * addresses from getkerninfo and the routing socket\n */\nstruct ifa_msghdr {\n        u_short ifam_msglen;    /* to skip over unknown messages */\n        u_char  ifam_version;   /* future binary compatibility */\n        u_char  ifam_type;      /* message type */\n        int     ifam_addrs;     /* like rtm_addrs */\n        int     ifam_flags;     /* value of ifa_flags */\n        u_short ifam_index;     /* index for associated ifp */\n        int     ifam_metric;    /* value of ifa_metric */\n};\n\n#ifndef NO_RTM\t/* conflicting with netlink */\n/* missing in net/route.h */\n#define RTM_VERSION     5       /* Up the ante and ignore older versions */\n#define RTM_IFINFO      0xe     /* iface going up/down etc. */\n#define RTM_NEWADDR     0xc     /* address being added to iface */\n#define RTA_IFA         0x20    /* interface addr sockaddr present */\n#endif\t/* NO_RTM */\n\n/* SA_SIZE is used in the userland nat.c modified */\n#define SA_SIZE(sa)                                             \\\n    (  (!(sa) ) ?      \\\n        sizeof(long)            :                               \\\n        1 + ( (sizeof(struct sockaddr) - 1) | (sizeof(long) - 1) ) )\n\n/* sys/time.h */\n/*\n * Getkerninfo clock information structure\n */\nstruct clockinfo {\n        int     hz;             /* clock frequency */\n        int     tick;           /* micro-seconds per hz tick */\n        int     spare;\n        int     stathz;         /* statistics clock frequency */\n        int     profhz;         /* profiling clock frequency */\n};\n\n/* no sin_len in sockaddr, we only remap in userland */\n#define\tsin_len\tsin_zero[0]\n\n#endif /* Linux/Win */\n\n/*\n * linux does not have a reentrant version of qsort,\n * so we the FreeBSD stdlib version.\n */\nvoid qsort_r(void *a, size_t n, size_t es, void *thunk,\n\tint cmp_t(void *, const void *, const void *));\n\n/* prototypes from libutil */\n/* humanize_number(3) */\n#define HN_DECIMAL              0x01\n#define HN_NOSPACE              0x02\n#define HN_B                    0x04\n#define HN_DIVISOR_1000         0x08\n\n#define HN_GETSCALE             0x10\n#define HN_AUTOSCALE            0x20\n\nint     humanize_number(char *_buf, size_t _len, int64_t _number,\n            const char *_suffix, int _scale, int _flags);\nint     expand_number(const char *_buf, int64_t *_num);\n\n#define setprogname(x)\t/* not present in linux */\n\nextern int optreset;\t/* not present in linux */\n\nsize_t strlcpy(char * dst, const char * src, size_t siz);\nlong long int strtonum(const char *nptr, long long minval,\n\tlong long maxval, const char **errstr);\n \nint sysctlbyname(const char *name, void *oldp, size_t *oldlenp,\n\tvoid *newp, size_t newlen);\n \n\n#else /* KERNEL_MODULE */\n\n/*\n * Part 4: kernel stuff\n */\n\n/* linux and windows kernel do not have bcopy ? */\n#define bcopy(_s, _d, _l)\tmemcpy(_d, _s, _l)\n/* definitions useful for the kernel side */\nstruct route_in6 {\n\tint dummy;\n};\n\n#ifdef __linux__\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)\t// or 2.4.x\n#include <linux/in6.h>\n#endif\n\n/* skb_dst() and skb_dst_set() was introduced from linux 2.6.31 */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)\nvoid skb_dst_set(struct sk_buff *skb, struct dst_entry *dst);\nstruct dst_entry *skb_dst(const struct sk_buff *skb);\n#endif\n\n/* The struct flowi changed */\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38)\t// check boundaries\n#define flow_daddr fl.u.ip4\n#else\n#define flow_daddr fl.nl_u.ip4_u\n#endif\n\n#endif /* __linux__ */\n\n/* \n * Do not load prio_heap.h header because of conflicting names\n * with our heap functions defined in include/netinet/ipfw/dn_heap.h\n * However do define struct ptr_heap used in linux 3.12.7 etc.\n */\n#define _LINUX_PRIO_HEAP_H\nstruct ptr_heap;\n\n/* \n * The following define prevent the ipv6.h header to be loaded.\n * Starting from the 2.6.38 kernel the ipv6.h file, which is included\n * by include/net/inetpeer.h in turn included by net/route.h\n * include the system tcp.h file while we want to include \n * our include/net/tcp.h instead.\n */\n#ifndef _NET_IPV6_H\n#define _NET_IPV6_H\nstatic inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)\n{\n        memcpy(a1, a2, sizeof(struct in6_addr));\n}\n#endif /* _NET_IPV6_H */\n\n#endif\t/* KERNEL_MODULE */\n\n/*\n * Part 5: windows specific stuff\n */\n\n#ifdef _WIN32\n#ifndef KERNEL_MODULE\n#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \\\n    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \\\n)\n\n#define METHOD_BUFFERED                 0\n#define METHOD_IN_DIRECT                1\n#define METHOD_OUT_DIRECT               2\n#define METHOD_NEITHER                  3\n#define FILE_ANY_ACCESS                 0\n#define FILE_READ_DATA            ( 0x0001 )    // file & pipe\n#define FILE_WRITE_DATA           ( 0x0002 )    // file & pipe\n#endif /* !KERNEL_MODULE */\n\n#define FILE_DEVICE_IPFW\t\t0x00654324\n#define IP_FW_BASE_CTL\t\t\t0x840\n#define IP_FW_SETSOCKOPT \\\n\tCTL_CODE(FILE_DEVICE_IPFW, IP_FW_BASE_CTL + 1, METHOD_BUFFERED, FILE_WRITE_DATA)\n#define IP_FW_GETSOCKOPT \\\n\tCTL_CODE(FILE_DEVICE_IPFW, IP_FW_BASE_CTL + 2, METHOD_BUFFERED, FILE_ANY_ACCESS)\n\n/*********************************\n* missing declarations in altq.c *\n**********************************/\n\n#define _IOWR(x,y,t) _IOW(x,y,t)\n\n/**********************************\n* missing declarations in ipfw2.c *\n***********************************/\n\n#define\tICMP_UNREACH_NET\t\t0\t/* bad net */\n#define\tICMP_UNREACH_HOST\t\t1\t/* bad host */\n#define\tICMP_UNREACH_PROTOCOL\t\t2\t/* bad protocol */\n#define\tICMP_UNREACH_PORT\t\t3\t/* bad port */\n#define\tICMP_UNREACH_NEEDFRAG\t\t4\t/* IP_DF caused drop */\n#define\tICMP_UNREACH_SRCFAIL\t\t5\t/* src route failed */\n#define\tICMP_UNREACH_NET_UNKNOWN\t6\t/* unknown net */\n#define\tICMP_UNREACH_HOST_UNKNOWN\t7\t/* unknown host */\n#define\tICMP_UNREACH_ISOLATED\t\t8\t/* src host isolated */\n#define\tICMP_UNREACH_NET_PROHIB\t\t9\t/* prohibited access */\n#define\tICMP_UNREACH_HOST_PROHIB\t10\t/* ditto */\n#define\tICMP_UNREACH_TOSNET\t\t11\t/* bad tos for net */\n#define\tICMP_UNREACH_TOSHOST\t\t12\t/* bad tos for host */\n#define\tICMP_UNREACH_FILTER_PROHIB\t13\t/* admin prohib */\n#define\tICMP_UNREACH_HOST_PRECEDENCE\t14\t/* host prec vio. */\n#define\tICMP_UNREACH_PRECEDENCE_CUTOFF\t15\t/* prec cutoff */\n\n\nstruct ether_addr;\nstruct ether_addr * ether_aton(const char *a);\n\n/*********************************\n* missing declarations in ipv6.c *\n**********************************/\n\nstruct hostent* gethostbyname2(const char *name, int af);\n\n#define strcasecmp strcmp // windows XXX ip_dummynet.c\n\n/********************\n* windows wrappings *\n*********************/\n\nint my_socket(int domain, int ty, int proto);\n#define socket(_a, _b, _c)\tmy_socket(_a, _b, _c)\n\n#endif /* _WIN32 */\n/*******************\n* SYSCTL emulation *\n********************/\n#if defined (_WIN32) || defined (EMULATE_SYSCTL)\n#define STRINGIFY(x) #x\n\n/* flag is set with the last 2 bits for access, as defined in glue.h\n * and the rest for type\n */\nenum {\n\tSYSCTLTYPE_INT = 0,\n\tSYSCTLTYPE_UINT,\n\tSYSCTLTYPE_SHORT,\n\tSYSCTLTYPE_USHORT,\n\tSYSCTLTYPE_LONG,\n\tSYSCTLTYPE_ULONG,\n\tSYSCTLTYPE_STRING,\n};\n\nstruct sysctlhead {\n\tuint32_t blocklen; //total size of the entry\n\tuint32_t namelen; //strlen(name) + '\\0'\n\tuint32_t flags; //type and access\n\tuint32_t datalen;\n};\n\n#ifdef _KERNEL\n\n#ifdef SYSCTL_NODE\n#undef SYSCTL_NODE\n#endif\n#define SYSCTL_NODE(a,b,c,d,e,f)\n#define SYSCTL_DECL(a)\n#define SYSCTL_VNET_PROC(a,b,c,d,e,f,g,h,i)\n\n#define GST_HARD_LIMIT 100\n\n/* In the module, GST is implemented as an array of\n * sysctlentry, but while passing data to the userland\n * pointers are useless, the buffer is actually made of:\n * - sysctlhead (fixed size, containing lengths)\n * - data (typically 32 bit)\n * - name (zero-terminated and padded to mod4)\n */\n\nstruct sysctlentry {\n\tstruct sysctlhead head;\n\tchar* name;\n\tvoid* data;\n};\n\nstruct sysctltable {\n\tint count; //number of valid tables\n\tint totalsize; //total size of valid entries of al the valid tables\n\tvoid* namebuffer; //a buffer for all chained names\n\tstruct sysctlentry entry[GST_HARD_LIMIT];\n};\n\n#ifdef SYSBEGIN\n#undef SYSBEGIN\n#endif\n#define SYSBEGIN(x) void sysctl_addgroup_##x() {\n#ifdef SYSEND\n#undef SYSEND\n#endif\n#define SYSEND }\n\n/* XXX remove duplication */\n#define SYSCTL_INT(a,b,c,d,e,f,g) \t\t\t\t\\\n\tsysctl_pushback(STRINGIFY(a) \".\" STRINGIFY(c) + 1,\t\\\n\t\t(d) | (SYSCTLTYPE_INT << 2), sizeof(*e), e)\n\n#define SYSCTL_VNET_INT(a,b,c,d,e,f,g)\t\t\t\t\\\n\tsysctl_pushback(STRINGIFY(a) \".\" STRINGIFY(c) + 1,\t\\\n\t\t(d) | (SYSCTLTYPE_INT << 2), sizeof(*e), e)\n\n#define SYSCTL_UINT(a,b,c,d,e,f,g)\t\t\t\t\\\n\tsysctl_pushback(STRINGIFY(a) \".\" STRINGIFY(c) + 1,\t\\\n\t\t(d) | (SYSCTLTYPE_UINT << 2), sizeof(*e), e)\n\n#define SYSCTL_VNET_UINT(a,b,c,d,e,f,g)\t\t\t\t\\\n\tsysctl_pushback(STRINGIFY(a) \".\" STRINGIFY(c) + 1,\t\\\n\t\t(d) | (SYSCTLTYPE_UINT << 2), sizeof(*e), e)\n\n#define SYSCTL_LONG(a,b,c,d,e,f,g)\t\t\t\t\\\n\tsysctl_pushback(STRINGIFY(a) \".\" STRINGIFY(c) + 1,\t\\\n\t\t(d) | (SYSCTLTYPE_LONG << 2), sizeof(*e), e)\n\n#define SYSCTL_ULONG(a,b,c,d,e,f,g)\t\t\t\t\\\n\tsysctl_pushback(STRINGIFY(a) \".\" STRINGIFY(c) + 1,\t\\\n\t\t(d) | (SYSCTLTYPE_ULONG << 2), sizeof(*e), e)\n#define TUNABLE_INT(a,b)\n\nvoid keinit_GST(void);\nvoid keexit_GST(void);\nint kesysctl_emu_set(void* p, int l);\nint kesysctl_emu_get(struct sockopt* sopt);\nvoid sysctl_pushback(char* name, int flags, int datalen, void* data);\n\n#endif /* _KERNEL */\n\nint sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,\n         size_t newlen);\n#endif /* _WIN32\" || EMULATE_SYSCTL */\n#ifdef _WIN32\nint do_cmd(int optname, void *optval, uintptr_t optlen);\n\n#endif /* _WIN32 */\n\n#define __PAST_END(v, idx)      v[idx]\n#endif /* !_GLUE_H */\n"
  },
  {
    "path": "ipfw/Makefile",
    "content": "#\n# $Id: Makefile 11688 2012-08-12 20:58:26Z luigi $\n#\n# GNUMakefile to build the userland part of ipfw on Linux and Windows\n#\n# Do not set with = or := so we can inherit from the caller\n\ninclude ../Makefile.inc\nTARGET := ipfw\n\nall: $(TARGET)\n\n#TCC=c:/path/to/tcc\n\n# common flags\nEXTRA_CFLAGS += -O1\nEXTRA_CFLAGS += -Wall\nEXTRA_CFLAGS += -include ../glue.h\nEXTRA_CFLAGS += -I ./include_e -I ./include\n\nifneq ($(VER),openwrt)\nifeq ($(OSARCH),Linux)\n    EXTRA_CFLAGS += -D__BSD_VISIBLE\n    EXTRA_CFLAGS += -Werror\n    # Required by GCC 4.6\n    EXTRA_CFLAGS += -Wno-unused-but-set-variable\nendif\nifeq ($(OSARCH),FreeBSD)\n    EXTRA_CFLAGS += -D__BSD_VISIBLE\n    EXTRA_CFLAGS += -Werror\nendif\nifeq ($(OSARCH),Darwin)\n    EXTRA_CFLAGS += -D__BSD_VISIBLE\n    EXTRA_CFLAGS += -Werror\nendif\n\nifeq ($(OSARCH),Windows)\n# we only support Cygwin and tcc as compilers.\nifeq ($(WIN64),1)\n    EXTRA_CFLAGS += -D_X64EMU\nendif\n\nifeq ($(TCC),)\t# cygwin\n    EXTRA_CFLAGS += -I/cygdrive/c/$(DDKDIR)/inc/ddk\n    EXTRA_CFLAGS += -I .\n    EXTRA_CFLAGS += -pipe -Wall\nelse\t\t#-- build with tcc\n    # TCC points to the root of tcc tree\n    CC=$(TCC)/tcc.exe\n    EXTRA_CFLAGS += -DTCC -I..\n    EXTRA_CFLAGS += -I$(TCC)/include/winapi -I$(TCC)/include\n    EXTRA_CFLAGS += -nostdinc\n\n    EFILES_. += err.h grp.h netdb.h pwd.h sysexits.h\n    EFILES_arpa += inet.h\n    EFILES_net += if.h\n    EFILES_netinet += in.h in_systm.h ip.h ip_icmp.h\n    EFILES_sys += cdefs.h wait.h ioctl.h socket.h\n\nendif\n    # EXTRA_CFLAGS += -D_WIN32 # see who defines it\n    EXTRA_CFLAGS += -Dsetsockopt=wnd_setsockopt\n    EXTRA_CFLAGS += -Dgetsockopt=wnd_getsockopt\n    EXTRA_CFLAGS += -DEMULATE_SYSCTL\n    EFILES_net += ethernet.h route.h\n    EFILES_netinet += ether.h icmp6.h\n    EFILES_sys += sysctl.h\n    TARGET = ipfw.exe\nipfw: $(TARGET)\nendif # windows\nendif # !openwrt\n\nCFLAGS += $(EXTRA_CFLAGS)\n# Location of OS headers and libraries. After our stuff.\nUSRDIR?= /usr\nifeq ($(TCC),)\n    CFLAGS += -I$(USRDIR)/include\n    LDFLAGS += -L$(USRDIR)/lib\nelse\n    LDFLAGS += -L. -L$(TCC)/lib -lws2_32\nendif\n\nOBJS = ipfw2.o dummynet.o main.o ipv6.o qsort_r.o\nOBJS += expand_number.o humanize_number.o glue.o\n\n# we don't use ALTQ\nCFLAGS += -DNO_ALTQ\n#OBJS += altq.o\n\n\n$(TARGET): $(OBJS)\n\t$(MSG) \"   LD  $@\"\n\t$(HIDE)$(CC) $(LDFLAGS) -o $@ $^\n\n$(OBJS) : ipfw2.h ../glue.h include_e\n\n# support to create empty dirs and files in include_e/\n# EDIRS is the list of directories, EFILES is the list of files.\nEFILES_sys  += sockio.h\nEFILES_.    += libutil.h\nEFILES_netinet += __emtpy.h\n\nM ?= $(shell pwd)\n\n# first make a list of directories from variable names\nEDIRS= $(subst EFILES_,,$(filter EFILES_%,$(.VARIABLES)))\n# then prepend the directory name to individual files.\n#       $(empty) serves to interpret the following space literally,\n#       and the \":  = \" substitution packs spaces into one.\nEFILES = $(foreach i,$(EDIRS),$(subst $(empty) , $(i)/, $(EFILES_$(i):  = )))\n\ninclude_e:\n\t$(MSG) \"building include_e in $M\"\n\t-@rm -rf $(M)/include_e opt_*\n\t-@mkdir -p $(M)/include_e\n\t-@(cd $(M)/include_e; mkdir -p $(EDIRS); touch $(EFILES) )\n\t-@(cd $(M)/include_e/netinet; \\\n\t\tfor i in ip_fw.h ip_dummynet.h tcp.h; do \\\n\t\tcp ../../../sys/netinet/$$i .; done; )\n\nclean distclean:\n\t-@rm -rf $(OBJS) $(TARGET) include_e\n\ndiff:\n\t-@(diff -upr $(BSD_HEAD)/sbin/ipfw .)\n\n"
  },
  {
    "path": "ipfw/add_rules",
    "content": "#!/bin/bash\n#\n# A test script to add rules\n\nPRG=./ipfw\n\nmyfun() {\n\t$PRG add 10 count icmp from any to 131.114.9.128\n\t$PRG add 20 count icmp from 131.114.9.128 to any\n\t$PRG add 20 count icmp from any to 131.114.9.130\n\t$PRG add 30 count icmp from 131.114.9.130 to any\n\t$PRG add 40 count icmp from any to 131.114.9.129\n\t$PRG add 50 count icmp from 131.114.9.129 to any\n\t$PRG add 60 count icmp from 131.114.9.236 to any\n\tsleep 1\n\t$PRG del 10\n\t$PRG del 20\n\t$PRG del 20\n\t$PRG del 30\n\t$PRG del 40\n\t$PRG del 50\n\t$PRG del 60\n}\n\nfor ((i=0;i<100;i++)) ; do\n\tmyfun\ndone\n"
  },
  {
    "path": "ipfw/dummynet.c",
    "content": "/*\n * Copyright (c) 2002-2003,2010 Luigi Rizzo\n *\n * Redistribution and use in source forms, with and without modification,\n * are permitted provided that this entire comment appears intact.\n *\n * Redistribution in binary form may occur without any restrictions.\n * Obviously, it would be nice if you gave credit where credit is due\n * but requiring it would be too onerous.\n *\n * This software is provided ``AS IS'' without any warranties of any kind.\n *\n * $FreeBSD: head/sbin/ipfw/dummynet.c 206843 2010-04-19 15:11:45Z luigi $\n *\n * dummynet support\n */\n\n#include <sys/types.h>\n#include <sys/socket.h>\n/* XXX there are several sysctl leftover here */\n#include <sys/sysctl.h>\n\n#include \"ipfw2.h\"\n\n#include <ctype.h>\n#include <err.h>\n#include <errno.h>\n#include <libutil.h>\n#include <netdb.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sysexits.h>\n\n#include <net/if.h>\n#include <netinet/in.h>\n#include <netinet/ip_fw.h>\n#include <netinet/ip_dummynet.h>\n#include <arpa/inet.h>\t/* inet_ntoa */\n\n\nstatic struct _s_x dummynet_params[] = {\n\t{ \"plr\",\t\tTOK_PLR },\n\t{ \"noerror\",\t\tTOK_NOERROR },\n\t{ \"buckets\",\t\tTOK_BUCKETS },\n\t{ \"dst-ip\",\t\tTOK_DSTIP },\n\t{ \"src-ip\",\t\tTOK_SRCIP },\n\t{ \"dst-port\",\t\tTOK_DSTPORT },\n\t{ \"src-port\",\t\tTOK_SRCPORT },\n\t{ \"proto\",\t\tTOK_PROTO },\n\t{ \"weight\",\t\tTOK_WEIGHT },\n\t{ \"lmax\",\t\tTOK_LMAX },\n\t{ \"maxlen\",\t\tTOK_LMAX },\n\t{ \"all\",\t\tTOK_ALL },\n\t{ \"mask\",\t\tTOK_MASK }, /* alias for both */\n\t{ \"sched_mask\",\t\tTOK_SCHED_MASK },\n\t{ \"flow_mask\",\t\tTOK_FLOW_MASK },\n\t{ \"droptail\",\t\tTOK_DROPTAIL },\n\t{ \"red\",\t\tTOK_RED },\n\t{ \"gred\",\t\tTOK_GRED },\n\t{ \"bw\",\t\t\tTOK_BW },\n\t{ \"bandwidth\",\t\tTOK_BW },\n\t{ \"delay\",\t\tTOK_DELAY },\n\t{ \"link\",\t\tTOK_LINK },\n\t{ \"pipe\",\t\tTOK_PIPE },\n\t{ \"queue\",\t\tTOK_QUEUE },\n\t{ \"flowset\",\t\tTOK_FLOWSET },\n\t{ \"sched\",\t\tTOK_SCHED },\n\t{ \"pri\",\t\tTOK_PRI },\n\t{ \"priority\",\t\tTOK_PRI },\n\t{ \"type\",\t\tTOK_TYPE },\n\t{ \"flow-id\",\t\tTOK_FLOWID},\n\t{ \"dst-ipv6\",\t\tTOK_DSTIP6},\n\t{ \"dst-ip6\",\t\tTOK_DSTIP6},\n\t{ \"src-ipv6\",\t\tTOK_SRCIP6},\n\t{ \"src-ip6\",\t\tTOK_SRCIP6},\n\t{ \"profile\",\t\tTOK_PROFILE},\n\t{ \"burst\",\t\tTOK_BURST},\n\t{ \"dummynet-params\",\tTOK_NULL },\n\t{ NULL, 0 }\t/* terminator */\n};\n\n#define O_NEXT(p, len) ((void *)((char *)p + len))\n\nstatic void\noid_fill(struct dn_id *oid, int len, int type, uintptr_t id)\n{\n\toid->len = len;\n\toid->type = type;\n\toid->subtype = 0;\n\toid->id = id;\n}\n\n/* make room in the buffer and move the pointer forward */\nstatic void *\no_next(struct dn_id **o, int len, int type)\n{\n\tstruct dn_id *ret = *o;\n\toid_fill(ret, len, type, 0);\n\t*o = O_NEXT(*o, len);\n\treturn ret;\n}\n\n/* handle variable length structures moving back the pointer and fixing length */\nstatic void *\no_compact(struct dn_id **o, int len, int real_length, int type)\n{\n        struct dn_id *ret = *o;\n\n        ret = O_NEXT(*o, -len);\n        oid_fill(ret, real_length, type, 0);\n        *o = O_NEXT(ret, real_length);\n        return ret;\n}\n\n#if 0\nstatic int\nsort_q(void *arg, const void *pa, const void *pb)\n{\n\tint rev = (co.do_sort < 0);\n\tint field = rev ? -co.do_sort : co.do_sort;\n\tlong long res = 0;\n\tconst struct dn_flow_queue *a = pa;\n\tconst struct dn_flow_queue *b = pb;\n\n\tswitch (field) {\n\tcase 1: /* pkts */\n\t\tres = a->len - b->len;\n\t\tbreak;\n\tcase 2: /* bytes */\n\t\tres = a->len_bytes - b->len_bytes;\n\t\tbreak;\n\n\tcase 3: /* tot pkts */\n\t\tres = a->tot_pkts - b->tot_pkts;\n\t\tbreak;\n\n\tcase 4: /* tot bytes */\n\t\tres = a->tot_bytes - b->tot_bytes;\n\t\tbreak;\n\t}\n\tif (res < 0)\n\t\tres = -1;\n\tif (res > 0)\n\t\tres = 1;\n\treturn (int)(rev ? res : -res);\n}\n#endif\n\n/* print a mask and header for the subsequent list of flows */\nstatic void\nprint_mask(struct ipfw_flow_id *id)\n{\n\tif (!IS_IP6_FLOW_ID(id)) {\n\t\tprintf(\"    \"\n\t\t    \"mask: %s 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\\n\",\n\t\t    id->extra ? \"queue,\" : \"\",\n\t\t    id->proto,\n\t\t    id->src_ip, id->src_port,\n\t\t    id->dst_ip, id->dst_port);\n\t} else {\n\t\tchar buf[255];\n\t\tprintf(\"\\n        mask: %sproto: 0x%02x, flow_id: 0x%08x,  \",\n\t\t    id->extra ? \"queue,\" : \"\",\n\t\t    id->proto, id->flow_id6);\n\t\tinet_ntop(AF_INET6, &(id->src_ip6), buf, sizeof(buf));\n\t\tprintf(\"%s/0x%04x -> \", buf, id->src_port);\n\t\tinet_ntop(AF_INET6, &(id->dst_ip6), buf, sizeof(buf));\n\t\tprintf(\"%s/0x%04x\\n\", buf, id->dst_port);\n\t}\n}\n\nstatic void\nprint_header(struct ipfw_flow_id *id)\n{\n\tif (!IS_IP6_FLOW_ID(id))\n\t\tprintf(\"BKT Prot ___Source IP/port____ \"\n\t\t    \"____Dest. IP/port____ \"\n\t\t    \"Tot_pkt/bytes Pkt/Byte Drp\\n\");\n\telse\n\t\tprintf(\"BKT ___Prot___ _flow-id_ \"\n\t\t    \"______________Source IPv6/port_______________ \"\n\t\t    \"_______________Dest. IPv6/port_______________ \"\n\t\t    \"Tot_pkt/bytes Pkt/Byte Drp\\n\");\n}\n\nstatic void\nlist_flow(struct dn_flow *ni, int *print)\n{\n\tchar buff[255];\n\tstruct protoent *pe = NULL;\n\tstruct in_addr ina;\n\tstruct ipfw_flow_id *id = &ni->fid;\n\n\tif (*print) {\n\t\tprint_header(&ni->fid);\n\t\t*print = 0;\n\t}\n\tpe = getprotobynumber(id->proto);\n\t\t/* XXX: Should check for IPv4 flows */\n\tprintf(\"%3u%c\", (ni->oid.id) & 0xff,\n\t\tid->extra ? '*' : ' ');\n\tif (!IS_IP6_FLOW_ID(id)) {\n\t\tif (pe)\n\t\t\tprintf(\"%-4s \", pe->p_name);\n\t\telse\n\t\t\tprintf(\"%4u \", id->proto);\n\t\tina.s_addr = htonl(id->src_ip);\n\t\tprintf(\"%15s/%-5d \",\n\t\t    inet_ntoa(ina), id->src_port);\n\t\tina.s_addr = htonl(id->dst_ip);\n\t\tprintf(\"%15s/%-5d \",\n\t\t    inet_ntoa(ina), id->dst_port);\n\t} else {\n\t\t/* Print IPv6 flows */\n\t\tif (pe != NULL)\n\t\t\tprintf(\"%9s \", pe->p_name);\n\t\telse\n\t\t\tprintf(\"%9u \", id->proto);\n\t\tprintf(\"%7d  %39s/%-5d \", id->flow_id6,\n\t\t    inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)),\n\t\t    id->src_port);\n\t\tprintf(\" %39s/%-5d \",\n\t\t    inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)),\n\t\t    id->dst_port);\n\t}\n\tpr_u64(&ni->tot_pkts, 4);\n\tpr_u64(&ni->tot_bytes, 8);\n\tprintf(\"%2u %4u %3u\\n\",\n\t    ni->length, ni->len_bytes, ni->drops);\n}\n\nstatic void\nprint_flowset_parms(struct dn_fs *fs, char *prefix)\n{\n\tint l;\n\tchar qs[30];\n\tchar plr[30];\n\tchar red[90];\t/* Display RED parameters */\n\n\tl = fs->qsize;\n\tif (fs->flags & DN_QSIZE_BYTES) {\n\t\tif (l >= 8192)\n\t\t\tsprintf(qs, \"%d KB\", l / 1024);\n\t\telse\n\t\t\tsprintf(qs, \"%d B\", l);\n\t} else\n\t\tsprintf(qs, \"%3d sl.\", l);\n\tif (fs->plr)\n\t\tsprintf(plr, \"plr %f\", 1.0 * fs->plr / (double)(0x7fffffff));\n\telse\n\t\tplr[0] = '\\0';\n\n\tif (fs->flags & DN_IS_RED)\t/* RED parameters */\n\t\tsprintf(red,\n\t\t    \"\\n\\t %cRED w_q %f min_th %d max_th %d max_p %f\",\n\t\t    (fs->flags & DN_IS_GENTLE_RED) ? 'G' : ' ',\n\t\t    1.0 * fs->w_q / (double)(1 << SCALE_RED),\n\t\t    fs->min_th,\n\t\t    fs->max_th,\n\t\t    1.0 * fs->max_p / (double)(1 << SCALE_RED));\n\telse\n\t\tsprintf(red, \"droptail\");\n\n\tif (prefix[0]) {\n\t    printf(\"%s %s%s %d queues (%d buckets) %s\\n\",\n\t\tprefix, qs, plr, fs->oid.id, fs->buckets, red);\n\t    prefix[0] = '\\0';\n\t} else {\n\t    printf(\"q%05d %s%s %d flows (%d buckets) sched %d \"\n\t\t\t\"weight %d lmax %d pri %d %s\\n\",\n\t\tfs->fs_nr, qs, plr, fs->oid.id, fs->buckets,\n\t\tfs->sched_nr, fs->par[0], fs->par[1], fs->par[2], red);\n\t    if (fs->flags & DN_HAVE_MASK)\n\t\tprint_mask(&fs->flow_mask);\n\t}\n}\n\nstatic void\nprint_extra_delay_parms(struct dn_profile *p)\n{\n\tdouble loss;\n\tif (p->samples_no <= 0)\n\t\treturn;\n\n\tloss = p->loss_level;\n\tloss /= p->samples_no;\n\tprintf(\"\\t profile: name \\\"%s\\\" loss %f samples %d\\n\",\n\t\tp->name, loss, p->samples_no);\n}\n\nstatic void\nflush_buf(char *buf)\n{\n\tif (buf[0])\n\t\tprintf(\"%s\\n\", buf);\n\tbuf[0] = '\\0';\n}\n\n/*\n * generic list routine. We expect objects in a specific order, i.e.\n * PIPES AND SCHEDULERS:\n *\tlink; scheduler; internal flowset if any; instances\n * we can tell a pipe from the number.\n *\n * FLOWSETS:\n *\tflowset; queues;\n * link i (int queue); scheduler i; si(i) { flowsets() : queues }\n */\nstatic void\nlist_pipes(struct dn_id *oid, struct dn_id *end)\n{\n    char buf[160];\t/* pending buffer */\n    int toPrint = 1;\t/* print header */\n\n    buf[0] = '\\0';\n    for (; oid != end; oid = O_NEXT(oid, oid->len)) {\n\tif (oid->len < sizeof(*oid))\n\t\terrx(1, \"invalid oid len %d\\n\", oid->len);\n\n\tswitch (oid->type) {\n\tdefault:\n\t    flush_buf(buf);\n\t    printf(\"unrecognized object %d size %d\\n\", oid->type, oid->len);\n\t    break;\n\tcase DN_TEXT: /* list of attached flowsets */\n\t    {\n\t\tint i, l;\n\t\tstruct {\n\t\t\tstruct dn_id id;\n\t\t\tuint32_t p[0];\n\t\t} *d = (void *)oid;\n\t\tl = (oid->len - sizeof(*oid))/sizeof(d->p[0]);\n\t\tif (l == 0)\n\t\t    break;\n\t\tprintf(\"   Children flowsets: \");\n\t\tfor (i = 0; i < l; i++)\n\t\t\tprintf(\"%u \", d->p[i]);\n\t\tprintf(\"\\n\");\n\t\tbreak;\n\t    }\n\tcase DN_CMD_GET:\n\t    if (co.verbose)\n\t\tprintf(\"answer for cmd %d, len %d\\n\", oid->type, oid->id);\n\t    break;\n\tcase DN_SCH: {\n\t    struct dn_sch *s = (struct dn_sch *)oid;\n\t    flush_buf(buf);\n\t    printf(\" sched %d type %s flags 0x%x %d buckets %d active\\n\",\n\t\t\ts->sched_nr,\n\t\t\ts->name, s->flags, s->buckets, s->oid.id);\n\t    if (s->flags & DN_HAVE_MASK)\n\t\tprint_mask(&s->sched_mask);\n\t    }\n\t    break;\n\n\tcase DN_FLOW:\n\t    list_flow((struct dn_flow *)oid, &toPrint);\n\t    break;\n\n\tcase DN_LINK: {\n\t    struct dn_link *p = (struct dn_link *)oid;\n\t    double b = p->bandwidth;\n\t    char bwbuf[30];\n\t    char burst[5 + 7];\n\n\t    /* This starts a new object so flush buffer */\n\t    flush_buf(buf);\n\t    /* data rate */\n\t    if (b == 0)\n\t\tsprintf(bwbuf, \"unlimited     \");\n\t    else if (b >= 1000000)\n\t\tsprintf(bwbuf, \"%7.3f Mbit/s\", b/1000000);\n\t    else if (b >= 1000)\n\t\tsprintf(bwbuf, \"%7.3f Kbit/s\", b/1000);\n\t    else\n\t\tsprintf(bwbuf, \"%7.3f bit/s \", b);\n\n\t    if (humanize_number(burst, sizeof(burst), p->burst,\n\t\t    \"\", HN_AUTOSCALE, 0) < 0 || co.verbose)\n\t\tsprintf(burst, \"%d\", (int)p->burst);\n\t    sprintf(buf, \"%05d: %s %4d ms burst %s\",\n\t\tp->link_nr % DN_MAX_ID, bwbuf, p->delay, burst);\n\t    }\n\t    break;\n\n\tcase DN_FS:\n\t    print_flowset_parms((struct dn_fs *)oid, buf);\n\t    break;\n\tcase DN_PROFILE:\n\t    flush_buf(buf);\n\t    print_extra_delay_parms((struct dn_profile *)oid);\n\t}\n\tflush_buf(buf); // XXX does it really go here ?\n    }\n}\n\n/*\n * Delete pipe, queue or scheduler i\n */\nint\nipfw_delete_pipe(int do_pipe, int i)\n{\n\tstruct {\n\t\tstruct dn_id oid;\n\t\tuintptr_t a[1];\t/* add more if we want a list */\n\t} cmd;\n\toid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION);\n\tcmd.oid.subtype = (do_pipe == 1) ? DN_LINK :\n\t\t( (do_pipe == 2) ? DN_FS : DN_SCH);\n\tcmd.a[0] = i;\n\ti = do_cmd(IP_DUMMYNET3, &cmd, cmd.oid.len);\n\tif (i) {\n\t\ti = 1;\n\t\twarn(\"rule %u: setsockopt(IP_DUMMYNET_DEL)\", i);\n\t}\n\treturn i;\n}\n\n/*\n * Code to parse delay profiles.\n *\n * Some link types introduce extra delays in the transmission\n * of a packet, e.g. because of MAC level framing, contention on\n * the use of the channel, MAC level retransmissions and so on.\n * From our point of view, the channel is effectively unavailable\n * for this extra time, which is constant or variable depending\n * on the link type. Additionally, packets may be dropped after this\n * time (e.g. on a wireless link after too many retransmissions).\n * We can model the additional delay with an empirical curve\n * that represents its distribution.\n *\n *      cumulative probability\n *      1.0 ^\n *          |\n *      L   +-- loss-level          x\n *          |                 ******\n *          |                *\n *          |           *****\n *          |          *\n *          |        **\n *          |       *\n *          +-------*------------------->\n *                      delay\n *\n * The empirical curve may have both vertical and horizontal lines.\n * Vertical lines represent constant delay for a range of\n * probabilities; horizontal lines correspond to a discontinuty\n * in the delay distribution: the link will use the largest delay\n * for a given probability.\n *\n * To pass the curve to dummynet, we must store the parameters\n * in a file as described below, and issue the command\n *\n *      ipfw pipe <n> config ... bw XXX profile <filename> ...\n *\n * The file format is the following, with whitespace acting as\n * a separator and '#' indicating the beginning a comment:\n *\n *\tsamples N\n *\t\tthe number of samples used in the internal\n *\t\trepresentation (2..1024; default 100);\n *\n *\tloss-level L\n *\t\tThe probability above which packets are lost.\n *\t       (0.0 <= L <= 1.0, default 1.0 i.e. no loss);\n *\n *\tname identifier\n *\t\tOptional a name (listed by \"ipfw pipe show\")\n *\t\tto identify the distribution;\n *\n *\t\"delay prob\" | \"prob delay\"\n *\t\tOne of these two lines is mandatory and defines\n *\t\tthe format of the following lines with data points.\n *\n *\tXXX YYY\n *\t\t2 or more lines representing points in the curve,\n *\t\twith either delay or probability first, according\n *\t\tto the chosen format.\n *\t\tThe unit for delay is milliseconds.\n *\n * Data points does not need to be ordered or equal to the number\n * specified in the \"samples\" line. ipfw will sort and interpolate\n * the curve as needed.\n *\n * Example of a profile file:\n\n\tname    bla_bla_bla\n\tsamples 100\n\tloss-level    0.86\n\tprob    delay\n\t0       200\t# minimum overhead is 200ms\n\t0.5     200\n\t0.5     300\n\t0.8     1000\n\t0.9     1300\n\t1       1300\n\n * Internally, we will convert the curve to a fixed number of\n * samples, and when it is time to transmit a packet we will\n * model the extra delay as extra bits in the packet.\n *\n */\n\n#define ED_MAX_LINE_LEN\t256+ED_MAX_NAME_LEN\n#define ED_TOK_SAMPLES\t\"samples\"\n#define ED_TOK_LOSS\t\"loss-level\"\n#define ED_TOK_NAME\t\"name\"\n#define ED_TOK_DELAY\t\"delay\"\n#define ED_TOK_PROB\t\"prob\"\n#define ED_TOK_BW\t\"bw\"\n#define ED_SEPARATORS\t\" \\t\\n\"\n#define ED_MIN_SAMPLES_NO\t2\n\n/*\n * returns 1 if s is a non-negative number, with at least one '.'\n */\nstatic int\nis_valid_number(const char *s)\n{\n\tint i, dots_found = 0;\n\tint len = strlen(s);\n\n\tfor (i = 0; i<len; ++i)\n\t\tif (!isdigit(s[i]) && (s[i] !='.' || ++dots_found > 1))\n\t\t\treturn 0;\n\treturn 1;\n}\n\n/*\n * Take as input a string describing a bandwidth value\n * and return the numeric bandwidth value.\n * set clocking interface or bandwidth value\n */\nstatic void\nread_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen)\n{\n\tif (*bandwidth != -1)\n\t\twarnx(\"duplicate token, override bandwidth value!\");\n\n\tif (arg[0] >= 'a' && arg[0] <= 'z') {\n\t\tif (!if_name) {\n\t\t\terrx(1, \"no if support\");\n\t\t}\n\t\tif (namelen >= IFNAMSIZ)\n\t\t\twarn(\"interface name truncated\");\n\t\tnamelen--;\n\t\t/* interface name */\n\t\tstrncpy(if_name, arg, namelen);\n\t\tif_name[namelen] = '\\0';\n\t\t*bandwidth = 0;\n\t} else {\t/* read bandwidth value */\n\t\tint bw;\n\t\tchar *end = NULL;\n\n\t\tbw = strtoul(arg, &end, 0);\n\t\tif (*end == 'K' || *end == 'k') {\n\t\t\tend++;\n\t\t\tbw *= 1000;\n\t\t} else if (*end == 'M' || *end == 'm') {\n\t\t\tend++;\n\t\t\tbw *= 1000000;\n\t\t}\n\t\tif ((*end == 'B' &&\n\t\t\t_substrcmp2(end, \"Bi\", \"Bit/s\") != 0) ||\n\t\t    _substrcmp2(end, \"by\", \"bytes\") == 0)\n\t\t\tbw *= 8;\n\n\t\tif (bw < 0)\n\t\t\terrx(EX_DATAERR, \"bandwidth too large\");\n\n\t\t*bandwidth = bw;\n\t\tif (if_name)\n\t\t\tif_name[0] = '\\0';\n\t}\n}\n\nstruct point {\n\tdouble prob;\n\tdouble delay;\n};\n\nstatic int\ncompare_points(const void *vp1, const void *vp2)\n{\n\tconst struct point *p1 = vp1;\n\tconst struct point *p2 = vp2;\n\tdouble res = 0;\n\n\tres = p1->prob - p2->prob;\n\tif (res == 0)\n\t\tres = p1->delay - p2->delay;\n\tif (res < 0)\n\t\treturn -1;\n\telse if (res > 0)\n\t\treturn 1;\n\telse\n\t\treturn 0;\n}\n\n#define ED_EFMT(s) EX_DATAERR,\"error in %s at line %d: \"#s,filename,lineno\n\n/*\n * Interpolate a set of proability-value tuples.\n *\n * This function takes as input a tuple of values <prob, value>\n * and samples the interpolated curve described from the tuples.\n *\n * The user defined points are stored in the ponts structure.\n * The number of points is stored in points_no.\n * The user defined sampling value is stored in samples_no.\n * The resulting samples are in the \"samples\" pointer.\n *\n *       We assume that The last point for the '1' value of the\n *       probability should be defined. (XXX add checks for this)\n *\n * The input data are points and points_no.\n * The output data are s (the array of s_no samples)\n * and s_no (the number of samples)\n *\n */\nstatic void\ninterpolate_samples(struct point *p, int points_no,\n\t\tint *samples, int samples_no, const char *filename)\n{\n\tdouble dy;\t\t/* delta on the y axis */\n\tdouble y;\t\t/* current value of y */\n\tdouble x;\t\t/* current value of x */\n\tdouble m;\t\t/* the y slope */\n\tint i;\t\t\t/* samples index */\n\tint curr;\t\t/* points current index */\n\n        /* make sure that there are enough points. */\n        /* XXX Duplicated should be removed */\n        if (points_no < 3)\n            errx(EX_DATAERR, \"%s too few samples, need at least %d\",\n                filename, 3);\n\n        qsort(p, points_no, sizeof(struct point), compare_points);\n\n\tdy = 1.0/samples_no;\n\ty = 0;\n\n\tfor (i=0, curr = 0; i < samples_no; i++, y+=dy) {\n\t\t/* This statment move the curr pointer to the next point\n\t\t * skipping the points with the same x value. We are\n\t\t * guaranteed to exit from the loop because the\n\t\t * last possible value of y is stricly less than 1\n\t\t * and the last possible value of the y points is 1 */\n\t\twhile ( y >= p[curr+1].prob ) curr++;\n\n\t\t/* compute the slope of the curve */\n\t\tm = (p[curr+1].delay - p[curr].delay) / (p[curr+1].prob - p[curr].prob);\n\t\t/* compute the x value starting from the current point */\n\t\tx = p[curr].delay + (y - p[curr].prob) * m;\n\t\tsamples[i] = x;\n\t}\n\n\t/* add the last sample */\n\tsamples[i] = p[curr+1].delay;\n}\n\n/*\n * p is the link (old pipe)\n * pf is the profile\n */\nstatic void\nload_extra_delays(const char *filename, struct dn_profile *p,\n\tstruct dn_link *link)\n{\n\tchar    line[ED_MAX_LINE_LEN];\n\tFILE    *f;\n\tint     lineno = 0;\n\n\tint     samples = -1;\n\tdouble  loss = -1.0;\n\tchar    profile_name[ED_MAX_NAME_LEN];\n\tint     delay_first = -1;\n\tint     do_points = 0;\n\tstruct point    points[ED_MAX_SAMPLES_NO];\n\tint     points_no = 0;\n\n\t/* XXX link never NULL? */\n\tp->link_nr = link->link_nr;\n\n\tprofile_name[0] = '\\0';\n\tf = fopen(filename, \"r\");\n\tif (f == NULL)\n\t\terr(EX_UNAVAILABLE, \"fopen: %s\", filename);\n\n\twhile (fgets(line, ED_MAX_LINE_LEN, f)) {\t /* read commands */\n\t\tchar *s, *cur = line, *name = NULL, *arg = NULL;\n\n\t\t++lineno;\n\n\t\t/* parse the line */\n\t\twhile (cur) {\n\t\t\ts = strsep(&cur, ED_SEPARATORS);\n\t\t\tif (s == NULL || *s == '#')\n\t\t\t\tbreak;\n\t\t\tif (*s == '\\0')\n\t\t\t\tcontinue;\n\t\t\tif (arg)\n\t\t\t\terrx(ED_EFMT(\"too many arguments\"));\n\t\t\tif (name == NULL)\n\t\t\t\tname = s;\n\t\t\telse\n\t\t\t\targ = s;\n\t\t}\n\n\t\tif ((name == NULL) || (*name == '#'))   /* empty line */\n\t\t\tcontinue;\n\t\tif (arg == NULL)\n\t\t\terrx(ED_EFMT(\"missing arg for %s\"), name);\n\n\t\tif (!strcasecmp(name, ED_TOK_SAMPLES)) {\n\t\t    if (samples > 0)\n\t\t\terrx(ED_EFMT(\"duplicate ``samples'' line\"));\n\t\t    if (atoi(arg) <=0)\n\t\t\terrx(ED_EFMT(\"invalid number of samples\"));\n\t\t    samples = atoi(arg);\n\t\t    if (samples>=ED_MAX_SAMPLES_NO-1)\n\t\t\t    errx(ED_EFMT(\"too many samples, maximum is %d\"),\n\t\t\t\tED_MAX_SAMPLES_NO-1);\n\t\t    do_points = 0;\n\t\t} else if (!strcasecmp(name, ED_TOK_BW)) {\n\t\t    char buf[IFNAMSIZ];\n\t\t    read_bandwidth(arg, &link->bandwidth, buf, sizeof(buf));\n\t\t    p->bandwidth = link->bandwidth;\n\t\t} else if (!strcasecmp(name, ED_TOK_LOSS)) {\n\t\t    if (loss != -1.0)\n\t\t\terrx(ED_EFMT(\"duplicated token: %s\"), name);\n\t\t    if (!is_valid_number(arg))\n\t\t\terrx(ED_EFMT(\"invalid %s\"), arg);\n\t\t    loss = atof(arg);\n\t\t    if (loss > 1)\n\t\t\terrx(ED_EFMT(\"%s greater than 1.0\"), name);\n\t\t    do_points = 0;\n\t\t} else if (!strcasecmp(name, ED_TOK_NAME)) {\n\t\t    if (profile_name[0] != '\\0')\n\t\t\terrx(ED_EFMT(\"duplicated token: %s\"), name);\n\t\t    strncpy(profile_name, arg, sizeof(profile_name) - 1);\n\t\t    profile_name[sizeof(profile_name)-1] = '\\0';\n\t\t    do_points = 0;\n\t\t} else if (!strcasecmp(name, ED_TOK_DELAY)) {\n\t\t    if (do_points)\n\t\t\terrx(ED_EFMT(\"duplicated token: %s\"), name);\n\t\t    delay_first = 1;\n\t\t    do_points = 1;\n\t\t} else if (!strcasecmp(name, ED_TOK_PROB)) {\n\t\t    if (do_points)\n\t\t\terrx(ED_EFMT(\"duplicated token: %s\"), name);\n\t\t    delay_first = 0;\n\t\t    do_points = 1;\n\t\t} else if (do_points) {\n\t\t    if (!is_valid_number(name) || !is_valid_number(arg))\n\t\t\terrx(ED_EFMT(\"invalid point found\"));\n\t\t    if (delay_first) {\n\t\t\tpoints[points_no].delay = atof(name);\n\t\t\tpoints[points_no].prob = atof(arg);\n\t\t    } else {\n\t\t\tpoints[points_no].delay = atof(arg);\n\t\t\tpoints[points_no].prob = atof(name);\n\t\t    }\n\t\t    if (points[points_no].prob > 1.0)\n\t\t\terrx(ED_EFMT(\"probability greater than 1.0\"));\n\t\t    ++points_no;\n\t\t} else {\n\t\t    errx(ED_EFMT(\"unrecognised command '%s'\"), name);\n\t\t}\n\t}\n\n\tfclose (f);\n\n\tif (samples == -1) {\n\t    warnx(\"'%s' not found, assuming 100\", ED_TOK_SAMPLES);\n\t    samples = 100;\n\t}\n\n\tif (loss == -1.0) {\n\t    warnx(\"'%s' not found, assuming no loss\", ED_TOK_LOSS);\n\t    loss = 1;\n\t}\n\n\tinterpolate_samples(points, points_no, p->samples, samples, filename);\n\n\tp->samples_no = samples++;\n\tp->loss_level = loss * samples;\n\tstrncpy(p->name, profile_name, sizeof(p->name));\n}\n\n/*\n * configuration of pipes, schedulers, flowsets.\n * When we configure a new scheduler, an empty pipe is created, so:\n *\n * do_pipe = 1 -> \"pipe N config ...\" only for backward compatibility\n *\tsched N+Delta type fifo sched_mask ...\n *\tpipe N+Delta <parameters>\n *\tflowset N+Delta pipe N+Delta (no parameters)\n *\tsched N type wf2q+ sched_mask ...\n *\tpipe N <parameters>\n *\n * do_pipe = 2 -> flowset N config\n *\tflowset N parameters\n *\n * do_pipe = 3 -> sched N config\n *\tsched N parameters (default no pipe)\n *\toptional Pipe N config ...\n * pipe ==>\n */\nvoid\nipfw_config_pipe(int ac, char **av)\n{\n\tint i;\n\tu_int j;\n\tchar *end;\n\tvoid *par = NULL;\n\tstruct dn_id *buf, *base;\n\tstruct dn_sch *sch = NULL;\n\tstruct dn_link *p = NULL;\n\tstruct dn_fs *fs = NULL;\n\tstruct dn_profile *pf = NULL;\n\tstruct ipfw_flow_id *mask = NULL;\n\tint lmax;\n\tuint32_t _foo = 0, *flags = &_foo , *buckets = &_foo;\n\tsize_t max_pf_size = sizeof(struct dn_profile) + ED_MAX_SAMPLES_NO * sizeof(int);\n\n\t/*\n\t * allocate space for 1 header,\n\t * 1 scheduler, 1 link, 1 flowset, 1 profile\n\t */\n\tlmax = sizeof(struct dn_id);\t/* command header */\n\tlmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +\n\t\tsizeof(struct dn_fs);\n\tlmax += max_pf_size;\n\n\tav++; ac--;\n\t/* Pipe number */\n\tif (ac && isdigit(**av)) {\n\t\ti = atoi(*av); av++; ac--;\n\t} else\n\t\ti = -1;\n\tif (i <= 0)\n\t\terrx(EX_USAGE, \"need a pipe/flowset/sched number\");\n\tbase = buf = safe_calloc(1, lmax);\n\t/* all commands start with a 'CONFIGURE' and a version */\n\to_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);\n\tbase->id = DN_API_VERSION;\n\n\tswitch (co.do_pipe) {\n\tcase 1: /* \"pipe N config ...\" */\n\t\t/* Allocate space for the WF2Q+ scheduler, its link\n\t\t * and the FIFO flowset. Set the number, but leave\n\t\t * the scheduler subtype and other parameters to 0\n\t\t * so the kernel will use appropriate defaults.\n\t\t * XXX todo: add a flag to record if a parameter\n\t\t * is actually configured.\n\t\t * If we do a 'pipe config' mask -> sched_mask.\n\t\t * The FIFO scheduler and link are derived from the\n\t\t * WF2Q+ one in the kernel.\n\t\t */\n\t\tsch = o_next(&buf, sizeof(*sch), DN_SCH);\n\t\tp = o_next(&buf, sizeof(*p), DN_LINK);\n\t\tfs = o_next(&buf, sizeof(*fs), DN_FS);\n\n\t\tsch->sched_nr = i;\n\t\tsch->oid.subtype = 0;\t/* defaults to WF2Q+ */\n\t\tmask = &sch->sched_mask;\n\t\tflags = &sch->flags;\n\t\tbuckets = &sch->buckets;\n\t\t*flags |= DN_PIPE_CMD;\n\n\t\tp->link_nr = i;\n\n\t\t/* This flowset is only for the FIFO scheduler */\n\t\tfs->fs_nr = i + 2*DN_MAX_ID;\n\t\tfs->sched_nr = i + DN_MAX_ID;\n\t\tbreak;\n\n\tcase 2: /* \"queue N config ... \" */\n\t\tfs = o_next(&buf, sizeof(*fs), DN_FS);\n\t\tfs->fs_nr = i;\n\t\tmask = &fs->flow_mask;\n\t\tflags = &fs->flags;\n\t\tbuckets = &fs->buckets;\n\t\tbreak;\n\n\tcase 3: /* \"sched N config ...\" */\n\t\tsch = o_next(&buf, sizeof(*sch), DN_SCH);\n\t\tfs = o_next(&buf, sizeof(*fs), DN_FS);\n\t\tsch->sched_nr = i;\n\t\tmask = &sch->sched_mask;\n\t\tflags = &sch->flags;\n\t\tbuckets = &sch->buckets;\n\t\t/* fs is used only with !MULTIQUEUE schedulers */\n\t\tfs->fs_nr = i + DN_MAX_ID;\n\t\tfs->sched_nr = i;\n\t\tbreak;\n\t}\n\t/* set to -1 those fields for which we want to reuse existing\n\t * values from the kernel.\n\t * Also, *_nr and subtype = 0 mean reuse the value from the kernel.\n\t * XXX todo: support reuse of the mask.\n\t */\n\tif (p)\n\t\tp->bandwidth = -1;\n\tfor (j = 0; j < sizeof(fs->par)/sizeof(fs->par[0]); j++)\n\t\tfs->par[j] = -1;\n\twhile (ac > 0) {\n\t\tdouble d;\n\t\tint tok = match_token(dummynet_params, *av);\n\t\tac--; av++;\n\n\t\tswitch(tok) {\n\t\tcase TOK_NOERROR:\n\t\t\tNEED(fs, \"noerror is only for pipes\");\n\t\t\tfs->flags |= DN_NOERROR;\n\t\t\tbreak;\n\n\t\tcase TOK_PLR:\n\t\t\tNEED(fs, \"plr is only for pipes\");\n\t\t\tNEED1(\"plr needs argument 0..1\\n\");\n\t\t\td = strtod(av[0], NULL);\n\t\t\tif (d > 1)\n\t\t\t\td = 1;\n\t\t\telse if (d < 0)\n\t\t\t\td = 0;\n\t\t\tfs->plr = (int)(d*0x7fffffff);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_QUEUE:\n\t\t\tNEED(fs, \"queue is only for pipes or flowsets\");\n\t\t\tNEED1(\"queue needs queue size\\n\");\n\t\t\tend = NULL;\n\t\t\tfs->qsize = strtoul(av[0], &end, 0);\n\t\t\tif (*end == 'K' || *end == 'k') {\n\t\t\t\tfs->flags |= DN_QSIZE_BYTES;\n\t\t\t\tfs->qsize *= 1024;\n\t\t\t} else if (*end == 'B' ||\n\t\t\t    _substrcmp2(end, \"by\", \"bytes\") == 0) {\n\t\t\t\tfs->flags |= DN_QSIZE_BYTES;\n\t\t\t}\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_BUCKETS:\n\t\t\tNEED(fs, \"buckets is only for pipes or flowsets\");\n\t\t\tNEED1(\"buckets needs argument\\n\");\n\t\t\t*buckets = strtoul(av[0], NULL, 0);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_FLOW_MASK:\n\t\tcase TOK_SCHED_MASK:\n\t\tcase TOK_MASK:\n\t\t\tNEED(mask, \"tok_mask\");\n\t\t\tNEED1(\"mask needs mask specifier\\n\");\n\t\t\t/*\n\t\t\t * per-flow queue, mask is dst_ip, dst_port,\n\t\t\t * src_ip, src_port, proto measured in bits\n\t\t\t */\n\t\t\tpar = NULL;\n\n\t\t\tbzero(mask, sizeof(*mask));\n\t\t\tend = NULL;\n\n\t\t\twhile (ac >= 1) {\n\t\t\t    uint32_t *p32 = NULL;\n\t\t\t    uint16_t *p16 = NULL;\n\t\t\t    uint32_t *p20 = NULL;\n\t\t\t    struct in6_addr *pa6 = NULL;\n\t\t\t    uint32_t a;\n\n\t\t\t    tok = match_token(dummynet_params, *av);\n\t\t\t    ac--; av++;\n\t\t\t    switch(tok) {\n\t\t\t    case TOK_ALL:\n\t\t\t\t    /*\n\t\t\t\t     * special case, all bits significant\n\t\t\t\t     * except 'extra' (the queue number)\n\t\t\t\t     */\n\t\t\t\t    mask->dst_ip = ~0;\n\t\t\t\t    mask->src_ip = ~0;\n\t\t\t\t    mask->dst_port = ~0;\n\t\t\t\t    mask->src_port = ~0;\n\t\t\t\t    mask->proto = ~0;\n\t\t\t\t    n2mask(&mask->dst_ip6, 128);\n\t\t\t\t    n2mask(&mask->src_ip6, 128);\n\t\t\t\t    mask->flow_id6 = ~0;\n\t\t\t\t    *flags |= DN_HAVE_MASK;\n\t\t\t\t    goto end_mask;\n\n\t\t\t    case TOK_QUEUE:\n\t\t\t\t    mask->extra = ~0;\n\t\t\t\t    *flags |= DN_HAVE_MASK;\n\t\t\t\t    goto end_mask;\n\n\t\t\t    case TOK_DSTIP:\n\t\t\t\t    mask->addr_type = 4;\n\t\t\t\t    p32 = &mask->dst_ip;\n\t\t\t\t    break;\n\n\t\t\t    case TOK_SRCIP:\n\t\t\t\t    mask->addr_type = 4;\n\t\t\t\t    p32 = &mask->src_ip;\n\t\t\t\t    break;\n\n\t\t\t    case TOK_DSTIP6:\n\t\t\t\t    mask->addr_type = 6;\n\t\t\t\t    pa6 = &mask->dst_ip6;\n\t\t\t\t    break;\n\n\t\t\t    case TOK_SRCIP6:\n\t\t\t\t    mask->addr_type = 6;\n\t\t\t\t    pa6 = &mask->src_ip6;\n\t\t\t\t    break;\n\n\t\t\t    case TOK_FLOWID:\n\t\t\t\t    mask->addr_type = 6;\n\t\t\t\t    p20 = &mask->flow_id6;\n\t\t\t\t    break;\n\n\t\t\t    case TOK_DSTPORT:\n\t\t\t\t    p16 = &mask->dst_port;\n\t\t\t\t    break;\n\n\t\t\t    case TOK_SRCPORT:\n\t\t\t\t    p16 = &mask->src_port;\n\t\t\t\t    break;\n\n\t\t\t    case TOK_PROTO:\n\t\t\t\t    break;\n\n\t\t\t    default:\n\t\t\t\t    ac++; av--; /* backtrack */\n\t\t\t\t    goto end_mask;\n\t\t\t    }\n\t\t\t    if (ac < 1)\n\t\t\t\t    errx(EX_USAGE, \"mask: value missing\");\n\t\t\t    if (*av[0] == '/') {\n\t\t\t\t    a = strtoul(av[0]+1, &end, 0);\n\t\t\t\t    if (pa6 == NULL)\n\t\t\t\t\t    a = (a == 32) ? ~0 : (1 << a) - 1;\n\t\t\t    } else\n\t\t\t\t    a = strtoul(av[0], &end, 0);\n\t\t\t    if (p32 != NULL)\n\t\t\t\t    *p32 = a;\n\t\t\t    else if (p16 != NULL) {\n\t\t\t\t    if (a > 0xFFFF)\n\t\t\t\t\t    errx(EX_DATAERR,\n\t\t\t\t\t\t\"port mask must be 16 bit\");\n\t\t\t\t    *p16 = (uint16_t)a;\n\t\t\t    } else if (p20 != NULL) {\n\t\t\t\t    if (a > 0xfffff)\n\t\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t\t    \"flow_id mask must be 20 bit\");\n\t\t\t\t    *p20 = (uint32_t)a;\n\t\t\t    } else if (pa6 != NULL) {\n\t\t\t\t    if (a > 128)\n\t\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t\t    \"in6addr invalid mask len\");\n\t\t\t\t    else\n\t\t\t\t\tn2mask(pa6, a);\n\t\t\t    } else {\n\t\t\t\t    if (a > 0xFF)\n\t\t\t\t\t    errx(EX_DATAERR,\n\t\t\t\t\t\t\"proto mask must be 8 bit\");\n\t\t\t\t    mask->proto = (uint8_t)a;\n\t\t\t    }\n\t\t\t    if (a != 0)\n\t\t\t\t    *flags |= DN_HAVE_MASK;\n\t\t\t    ac--; av++;\n\t\t\t} /* end while, config masks */\nend_mask:\n\t\t\tbreak;\n\n\t\tcase TOK_RED:\n\t\tcase TOK_GRED:\n\t\t\tNEED1(\"red/gred needs w_q/min_th/max_th/max_p\\n\");\n\t\t\tfs->flags |= DN_IS_RED;\n\t\t\tif (tok == TOK_GRED)\n\t\t\t\tfs->flags |= DN_IS_GENTLE_RED;\n\t\t\t/*\n\t\t\t * the format for parameters is w_q/min_th/max_th/max_p\n\t\t\t */\n\t\t\tif ((end = strsep(&av[0], \"/\"))) {\n\t\t\t    double w_q = strtod(end, NULL);\n\t\t\t    if (w_q > 1 || w_q <= 0)\n\t\t\t\terrx(EX_DATAERR, \"0 < w_q <= 1\");\n\t\t\t    fs->w_q = (int) (w_q * (1 << SCALE_RED));\n\t\t\t}\n\t\t\tif ((end = strsep(&av[0], \"/\"))) {\n\t\t\t    fs->min_th = strtoul(end, &end, 0);\n\t\t\t    if (*end == 'K' || *end == 'k')\n\t\t\t\tfs->min_th *= 1024;\n\t\t\t}\n\t\t\tif ((end = strsep(&av[0], \"/\"))) {\n\t\t\t    fs->max_th = strtoul(end, &end, 0);\n\t\t\t    if (*end == 'K' || *end == 'k')\n\t\t\t\tfs->max_th *= 1024;\n\t\t\t}\n\t\t\tif ((end = strsep(&av[0], \"/\"))) {\n\t\t\t    double max_p = strtod(end, NULL);\n\t\t\t    if (max_p > 1 || max_p <= 0)\n\t\t\t\terrx(EX_DATAERR, \"0 < max_p <= 1\");\n\t\t\t    fs->max_p = (int)(max_p * (1 << SCALE_RED));\n\t\t\t}\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_DROPTAIL:\n\t\t\tNEED(fs, \"droptail is only for flowsets\");\n\t\t\tfs->flags &= ~(DN_IS_RED|DN_IS_GENTLE_RED);\n\t\t\tbreak;\n\n\t\tcase TOK_BW:\n\t\t\tNEED(p, \"bw is only for links\");\n\t\t\tNEED1(\"bw needs bandwidth or interface\\n\");\n\t\t\tread_bandwidth(av[0], &p->bandwidth, NULL, 0);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_DELAY:\n\t\t\tNEED(p, \"delay is only for links\");\n\t\t\tNEED1(\"delay needs argument 0..10000ms\\n\");\n\t\t\tp->delay = strtoul(av[0], NULL, 0);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_TYPE: {\n\t\t\tint l;\n\t\t\tNEED(sch, \"type is only for schedulers\");\n\t\t\tNEED1(\"type needs a string\");\n\t\t\tl = strlen(av[0]);\n\t\t\tif (l == 0 || l > 15)\n\t\t\t\terrx(1, \"type %s too long\\n\", av[0]);\n\t\t\tstrcpy(sch->name, av[0]);\n\t\t\tsch->oid.subtype = 0; /* use string */\n\t\t\tac--; av++;\n\t\t\tbreak;\n\t\t    }\n\n\t\tcase TOK_WEIGHT:\n\t\t\tNEED(fs, \"weight is only for flowsets\");\n\t\t\tNEED1(\"weight needs argument\\n\");\n\t\t\tfs->par[0] = strtol(av[0], &end, 0);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_LMAX:\n\t\t\tNEED(fs, \"lmax is only for flowsets\");\n\t\t\tNEED1(\"lmax needs argument\\n\");\n\t\t\tfs->par[1] = strtol(av[0], &end, 0);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_PRI:\n\t\t\tNEED(fs, \"priority is only for flowsets\");\n\t\t\tNEED1(\"priority needs argument\\n\");\n\t\t\tfs->par[2] = strtol(av[0], &end, 0);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_SCHED:\n\t\tcase TOK_PIPE:\n\t\t\tNEED(fs, \"pipe/sched\");\n\t\t\tNEED1(\"pipe/link/sched needs number\\n\");\n\t\t\tfs->sched_nr = strtoul(av[0], &end, 0);\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tcase TOK_PROFILE:\n\t\t    {\n\t\t\tsize_t real_length;\n\n\t\t\tNEED((!pf), \"profile already set\");\n\t\t\tNEED(p, \"profile\");\n\t\t\tNEED1(\"extra delay needs the file name\\n\");\n\n\t\t\t/* load the profile structure using the DN_API */\n\t\t\tpf = o_next(&buf, max_pf_size, DN_PROFILE);\n\t\t\tload_extra_delays(av[0], pf, p); //XXX can't fail?\n\n\t\t\t/* compact the dn_id structure */\n\t\t\treal_length = sizeof(struct dn_profile) +\n\t\t\t\tpf->samples_no * sizeof(int);\n\t\t\to_compact(&buf, max_pf_size, real_length, DN_PROFILE);\n\t\t\t--ac; ++av;\n\t\t    }\n\t\t\tbreak;\n\n\t\tcase TOK_BURST:\n\t\t\tNEED(p, \"burst\");\n\t\t\tNEED1(\"burst needs argument\\n\");\n\t\t\terrno = 0;\n\t\t\tif (expand_number(av[0], (int64_t *)&p->burst) < 0)\n\t\t\t\tif (errno != ERANGE)\n\t\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t\t    \"burst: invalid argument\");\n\t\t\tif (errno || p->burst > (1ULL << 48) - 1)\n\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t    \"burst: out of range (0..2^48-1)\");\n\t\t\tac--; av++;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\terrx(EX_DATAERR, \"unrecognised option ``%s''\", av[-1]);\n\t\t}\n\t}\n\n\t/* check validity of parameters */\n\tif (p) {\n\t\tif (p->delay > 10000)\n\t\t\terrx(EX_DATAERR, \"delay must be < 10000\");\n\t\tif (p->bandwidth == -1)\n\t\t\tp->bandwidth = 0;\n\t}\n\tif (fs) {\n\t\t/* XXX accept a 0 scheduler to keep the default */\n\t    if (fs->flags & DN_QSIZE_BYTES) {\n\t\tsize_t len;\n\t\tlong limit;\n\n\t\tlen = sizeof(limit);\n\t\tif (sysctlbyname(\"net.inet.ip.dummynet.pipe_byte_limit\",\n\t\t\t&limit, &len, NULL, 0) == -1)\n\t\t\tlimit = 1024*1024;\n\t\tif (fs->qsize > limit)\n\t\t\terrx(EX_DATAERR, \"queue size must be < %ldB\", limit);\n\t    } else {\n\t\tsize_t len;\n\t\tlong limit;\n\n\t\tlen = sizeof(limit);\n\t\tif (sysctlbyname(\"net.inet.ip.dummynet.pipe_slot_limit\",\n\t\t\t&limit, &len, NULL, 0) == -1)\n\t\t\tlimit = 100;\n\t\tif (fs->qsize > limit)\n\t\t\terrx(EX_DATAERR, \"2 <= queue size <= %ld\", limit);\n\t    }\n\n\t    if (fs->flags & DN_IS_RED) {\n\t\tsize_t len;\n\t\tint lookup_depth, avg_pkt_size;\n\t\tdouble w_q;\n\n\t\tif (fs->min_th >= fs->max_th)\n\t\t    errx(EX_DATAERR, \"min_th %d must be < than max_th %d\",\n\t\t\tfs->min_th, fs->max_th);\n\t\tif (fs->max_th == 0)\n\t\t    errx(EX_DATAERR, \"max_th must be > 0\");\n\n\t\tlen = sizeof(int);\n\t\tif (sysctlbyname(\"net.inet.ip.dummynet.red_lookup_depth\",\n\t\t\t&lookup_depth, &len, NULL, 0) == -1)\n\t\t\tlookup_depth = 256;\n\t\tif (lookup_depth == 0)\n\t\t    errx(EX_DATAERR, \"net.inet.ip.dummynet.red_lookup_depth\"\n\t\t\t\" must be greater than zero\");\n\n\t\tlen = sizeof(int);\n\t\tif (sysctlbyname(\"net.inet.ip.dummynet.red_avg_pkt_size\",\n\t\t\t&avg_pkt_size, &len, NULL, 0) == -1)\n\t\t\tavg_pkt_size = 512;\n\n\t\tif (avg_pkt_size == 0)\n\t\t\terrx(EX_DATAERR,\n\t\t\t    \"net.inet.ip.dummynet.red_avg_pkt_size must\"\n\t\t\t    \" be greater than zero\");\n\n\t\t/*\n\t\t * Ticks needed for sending a medium-sized packet.\n\t\t * Unfortunately, when we are configuring a WF2Q+ queue, we\n\t\t * do not have bandwidth information, because that is stored\n\t\t * in the parent pipe, and also we have multiple queues\n\t\t * competing for it. So we set s=0, which is not very\n\t\t * correct. But on the other hand, why do we want RED with\n\t\t * WF2Q+ ?\n\t\t */\n#if 0\n\t\tif (p.bandwidth==0) /* this is a WF2Q+ queue */\n\t\t\ts = 0;\n\t\telse\n\t\t\ts = (double)ck.hz * avg_pkt_size * 8 / p.bandwidth;\n#endif\n\t\t/*\n\t\t * max idle time (in ticks) before avg queue size becomes 0.\n\t\t * NOTA:  (3/w_q) is approx the value x so that\n\t\t * (1-w_q)^x < 10^-3.\n\t\t */\n\t\tw_q = ((double)fs->w_q) / (1 << SCALE_RED);\n#if 0 // go in kernel\n\t\tidle = s * 3. / w_q;\n\t\tfs->lookup_step = (int)idle / lookup_depth;\n\t\tif (!fs->lookup_step)\n\t\t\tfs->lookup_step = 1;\n\t\tweight = 1 - w_q;\n\t\tfor (t = fs->lookup_step; t > 1; --t)\n\t\t\tweight *= 1 - w_q;\n\t\tfs->lookup_weight = (int)(weight * (1 << SCALE_RED));\n#endif /* code moved in the kernel */\n\t    }\n\t}\n\n\ti = do_cmd(IP_DUMMYNET3, base, (char *)buf - (char *)base);\n\n\tif (i)\n\t\terr(1, \"setsockopt(%s)\", \"IP_DUMMYNET_CONFIGURE\");\n}\n\nvoid\ndummynet_flush(void)\n{\n\tstruct dn_id oid;\n\toid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION);\n\tdo_cmd(IP_DUMMYNET3, &oid, oid.len);\n}\n\n/* Parse input for 'ipfw [pipe|sched|queue] show [range list]'\n * Returns the number of ranges, and possibly stores them\n * in the array v of size len.\n */\nstatic int\nparse_range(int ac, char *av[], uint32_t *v, int len)\n{\n\tint n = 0;\n\tchar *endptr, *s;\n\tuint32_t base[2];\n\n\tif (v == NULL || len < 2) {\n\t\tv = base;\n\t\tlen = 2;\n\t}\n\n\tfor (s = *av; s != NULL; av++, ac--) {\n\t\tv[0] = strtoul(s, &endptr, 10);\n\t\tv[1] = (*endptr != '-') ? v[0] :\n\t\t\t strtoul(endptr+1, &endptr, 10);\n\t\tif (*endptr == '\\0') { /* prepare for next round */\n\t\t\ts = (ac > 0) ? *(av+1) : NULL;\n\t\t} else {\n\t\t\tif (*endptr != ',') {\n\t\t\t\twarn(\"invalid number: %s\", s);\n\t\t\t\ts = ++endptr;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* continue processing from here */\n\t\t\ts = ++endptr;\n\t\t\tac++;\n\t\t\tav--;\n\t\t}\n\t\tif (v[1] < v[0] ||\n\t\t\tv[1] >= DN_MAX_ID-1 ||\n\t\t\tv[1] >= DN_MAX_ID-1) {\n\t\t\tcontinue; /* invalid entry */\n\t\t}\n\t\tn++;\n\t\t/* translate if 'pipe list' */\n\t\tif (co.do_pipe == 1) {\n\t\t\tv[0] += DN_MAX_ID;\n\t\t\tv[1] += DN_MAX_ID;\n\t\t}\n\t\tv = (n*2 < len) ? v + 2 : base;\n\t}\n\treturn n;\n}\n\n/* main entry point for dummynet list functions. co.do_pipe indicates\n * which function we want to support.\n * av may contain filtering arguments, either individual entries\n * or ranges, or lists (space or commas are valid separators).\n * Format for a range can be n1-n2 or n3 n4 n5 ...\n * In a range n1 must be <= n2, otherwise the range is ignored.\n * A number 'n4' is translate in a range 'n4-n4'\n * All number must be > 0 and < DN_MAX_ID-1\n */\nvoid\ndummynet_list(int ac, char *av[], int show_counters)\n{\n\tstruct dn_id *oid, *x = NULL;\n\tint ret, i;\n\tint n; \t\t/* # of ranges */\n\tu_int buflen, l;\n\tu_int max_size;\t/* largest obj passed up */\n\n\t(void)show_counters;\t// XXX unused, but we should use it.\n\tac--;\n\tav++; \t\t/* skip 'list' | 'show' word */\n\n\tn = parse_range(ac, av, NULL, 0);\t/* Count # of ranges. */\n\n\t/* Allocate space to store ranges */\n\tl = sizeof(*oid) + sizeof(uint32_t) * n * 2;\n\toid = safe_calloc(1, l);\n\toid_fill(oid, l, DN_CMD_GET, DN_API_VERSION);\n\n\tif (n > 0)\t/* store ranges in idx */\n\t\tparse_range(ac, av, (uint32_t *)(oid + 1), n*2);\n\t/*\n\t * Compute the size of the largest object returned. If the\n\t * response leaves at least this much spare space in the\n\t * buffer, then surely the response is complete; otherwise\n\t * there might be a risk of truncation and we will need to\n\t * retry with a larger buffer.\n\t * XXX don't bother with smaller structs.\n\t */\n\tmax_size = sizeof(struct dn_fs);\n\tif (max_size < sizeof(struct dn_sch))\n\t\tmax_size = sizeof(struct dn_sch);\n\tif (max_size < sizeof(struct dn_flow))\n\t\tmax_size = sizeof(struct dn_flow);\n\n\tswitch (co.do_pipe) {\n\tcase 1:\n\t\toid->subtype = DN_LINK;\t/* list pipe */\n\t\tbreak;\n\tcase 2:\n\t\toid->subtype = DN_FS;\t/* list queue */\n\t\tbreak;\n\tcase 3:\n\t\toid->subtype = DN_SCH;\t/* list sched */\n\t\tbreak;\n\t}\n\n\t/*\n\t * Ask the kernel an estimate of the required space (result\n\t * in oid.id), unless we are requesting a subset of objects,\n\t * in which case the kernel does not give an exact answer.\n\t * In any case, space might grow in the meantime due to the\n\t * creation of new queues, so we must be prepared to retry.\n\t */\n\tif (n > 0) {\n\t\tbuflen = 4*1024;\n\t} else {\n\t\tret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);\n\t\tif (ret != 0 || oid->id <= sizeof(*oid))\n\t\t\tgoto done;\n\t\tbuflen = oid->id + max_size;\n\t\toid->len = sizeof(*oid); /* restore */\n\t}\n\t/* Try a few times, until the buffer fits */\n\tfor (i = 0; i < 20; i++) {\n\t\tl = buflen;\n\t\tx = safe_realloc(x, l);\n\t\tbcopy(oid, x, oid->len);\n\t\tret = do_cmd(-IP_DUMMYNET3, x, (uintptr_t)&l);\n\t\tif (ret != 0 || x->id <= sizeof(*oid))\n\t\t\tgoto done; /* no response */\n\t\tif (l + max_size <= buflen)\n\t\t\tbreak; /* ok */\n\t\tbuflen *= 2;\t /* double for next attempt */\n\t}\n\tlist_pipes(x, O_NEXT(x, l));\ndone:\n\tif (x)\n\t\tfree(x);\n\tfree(oid);\n}\n"
  },
  {
    "path": "ipfw/expand_number.c",
    "content": "/*-\n * Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>\n * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n// #include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/lib/libutil/expand_number.c,v 1.2.4.2 2009/06/10 14:52:34 des Exp $\");\n\n#include <sys/types.h>\n#include <ctype.h>\n#include <errno.h>\n#include <inttypes.h>\n//#include <libutil.h>\n#include <stdint.h>\n\n/*\n * Convert an expression of the following forms to a int64_t.\n * \t1) A positive decimal number.\n *\t2) A positive decimal number followed by a 'b' or 'B' (mult by 1).\n *\t3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).\n *\t4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).\n *\t5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).\n *\t6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40).\n *\t7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50).\n *\t8) A positive decimal number followed by a 'e' or 'E' (mult by 1 << 60).\n */\nint\nexpand_number(const char *buf, int64_t *num)\n{\n\tstatic const char unit[] = \"bkmgtpe\";\n\tchar *endptr, s;\n\tint64_t number;\n\tint i;\n\n\tnumber = strtoimax(buf, &endptr, 0);\n\n\tif (endptr == buf) {\n\t\t/* No valid digits. */\n\t\terrno = EINVAL;\n\t\treturn (-1);\n\t}\n\n\tif (*endptr == '\\0') {\n\t\t/* No unit. */\n\t\t*num = number;\n\t\treturn (0);\n\t}\n\n\ts = tolower(*endptr);\n\tswitch (s) {\n\tcase 'b':\n\tcase 'k':\n\tcase 'm':\n\tcase 'g':\n\tcase 't':\n\tcase 'p':\n\tcase 'e':\n\t\tbreak;\n\tdefault:\n\t\t/* Unrecognized unit. */\n\t\terrno = EINVAL;\n\t\treturn (-1);\n\t}\n\n\tfor (i = 0; unit[i] != '\\0'; i++) {\n\t\tif (s == unit[i])\n\t\t\tbreak;\n\t\tif ((number < 0 && (number << 10) > number) ||\n\t\t    (number >= 0 && (number << 10) < number)) {\n\t\t\terrno = ERANGE;\n\t\t\treturn (-1);\n\t\t}\n\t\tnumber <<= 10;\n\t}\n\n\t*num = number;\n\treturn (0);\n}\n"
  },
  {
    "path": "ipfw/glue.c",
    "content": "/*\n * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: glue.c 12264 2013-04-27 20:21:06Z luigi $\n *\n * Userland functions missing in linux/Windows\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#ifdef _WIN32\n#include <netdb.h>\n#include <windows.h>\n#endif /* _WIN32 */\n\n#ifndef HAVE_NAT\n/* dummy nat functions */\nvoid\nipfw_show_nat(int ac, char **av)\n{\n\tfprintf(stderr, \"%s unsupported\\n\", __FUNCTION__);\n}\n\nvoid\nipfw_config_nat(int ac, char **av)\n{\n\tfprintf(stderr, \"%s unsupported\\n\", __FUNCTION__);\n}\n#endif\n\n#ifdef __linux__\nint optreset;\t/* missing in linux */\n#endif\n\n/*\n * not implemented in linux.\n * taken from /usr/src/lib/libc/string/strlcpy.c\n */\nsize_t\nstrlcpy(char *dst, const char *src, size_t siz)\n{\n        char *d = dst;\n        const char *s = src;\n        size_t n = siz;\n\n        /* Copy as many bytes as will fit */\n        if (n != 0 && --n != 0) {\n                do {\n                        if ((*d++ = *s++) == 0)\n                                break;\n                } while (--n != 0);\n        }\n\n        /* Not enough room in dst, add NUL and traverse rest of src */\n        if (n == 0) {\n                if (siz != 0)\n                        *d = '\\0';              /* NUL-terminate dst */\n                while (*s++)\n                        ;\n        }\n\n        return(s - src - 1);    /* count does not include NUL */\n}\n\n\n/* missing in linux and windows */\nlong long int\nstrtonum(const char *nptr, long long minval, long long maxval,\n         const char **errstr)\n{\n\tlong long ret;\n\tint errno_c = errno;\t/* save actual errno */\n\n\terrno = 0;\n#ifdef TCC\n\tret = strtol(nptr, (char **)errstr, 0);\n#else\n\tret = strtoll(nptr, (char **)errstr, 0);\n#endif\n\t/* We accept only a string that represent exactly a number (ie. start\n\t * and end with a digit).\n\t * FreeBSD version wants errstr==NULL if no error occurs, otherwise\n\t * errstr should point to an error string.\n\t * For our purspose, we implement only the invalid error, ranges\n\t * error aren't checked\n\t */\n\tif (errno != 0 || nptr == *errstr || **errstr != '\\0')\n\t\t*errstr = \"invalid\";\n\telse  {\n\t\t*errstr = NULL;\n\t\terrno = errno_c;\n\t}\n\treturn ret;\n}\n\n#if defined (_WIN32) || defined (EMULATE_SYSCTL)\n//XXX missing prerequisites\n#include <net/if.h> \t\t//openwrt\n#include <netinet/ip.h> \t//openwrt\n#include <netinet/ip_fw.h>\n#include <netinet/ip_dummynet.h>\n#endif\n\n/*\n * set or get system information\n * XXX lock acquisition/serialize calls\n *\n * we export this as sys/module/ipfw_mod/parameters/___\n * This function get or/and set the value of the sysctl passed by\n * the name parameter. If the old value is not desired,\n * oldp and oldlenp should be set to NULL.\n *\n * XXX\n * I do not know how this works in FreeBSD in the case\n * where there are no write permission on the sysctl var.\n * We read the value and set return variables in any way\n * but returns -1 on write failures, regardless the\n * read success.\n *\n * Since there is no information on types, in the following\n * code we assume a length of 4 is a int.\n *\n * Returns 0 on success, -1 on errors.\n */\nint\nsysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,\n         size_t newlen)\n{\n#if defined (_WIN32) || defined (EMULATE_SYSCTL)\n\t/*\n\t * we embed the sysctl request in the usual sockopt mechanics.\n\t * the sockopt buffer il filled with a dn_id with IP_DUMMYNET3\n\t * command, and the special DN_SYSCTL_GET and DN_SYSCTL_SET\n\t * subcommands.\n\t * the syntax of this function is fully compatible with\n\t * POSIX sysctlby name:\n\t * if newp and newlen are != 0 => this is a set\n\t * else if oldp and oldlen are != 0 => this is a get\n\t *\t\tto avoid too much overhead in the module, the whole\n\t *\t\tsysctltable is returned, and the parsing is done in userland,\n\t *\t\ta probe request is done to retrieve the size needed to\n\t *\t\ttransfer the table, before the real request\n\t * if both old and new params = 0 => this is a print\n\t *\t\tthis is a special request, done only by main()\n\t *\t\tto implement the extension './ipfw sysctl',\n\t *\t\ta command that bypasses the normal getopt, and that\n\t *\t\tis available on those platforms that use this\n\t *\t\tsysctl emulation.\n\t *\t\tin this case, a negative oldlen signals that *oldp\n\t *\t\tis actually a FILE* to print somewhere else than stdout\n\t */\n\n\tint l;\n\tint ret;\n\tstruct dn_id* oid;\n\tstruct sysctlhead* entry;\n\tchar* pstring;\n\tchar* pdata;\n\tFILE* fp;\n\n\tif((oldlenp != NULL) && (*oldlenp < 0))\n\t\tfp = (FILE*)oldp;\n\telse\n\t\tfp = stdout;\n\tif(newp != NULL && newlen != 0)\n\t{\n\t\t//this is a set\n\t\tl = sizeof(struct dn_id) + sizeof(struct sysctlhead) + strlen(name)+1 + newlen;\n\t\toid = malloc(l);\n\t\tif (oid == NULL)\n\t\t\treturn -1;\n\t\toid->len = l;\n\t\toid->type = DN_SYSCTL_SET;\n\t\toid->id = DN_API_VERSION;\n\n\t\tentry = (struct sysctlhead*)(oid+1);\n\t\tpdata = (char*)(entry+1);\n\t\tpstring = pdata + newlen;\n\n\t\tentry->blocklen = ((sizeof(struct sysctlhead) + strlen(name)+1 + newlen) + 3) & ~3;\n\t\tentry->namelen = strlen(name)+1;\n\t\tentry->flags = 0;\n\t\tentry->datalen = newlen;\n\n\t\tbcopy(newp, pdata, newlen);\n\t\tbcopy(name, pstring, strlen(name)+1);\n\n\t\tret = do_cmd(IP_DUMMYNET3, oid, (uintptr_t)l);\n\t\tif (ret != 0)\n\t\t\treturn -1;\n\t}\n\telse\n\t{\n\t\t//this is a get or a print\n\t\tl = sizeof(struct dn_id);\n\t\toid = malloc(l);\n\t\tif (oid == NULL)\n\t\t\treturn -1;\n\t\toid->len = l;\n\t\toid->type = DN_SYSCTL_GET;\n\t\toid->id = DN_API_VERSION;\n\n\t\tret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);\n\t\tif (ret != 0)\n\t\t\treturn -1;\n\n\t\tl=oid->id;\n\t\tfree(oid);\n\t\toid = malloc(l);\n\t\tif (oid == NULL)\n\t\t\treturn -1;\n\t\toid->len = l;\n\t\toid->type = DN_SYSCTL_GET;\n\t\toid->id = DN_API_VERSION;\n\n\t\tret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);\n\t\tif (ret != 0)\n\t\t\treturn -1;\n\n\t\tentry = (struct sysctlhead*)(oid+1);\n\t\twhile(entry->blocklen != 0)\n\t\t{\n\t\t\tpdata = (char*)(entry+1);\n\t\t\tpstring = pdata+entry->datalen;\n\n\t\t\t//time to check if this is a get or a print\n\t\t\tif(name != NULL && oldp != NULL && *oldlenp > 0)\n\t\t\t{\n\t\t\t\t//this is a get\n\t\t\t\tif(strcmp(name,pstring) == 0)\n\t\t\t\t{\n\t\t\t\t\t//match found, sanity chech on len\n\t\t\t\t\tif(*oldlenp < entry->datalen)\n\t\t\t\t\t{\n\t\t\t\t\t\tprintf(\"%s error: buffer too small\\n\",__FUNCTION__);\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\t*oldlenp = entry->datalen;\n\t\t\t\t\tbcopy(pdata, oldp, *oldlenp);\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t//this is a print\n\t\t\t\tif( name == NULL )\n\t\t\t\t\tgoto print;\n\t\t\t\tif ( (strncmp(pstring,name,strlen(name)) == 0) && ( pstring[strlen(name)]=='\\0' || pstring[strlen(name)]=='.' ) )\n\t\t\t\t\t\tgoto print;\n\t\t\t\telse\n\t\t\t\t\t\tgoto skip;\nprint:\n\t\t\t\tfprintf(fp, \"%s: \",pstring);\n\t\t\t\tswitch( entry->flags >> 2 )\n\t\t\t\t{\n\t\t\t\t\tcase SYSCTLTYPE_LONG:\n\t\t\t\t\t\tfprintf(fp, \"%li \", *(long*)(pdata));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SYSCTLTYPE_UINT:\n\t\t\t\t\t\tfprintf(fp, \"%u \", *(unsigned int*)(pdata));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SYSCTLTYPE_ULONG:\n\t\t\t\t\t\tfprintf(fp, \"%lu \", *(unsigned long*)(pdata));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SYSCTLTYPE_INT:\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tfprintf(fp, \"%i \", *(int*)(pdata));\n\t\t\t\t}\n\t\t\t\tif( (entry->flags & 0x00000003) == CTLFLAG_RD )\n\t\t\t\t\tfprintf(fp, \"\\t(read only)\\n\");\n\t\t\t\telse\n\t\t\t\t\tfprintf(fp, \"\\n\");\nskip:\t\t\t;\n\t\t\t}\n\t\t\tentry = (struct sysctlhead*)((unsigned char*)entry + entry->blocklen);\n\t\t}\n\t\tfree(oid);\n\t\treturn 0;\n\t}\n\t//fallback for invalid options\n\treturn -1;\n\n#else /* __linux__ */\n\tFILE *fp;\n\tchar *basename = \"/sys/module/ipfw_mod/parameters/\";\n\tchar filename[256];\t/* full filename */\n\tchar *varp;\n\tint ret = 0;\t\t/* return value */\n\tlong d;\n\n\tif (name == NULL) /* XXX set errno */\n\t\treturn -1;\n\n\t/* locate the filename */\n\tvarp = strrchr(name, '.');\n\tif (varp == NULL) /* XXX set errno */\n\t\treturn -1;\n\n\tsnprintf(filename, sizeof(filename), \"%s%s\", basename, varp+1);\n\n\t/*\n\t * XXX we could open the file here, in rw mode\n\t * but need to check if a file have write\n\t * permissions.\n\t */\n\n\t/* check parameters */\n\tif (oldp && oldlenp) { /* read mode */\n\t\tfp = fopen(filename, \"r\");\n\t\tif (fp == NULL) {\n\t\t\tfprintf(stderr, \"%s fopen error reading filename %s\\n\", __FUNCTION__, filename);\n\t\t\treturn -1;\n\t\t}\n\t\tif (fscanf(fp, \"%ld\", &d) != 1) {\n\t\t\tret = -1;\n\t\t} else if (*oldlenp == sizeof(int)) {\n\t\t\tint dst = d;\n\t\t\tmemcpy(oldp, &dst, *oldlenp);\n\t\t} else if (*oldlenp == sizeof(long)) {\n\t\t\tmemcpy(oldp, &d, *oldlenp);\n\t\t} else {\n\t\t\tfprintf(stderr, \"unknown paramerer len %d\\n\",\n\t\t\t\t(int)*oldlenp);\n\t\t}\n\t\tfclose(fp);\n\t}\n\n\tif (newp && newlen) { /* write */\n\t\tfp = fopen(filename, \"w\");\n\t\tif (fp == NULL) {\n\t\t\tfprintf(stderr, \"%s fopen error writing filename %s\\n\", __FUNCTION__, filename);\n\t\t\treturn -1;\n\t\t}\n\t\tif (newlen == sizeof(int)) {\n\t\t\tif (fprintf(fp, \"%d\", *(int *)newp) < 1)\n\t\t\t\tret = -1;\n\t\t} else if (newlen == sizeof(long)) {\n\t\t\tif (fprintf(fp, \"%ld\", *(long *)newp) < 1)\n\t\t\t\tret = -1;\n\t\t} else {\n\t\t\tfprintf(stderr, \"unknown paramerer len %d\\n\",\n\t\t\t\t(int)newlen);\n\t\t}\n\n\t\tfclose(fp);\n\t}\n\n\treturn ret;\n#endif /* __linux__ */\n}\n\n#ifdef _WIN32\n/*\n * On windows, set/getsockopt are mapped to DeviceIoControl()\n */\nint\nwnd_setsockopt(int s, int level, int sopt_name, const void *optval,\n                socklen_t optlen)\n{\n    size_t len = sizeof (struct sockopt) + optlen;\n    struct sockopt *sock;\n    DWORD n;\n    BOOL result;\n    HANDLE _dev_h = (HANDLE)s;\n\n    /* allocate a data structure for communication */\n    sock = malloc(len);\n    if (sock == NULL)\n        return -1;\n\n    sock->sopt_dir = SOPT_SET;\n    sock->sopt_name = sopt_name;\n    sock->sopt_valsize = optlen;\n    sock->sopt_val = (void *)(sock+1);\n\n    memcpy(sock->sopt_val, optval, optlen);\n    result = DeviceIoControl (_dev_h, IP_FW_SETSOCKOPT, sock, len,\n\t\tNULL, 0, &n, NULL);\n    free (sock);\n\n    return (result ? 0 : -1);\n}\n\nint\nwnd_getsockopt(int s, int level, int sopt_name, void *optval,\n                socklen_t *optlen)\n{\n    size_t len = sizeof (struct sockopt) + *optlen;\n    struct sockopt *sock;\n    DWORD n;\n    BOOL result;\n    HANDLE _dev_h = (HANDLE)s;\n\n    sock = malloc(len);\n    if (sock == NULL)\n        return -1;\n\n    sock->sopt_dir = SOPT_GET;\n    sock->sopt_name = sopt_name;\n    sock->sopt_valsize = *optlen;\n    sock->sopt_val = (void *)(sock+1);\n\n    memcpy (sock->sopt_val, optval, *optlen);\n\n    result = DeviceIoControl (_dev_h, IP_FW_GETSOCKOPT, sock, len,\n\t\tsock, len, &n, NULL);\n\t//printf(\"len = %i, returned = %u, valsize = %i\\n\",len,n,sock->sopt_valsize);\n    *optlen = sock->sopt_valsize;\n    memcpy (optval, sock->sopt_val, *optlen);\n    free (sock);\n    return (result ? 0 : -1);\n}\n\nint\nmy_socket(int domain, int ty, int proto)\n{\n    TCHAR *pcCommPort = TEXT(\"\\\\\\\\.\\\\Ipfw\");\n    HANDLE _dev_h = INVALID_HANDLE_VALUE;\n\n    /* Special Handling For Accessing Device On Windows 2000 Terminal Server\n       See Microsoft KB Article 259131 */\n    if (_dev_h == INVALID_HANDLE_VALUE) {\n        _dev_h = CreateFile (pcCommPort,\n\t\tGENERIC_READ | GENERIC_WRITE,\n\t\t0, NULL,\n\t\tOPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\n    }\n    if (_dev_h == INVALID_HANDLE_VALUE) {\n\tprintf(\"%s failed %u, cannot talk to kernel module\\n\",\n\t\t__FUNCTION__, (unsigned)GetLastError());\n        return -1;\n    }\n    return (int)_dev_h;\n}\n\nstruct hostent* gethostbyname2(const char *name, int af)\n{\n\treturn gethostbyname(name);\n}\n\nstruct ether_addr* ether_aton(const char *a)\n{\n\tfprintf(stderr, \"%s empty\\n\", __FUNCTION__);\n\treturn NULL;\n}\n\n#ifdef TCC\nint     opterr = 1,             /* if error message should be printed */\n        optind = 1,             /* index into parent argv vector */\n        optopt,                 /* character checked for validity */\n        optreset;               /* reset getopt */\nchar    *optarg;                /* argument associated with option */\n\n#define BADCH   (int)'?'\n#define BADARG  (int)':'\n#define EMSG    \"\"\n\n#define PROGNAME\t\"ipfw\"\n/*\n * getopt --\n *      Parse argc/argv argument vector.\n */\nint\ngetopt(nargc, nargv, ostr)\n        int nargc;\n        char * const nargv[];\n        const char *ostr;\n{\n        static char *place = EMSG;              /* option letter processing */\n        char *oli;                              /* option letter list index */\n\n        if (optreset || *place == 0) {          /* update scanning pointer */\n                optreset = 0;\n                place = nargv[optind];\n                if (optind >= nargc || *place++ != '-') {\n                        /* Argument is absent or is not an option */\n                        place = EMSG;\n                        return (-1);\n                }\n                optopt = *place++;\n                if (optopt == '-' && *place == 0) {\n                        /* \"--\" => end of options */\n                        ++optind;\n                        place = EMSG;\n                        return (-1);\n                }\n                if (optopt == 0) {\n                        /* Solitary '-', treat as a '-' option\n                           if the program (eg su) is looking for it. */\n                        place = EMSG;\n                        if (strchr(ostr, '-') == NULL)\n                                return (-1);\n                        optopt = '-';\n                }\n        } else\n                optopt = *place++;\n\n        /* See if option letter is one the caller wanted... */\n        if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {\n                if (*place == 0)\n                        ++optind;\n                if (opterr && *ostr != ':')\n                        (void)fprintf(stderr,\n                            \"%s: illegal option -- %c\\n\", PROGNAME,\n                            optopt);\n                return (BADCH);\n        }\n\n        /* Does this option need an argument? */\n        if (oli[1] != ':') {\n                /* don't need argument */\n                optarg = NULL;\n                if (*place == 0)\n                        ++optind;\n        } else {\n                /* Option-argument is either the rest of this argument or the\n                   entire next argument. */\n                if (*place)\n                        optarg = place;\n                else if (nargc > ++optind)\n                        optarg = nargv[optind];\n                else {\n                        /* option-argument absent */\n                        place = EMSG;\n                        if (*ostr == ':')\n                                return (BADARG);\n                        if (opterr)\n                                (void)fprintf(stderr,\n                                    \"%s: option requires an argument -- %c\\n\",\n                                    PROGNAME, optopt);\n                        return (BADCH);\n                }\n                place = EMSG;\n                ++optind;\n        }\n        return (optopt);                        /* return option letter */\n}\n\n//static FILE *err_file = stderr;\nvoid\nverrx(int ex, int eval, const char *fmt, va_list ap)\n{\n        fprintf(stderr, \"%s: \", PROGNAME);\n        if (fmt != NULL)\n                vfprintf(stderr, fmt, ap);\n        fprintf(stderr, \"\\n\");\n\tif (ex)\n\t\texit(eval);\n}\nvoid\nerrx(int eval, const char *fmt, ...)\n{\n        va_list ap;\n        va_start(ap, fmt);\n        verrx(1, eval, fmt, ap);\n        va_end(ap);\n}\n\nvoid\nwarnx(const char *fmt, ...)\n{\n        va_list ap;\n        va_start(ap, fmt);\n\tverrx(0, 0, fmt, ap);\n        va_end(ap);\n}\n\nchar *\nstrsep(char **stringp, const char *delim)\n{\n        char *s;\n        const char *spanp;\n        int c, sc;\n        char *tok;\n\n        if ((s = *stringp) == NULL)\n                return (NULL);\n        for (tok = s;;) {\n                c = *s++;\n                spanp = delim;\n                do {\n                        if ((sc = *spanp++) == c) {\n                                if (c == 0)\n                                        s = NULL;\n                                else\n                                        s[-1] = 0;\n                                *stringp = s;\n                                return (tok);\n                        }\n                } while (sc != 0);\n        }\n        /* NOTREACHED */\n}\n\nstatic unsigned char\ntolower(unsigned char c)\n{\n\treturn (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;\n}\n\nstatic int isdigit(unsigned char c)\n{\n\treturn (c >= '0' && c <= '9');\n}\n\nstatic int isxdigit(unsigned char c)\n{\n\treturn (strchr(\"0123456789ABCDEFabcdef\", c) ? 1 : 0);\n}\n\nstatic int isspace(unsigned char c)\n{\n\treturn (strchr(\" \\t\\n\\r\", c) ? 1 : 0);\n}\n\nstatic int isascii(unsigned char c)\n{\n\treturn (c < 128);\n}\n\nstatic int islower(unsigned char c)\n{\n\treturn (c >= 'a' && c <= 'z');\n}\n\nint\nstrcasecmp(const char *s1, const char *s2)\n{\n        const unsigned char\n                        *us1 = (const unsigned char *)s1,\n                        *us2 = (const unsigned char *)s2;\n\n        while (tolower(*us1) == tolower(*us2++))\n                if (*us1++ == '\\0')\n                        return (0);\n        return (tolower(*us1) - tolower(*--us2));\n}\n\nintmax_t\nstrtoimax(const char * restrict nptr, char ** restrict endptr, int base)\n{\n\treturn strtol(nptr, endptr,base);\n}\n\nvoid\nsetservent(int a)\n{\n}\n\n#define NS_INADDRSZ 128\n\nint\ninet_pton(int af, const char *src, void *dst)\n{\n        static const char digits[] = \"0123456789\";\n        int saw_digit, octets, ch;\n        u_char tmp[NS_INADDRSZ], *tp;\n\n\tif (af != AF_INET) {\n\t\terrno = EINVAL;\n\t\treturn -1;\n\t}\n\n        saw_digit = 0;\n        octets = 0;\n        *(tp = tmp) = 0;\n        while ((ch = *src++) != '\\0') {\n                const char *pch;\n\n                if ((pch = strchr(digits, ch)) != NULL) {\n                        u_int new = *tp * 10 + (pch - digits);\n\n                        if (saw_digit && *tp == 0)\n                                return (0);\n                        if (new > 255)\n                                return (0);\n                        *tp = new;\n                        if (!saw_digit) {\n                                if (++octets > 4)\n                                        return (0);\n                                saw_digit = 1;\n                        }\n                } else if (ch == '.' && saw_digit) {\n                        if (octets == 4)\n                                return (0);\n                        *++tp = 0;\n                        saw_digit = 0;\n                } else\n                        return (0);\n        }\n        if (octets < 4)\n                return (0);\n        memcpy(dst, tmp, NS_INADDRSZ);\n        return (1);\n}\n\nconst char *\ninet_ntop(int af, const void *_src, char *dst, socklen_t size)\n{\n        static const char fmt[] = \"%u.%u.%u.%u\";\n        char tmp[sizeof \"255.255.255.255\"];\n\tconst u_char *src = _src;\n        int l;\n\tif (af != AF_INET) {\n\t\terrno = EINVAL;\n\t\treturn NULL;\n\t}\n\n        l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);\n        if (l <= 0 || (socklen_t) l >= size) {\n                errno = ENOSPC;\n                return (NULL);\n        }\n        strlcpy(dst, tmp, size);\n        return (dst);\n}\n\n/*%\n * Check whether \"cp\" is a valid ascii representation\n * of an Internet address and convert to a binary address.\n * Returns 1 if the address is valid, 0 if not.\n * This replaces inet_addr, the return value from which\n * cannot distinguish between failure and a local broadcast address.\n */\nint\ninet_aton(const char *cp, struct in_addr *addr) {\n        u_long val;\n        int base, n;\n        char c;\n        u_int8_t parts[4];\n        u_int8_t *pp = parts;\n        int digit;\n\n        c = *cp;\n        for (;;) {\n                /*\n                 * Collect number up to ``.''.\n                 * Values are specified as for C:\n                 * 0x=hex, 0=octal, isdigit=decimal.\n                 */\n                if (!isdigit((unsigned char)c))\n                        return (0);\n                val = 0; base = 10; digit = 0;\n                if (c == '0') {\n                        c = *++cp;\n                        if (c == 'x' || c == 'X')\n                                base = 16, c = *++cp;\n                        else {\n                                base = 8;\n                                digit = 1 ;\n                        }\n                }\n                for (;;) {\n                        if (isascii(c) && isdigit((unsigned char)c)) {\n                                if (base == 8 && (c == '8' || c == '9'))\n                                        return (0);\n                                val = (val * base) + (c - '0');\n                                c = *++cp;\n                                digit = 1;\n                        } else if (base == 16 && isascii(c) &&\n                                   isxdigit((unsigned char)c)) {\n                                val = (val << 4) |\n                                        (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));\n                                c = *++cp;\n                                digit = 1;\n                        } else\n                                break;\n                }\n                if (c == '.') {\n                        /*\n                         * Internet format:\n                         *      a.b.c.d\n                         *      a.b.c   (with c treated as 16 bits)\n                         *      a.b     (with b treated as 24 bits)\n                         */\n                        if (pp >= parts + 3 || val > 0xffU)\n                                return (0);\n                        *pp++ = val;\n                        c = *++cp;\n                } else\n                        break;\n        }\n        /*\n         * Check for trailing characters.\n         */\n        if (c != '\\0' && (!isascii(c) || !isspace((unsigned char)c)))\n                return (0);\n        /*\n         * Did we get a valid digit?\n         */\n        if (!digit)\n                return (0);\n        /*\n         * Concoct the address according to\n         * the number of parts specified.\n         */\n        n = pp - parts + 1;\n        switch (n) {\n        case 1:                         /*%< a -- 32 bits */\n                break;\n\n        case 2:                         /*%< a.b -- 8.24 bits */\n                if (val > 0xffffffU)\n                        return (0);\n                val |= parts[0] << 24;\n                break;\n\n        case 3:                         /*%< a.b.c -- 8.8.16 bits */\n                if (val > 0xffffU)\n                        return (0);\n                val |= (parts[0] << 24) | (parts[1] << 16);\n                break;\n\n        case 4:                         /*%< a.b.c.d -- 8.8.8.8 bits */\n                if (val > 0xffU)\n                        return (0);\n                val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);\n                break;\n        }\n        if (addr != NULL)\n                addr->s_addr = htonl(val);\n        return (1);\n}\n\n#endif /* TCC */\n\n#endif /* _WIN32 */\n"
  },
  {
    "path": "ipfw/humanize_number.c",
    "content": "/*\t$NetBSD: humanize_number.c,v 1.13 2007/12/14 17:26:19 christos Exp $\t*/\n\n/*\n * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.\n * All rights reserved.\n *\n * This code is derived from software contributed to The NetBSD Foundation\n * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,\n * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *      This product includes software developed by the NetBSD\n *      Foundation, Inc. and its contributors.\n * 4. Neither the name of The NetBSD Foundation nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\n * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\n * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\n// #include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/lib/libutil/humanize_number.c,v 1.2.10.1 2008/04/20 16:29:01 antoine Exp $\");\n\n#include <sys/types.h>\n#include <assert.h>\n#include <inttypes.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n// #include <locale.h>\n//#include <libutil.h>\n\nint\nhumanize_number(char *buf, size_t len, int64_t bytes,\n    const char *suffix, int scale, int flags)\n{\n\tconst char *prefixes, *sep;\n\tint\tb, i, r, maxscale, s1, s2, sign;\n\tint64_t\tdivisor, max;\n\tsize_t\tbaselen;\n\n\tassert(buf != NULL);\n\tassert(suffix != NULL);\n\tassert(scale >= 0);\n\n\tif (flags & HN_DIVISOR_1000) {\n\t\t/* SI for decimal multiplies */\n\t\tdivisor = 1000;\n\t\tif (flags & HN_B)\n\t\t\tprefixes = \"B\\0k\\0M\\0G\\0T\\0P\\0E\";\n\t\telse\n\t\t\tprefixes = \"\\0\\0k\\0M\\0G\\0T\\0P\\0E\";\n\t} else {\n\t\t/*\n\t\t * binary multiplies\n\t\t * XXX IEC 60027-2 recommends Ki, Mi, Gi...\n\t\t */\n\t\tdivisor = 1024;\n\t\tif (flags & HN_B)\n\t\t\tprefixes = \"B\\0K\\0M\\0G\\0T\\0P\\0E\";\n\t\telse\n\t\t\tprefixes = \"\\0\\0K\\0M\\0G\\0T\\0P\\0E\";\n\t}\n\n#define\tSCALE2PREFIX(scale)\t(&prefixes[(scale) << 1])\n\tmaxscale = 7;\n\n\tif (scale >= maxscale &&\n\t    (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)\n\t\treturn (-1);\n\n\tif (buf == NULL || suffix == NULL)\n\t\treturn (-1);\n\n\tif (len > 0)\n\t\tbuf[0] = '\\0';\n\tif (bytes < 0) {\n\t\tsign = -1;\n\t\tbytes *= -100;\n\t\tbaselen = 3;\t\t/* sign, digit, prefix */\n\t} else {\n\t\tsign = 1;\n\t\tbytes *= 100;\n\t\tbaselen = 2;\t\t/* digit, prefix */\n\t}\n\tif (flags & HN_NOSPACE)\n\t\tsep = \"\";\n\telse {\n\t\tsep = \" \";\n\t\tbaselen++;\n\t}\n\tbaselen += strlen(suffix);\n\n\t/* Check if enough room for `x y' + suffix + `\\0' */\n\tif (len < baselen + 1)\n\t\treturn (-1);\n\n\tif (scale & (HN_AUTOSCALE | HN_GETSCALE)) {\n\t\t/* See if there is additional columns can be used. */\n\t\tfor (max = 100, i = len - baselen; i-- > 0;)\n\t\t\tmax *= 10;\n\n\t\t/*\n\t\t * Divide the number until it fits the given column.\n\t\t * If there will be an overflow by the rounding below,\n\t\t * divide once more.\n\t\t */\n\t\tfor (i = 0; bytes >= max - 50 && i < maxscale; i++)\n\t\t\tbytes /= divisor;\n\n\t\tif (scale & HN_GETSCALE)\n\t\t\treturn (i);\n\t} else\n\t\tfor (i = 0; i < scale && i < maxscale; i++)\n\t\t\tbytes /= divisor;\n\n\t/* If a value <= 9.9 after rounding and ... */\n\tif (bytes < 995 && i > 0 && flags & HN_DECIMAL) {\n\t\t/* baselen + \\0 + .N */\n\t\tif (len < baselen + 1 + 2)\n\t\t\treturn (-1);\n\t\tb = ((int)bytes + 5) / 10;\n\t\ts1 = b / 10;\n\t\ts2 = b % 10;\n\t\tr = snprintf(buf, len, \"%d%s%d%s%s%s\",\n\t\t    sign * s1, \".\", s2,\n\t\t    sep, SCALE2PREFIX(i), suffix);\n\t} else\n\t\tr = snprintf(buf, len, \"%\" PRId64 \"%s%s%s\",\n\t\t    sign * ((bytes + 50) / 100),\n\t\t    sep, SCALE2PREFIX(i), suffix);\n\n\treturn (r);\n}\n"
  },
  {
    "path": "ipfw/include/alias.h",
    "content": "#ifndef _ALIAS_H_\n#define\t_ALIAS_H_\n\n#define LIBALIAS_BUF_SIZE 128\n\n/*\n * If PKT_ALIAS_LOG is set, a message will be printed to /var/log/alias.log\n * every time a link is created or deleted.  This is useful for debugging.\n */\n#define\tPKT_ALIAS_LOG\t\t\t0x01\n\n/*\n * If PKT_ALIAS_DENY_INCOMING is set, then incoming connections (e.g. to ftp,\n * telnet or web servers will be prevented by the aliasing mechanism.\n */\n#define\tPKT_ALIAS_DENY_INCOMING\t\t0x02\n\n/*\n * If PKT_ALIAS_SAME_PORTS is set, packets will be attempted sent from the\n * same port as they originated on.  This allows e.g. rsh to work *99% of the\n * time*, but _not_ 100% (it will be slightly flakey instead of not working\n * at all).  This mode bit is set by PacketAliasInit(), so it is a default\n * mode of operation.\n */\n#define\tPKT_ALIAS_SAME_PORTS\t\t0x04\n\n/*\n * If PKT_ALIAS_USE_SOCKETS is set, then when partially specified links (e.g.\n * destination port and/or address is zero), the packet aliasing engine will\n * attempt to allocate a socket for the aliasing port it chooses.  This will\n * avoid interference with the host machine.  Fully specified links do not\n * require this.  This bit is set after a call to PacketAliasInit(), so it is\n * a default mode of operation.\n */\n#ifndef\tNO_USE_SOCKETS\n#define\tPKT_ALIAS_USE_SOCKETS\t\t0x08\n#endif\n/*-\n * If PKT_ALIAS_UNREGISTERED_ONLY is set, then only packets with\n * unregistered source addresses will be aliased.  Private\n * addresses are those in the following ranges:\n *\n *\t\t10.0.0.0     ->   10.255.255.255\n *\t\t172.16.0.0   ->   172.31.255.255\n *\t\t192.168.0.0  ->   192.168.255.255\n */\n#define\tPKT_ALIAS_UNREGISTERED_ONLY\t0x10\n\n/*\n * If PKT_ALIAS_RESET_ON_ADDR_CHANGE is set, then the table of dynamic\n * aliasing links will be reset whenever PacketAliasSetAddress() changes the\n * default aliasing address.  If the default aliasing address is left\n * unchanged by this function call, then the table of dynamic aliasing links\n * will be left intact.  This bit is set after a call to PacketAliasInit().\n */\n#define\tPKT_ALIAS_RESET_ON_ADDR_CHANGE\t0x20\n\n\n/*\n * If PKT_ALIAS_PROXY_ONLY is set, then NAT will be disabled and only\n * transparent proxying is performed.\n */\n#define\tPKT_ALIAS_PROXY_ONLY\t\t0x40\n\n/*\n * If PKT_ALIAS_REVERSE is set, the actions of PacketAliasIn() and\n * PacketAliasOut() are reversed.\n */\n#define\tPKT_ALIAS_REVERSE\t\t0x80\n\n#endif\t\t\t\t/* !_ALIAS_H_ */\n"
  },
  {
    "path": "ipfw/include/net/if_dl.h",
    "content": "/*-\n * Copyright (c) 1990, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)if_dl.h\t8.1 (Berkeley) 6/10/93\n * $FreeBSD: src/sys/net/if_dl.h,v 1.14 2005/01/07 01:45:34 imp Exp $\n */\n\n#ifndef _NET_IF_DL_H_\n#define _NET_IF_DL_H_\n\n/*\n * A Link-Level Sockaddr may specify the interface in one of two\n * ways: either by means of a system-provided index number (computed\n * anew and possibly differently on every reboot), or by a human-readable\n * string such as \"il0\" (for managerial convenience).\n *\n * Census taking actions, such as something akin to SIOCGCONF would return\n * both the index and the human name.\n *\n * High volume transactions (such as giving a link-level ``from'' address\n * in a recvfrom or recvmsg call) may be likely only to provide the indexed\n * form, (which requires fewer copy operations and less space).\n *\n * The form and interpretation  of the link-level address is purely a matter\n * of convention between the device driver and its consumers; however, it is\n * expected that all drivers for an interface of a given if_type will agree.\n */\n\n/*\n * Structure of a Link-Level sockaddr:\n */\nstruct sockaddr_dl {\n\tu_char\tsdl_len;\t/* Total length of sockaddr */\n\tu_char\tsdl_family;\t/* AF_LINK */\n\tu_short\tsdl_index;\t/* if != 0, system given index for interface */\n\tu_char\tsdl_type;\t/* interface type */\n\tu_char\tsdl_nlen;\t/* interface name length, no trailing 0 reqd. */\n\tu_char\tsdl_alen;\t/* link level address length */\n\tu_char\tsdl_slen;\t/* link layer selector length */\n\tchar\tsdl_data[46];\t/* minimum work area, can be larger;\n\t\t\t\t   contains both if name and ll address */\n};\n\n#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))\n\n#ifndef _KERNEL\n\n#include <sys/cdefs.h>\n\n__BEGIN_DECLS\nvoid\tlink_addr(const char *, struct sockaddr_dl *);\nchar\t*link_ntoa(const struct sockaddr_dl *);\n__END_DECLS\n\n#endif /* !_KERNEL */\n\n#endif\n"
  },
  {
    "path": "ipfw/include/net/pfvar.h",
    "content": "#ifndef _PF_VAR_H_\n#define _PF_VAR_H_\n\n/*\n * replacement for FreeBSD's pfqueue.h\n */\n#include <sys/queue.h>\n\n#define DIOCSTARTALTQ   _IO  ('D', 42)\n#define DIOCSTOPALTQ    _IO  ('D', 43)\n\nstruct pf_altq {\n\tTAILQ_ENTRY(pf_altq)     entries;\n\t/* ... */\n        u_int32_t                qid;           /* return value */\n\n#define PF_QNAME_SIZE            64\n        char                     qname[PF_QNAME_SIZE];  /* queue name */\n\n};\n\nstruct pfioc_altq {\n        u_int32_t        action;\n        u_int32_t        ticket;\n        u_int32_t        nr;\n        struct pf_altq   altq;\n};\n\n#define DIOCGETALTQS    _IOWR('D', 47, struct pfioc_altq)\n#define DIOCGETALTQ    _IOWR('D', 48, struct pfioc_altq)\n\n#endif /* !_PF_VAR_H */\n"
  },
  {
    "path": "ipfw/include/timeconv.h",
    "content": "/*\n * simple override for _long_to_time()\n */\n#ifndef _TIMECONV_H_\n#define _TIMECONV_H_\nstatic __inline time_t\n_long_to_time(long tlong)\n{\n    if (sizeof(long) == sizeof(__int32_t))\n        return((time_t)(__int32_t)(tlong));\n    return((time_t)tlong);\n}\n\n#endif /* _TIMECONV_H_ */\n"
  },
  {
    "path": "ipfw/ipfw.8",
    "content": ".\\\"\n.\\\" $FreeBSD$\n.\\\"\n.Dd October 25, 2012\n.Dt IPFW 8\n.Os\n.Sh NAME\n.Nm ipfw\n.Nd User interface for firewall, traffic shaper, packet scheduler,\nin-kernel NAT.\n.Sh SYNOPSIS\n.Ss FIREWALL CONFIGURATION\n.Nm\n.Op Fl cq\n.Cm add\n.Ar rule\n.Nm\n.Op Fl acdefnNStT\n.Op Cm set Ar N\n.Brq Cm list | show\n.Op Ar rule | first-last ...\n.Nm\n.Op Fl f | q\n.Op Cm set Ar N\n.Cm flush\n.Nm\n.Op Fl q\n.Op Cm set Ar N\n.Brq Cm delete | zero | resetlog\n.Op Ar number ...\n.Pp\n.Nm\n.Cm set Oo Cm disable Ar number ... Oc Op Cm enable Ar number ...\n.Nm\n.Cm set move\n.Op Cm rule\n.Ar number Cm to Ar number\n.Nm\n.Cm set swap Ar number number\n.Nm\n.Cm set show\n.Ss SYSCTL SHORTCUTS\n.Nm\n.Cm enable\n.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive\n.Nm\n.Cm disable\n.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive\n.Ss LOOKUP TABLES\n.Nm\n.Cm table Ar number Cm add Ar addr Ns Oo / Ns Ar masklen Oc Op Ar value\n.Nm\n.Cm table Ar number Cm delete Ar addr Ns Op / Ns Ar masklen\n.Nm\n.Cm table\n.Brq Ar number | all\n.Cm flush\n.Nm\n.Cm table\n.Brq Ar number | all\n.Cm list\n.Ss DUMMYNET CONFIGURATION (TRAFFIC SHAPER AND PACKET SCHEDULER)\n.Nm\n.Brq Cm pipe | queue | sched\n.Ar number\n.Cm config\n.Ar config-options\n.Nm\n.Op Fl s Op Ar field\n.Brq Cm pipe | queue | sched\n.Brq Cm delete | list | show\n.Op Ar number ...\n.Ss IN-KERNEL NAT\n.Nm\n.Op Fl q\n.Cm nat\n.Ar number\n.Cm config\n.Ar config-options\n.Pp\n.Nm\n.Op Fl cfnNqS\n.Oo\n.Fl p Ar preproc\n.Oo\n.Ar preproc-flags\n.Oc\n.Oc\n.Ar pathname\n.Sh DESCRIPTION\nThe\n.Nm\nutility is the user interface for controlling the\n.Xr ipfw 4\nfirewall, the\n.Xr dummynet 4\ntraffic shaper/packet scheduler, and the\nin-kernel NAT services.\n.Pp\nA firewall configuration, or\n.Em ruleset ,\nis made of a list of\n.Em rules\nnumbered from 1 to 65535.\nPackets are passed to the firewall\nfrom a number of different places in the protocol stack\n(depending on the source and destination of the packet,\nit is possible for the firewall to be\ninvoked multiple times on the same packet).\nThe packet passed to the firewall is compared\nagainst each of the rules in the\n.Em ruleset ,\nin rule-number order\n(multiple rules with the same number are permitted, in which case\nthey are processed in order of insertion).\nWhen a match is found, the action corresponding to the\nmatching rule is performed.\n.Pp\nDepending on the action and certain system settings, packets\ncan be reinjected into the firewall at some rule after the\nmatching one for further processing.\n.Pp\nA ruleset always includes a\n.Em default\nrule (numbered 65535) which cannot be modified or deleted,\nand matches all packets.\nThe action associated with the\n.Em default\nrule can be either\n.Cm deny\nor\n.Cm allow\ndepending on how the kernel is configured.\n.Pp\nIf the ruleset includes one or more rules with the\n.Cm keep-state\nor\n.Cm limit\noption,\nthe firewall will have a\n.Em stateful\nbehaviour, i.e., upon a match it will create\n.Em dynamic rules ,\ni.e., rules that match packets with the same 5-tuple\n(protocol, source and destination addresses and ports)\nas the packet which caused their creation.\nDynamic rules, which have a limited lifetime, are checked\nat the first occurrence of a\n.Cm check-state ,\n.Cm keep-state\nor\n.Cm limit\nrule, and are typically used to open the firewall on-demand to\nlegitimate traffic only.\nSee the\n.Sx STATEFUL FIREWALL\nand\n.Sx EXAMPLES\nSections below for more information on the stateful behaviour of\n.Nm .\n.Pp\nAll rules (including dynamic ones) have a few associated counters:\na packet count, a byte count, a log count and a timestamp\nindicating the time of the last match.\nCounters can be displayed or reset with\n.Nm\ncommands.\n.Pp\nEach rule belongs to one of 32 different\n.Em sets\n, and there are\n.Nm\ncommands to atomically manipulate sets, such as enable,\ndisable, swap sets, move all rules in a set to another\none, delete all rules in a set.\nThese can be useful to\ninstall temporary configurations, or to test them.\nSee Section\n.Sx SETS OF RULES\nfor more information on\n.Em sets .\n.Pp\nRules can be added with the\n.Cm add\ncommand; deleted individually or in groups with the\n.Cm delete\ncommand, and globally (except those in set 31) with the\n.Cm flush\ncommand; displayed, optionally with the content of the\ncounters, using the\n.Cm show\nand\n.Cm list\ncommands.\nFinally, counters can be reset with the\n.Cm zero\nand\n.Cm resetlog\ncommands.\n.Pp\n.Ss COMMAND OPTIONS\nThe following general options are available when invoking\n.Nm :\n.Bl -tag -width indent\n.It Fl a\nShow counter values when listing rules.\nThe\n.Cm show\ncommand implies this option.\n.It Fl b\nOnly show the action and the comment, not the body of a rule.\nImplies\n.Fl c .\n.It Fl c\nWhen entering or showing rules, print them in compact form,\ni.e., omitting the \"ip from any to any\" string\nwhen this does not carry any additional information.\n.It Fl d\nWhen listing, show dynamic rules in addition to static ones.\n.It Fl e\nWhen listing and\n.Fl d\nis specified, also show expired dynamic rules.\n.It Fl f\nDo not ask for confirmation for commands that can cause problems\nif misused, i.e.,\n.Cm flush .\nIf there is no tty associated with the process, this is implied.\n.It Fl i\nWhen listing a table (see the\n.Sx LOOKUP TABLES\nsection below for more information on lookup tables), format values\nas IP addresses.\nBy default, values are shown as integers.\n.It Fl n\nOnly check syntax of the command strings, without actually passing\nthem to the kernel.\n.It Fl N\nTry to resolve addresses and service names in output.\n.It Fl q\nBe quiet when executing the\n.Cm add ,\n.Cm nat ,\n.Cm zero ,\n.Cm resetlog\nor\n.Cm flush\ncommands;\n(implies\n.Fl f ) .\nThis is useful when updating rulesets by executing multiple\n.Nm\ncommands in a script\n(e.g.,\n.Ql sh\\ /etc/rc.firewall ) ,\nor by processing a file with many\n.Nm\nrules across a remote login session.\nIt also stops a table add or delete\nfrom failing if the entry already exists or is not present.\n.Pp\nThe reason why this option may be important is that\nfor some of these actions,\n.Nm\nmay print a message; if the action results in blocking the\ntraffic to the remote client,\nthe remote login session will be closed\nand the rest of the ruleset will not be processed.\nAccess to the console would then be required to recover.\n.It Fl S\nWhen listing rules, show the\n.Em set\neach rule belongs to.\nIf this flag is not specified, disabled rules will not be\nlisted.\n.It Fl s Op Ar field\nWhen listing pipes, sort according to one of the four\ncounters (total or current packets or bytes).\n.It Fl t\nWhen listing, show last match timestamp converted with ctime().\n.It Fl T\nWhen listing, show last match timestamp as seconds from the epoch.\nThis form can be more convenient for postprocessing by scripts.\n.El\n.Ss LIST OF RULES AND PREPROCESSING\nTo ease configuration, rules can be put into a file which is\nprocessed using\n.Nm\nas shown in the last synopsis line.\nAn absolute\n.Ar pathname\nmust be used.\nThe file will be read line by line and applied as arguments to the\n.Nm\nutility.\n.Pp\nOptionally, a preprocessor can be specified using\n.Fl p Ar preproc\nwhere\n.Ar pathname\nis to be piped through.\nUseful preprocessors include\n.Xr cpp 1\nand\n.Xr m4 1 .\nIf\n.Ar preproc\ndoes not start with a slash\n.Pq Ql /\nas its first character, the usual\n.Ev PATH\nname search is performed.\nCare should be taken with this in environments where not all\nfile systems are mounted (yet) by the time\n.Nm\nis being run (e.g.\\& when they are mounted over NFS).\nOnce\n.Fl p\nhas been specified, any additional arguments are passed on to the preprocessor\nfor interpretation.\nThis allows for flexible configuration files (like conditionalizing\nthem on the local hostname) and the use of macros to centralize\nfrequently required arguments like IP addresses.\n.Ss TRAFFIC SHAPER CONFIGURATION\nThe\n.Nm\n.Cm pipe , queue\nand\n.Cm sched\ncommands are used to configure the traffic shaper and packet scheduler.\nSee the\n.Sx TRAFFIC SHAPER (DUMMYNET) CONFIGURATION\nSection below for details.\n.Pp\nIf the world and the kernel get out of sync the\n.Nm\nABI may break, preventing you from being able to add any rules.\nThis can adversely affect the booting process.\nYou can use\n.Nm\n.Cm disable\n.Cm firewall\nto temporarily disable the firewall to regain access to the network,\nallowing you to fix the problem.\n.Sh PACKET FLOW\nA packet is checked against the active ruleset in multiple places\nin the protocol stack, under control of several sysctl variables.\nThese places and variables are shown below, and it is important to\nhave this picture in mind in order to design a correct ruleset.\n.Bd -literal -offset indent\n       ^    to upper layers    V\n       |                       |\n       +----------->-----------+\n       ^                       V\n [ip(6)_input]           [ip(6)_output]     net.inet(6).ip(6).fw.enable=1\n       |                       |\n       ^                       V\n [ether_demux]        [ether_output_frame]  net.link.ether.ipfw=1\n       |                       |\n       +-->--[bdg_forward]-->--+            net.link.bridge.ipfw=1\n       ^                       V\n       |      to devices       |\n.Ed\n.Pp\nThe number of\ntimes the same packet goes through the firewall can\nvary between 0 and 4 depending on packet source and\ndestination, and system configuration.\n.Pp\nNote that as packets flow through the stack, headers can be\nstripped or added to it, and so they may or may not be available\nfor inspection.\nE.g., incoming packets will include the MAC header when\n.Nm\nis invoked from\n.Cm ether_demux() ,\nbut the same packets will have the MAC header stripped off when\n.Nm\nis invoked from\n.Cm ip_input()\nor\n.Cm ip6_input() .\n.Pp\nAlso note that each packet is always checked against the complete ruleset,\nirrespective of the place where the check occurs, or the source of the packet.\nIf a rule contains some match patterns or actions which are not valid\nfor the place of invocation (e.g.\\& trying to match a MAC header within\n.Cm ip_input\nor\n.Cm ip6_input ),\nthe match pattern will not match, but a\n.Cm not\noperator in front of such patterns\n.Em will\ncause the pattern to\n.Em always\nmatch on those packets.\nIt is thus the responsibility of\nthe programmer, if necessary, to write a suitable ruleset to\ndifferentiate among the possible places.\n.Cm skipto\nrules can be useful here, as an example:\n.Bd -literal -offset indent\n# packets from ether_demux or bdg_forward\nipfw add 10 skipto 1000 all from any to any layer2 in\n# packets from ip_input\nipfw add 10 skipto 2000 all from any to any not layer2 in\n# packets from ip_output\nipfw add 10 skipto 3000 all from any to any not layer2 out\n# packets from ether_output_frame\nipfw add 10 skipto 4000 all from any to any layer2 out\n.Ed\n.Pp\n(yes, at the moment there is no way to differentiate between\nether_demux and bdg_forward).\n.Sh SYNTAX\nIn general, each keyword or argument must be provided as\na separate command line argument, with no leading or trailing\nspaces.\nKeywords are case-sensitive, whereas arguments may\nor may not be case-sensitive depending on their nature\n(e.g.\\& uid's are, hostnames are not).\n.Pp\nSome arguments (e.g., port or address lists) are comma-separated\nlists of values.\nIn this case, spaces after commas ',' are allowed to make\nthe line more readable.\nYou can also put the entire\ncommand (including flags) into a single argument.\nE.g., the following forms are equivalent:\n.Bd -literal -offset indent\nipfw -q add deny src-ip 10.0.0.0/24,127.0.0.1/8\nipfw -q add deny src-ip 10.0.0.0/24, 127.0.0.1/8\nipfw \"-q add deny src-ip 10.0.0.0/24, 127.0.0.1/8\"\n.Ed\n.Sh RULE FORMAT\nThe format of firewall rules is the following:\n.Bd -ragged -offset indent\n.Bk -words\n.Op Ar rule_number\n.Op Cm set Ar set_number\n.Op Cm prob Ar match_probability\n.Ar action\n.Op Cm log Op Cm logamount Ar number\n.Op Cm altq Ar queue\n.Oo\n.Bro Cm tag | untag\n.Brc Ar number\n.Oc\n.Ar body\n.Ek\n.Ed\n.Pp\nwhere the body of the rule specifies which information is used\nfor filtering packets, among the following:\n.Pp\n.Bl -tag -width \"Source and dest. addresses and ports\" -offset XXX -compact\n.It Layer-2 header fields\nWhen available\n.It IPv4 and IPv6 Protocol\nTCP, UDP, ICMP, etc.\n.It Source and dest. addresses and ports\n.It Direction\nSee Section\n.Sx PACKET FLOW\n.It Transmit and receive interface\nBy name or address\n.It Misc. IP header fields\nVersion, type of service, datagram length, identification,\nfragment flag (non-zero IP offset),\nTime To Live\n.It IP options\n.It IPv6 Extension headers\nFragmentation, Hop-by-Hop options,\nRouting Headers, Source routing rthdr0, Mobile IPv6 rthdr2, IPSec options.\n.It IPv6 Flow-ID\n.It Misc. TCP header fields\nTCP flags (SYN, FIN, ACK, RST, etc.),\nsequence number, acknowledgment number,\nwindow\n.It TCP options\n.It ICMP types\nfor ICMP packets\n.It ICMP6 types\nfor ICMP6 packets\n.It User/group ID\nWhen the packet can be associated with a local socket.\n.It Divert status\nWhether a packet came from a divert socket (e.g.,\n.Xr natd 8 ) .\n.It Fib annotation state\nWhether a packet has been tagged for using a specific FIB (routing table)\nin future forwarding decisions.\n.El\n.Pp\nNote that some of the above information, e.g.\\& source MAC or IP addresses and\nTCP/UDP ports, can be easily spoofed, so filtering on those fields\nalone might not guarantee the desired results.\n.Bl -tag -width indent\n.It Ar rule_number\nEach rule is associated with a\n.Ar rule_number\nin the range 1..65535, with the latter reserved for the\n.Em default\nrule.\nRules are checked sequentially by rule number.\nMultiple rules can have the same number, in which case they are\nchecked (and listed) according to the order in which they have\nbeen added.\nIf a rule is entered without specifying a number, the kernel will\nassign one in such a way that the rule becomes the last one\nbefore the\n.Em default\nrule.\nAutomatic rule numbers are assigned by incrementing the last\nnon-default rule number by the value of the sysctl variable\n.Ar net.inet.ip.fw.autoinc_step\nwhich defaults to 100.\nIf this is not possible (e.g.\\& because we would go beyond the\nmaximum allowed rule number), the number of the last\nnon-default value is used instead.\n.It Cm set Ar set_number\nEach rule is associated with a\n.Ar set_number\nin the range 0..31.\nSets can be individually disabled and enabled, so this parameter\nis of fundamental importance for atomic ruleset manipulation.\nIt can be also used to simplify deletion of groups of rules.\nIf a rule is entered without specifying a set number,\nset 0 will be used.\n.br\nSet 31 is special in that it cannot be disabled,\nand rules in set 31 are not deleted by the\n.Nm ipfw flush\ncommand (but you can delete them with the\n.Nm ipfw delete set 31\ncommand).\nSet 31 is also used for the\n.Em default\nrule.\n.It Cm prob Ar match_probability\nA match is only declared with the specified probability\n(floating point number between 0 and 1).\nThis can be useful for a number of applications such as\nrandom packet drop or\n(in conjunction with\n.Nm dummynet )\nto simulate the effect of multiple paths leading to out-of-order\npacket delivery.\n.Pp\nNote: this condition is checked before any other condition, including\nones such as keep-state or check-state which might have side effects.\n.It Cm log Op Cm logamount Ar number\nPackets matching a rule with the\n.Cm log\nkeyword will be made available for logging in two ways:\nif the sysctl variable\n.Va net.inet.ip.fw.verbose\nis set to 0 (default), one can use\n.Xr bpf 4\nattached to the\n.Li ipfw0\npseudo interface.\nThis pseudo interface can be created after a boot\nmanually by using the following command:\n.Bd -literal -offset indent\n# ifconfig ipfw0 create\n.Ed\n.Pp\nOr, automatically at boot time by adding the following\nline to the\n.Xr rc.conf 5\nfile:\n.Bd -literal -offset indent\nfirewall_logif=\"YES\"\n.Ed\n.Pp\nThere is no overhead if no\n.Xr bpf 4\nis attached to the pseudo interface.\n.Pp\nIf\n.Va net.inet.ip.fw.verbose\nis set to 1, packets will be logged to\n.Xr syslogd 8\nwith a\n.Dv LOG_SECURITY\nfacility up to a maximum of\n.Cm logamount\npackets.\nIf no\n.Cm logamount\nis specified, the limit is taken from the sysctl variable\n.Va net.inet.ip.fw.verbose_limit .\nIn both cases, a value of 0 means unlimited logging.\n.Pp\nOnce the limit is reached, logging can be re-enabled by\nclearing the logging counter or the packet counter for that entry, see the\n.Cm resetlog\ncommand.\n.Pp\nNote: logging is done after all other packet matching conditions\nhave been successfully verified, and before performing the final\naction (accept, deny, etc.) on the packet.\n.It Cm tag Ar number\nWhen a packet matches a rule with the\n.Cm tag\nkeyword, the numeric tag for the given\n.Ar number\nin the range 1..65534 will be attached to the packet.\nThe tag acts as an internal marker (it is not sent out over\nthe wire) that can be used to identify these packets later on.\nThis can be used, for example, to provide trust between interfaces\nand to start doing policy-based filtering.\nA packet can have multiple tags at the same time.\nTags are \"sticky\", meaning once a tag is applied to a packet by a\nmatching rule it exists until explicit removal.\nTags are kept with the packet everywhere within the kernel, but are\nlost when packet leaves the kernel, for example, on transmitting\npacket out to the network or sending packet to a\n.Xr divert 4\nsocket.\n.Pp\nTo check for previously applied tags, use the\n.Cm tagged\nrule option.\nTo delete previously applied tag, use the\n.Cm untag\nkeyword.\n.Pp\nNote: since tags are kept with the packet everywhere in kernelspace,\nthey can be set and unset anywhere in the kernel network subsystem\n(using the\n.Xr mbuf_tags 9\nfacility), not only by means of the\n.Xr ipfw 4\n.Cm tag\nand\n.Cm untag\nkeywords.\nFor example, there can be a specialized\n.Xr netgraph 4\nnode doing traffic analyzing and tagging for later inspecting\nin firewall.\n.It Cm untag Ar number\nWhen a packet matches a rule with the\n.Cm untag\nkeyword, the tag with the number\n.Ar number\nis searched among the tags attached to this packet and,\nif found, removed from it.\nOther tags bound to packet, if present, are left untouched.\n.It Cm altq Ar queue\nWhen a packet matches a rule with the\n.Cm altq\nkeyword, the ALTQ identifier for the given\n.Ar queue\n(see\n.Xr altq 4 )\nwill be attached.\nNote that this ALTQ tag is only meaningful for packets going \"out\" of IPFW,\nand not being rejected or going to divert sockets.\nNote that if there is insufficient memory at the time the packet is\nprocessed, it will not be tagged, so it is wise to make your ALTQ\n\"default\" queue policy account for this.\nIf multiple\n.Cm altq\nrules match a single packet, only the first one adds the ALTQ classification\ntag.\nIn doing so, traffic may be shaped by using\n.Cm count Cm altq Ar queue\nrules for classification early in the ruleset, then later applying\nthe filtering decision.\nFor example,\n.Cm check-state\nand\n.Cm keep-state\nrules may come later and provide the actual filtering decisions in\naddition to the fallback ALTQ tag.\n.Pp\nYou must run\n.Xr pfctl 8\nto set up the queues before IPFW will be able to look them up by name,\nand if the ALTQ disciplines are rearranged, the rules in containing the\nqueue identifiers in the kernel will likely have gone stale and need\nto be reloaded.\nStale queue identifiers will probably result in misclassification.\n.Pp\nAll system ALTQ processing can be turned on or off via\n.Nm\n.Cm enable Ar altq\nand\n.Nm\n.Cm disable Ar altq .\nThe usage of\n.Va net.inet.ip.fw.one_pass\nis irrelevant to ALTQ traffic shaping, as the actual rule action is followed\nalways after adding an ALTQ tag.\n.El\n.Ss RULE ACTIONS\nA rule can be associated with one of the following actions, which\nwill be executed when the packet matches the body of the rule.\n.Bl -tag -width indent\n.It Cm allow | accept | pass | permit\nAllow packets that match rule.\nThe search terminates.\n.It Cm check-state\nChecks the packet against the dynamic ruleset.\nIf a match is found, execute the action associated with\nthe rule which generated this dynamic rule, otherwise\nmove to the next rule.\n.br\n.Cm Check-state\nrules do not have a body.\nIf no\n.Cm check-state\nrule is found, the dynamic ruleset is checked at the first\n.Cm keep-state\nor\n.Cm limit\nrule.\n.It Cm count\nUpdate counters for all packets that match rule.\nThe search continues with the next rule.\n.It Cm deny | drop\nDiscard packets that match this rule.\nThe search terminates.\n.It Cm divert Ar port\nDivert packets that match this rule to the\n.Xr divert 4\nsocket bound to port\n.Ar port .\nThe search terminates.\n.It Cm fwd | forward Ar ipaddr | tablearg Ns Op , Ns Ar port\nChange the next-hop on matching packets to\n.Ar ipaddr ,\nwhich can be an IP address or a host name.\nFor IPv4, the next hop can also be supplied by the last table\nlooked up for the packet by using the\n.Cm tablearg\nkeyword instead of an explicit address.\nThe search terminates if this rule matches.\n.Pp\nIf\n.Ar ipaddr\nis a local address, then matching packets will be forwarded to\n.Ar port\n(or the port number in the packet if one is not specified in the rule)\non the local machine.\n.br\nIf\n.Ar ipaddr\nis not a local address, then the port number\n(if specified) is ignored, and the packet will be\nforwarded to the remote address, using the route as found in\nthe local routing table for that IP.\n.br\nA\n.Ar fwd\nrule will not match layer-2 packets (those received\non ether_input, ether_output, or bridged).\n.br\nThe\n.Cm fwd\naction does not change the contents of the packet at all.\nIn particular, the destination address remains unmodified, so\npackets forwarded to another system will usually be rejected by that system\nunless there is a matching rule on that system to capture them.\nFor packets forwarded locally,\nthe local address of the socket will be\nset to the original destination address of the packet.\nThis makes the\n.Xr netstat 1\nentry look rather weird but is intended for\nuse with transparent proxy servers.\n.It Cm nat Ar nat_nr | tablearg\nPass packet to a\nnat instance\n(for network address translation, address redirect, etc.):\nsee the\n.Sx NETWORK ADDRESS TRANSLATION (NAT)\nSection for further information.\n.It Cm pipe Ar pipe_nr\nPass packet to a\n.Nm dummynet\n.Dq pipe\n(for bandwidth limitation, delay, etc.).\nSee the\n.Sx TRAFFIC SHAPER (DUMMYNET) CONFIGURATION\nSection for further information.\nThe search terminates; however, on exit from the pipe and if\nthe\n.Xr sysctl 8\nvariable\n.Va net.inet.ip.fw.one_pass\nis not set, the packet is passed again to the firewall code\nstarting from the next rule.\n.It Cm queue Ar queue_nr\nPass packet to a\n.Nm dummynet\n.Dq queue\n(for bandwidth limitation using WF2Q+).\n.It Cm reject\n(Deprecated).\nSynonym for\n.Cm unreach host .\n.It Cm reset\nDiscard packets that match this rule, and if the\npacket is a TCP packet, try to send a TCP reset (RST) notice.\nThe search terminates.\n.It Cm reset6\nDiscard packets that match this rule, and if the\npacket is a TCP packet, try to send a TCP reset (RST) notice.\nThe search terminates.\n.It Cm skipto Ar number | tablearg\nSkip all subsequent rules numbered less than\n.Ar number .\nThe search continues with the first rule numbered\n.Ar number\nor higher.\nIt is possible to use the\n.Cm tablearg\nkeyword with a skipto for a\n.Em computed\nskipto, but care should be used, as no destination caching\nis possible in this case so the rules are always walked to find it,\nstarting from the\n.Cm skipto .\n.It Cm call Ar number | tablearg\nThe current rule number is saved in the internal stack and\nruleset processing continues with the first rule numbered\n.Ar number\nor higher.\nIf later a rule with the\n.Cm return\naction is encountered, the processing returns to the first rule\nwith number of this\n.Cm call\nrule plus one or higher\n(the same behaviour as with packets returning from\n.Xr divert 4\nsocket after a\n.Cm divert\naction).\nThis could be used to make somewhat like an assembly language\n.Dq subroutine\ncalls to rules with common checks for different interfaces, etc.\n.Pp\nRule with any number could be called, not just forward jumps as with\n.Cm skipto .\nSo, to prevent endless loops in case of mistakes, both\n.Cm call\nand\n.Cm return\nactions don't do any jumps and simply go to the next rule if memory\ncannot be allocated or stack overflowed/underflowed.\n.Pp\nInternally stack for rule numbers is implemented using\n.Xr mbuf_tags 9\nfacility and currently has size of 16 entries.\nAs mbuf tags are lost when packet leaves the kernel,\n.Cm divert\nshould not be used in subroutines to avoid endless loops\nand other undesired effects.\n.It Cm return\nTakes rule number saved to internal stack by the last\n.Cm call\naction and returns ruleset processing to the first rule\nwith number greater than number of corresponding\n.Cm call\nrule.\nSee description of the\n.Cm call\naction for more details.\n.Pp\nNote that\n.Cm return\nrules usually end a\n.Dq subroutine\nand thus are unconditional, but\n.Nm\ncommand-line utility currently requires every action except\n.Cm check-state\nto have body.\nWhile it is sometimes useful to return only on some packets,\nusually you want to print just\n.Dq return\nfor readability.\nA workaround for this is to use new syntax and\n.Fl c\nswitch:\n.Bd -literal -offset indent\n# Add a rule without actual body\nipfw add 2999 return via any\n\n# List rules without \"from any to any\" part\nipfw -c list\n.Ed\n.Pp\nThis cosmetic annoyance may be fixed in future releases.\n.It Cm tee Ar port\nSend a copy of packets matching this rule to the\n.Xr divert 4\nsocket bound to port\n.Ar port .\nThe search continues with the next rule.\n.It Cm unreach Ar code\nDiscard packets that match this rule, and try to send an ICMP\nunreachable notice with code\n.Ar code ,\nwhere\n.Ar code\nis a number from 0 to 255, or one of these aliases:\n.Cm net , host , protocol , port ,\n.Cm needfrag , srcfail , net-unknown , host-unknown ,\n.Cm isolated , net-prohib , host-prohib , tosnet ,\n.Cm toshost , filter-prohib , host-precedence\nor\n.Cm precedence-cutoff .\nThe search terminates.\n.It Cm unreach6 Ar code\nDiscard packets that match this rule, and try to send an ICMPv6\nunreachable notice with code\n.Ar code ,\nwhere\n.Ar code\nis a number from 0, 1, 3 or 4, or one of these aliases:\n.Cm no-route, admin-prohib, address\nor\n.Cm port .\nThe search terminates.\n.It Cm netgraph Ar cookie\nDivert packet into netgraph with given\n.Ar cookie .\nThe search terminates.\nIf packet is later returned from netgraph it is either\naccepted or continues with the next rule, depending on\n.Va net.inet.ip.fw.one_pass\nsysctl variable.\n.It Cm ngtee Ar cookie\nA copy of packet is diverted into netgraph, original\npacket continues with the next rule.\nSee\n.Xr ng_ipfw 4\nfor more information on\n.Cm netgraph\nand\n.Cm ngtee\nactions.\n.It Cm setfib Ar fibnum | tablearg\nThe packet is tagged so as to use the FIB (routing table)\n.Ar fibnum\nin any subsequent forwarding decisions.\nIn the current implementation, this is limited to the values 0 through 15, see\n.Xr setfib 2 .\nProcessing continues at the next rule.\nIt is possible to use the\n.Cm tablearg\nkeyword with setfib.\nIf the tablearg value is not within the compiled range of fibs,\nthe packet's fib is set to 0.\n.It Cm setdscp Ar DSCP | number | tablearg\nSet specified DiffServ codepoint for an IPv4/IPv6 packet.\nProcessing continues at the next rule.\nSupported values are:\n.Pp\n.Cm CS0\n.Pq Dv 000000 ,\n.Cm CS1\n.Pq Dv 001000 ,\n.Cm CS2\n.Pq Dv 010000 ,\n.Cm CS3\n.Pq Dv 011000 ,\n.Cm CS4\n.Pq Dv 100000 ,\n.Cm CS5\n.Pq Dv 101000 ,\n.Cm CS6\n.Pq Dv 110000 ,\n.Cm CS7\n.Pq Dv 111000 ,\n.Cm AF11\n.Pq Dv 001010 ,\n.Cm AF12\n.Pq Dv 001100 ,\n.Cm AF13\n.Pq Dv 001110 ,\n.Cm AF21\n.Pq Dv 010010 ,\n.Cm AF22\n.Pq Dv 010100 ,\n.Cm AF23\n.Pq Dv 010110 ,\n.Cm AF31\n.Pq Dv 011010 ,\n.Cm AF32\n.Pq Dv 011100 ,\n.Cm AF33\n.Pq Dv 011110 ,\n.Cm AF41\n.Pq Dv 100010 ,\n.Cm AF42\n.Pq Dv 100100 ,\n.Cm AF43\n.Pq Dv 100110 ,\n.Cm EF\n.Pq Dv 101110 ,\n.Cm BE\n.Pq Dv 000000 .\nAdditionally, DSCP value can be specified by number (0..64).\nIt is also possible to use the\n.Cm tablearg\nkeyword with setdscp.\nIf the tablearg value is not within the 0..64 range, lower 6 bits of supplied\nvalue are used.\n.It Cm reass\nQueue and reassemble IP fragments.\nIf the packet is not fragmented, counters are updated and\nprocessing continues with the next rule.\nIf the packet is the last logical fragment, the packet is reassembled and, if\n.Va net.inet.ip.fw.one_pass\nis set to 0, processing continues with the next rule.\nOtherwise, the packet is allowed to pass and the search terminates.\nIf the packet is a fragment in the middle of a logical group of fragments,\nit is consumed and\nprocessing stops immediately.\n.Pp\nFragment handling can be tuned via\n.Va net.inet.ip.maxfragpackets\nand\n.Va net.inet.ip.maxfragsperpacket\nwhich limit, respectively, the maximum number of processable\nfragments (default: 800) and\nthe maximum number of fragments per packet (default: 16).\n.Pp\nNOTA BENE: since fragments do not contain port numbers,\nthey should be avoided with the\n.Nm reass\nrule.\nAlternatively, direction-based (like\n.Nm in\n/\n.Nm out\n) and source-based (like\n.Nm via\n) match patterns can be used to select fragments.\n.Pp\nUsually a simple rule like:\n.Bd -literal -offset indent\n# reassemble incoming fragments\nipfw add reass all from any to any in\n.Ed\n.Pp\nis all you need at the beginning of your ruleset.\n.El\n.Ss RULE BODY\nThe body of a rule contains zero or more patterns (such as\nspecific source and destination addresses or ports,\nprotocol options, incoming or outgoing interfaces, etc.)\nthat the packet must match in order to be recognised.\nIn general, the patterns are connected by (implicit)\n.Cm and\noperators -- i.e., all must match in order for the\nrule to match.\nIndividual patterns can be prefixed by the\n.Cm not\noperator to reverse the result of the match, as in\n.Pp\n.Dl \"ipfw add 100 allow ip from not 1.2.3.4 to any\"\n.Pp\nAdditionally, sets of alternative match patterns\n.Pq Em or-blocks\ncan be constructed by putting the patterns in\nlists enclosed between parentheses ( ) or braces { }, and\nusing the\n.Cm or\noperator as follows:\n.Pp\n.Dl \"ipfw add 100 allow ip from { x or not y or z } to any\"\n.Pp\nOnly one level of parentheses is allowed.\nBeware that most shells have special meanings for parentheses\nor braces, so it is advisable to put a backslash \\\\ in front of them\nto prevent such interpretations.\n.Pp\nThe body of a rule must in general include a source and destination\naddress specifier.\nThe keyword\n.Ar any\ncan be used in various places to specify that the content of\na required field is irrelevant.\n.Pp\nThe rule body has the following format:\n.Bd -ragged -offset indent\n.Op Ar proto Cm from Ar src Cm to Ar dst\n.Op Ar options\n.Ed\n.Pp\nThe first part (proto from src to dst) is for backward\ncompatibility with earlier versions of\n.Fx .\nIn modern\n.Fx\nany match pattern (including MAC headers, IP protocols,\naddresses and ports) can be specified in the\n.Ar options\nsection.\n.Pp\nRule fields have the following meaning:\n.Bl -tag -width indent\n.It Ar proto : protocol | Cm { Ar protocol Cm or ... }\n.It Ar protocol : Oo Cm not Oc Ar protocol-name | protocol-number\nAn IP protocol specified by number or name\n(for a complete list see\n.Pa /etc/protocols ) ,\nor one of the following keywords:\n.Bl -tag -width indent\n.It Cm ip4 | ipv4\nMatches IPv4 packets.\n.It Cm ip6 | ipv6\nMatches IPv6 packets.\n.It Cm ip | all\nMatches any packet.\n.El\n.Pp\nThe\n.Cm ipv6\nin\n.Cm proto\noption will be treated as inner protocol.\nAnd, the\n.Cm ipv4\nis not available in\n.Cm proto\noption.\n.Pp\nThe\n.Cm { Ar protocol Cm or ... }\nformat (an\n.Em or-block )\nis provided for convenience only but its use is deprecated.\n.It Ar src No and Ar dst : Bro Cm addr | Cm { Ar addr Cm or ... } Brc Op Oo Cm not Oc Ar ports\nAn address (or a list, see below)\noptionally followed by\n.Ar ports\nspecifiers.\n.Pp\nThe second format\n.Em ( or-block\nwith multiple addresses) is provided for convenience only and\nits use is discouraged.\n.It Ar addr : Oo Cm not Oc Bro\n.Cm any | me | me6 |\n.Cm table Ns Pq Ar number Ns Op , Ns Ar value\n.Ar | addr-list | addr-set\n.Brc\n.Bl -tag -width indent\n.It Cm any\nmatches any IP address.\n.It Cm me\nmatches any IP address configured on an interface in the system.\n.It Cm me6\nmatches any IPv6 address configured on an interface in the system.\nThe address list is evaluated at the time the packet is\nanalysed.\n.It Cm table Ns Pq Ar number Ns Op , Ns Ar value\nMatches any IPv4 address for which an entry exists in the lookup table\n.Ar number .\nIf an optional 32-bit unsigned\n.Ar value\nis also specified, an entry will match only if it has this value.\nSee the\n.Sx LOOKUP TABLES\nsection below for more information on lookup tables.\n.El\n.It Ar addr-list : ip-addr Ns Op Ns , Ns Ar addr-list\n.It Ar ip-addr :\nA host or subnet address specified in one of the following ways:\n.Bl -tag -width indent\n.It Ar numeric-ip | hostname\nMatches a single IPv4 address, specified as dotted-quad or a hostname.\nHostnames are resolved at the time the rule is added to the firewall list.\n.It Ar addr Ns / Ns Ar masklen\nMatches all addresses with base\n.Ar addr\n(specified as an IP address, a network number, or a hostname)\nand mask width of\n.Cm masklen\nbits.\nAs an example, 1.2.3.4/25 or 1.2.3.0/25 will match\nall IP numbers from 1.2.3.0 to 1.2.3.127 .\n.It Ar addr Ns : Ns Ar mask\nMatches all addresses with base\n.Ar addr\n(specified as an IP address, a network number, or a hostname)\nand the mask of\n.Ar mask ,\nspecified as a dotted quad.\nAs an example, 1.2.3.4:255.0.255.0 or 1.0.3.0:255.0.255.0 will match\n1.*.3.*.\nThis form is advised only for non-contiguous\nmasks.\nIt is better to resort to the\n.Ar addr Ns / Ns Ar masklen\nformat for contiguous masks, which is more compact and less\nerror-prone.\n.El\n.It Ar addr-set : addr Ns Oo Ns / Ns Ar masklen Oc Ns Cm { Ns Ar list Ns Cm }\n.It Ar list : Bro Ar num | num-num Brc Ns Op Ns , Ns Ar list\nMatches all addresses with base address\n.Ar addr\n(specified as an IP address, a network number, or a hostname)\nand whose last byte is in the list between braces { } .\nNote that there must be no spaces between braces and\nnumbers (spaces after commas are allowed).\nElements of the list can be specified as single entries\nor ranges.\nThe\n.Ar masklen\nfield is used to limit the size of the set of addresses,\nand can have any value between 24 and 32.\nIf not specified,\nit will be assumed as 24.\n.br\nThis format is particularly useful to handle sparse address sets\nwithin a single rule.\nBecause the matching occurs using a\nbitmask, it takes constant time and dramatically reduces\nthe complexity of rulesets.\n.br\nAs an example, an address specified as 1.2.3.4/24{128,35-55,89}\nor 1.2.3.0/24{128,35-55,89}\nwill match the following IP addresses:\n.br\n1.2.3.128, 1.2.3.35 to 1.2.3.55, 1.2.3.89 .\n.It Ar addr6-list : ip6-addr Ns Op Ns , Ns Ar addr6-list\n.It Ar ip6-addr :\nA host or subnet specified one of the following ways:\n.Bl -tag -width indent\n.It Ar numeric-ip | hostname\nMatches a single IPv6 address as allowed by\n.Xr inet_pton 3\nor a hostname.\nHostnames are resolved at the time the rule is added to the firewall\nlist.\n.It Ar addr Ns / Ns Ar masklen\nMatches all IPv6 addresses with base\n.Ar addr\n(specified as allowed by\n.Xr inet_pton\nor a hostname)\nand mask width of\n.Cm masklen\nbits.\n.El\n.Pp\nNo support for sets of IPv6 addresses is provided because IPv6 addresses\nare typically random past the initial prefix.\n.It Ar ports : Bro Ar port | port Ns \\&- Ns Ar port Ns Brc Ns Op , Ns Ar ports\nFor protocols which support port numbers (such as TCP and UDP), optional\n.Cm ports\nmay be specified as one or more ports or port ranges, separated\nby commas but no spaces, and an optional\n.Cm not\noperator.\nThe\n.Ql \\&-\nnotation specifies a range of ports (including boundaries).\n.Pp\nService names (from\n.Pa /etc/services )\nmay be used instead of numeric port values.\nThe length of the port list is limited to 30 ports or ranges,\nthough one can specify larger ranges by using an\n.Em or-block\nin the\n.Cm options\nsection of the rule.\n.Pp\nA backslash\n.Pq Ql \\e\ncan be used to escape the dash\n.Pq Ql -\ncharacter in a service name (from a shell, the backslash must be\ntyped twice to avoid the shell itself interpreting it as an escape\ncharacter).\n.Pp\n.Dl \"ipfw add count tcp from any ftp\\e\\e-data-ftp to any\"\n.Pp\nFragmented packets which have a non-zero offset (i.e., not the first\nfragment) will never match a rule which has one or more port\nspecifications.\nSee the\n.Cm frag\noption for details on matching fragmented packets.\n.El\n.Ss RULE OPTIONS (MATCH PATTERNS)\nAdditional match patterns can be used within\nrules.\nZero or more of these so-called\n.Em options\ncan be present in a rule, optionally prefixed by the\n.Cm not\noperand, and possibly grouped into\n.Em or-blocks .\n.Pp\nThe following match patterns can be used (listed in alphabetical order):\n.Bl -tag -width indent\n.It Cm // this is a comment.\nInserts the specified text as a comment in the rule.\nEverything following // is considered as a comment and stored in the rule.\nYou can have comment-only rules, which are listed as having a\n.Cm count\naction followed by the comment.\n.It Cm bridged\nAlias for\n.Cm layer2 .\n.It Cm diverted\nMatches only packets generated by a divert socket.\n.It Cm diverted-loopback\nMatches only packets coming from a divert socket back into the IP stack\ninput for delivery.\n.It Cm diverted-output\nMatches only packets going from a divert socket back outward to the IP\nstack output for delivery.\n.It Cm dst-ip Ar ip-address\nMatches IPv4 packets whose destination IP is one of the address(es)\nspecified as argument.\n.It Bro Cm dst-ip6 | dst-ipv6 Brc Ar ip6-address\nMatches IPv6 packets whose destination IP is one of the address(es)\nspecified as argument.\n.It Cm dst-port Ar ports\nMatches IP packets whose destination port is one of the port(s)\nspecified as argument.\n.It Cm established\nMatches TCP packets that have the RST or ACK bits set.\n.It Cm ext6hdr Ar header\nMatches IPv6 packets containing the extended header given by\n.Ar header .\nSupported headers are:\n.Pp\nFragment,\n.Pq Cm frag ,\nHop-to-hop options\n.Pq Cm hopopt ,\nany type of Routing Header\n.Pq Cm route ,\nSource routing Routing Header Type 0\n.Pq Cm rthdr0 ,\nMobile IPv6 Routing Header Type 2\n.Pq Cm rthdr2 ,\nDestination options\n.Pq Cm dstopt ,\nIPSec authentication headers\n.Pq Cm ah ,\nand IPsec encapsulated security payload headers\n.Pq Cm esp .\n.It Cm fib Ar fibnum\nMatches a packet that has been tagged to use\nthe given FIB (routing table) number.\n.It Cm flow-id Ar labels\nMatches IPv6 packets containing any of the flow labels given in\n.Ar labels .\n.Ar labels\nis a comma separated list of numeric flow labels.\n.It Cm frag\nMatches packets that are fragments and not the first\nfragment of an IP datagram.\nNote that these packets will not have\nthe next protocol header (e.g.\\& TCP, UDP) so options that look into\nthese headers cannot match.\n.It Cm gid Ar group\nMatches all TCP or UDP packets sent by or received for a\n.Ar group .\nA\n.Ar group\nmay be specified by name or number.\n.It Cm jail Ar prisonID\nMatches all TCP or UDP packets sent by or received for the\njail whos prison ID is\n.Ar prisonID .\n.It Cm icmptypes Ar types\nMatches ICMP packets whose ICMP type is in the list\n.Ar types .\nThe list may be specified as any combination of\nindividual types (numeric) separated by commas.\n.Em Ranges are not allowed .\nThe supported ICMP types are:\n.Pp\necho reply\n.Pq Cm 0 ,\ndestination unreachable\n.Pq Cm 3 ,\nsource quench\n.Pq Cm 4 ,\nredirect\n.Pq Cm 5 ,\necho request\n.Pq Cm 8 ,\nrouter advertisement\n.Pq Cm 9 ,\nrouter solicitation\n.Pq Cm 10 ,\ntime-to-live exceeded\n.Pq Cm 11 ,\nIP header bad\n.Pq Cm 12 ,\ntimestamp request\n.Pq Cm 13 ,\ntimestamp reply\n.Pq Cm 14 ,\ninformation request\n.Pq Cm 15 ,\ninformation reply\n.Pq Cm 16 ,\naddress mask request\n.Pq Cm 17\nand address mask reply\n.Pq Cm 18 .\n.It Cm icmp6types Ar types\nMatches ICMP6 packets whose ICMP6 type is in the list of\n.Ar types .\nThe list may be specified as any combination of\nindividual types (numeric) separated by commas.\n.Em Ranges are not allowed .\n.It Cm in | out\nMatches incoming or outgoing packets, respectively.\n.Cm in\nand\n.Cm out\nare mutually exclusive (in fact,\n.Cm out\nis implemented as\n.Cm not in Ns No ).\n.It Cm ipid Ar id-list\nMatches IPv4 packets whose\n.Cm ip_id\nfield has value included in\n.Ar id-list ,\nwhich is either a single value or a list of values or ranges\nspecified in the same way as\n.Ar ports .\n.It Cm iplen Ar len-list\nMatches IP packets whose total length, including header and data, is\nin the set\n.Ar len-list ,\nwhich is either a single value or a list of values or ranges\nspecified in the same way as\n.Ar ports .\n.It Cm ipoptions Ar spec\nMatches packets whose IPv4 header contains the comma separated list of\noptions specified in\n.Ar spec .\nThe supported IP options are:\n.Pp\n.Cm ssrr\n(strict source route),\n.Cm lsrr\n(loose source route),\n.Cm rr\n(record packet route) and\n.Cm ts\n(timestamp).\nThe absence of a particular option may be denoted\nwith a\n.Ql \\&! .\n.It Cm ipprecedence Ar precedence\nMatches IPv4 packets whose precedence field is equal to\n.Ar precedence .\n.It Cm ipsec\nMatches packets that have IPSEC history associated with them\n(i.e., the packet comes encapsulated in IPSEC, the kernel\nhas IPSEC support and IPSEC_FILTERTUNNEL option, and can correctly\ndecapsulate it).\n.Pp\nNote that specifying\n.Cm ipsec\nis different from specifying\n.Cm proto Ar ipsec\nas the latter will only look at the specific IP protocol field,\nirrespective of IPSEC kernel support and the validity of the IPSEC data.\n.Pp\nFurther note that this flag is silently ignored in kernels without\nIPSEC support.\nIt does not affect rule processing when given and the\nrules are handled as if with no\n.Cm ipsec\nflag.\n.It Cm iptos Ar spec\nMatches IPv4 packets whose\n.Cm tos\nfield contains the comma separated list of\nservice types specified in\n.Ar spec .\nThe supported IP types of service are:\n.Pp\n.Cm lowdelay\n.Pq Dv IPTOS_LOWDELAY ,\n.Cm throughput\n.Pq Dv IPTOS_THROUGHPUT ,\n.Cm reliability\n.Pq Dv IPTOS_RELIABILITY ,\n.Cm mincost\n.Pq Dv IPTOS_MINCOST ,\n.Cm congestion\n.Pq Dv IPTOS_ECN_CE .\nThe absence of a particular type may be denoted\nwith a\n.Ql \\&! .\n.It Cm dscp spec Ns Op , Ns Ar spec\nMatches IPv4/IPv6 packets whose\n.Cm DS\nfield value is contained in\n.Ar spec\nmask.\nMultiple values can be specified via\nthe comma separated list.\nValue can be one of keywords used in\n.Cm setdscp\naction or exact number.\n.It Cm ipttl Ar ttl-list\nMatches IPv4 packets whose time to live is included in\n.Ar ttl-list ,\nwhich is either a single value or a list of values or ranges\nspecified in the same way as\n.Ar ports .\n.It Cm ipversion Ar ver\nMatches IP packets whose IP version field is\n.Ar ver .\n.It Cm keep-state\nUpon a match, the firewall will create a dynamic rule, whose\ndefault behaviour is to match bidirectional traffic between\nsource and destination IP/port using the same protocol.\nThe rule has a limited lifetime (controlled by a set of\n.Xr sysctl 8\nvariables), and the lifetime is refreshed every time a matching\npacket is found.\n.It Cm layer2\nMatches only layer2 packets, i.e., those passed to\n.Nm\nfrom ether_demux() and ether_output_frame().\n.It Cm limit Bro Cm src-addr | src-port | dst-addr | dst-port Brc Ar N\nThe firewall will only allow\n.Ar N\nconnections with the same\nset of parameters as specified in the rule.\nOne or more\nof source and destination addresses and ports can be\nspecified.\nCurrently,\nonly IPv4 flows are supported.\n.It Cm lookup Bro Cm dst-ip | dst-port | src-ip | src-port | uid | jail Brc Ar N\nSearch an entry in lookup table\n.Ar N\nthat matches the field specified as argument.\nIf not found, the match fails.\nOtherwise, the match succeeds and\n.Cm tablearg\nis set to the value extracted from the table.\n.Pp\nThis option can be useful to quickly dispatch traffic based on\ncertain packet fields.\nSee the\n.Sx LOOKUP TABLES\nsection below for more information on lookup tables.\n.It Cm { MAC | mac } Ar dst-mac src-mac\nMatch packets with a given\n.Ar dst-mac\nand\n.Ar src-mac\naddresses, specified as the\n.Cm any\nkeyword (matching any MAC address), or six groups of hex digits\nseparated by colons,\nand optionally followed by a mask indicating the significant bits.\nThe mask may be specified using either of the following methods:\n.Bl -enum -width indent\n.It\nA slash\n.Pq /\nfollowed by the number of significant bits.\nFor example, an address with 33 significant bits could be specified as:\n.Pp\n.Dl \"MAC 10:20:30:40:50:60/33 any\"\n.Pp\n.It\nAn ampersand\n.Pq &\nfollowed by a bitmask specified as six groups of hex digits separated\nby colons.\nFor example, an address in which the last 16 bits are significant could\nbe specified as:\n.Pp\n.Dl \"MAC 10:20:30:40:50:60&00:00:00:00:ff:ff any\"\n.Pp\nNote that the ampersand character has a special meaning in many shells\nand should generally be escaped.\n.Pp\n.El\nNote that the order of MAC addresses (destination first,\nsource second) is\nthe same as on the wire, but the opposite of the one used for\nIP addresses.\n.It Cm mac-type Ar mac-type\nMatches packets whose Ethernet Type field\ncorresponds to one of those specified as argument.\n.Ar mac-type\nis specified in the same way as\n.Cm port numbers\n(i.e., one or more comma-separated single values or ranges).\nYou can use symbolic names for known values such as\n.Em vlan , ipv4, ipv6 .\nValues can be entered as decimal or hexadecimal (if prefixed by 0x),\nand they are always printed as hexadecimal (unless the\n.Cm -N\noption is used, in which case symbolic resolution will be attempted).\n.It Cm proto Ar protocol\nMatches packets with the corresponding IP protocol.\n.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar table Ns Pq Ar number Ns Op , Ns Ar value | Ar ipno | Ar any\nMatches packets received, transmitted or going through,\nrespectively, the interface specified by exact name\n.Po Ar ifX Pc ,\nby device name\n.Po Ar if* Pc ,\nby IP address, or through some interface.\n.Pp\nThe\n.Cm via\nkeyword causes the interface to always be checked.\nIf\n.Cm recv\nor\n.Cm xmit\nis used instead of\n.Cm via ,\nthen only the receive or transmit interface (respectively)\nis checked.\nBy specifying both, it is possible to match packets based on\nboth receive and transmit interface, e.g.:\n.Pp\n.Dl \"ipfw add deny ip from any to any out recv ed0 xmit ed1\"\n.Pp\nThe\n.Cm recv\ninterface can be tested on either incoming or outgoing packets,\nwhile the\n.Cm xmit\ninterface can only be tested on outgoing packets.\nSo\n.Cm out\nis required (and\n.Cm in\nis invalid) whenever\n.Cm xmit\nis used.\n.Pp\nA packet might not have a receive or transmit interface: packets\noriginating from the local host have no receive interface,\nwhile packets destined for the local host have no transmit\ninterface.\n.It Cm setup\nMatches TCP packets that have the SYN bit set but no ACK bit.\nThis is the short form of\n.Dq Li tcpflags\\ syn,!ack .\n.It Cm sockarg\nMatches packets that are associated to a local socket and\nfor which the SO_USER_COOKIE socket option has been set\nto a non-zero value.\nAs a side effect, the value of the\noption is made available as\n.Cm tablearg\nvalue, which in turn can be used as\n.Cm skipto\nor\n.Cm pipe\nnumber.\n.It Cm src-ip Ar ip-address\nMatches IPv4 packets whose source IP is one of the address(es)\nspecified as an argument.\n.It Cm src-ip6 Ar ip6-address\nMatches IPv6 packets whose source IP is one of the address(es)\nspecified as an argument.\n.It Cm src-port Ar ports\nMatches IP packets whose source port is one of the port(s)\nspecified as argument.\n.It Cm tagged Ar tag-list\nMatches packets whose tags are included in\n.Ar tag-list ,\nwhich is either a single value or a list of values or ranges\nspecified in the same way as\n.Ar ports .\nTags can be applied to the packet using\n.Cm tag\nrule action parameter (see it's description for details on tags).\n.It Cm tcpack Ar ack\nTCP packets only.\nMatch if the TCP header acknowledgment number field is set to\n.Ar ack .\n.It Cm tcpdatalen Ar tcpdatalen-list\nMatches TCP packets whose length of TCP data is\n.Ar tcpdatalen-list ,\nwhich is either a single value or a list of values or ranges\nspecified in the same way as\n.Ar ports .\n.It Cm tcpflags Ar spec\nTCP packets only.\nMatch if the TCP header contains the comma separated list of\nflags specified in\n.Ar spec .\nThe supported TCP flags are:\n.Pp\n.Cm fin ,\n.Cm syn ,\n.Cm rst ,\n.Cm psh ,\n.Cm ack\nand\n.Cm urg .\nThe absence of a particular flag may be denoted\nwith a\n.Ql \\&! .\nA rule which contains a\n.Cm tcpflags\nspecification can never match a fragmented packet which has\na non-zero offset.\nSee the\n.Cm frag\noption for details on matching fragmented packets.\n.It Cm tcpseq Ar seq\nTCP packets only.\nMatch if the TCP header sequence number field is set to\n.Ar seq .\n.It Cm tcpwin Ar tcpwin-list\nMatches TCP packets whose  header window field is set to\n.Ar tcpwin-list ,\nwhich is either a single value or a list of values or ranges\nspecified in the same way as\n.Ar ports .\n.It Cm tcpoptions Ar spec\nTCP packets only.\nMatch if the TCP header contains the comma separated list of\noptions specified in\n.Ar spec .\nThe supported TCP options are:\n.Pp\n.Cm mss\n(maximum segment size),\n.Cm window\n(tcp window advertisement),\n.Cm sack\n(selective ack),\n.Cm ts\n(rfc1323 timestamp) and\n.Cm cc\n(rfc1644 t/tcp connection count).\nThe absence of a particular option may be denoted\nwith a\n.Ql \\&! .\n.It Cm uid Ar user\nMatch all TCP or UDP packets sent by or received for a\n.Ar user .\nA\n.Ar user\nmay be matched by name or identification number.\n.It Cm verrevpath\nFor incoming packets,\na routing table lookup is done on the packet's source address.\nIf the interface on which the packet entered the system matches the\noutgoing interface for the route,\nthe packet matches.\nIf the interfaces do not match up,\nthe packet does not match.\nAll outgoing packets or packets with no incoming interface match.\n.Pp\nThe name and functionality of the option is intentionally similar to\nthe Cisco IOS command:\n.Pp\n.Dl ip verify unicast reverse-path\n.Pp\nThis option can be used to make anti-spoofing rules to reject all\npackets with source addresses not from this interface.\nSee also the option\n.Cm antispoof .\n.It Cm versrcreach\nFor incoming packets,\na routing table lookup is done on the packet's source address.\nIf a route to the source address exists, but not the default route\nor a blackhole/reject route, the packet matches.\nOtherwise, the packet does not match.\nAll outgoing packets match.\n.Pp\nThe name and functionality of the option is intentionally similar to\nthe Cisco IOS command:\n.Pp\n.Dl ip verify unicast source reachable-via any\n.Pp\nThis option can be used to make anti-spoofing rules to reject all\npackets whose source address is unreachable.\n.It Cm antispoof\nFor incoming packets, the packet's source address is checked if it\nbelongs to a directly connected network.\nIf the network is directly connected, then the interface the packet\ncame on in is compared to the interface the network is connected to.\nWhen incoming interface and directly connected interface are not the\nsame, the packet does not match.\nOtherwise, the packet does match.\nAll outgoing packets match.\n.Pp\nThis option can be used to make anti-spoofing rules to reject all\npackets that pretend to be from a directly connected network but do\nnot come in through that interface.\nThis option is similar to but more restricted than\n.Cm verrevpath\nbecause it engages only on packets with source addresses of directly\nconnected networks instead of all source addresses.\n.El\n.Sh LOOKUP TABLES\nLookup tables are useful to handle large sparse sets of\naddresses or other search keys (e.g., ports, jail IDs, interface names).\nIn the rest of this section we will use the term ``address''.\nThere may be up to 65535 different lookup tables, numbered 0 to 65534.\n.Pp\nEach entry is represented by an\n.Ar addr Ns Op / Ns Ar masklen\nand will match all addresses with base\n.Ar addr\n(specified as an IPv4/IPv6 address, a hostname or an unsigned integer)\nand mask width of\n.Ar masklen\nbits.\nIf\n.Ar masklen\nis not specified, it defaults to 32 for IPv4 and 128 for IPv6.\nWhen looking up an IP address in a table, the most specific\nentry will match.\nAssociated with each entry is a 32-bit unsigned\n.Ar value ,\nwhich can optionally be checked by a rule matching code.\nWhen adding an entry, if\n.Ar value\nis not specified, it defaults to 0.\n.Pp\nAn entry can be added to a table\n.Pq Cm add ,\nor removed from a table\n.Pq Cm delete .\nA table can be examined\n.Pq Cm list\nor flushed\n.Pq Cm flush .\n.Pp\nInternally, each table is stored in a Radix tree, the same way as\nthe routing table (see\n.Xr route 4 ) .\n.Pp\nLookup tables currently support only ports, jail IDs, IPv4/IPv6  addresses\nand interface names.\nWildcards is not supported for interface names.\n.Pp\nThe\n.Cm tablearg\nfeature provides the ability to use a value, looked up in the table, as\nthe argument for a rule action, action parameter or rule option.\nThis can significantly reduce number of rules in some configurations.\nIf two tables are used in a rule, the result of the second (destination)\nis used.\nThe\n.Cm tablearg\nargument can be used with the following actions:\n.Cm nat, pipe , queue, divert, tee, netgraph, ngtee, fwd, skipto, setfib,\naction parameters:\n.Cm tag, untag,\nrule options:\n.Cm limit, tagged.\n.Pp\nWhen used with\n.Cm fwd\nit is possible to supply table entries with values\nthat are in the form of IP addresses or hostnames.\nSee the\n.Sx EXAMPLES\nSection for example usage of tables and the tablearg keyword.\n.Pp\nWhen used with the\n.Cm skipto\naction, the user should be aware that the code will walk the ruleset\nup to a rule equal to, or past, the given number,\nand should therefore try keep the\nruleset compact between the skipto and the target rules.\n.Sh SETS OF RULES\nEach rule belongs to one of 32 different\n.Em sets\n, numbered 0 to 31.\nSet 31 is reserved for the default rule.\n.Pp\nBy default, rules are put in set 0, unless you use the\n.Cm set N\nattribute when entering a new rule.\nSets can be individually and atomically enabled or disabled,\nso this mechanism permits an easy way to store multiple configurations\nof the firewall and quickly (and atomically) switch between them.\nThe command to enable/disable sets is\n.Bd -ragged -offset indent\n.Nm\n.Cm set Oo Cm disable Ar number ... Oc Op Cm enable Ar number ...\n.Ed\n.Pp\nwhere multiple\n.Cm enable\nor\n.Cm disable\nsections can be specified.\nCommand execution is atomic on all the sets specified in the command.\nBy default, all sets are enabled.\n.Pp\nWhen you disable a set, its rules behave as if they do not exist\nin the firewall configuration, with only one exception:\n.Bd -ragged -offset indent\ndynamic rules created from a rule before it had been disabled\nwill still be active until they expire.\nIn order to delete\ndynamic rules you have to explicitly delete the parent rule\nwhich generated them.\n.Ed\n.Pp\nThe set number of rules can be changed with the command\n.Bd -ragged -offset indent\n.Nm\n.Cm set move\n.Brq Cm rule Ar rule-number | old-set\n.Cm to Ar new-set\n.Ed\n.Pp\nAlso, you can atomically swap two rulesets with the command\n.Bd -ragged -offset indent\n.Nm\n.Cm set swap Ar first-set second-set\n.Ed\n.Pp\nSee the\n.Sx EXAMPLES\nSection on some possible uses of sets of rules.\n.Sh STATEFUL FIREWALL\nStateful operation is a way for the firewall to dynamically\ncreate rules for specific flows when packets that\nmatch a given pattern are detected.\nSupport for stateful\noperation comes through the\n.Cm check-state , keep-state\nand\n.Cm limit\noptions of\n.Nm rules .\n.Pp\nDynamic rules are created when a packet matches a\n.Cm keep-state\nor\n.Cm limit\nrule, causing the creation of a\n.Em dynamic\nrule which will match all and only packets with\na given\n.Em protocol\nbetween a\n.Em src-ip/src-port dst-ip/dst-port\npair of addresses\n.Em ( src\nand\n.Em dst\nare used here only to denote the initial match addresses, but they\nare completely equivalent afterwards).\nDynamic rules will be checked at the first\n.Cm check-state, keep-state\nor\n.Cm limit\noccurrence, and the action performed upon a match will be the same\nas in the parent rule.\n.Pp\nNote that no additional attributes other than protocol and IP addresses\nand ports are checked on dynamic rules.\n.Pp\nThe typical use of dynamic rules is to keep a closed firewall configuration,\nbut let the first TCP SYN packet from the inside network install a\ndynamic rule for the flow so that packets belonging to that session\nwill be allowed through the firewall:\n.Pp\n.Dl \"ipfw add check-state\"\n.Dl \"ipfw add allow tcp from my-subnet to any setup keep-state\"\n.Dl \"ipfw add deny tcp from any to any\"\n.Pp\nA similar approach can be used for UDP, where an UDP packet coming\nfrom the inside will install a dynamic rule to let the response through\nthe firewall:\n.Pp\n.Dl \"ipfw add check-state\"\n.Dl \"ipfw add allow udp from my-subnet to any keep-state\"\n.Dl \"ipfw add deny udp from any to any\"\n.Pp\nDynamic rules expire after some time, which depends on the status\nof the flow and the setting of some\n.Cm sysctl\nvariables.\nSee Section\n.Sx SYSCTL VARIABLES\nfor more details.\nFor TCP sessions, dynamic rules can be instructed to periodically\nsend keepalive packets to refresh the state of the rule when it is\nabout to expire.\n.Pp\nSee Section\n.Sx EXAMPLES\nfor more examples on how to use dynamic rules.\n.Sh TRAFFIC SHAPER (DUMMYNET) CONFIGURATION\n.Nm\nis also the user interface for the\n.Nm dummynet\ntraffic shaper, packet scheduler and network emulator, a subsystem that\ncan artificially queue, delay or drop packets\nemulating the behaviour of certain network links\nor queueing systems.\n.Pp\n.Nm dummynet\noperates by first using the firewall to select packets\nusing any match pattern that can be used in\n.Nm\nrules.\nMatching packets are then passed to either of two\ndifferent objects, which implement the traffic regulation:\n.Bl -hang -offset XXXX\n.It Em pipe\nA\n.Em pipe\nemulates a\n.Em link\nwith given bandwidth and propagation delay,\ndriven by a FIFO scheduler and a single queue with programmable\nqueue size and packet loss rate.\nPackets are appended to the queue as they come out from\n.Nm ipfw ,\nand then transferred in FIFO order to the link at the desired rate.\n.It Em queue\nA\n.Em queue\nis an abstraction used to implement packet scheduling\nusing one of several packet scheduling algorithms.\nPackets sent to a\n.Em queue\nare first grouped into flows according to a mask on the 5-tuple.\nFlows are then passed to the scheduler associated to the\n.Em queue ,\nand each flow uses scheduling parameters (weight and others)\nas configured in the\n.Em queue\nitself.\nA scheduler in turn is connected to an emulated link,\nand arbitrates the link's bandwidth among backlogged flows according to\nweights and to the features of the scheduling algorithm in use.\n.El\n.Pp\nIn practice,\n.Em pipes\ncan be used to set hard limits to the bandwidth that a flow can use, whereas\n.Em queues\ncan be used to determine how different flows share the available bandwidth.\n.Pp\nA graphical representation of the binding of queues,\nflows, schedulers and links is below.\n.Bd -literal -offset indent\n                 (flow_mask|sched_mask)  sched_mask\n         +---------+   weight Wx  +-------------+\n         |         |->-[flow]-->--|             |-+\n    -->--| QUEUE x |   ...        |             | |\n         |         |->-[flow]-->--| SCHEDuler N | |\n         +---------+              |             | |\n             ...                  |             +--[LINK N]-->--\n         +---------+   weight Wy  |             | +--[LINK N]-->--\n         |         |->-[flow]-->--|             | |\n    -->--| QUEUE y |   ...        |             | |\n         |         |->-[flow]-->--|             | |\n         +---------+              +-------------+ |\n                                    +-------------+\n.Ed\nIt is important to understand the role of the SCHED_MASK\nand FLOW_MASK, which are configured through the commands\n.Dl \"ipfw sched N config mask SCHED_MASK ...\"\nand\n.Dl \"ipfw queue X config mask FLOW_MASK ...\" .\n.Pp\nThe SCHED_MASK is used to assign flows to one or more\nscheduler instances, one for each\nvalue of the packet's 5-tuple after applying SCHED_MASK.\nAs an example, using ``src-ip 0xffffff00'' creates one instance\nfor each /24 destination subnet.\n.Pp\nThe FLOW_MASK, together with the SCHED_MASK, is used to split\npackets into flows.\nAs an example, using\n``src-ip 0x000000ff''\ntogether with the previous SCHED_MASK makes a flow for\neach individual source address.\nIn turn, flows for each /24\nsubnet will be sent to the same scheduler instance.\n.Pp\nThe above diagram holds even for the\n.Em pipe\ncase, with the only restriction that a\n.Em pipe\nonly supports a SCHED_MASK, and forces the use of a FIFO\nscheduler (these are for backward compatibility reasons;\nin fact, internally, a\n.Nm dummynet's\npipe is implemented exactly as above).\n.Pp\nThere are two modes of\n.Nm dummynet\noperation:\n.Dq normal\nand\n.Dq fast .\nThe\n.Dq normal\nmode tries to emulate a real link: the\n.Nm dummynet\nscheduler ensures that the packet will not leave the pipe faster than it\nwould on the real link with a given bandwidth.\nThe\n.Dq fast\nmode allows certain packets to bypass the\n.Nm dummynet\nscheduler (if packet flow does not exceed pipe's bandwidth).\nThis is the reason why the\n.Dq fast\nmode requires less CPU cycles per packet (on average) and packet latency\ncan be significantly lower in comparison to a real link with the same\nbandwidth.\nThe default mode is\n.Dq normal .\nThe\n.Dq fast\nmode can be enabled by setting the\n.Va net.inet.ip.dummynet.io_fast\n.Xr sysctl 8\nvariable to a non-zero value.\n.Pp\n.Ss PIPE, QUEUE AND SCHEDULER CONFIGURATION\nThe\n.Em pipe ,\n.Em queue\nand\n.Em scheduler\nconfiguration commands are the following:\n.Bd -ragged -offset indent\n.Cm pipe Ar number Cm config Ar pipe-configuration\n.Pp\n.Cm queue Ar number Cm config Ar queue-configuration\n.Pp\n.Cm sched Ar number Cm config Ar sched-configuration\n.Ed\n.Pp\nThe following parameters can be configured for a pipe:\n.Pp\n.Bl -tag -width indent -compact\n.It Cm bw Ar bandwidth | device\nBandwidth, measured in\n.Sm off\n.Op Cm K | M\n.Brq Cm bit/s | Byte/s .\n.Sm on\n.Pp\nA value of 0 (default) means unlimited bandwidth.\nThe unit must immediately follow the number, as in\n.Pp\n.Dl \"ipfw pipe 1 config bw 300Kbit/s\"\n.Pp\nIf a device name is specified instead of a numeric value, as in\n.Pp\n.Dl \"ipfw pipe 1 config bw tun0\"\n.Pp\nthen the transmit clock is supplied by the specified device.\nAt the moment only the\n.Xr tun 4\ndevice supports this\nfunctionality, for use in conjunction with\n.Xr ppp 8 .\n.Pp\n.It Cm delay Ar ms-delay\nPropagation delay, measured in milliseconds.\nThe value is rounded to the next multiple of the clock tick\n(typically 10ms, but it is a good practice to run kernels\nwith\n.Dq \"options HZ=1000\"\nto reduce\nthe granularity to 1ms or less).\nThe default value is 0, meaning no delay.\n.Pp\n.It Cm burst Ar size\nIf the data to be sent exceeds the pipe's bandwidth limit\n(and the pipe was previously idle), up to\n.Ar size\nbytes of data are allowed to bypass the\n.Nm dummynet\nscheduler, and will be sent as fast as the physical link allows.\nAny additional data will be transmitted at the rate specified\nby the\n.Nm pipe\nbandwidth.\nThe burst size depends on how long the pipe has been idle;\nthe effective burst size is calculated as follows:\nMAX(\n.Ar size\n,\n.Nm bw\n* pipe_idle_time).\n.Pp\n.It Cm profile Ar filename\nA file specifying the additional overhead incurred in the transmission\nof a packet on the link.\n.Pp\nSome link types introduce extra delays in the transmission\nof a packet, e.g., because of MAC level framing, contention on\nthe use of the channel, MAC level retransmissions and so on.\nFrom our point of view, the channel is effectively unavailable\nfor this extra time, which is constant or variable depending\non the link type.\nAdditionally, packets may be dropped after this\ntime (e.g., on a wireless link after too many retransmissions).\nWe can model the additional delay with an empirical curve\nthat represents its distribution.\n.Bd -literal -offset indent\n      cumulative probability\n      1.0 ^\n          |\n      L   +-- loss-level          x\n          |                 ******\n          |                *\n          |           *****\n          |          *\n          |        **\n          |       *\n          +-------*------------------->\n                      delay\n.Ed\nThe empirical curve may have both vertical and horizontal lines.\nVertical lines represent constant delay for a range of\nprobabilities.\nHorizontal lines correspond to a discontinuity in the delay\ndistribution: the pipe will use the largest delay for a\ngiven probability.\n.Pp\nThe file format is the following, with whitespace acting as\na separator and '#' indicating the beginning a comment:\n.Bl -tag -width indent\n.It Cm name Ar identifier\noptional name (listed by \"ipfw pipe show\")\nto identify the delay distribution;\n.It Cm bw Ar value\nthe bandwidth used for the pipe.\nIf not specified here, it must be present\nexplicitly as a configuration parameter for the pipe;\n.It Cm loss-level Ar L\nthe probability above which packets are lost.\n(0.0 <= L <= 1.0, default 1.0 i.e., no loss);\n.It Cm samples Ar N\nthe number of samples used in the internal\nrepresentation of the curve (2..1024; default 100);\n.It Cm \"delay prob\" | \"prob delay\"\nOne of these two lines is mandatory and defines\nthe format of the following lines with data points.\n.It Ar XXX Ar YYY\n2 or more lines representing points in the curve,\nwith either delay or probability first, according\nto the chosen format.\nThe unit for delay is milliseconds.\nData points do not need to be sorted.\nAlso, the number of actual lines can be different\nfrom the value of the \"samples\" parameter:\n.Nm\nutility will sort and interpolate\nthe curve as needed.\n.El\n.Pp\nExample of a profile file:\n.Bd -literal -offset indent\nname    bla_bla_bla\nsamples 100\nloss-level    0.86\nprob    delay\n0       200\t# minimum overhead is 200ms\n0.5     200\n0.5     300\n0.8     1000\n0.9     1300\n1       1300\n#configuration file end\n.Ed\n.El\n.Pp\nThe following parameters can be configured for a queue:\n.Pp\n.Bl -tag -width indent -compact\n.It Cm pipe Ar pipe_nr\nConnects a queue to the specified pipe.\nMultiple queues (with the same or different weights) can be connected to\nthe same pipe, which specifies the aggregate rate for the set of queues.\n.Pp\n.It Cm weight Ar weight\nSpecifies the weight to be used for flows matching this queue.\nThe weight must be in the range 1..100, and defaults to 1.\n.El\n.Pp\nThe following case-insensitive parameters can be configured for a\nscheduler:\n.Pp\n.Bl -tag -width indent -compact\n.It Cm type Ar {fifo | wf2q+ | rr | qfq}\nspecifies the scheduling algorithm to use.\n.Bl -tag -width indent -compact\n.It Cm fifo\nis just a FIFO scheduler (which means that all packets\nare stored in the same queue as they arrive to the scheduler).\nFIFO has O(1) per-packet time complexity, with very low\nconstants (estimate 60-80ns on a 2GHz desktop machine)\nbut gives no service guarantees.\n.It Cm wf2q+\nimplements the WF2Q+ algorithm, which is a Weighted Fair Queueing\nalgorithm which permits flows to share bandwidth according to\ntheir weights.\nNote that weights are not priorities; even a flow\nwith a minuscule weight will never starve.\nWF2Q+ has O(log N) per-packet processing cost, where N is the number\nof flows, and is the default algorithm used by previous versions\ndummynet's queues.\n.It Cm rr\nimplements the Deficit Round Robin algorithm, which has O(1) processing\ncosts (roughly, 100-150ns per packet)\nand permits bandwidth allocation according to weights, but\nwith poor service guarantees.\n.It Cm qfq\nimplements the QFQ algorithm, which is a very fast variant of\nWF2Q+, with similar service guarantees and O(1) processing\ncosts (roughly, 200-250ns per packet).\n.El\n.El\n.Pp\nIn addition to the type, all parameters allowed for a pipe can also\nbe specified for a scheduler.\n.Pp\nFinally, the following parameters can be configured for both\npipes and queues:\n.Pp\n.Bl -tag -width XXXX -compact\n.It Cm buckets Ar hash-table-size\nSpecifies the size of the hash table used for storing the\nvarious queues.\nDefault value is 64 controlled by the\n.Xr sysctl 8\nvariable\n.Va net.inet.ip.dummynet.hash_size ,\nallowed range is 16 to 65536.\n.Pp\n.It Cm mask Ar mask-specifier\nPackets sent to a given pipe or queue by an\n.Nm\nrule can be further classified into multiple flows, each of which is then\nsent to a different\n.Em dynamic\npipe or queue.\nA flow identifier is constructed by masking the IP addresses,\nports and protocol types as specified with the\n.Cm mask\noptions in the configuration of the pipe or queue.\nFor each different flow identifier, a new pipe or queue is created\nwith the same parameters as the original object, and matching packets\nare sent to it.\n.Pp\nThus, when\n.Em dynamic pipes\nare used, each flow will get the same bandwidth as defined by the pipe,\nwhereas when\n.Em dynamic queues\nare used, each flow will share the parent's pipe bandwidth evenly\nwith other flows generated by the same queue (note that other queues\nwith different weights might be connected to the same pipe).\n.br\nAvailable mask specifiers are a combination of one or more of the following:\n.Pp\n.Cm dst-ip Ar mask ,\n.Cm dst-ip6 Ar mask ,\n.Cm src-ip Ar mask ,\n.Cm src-ip6 Ar mask ,\n.Cm dst-port Ar mask ,\n.Cm src-port Ar mask ,\n.Cm flow-id Ar mask ,\n.Cm proto Ar mask\nor\n.Cm all ,\n.Pp\nwhere the latter means all bits in all fields are significant.\n.Pp\n.It Cm noerror\nWhen a packet is dropped by a\n.Nm dummynet\nqueue or pipe, the error\nis normally reported to the caller routine in the kernel, in the\nsame way as it happens when a device queue fills up.\nSetting this\noption reports the packet as successfully delivered, which can be\nneeded for some experimental setups where you want to simulate\nloss or congestion at a remote router.\n.Pp\n.It Cm plr Ar packet-loss-rate\nPacket loss rate.\nArgument\n.Ar packet-loss-rate\nis a floating-point number between 0 and 1, with 0 meaning no\nloss, 1 meaning 100% loss.\nThe loss rate is internally represented on 31 bits.\n.Pp\n.It Cm queue Brq Ar slots | size Ns Cm Kbytes\nQueue size, in\n.Ar slots\nor\n.Cm KBytes .\nDefault value is 50 slots, which\nis the typical queue size for Ethernet devices.\nNote that for slow speed links you should keep the queue\nsize short or your traffic might be affected by a significant\nqueueing delay.\nE.g., 50 max-sized ethernet packets (1500 bytes) mean 600Kbit\nor 20s of queue on a 30Kbit/s pipe.\nEven worse effects can result if you get packets from an\ninterface with a much larger MTU, e.g.\\& the loopback interface\nwith its 16KB packets.\nThe\n.Xr sysctl 8\nvariables\n.Em net.inet.ip.dummynet.pipe_byte_limit\nand\n.Em net.inet.ip.dummynet.pipe_slot_limit\ncontrol the maximum lengths that can be specified.\n.Pp\n.It Cm red | gred Ar w_q Ns / Ns Ar min_th Ns / Ns Ar max_th Ns / Ns Ar max_p\nMake use of the RED (Random Early Detection) queue management algorithm.\n.Ar w_q\nand\n.Ar max_p\nare floating\npoint numbers between 0 and 1 (0 not included), while\n.Ar min_th\nand\n.Ar max_th\nare integer numbers specifying thresholds for queue management\n(thresholds are computed in bytes if the queue has been defined\nin bytes, in slots otherwise).\nThe\n.Nm dummynet\nalso supports the gentle RED variant (gred).\nThree\n.Xr sysctl 8\nvariables can be used to control the RED behaviour:\n.Bl -tag -width indent\n.It Va net.inet.ip.dummynet.red_lookup_depth\nspecifies the accuracy in computing the average queue\nwhen the link is idle (defaults to 256, must be greater than zero)\n.It Va net.inet.ip.dummynet.red_avg_pkt_size\nspecifies the expected average packet size (defaults to 512, must be\ngreater than zero)\n.It Va net.inet.ip.dummynet.red_max_pkt_size\nspecifies the expected maximum packet size, only used when queue\nthresholds are in bytes (defaults to 1500, must be greater than zero).\n.El\n.El\n.Pp\nWhen used with IPv6 data,\n.Nm dummynet\ncurrently has several limitations.\nInformation necessary to route link-local packets to an\ninterface is not available after processing by\n.Nm dummynet\nso those packets are dropped in the output path.\nCare should be taken to ensure that link-local packets are not passed to\n.Nm dummynet .\n.Sh CHECKLIST\nHere are some important points to consider when designing your\nrules:\n.Bl -bullet\n.It\nRemember that you filter both packets going\n.Cm in\nand\n.Cm out .\nMost connections need packets going in both directions.\n.It\nRemember to test very carefully.\nIt is a good idea to be near the console when doing this.\nIf you cannot be near the console,\nuse an auto-recovery script such as the one in\n.Pa /usr/share/examples/ipfw/change_rules.sh .\n.It\nDo not forget the loopback interface.\n.El\n.Sh FINE POINTS\n.Bl -bullet\n.It\nThere are circumstances where fragmented datagrams are unconditionally\ndropped.\nTCP packets are dropped if they do not contain at least 20 bytes of\nTCP header, UDP packets are dropped if they do not contain a full 8\nbyte UDP header, and ICMP packets are dropped if they do not contain\n4 bytes of ICMP header, enough to specify the ICMP type, code, and\nchecksum.\nThese packets are simply logged as\n.Dq pullup failed\nsince there may not be enough good data in the packet to produce a\nmeaningful log entry.\n.It\nAnother type of packet is unconditionally dropped, a TCP packet with a\nfragment offset of one.\nThis is a valid packet, but it only has one use, to try\nto circumvent firewalls.\nWhen logging is enabled, these packets are\nreported as being dropped by rule -1.\n.It\nIf you are logged in over a network, loading the\n.Xr kld 4\nversion of\n.Nm\nis probably not as straightforward as you would think.\nThe following command line is recommended:\n.Bd -literal -offset indent\nkldload ipfw && \\e\nipfw add 32000 allow ip from any to any\n.Ed\n.Pp\nAlong the same lines, doing an\n.Bd -literal -offset indent\nipfw flush\n.Ed\n.Pp\nin similar surroundings is also a bad idea.\n.It\nThe\n.Nm\nfilter list may not be modified if the system security level\nis set to 3 or higher\n(see\n.Xr init 8\nfor information on system security levels).\n.El\n.Sh PACKET DIVERSION\nA\n.Xr divert 4\nsocket bound to the specified port will receive all packets\ndiverted to that port.\nIf no socket is bound to the destination port, or if the divert module is\nnot loaded, or if the kernel was not compiled with divert socket support,\nthe packets are dropped.\n.Sh NETWORK ADDRESS TRANSLATION (NAT)\n.Nm\nsupport in-kernel NAT using the kernel version of\n.Xr libalias 3 .\n.Pp\nThe nat configuration command is the following:\n.Bd -ragged -offset indent\n.Bk -words\n.Cm nat\n.Ar nat_number\n.Cm config\n.Ar nat-configuration\n.Ek\n.Ed\n.Pp\nThe following parameters can be configured:\n.Bl -tag -width indent\n.It Cm ip Ar ip_address\nDefine an ip address to use for aliasing.\n.It Cm if Ar nic\nUse ip address of NIC for aliasing, dynamically changing\nit if NIC's ip address changes.\n.It Cm log\nEnable logging on this nat instance.\n.It Cm deny_in\nDeny any incoming connection from outside world.\n.It Cm same_ports\nTry to leave the alias port numbers unchanged from\nthe actual local port numbers.\n.It Cm unreg_only\nTraffic on the local network not originating from an\nunregistered address spaces will be ignored.\n.It Cm reset\nReset table of the packet aliasing engine on address change.\n.It Cm reverse\nReverse the way libalias handles aliasing.\n.It Cm proxy_only\nObey transparent proxy rules only, packet aliasing is not performed.\n.It Cm skip_global\nSkip instance in case of global state lookup (see below).\n.El\n.Pp\nSome specials value can be supplied instead of\n.Va nat_number:\n.Bl -tag -width indent\n.It Cm global\nLooks up translation state in all configured nat instances.\nIf an entry is found, packet is aliased according to that entry.\nIf no entry was found in any of the instances, packet is passed unchanged,\nand no new entry will be created.\nSee section\n.Sx MULTIPLE INSTANCES\nin\n.Xr natd 8\nfor more information.\n.It Cm tablearg\nUses argument supplied in lookup table.\nSee\n.Sx LOOKUP TABLES\nsection below for more information on lookup tables.\n.El\n.Pp\nTo let the packet continue after being (de)aliased, set the sysctl variable\n.Va net.inet.ip.fw.one_pass\nto 0.\nFor more information about aliasing modes, refer to\n.Xr libalias 3 .\nSee Section\n.Sx EXAMPLES\nfor some examples about nat usage.\n.Ss REDIRECT AND LSNAT SUPPORT IN IPFW\nRedirect and LSNAT support follow closely the syntax used in\n.Xr natd 8 .\nSee Section\n.Sx EXAMPLES\nfor some examples on how to do redirect and lsnat.\n.Ss SCTP NAT SUPPORT\nSCTP nat can be configured in a similar manner to TCP through the\n.Nm\ncommand line tool.\nThe main difference is that\n.Nm sctp nat\ndoes not do port translation.\nSince the local and global side ports will be the same,\nthere is no need to specify both.\nPorts are redirected as follows:\n.Bd -ragged -offset indent\n.Bk -words\n.Cm nat\n.Ar nat_number\n.Cm config if\n.Ar nic\n.Cm redirect_port sctp\n.Ar ip_address [,addr_list] {[port | port-port] [,ports]}\n.Ek\n.Ed\n.Pp\nMost\n.Nm sctp nat\nconfiguration can be done in real-time through the\n.Xr sysctl 8\ninterface.\nAll may be changed dynamically, though the hash_table size will only\nchange for new\n.Nm nat\ninstances.\nSee\n.Sx SYSCTL VARIABLES\nfor more info.\n.Sh LOADER TUNABLES\nTunables can be set in\n.Xr loader 8\nprompt,\n.Xr loader.conf 5\nor\n.Xr kenv 1\nbefore ipfw module gets loaded.\n.Bl -tag -width indent\n.It Va net.inet.ip.fw.default_to_accept: No 0\nDefines ipfw last rule behavior.\nThis value overrides\n.Cd \"options IPFW_DEFAULT_TO_(ACCEPT|DENY)\"\nfrom kernel configuration file.\n.It Va net.inet.ip.fw.tables_max: No 128\nDefines number of tables available in ipfw.\nNumber cannot exceed 65534.\n.El\n.Sh SYSCTL VARIABLES\nA set of\n.Xr sysctl 8\nvariables controls the behaviour of the firewall and\nassociated modules\n.Pq Nm dummynet , bridge , sctp nat .\nThese are shown below together with their default value\n(but always check with the\n.Xr sysctl 8\ncommand what value is actually in use) and meaning:\n.Bl -tag -width indent\n.It Va net.inet.ip.alias.sctp.accept_global_ootb_addip: No 0\nDefines how the\n.Nm nat\nresponds to receipt of global OOTB ASCONF-AddIP:\n.Bl -tag -width indent\n.It Cm 0\nNo response (unless a partially matching association exists -\nports and vtags match but global address does not)\n.It Cm 1\n.Nm nat\nwill accept and process all OOTB global AddIP messages.\n.El\n.Pp\nOption 1 should never be selected as this forms a security risk.\nAn attacker can\nestablish multiple fake associations by sending AddIP messages.\n.It Va net.inet.ip.alias.sctp.chunk_proc_limit: No 5\nDefines the maximum number of chunks in an SCTP packet that will be\nparsed for a\npacket that matches an existing association.\nThis value is enforced to be greater or equal than\n.Cm net.inet.ip.alias.sctp.initialising_chunk_proc_limit .\nA high value is\na DoS risk yet setting too low a value may result in\nimportant control chunks in\nthe packet not being located and parsed.\n.It Va net.inet.ip.alias.sctp.error_on_ootb: No 1\nDefines when the\n.Nm nat\nresponds to any Out-of-the-Blue (OOTB) packets with ErrorM packets.\nAn OOTB packet is a packet that arrives with no existing association\nregistered in the\n.Nm nat\nand is not an INIT or ASCONF-AddIP packet:\n.Bl -tag -width indent\n.It Cm 0\nErrorM is never sent in response to OOTB packets.\n.It Cm 1\nErrorM is only sent to OOTB packets received on the local side.\n.It Cm 2\nErrorM is sent to the local side and on the global side ONLY if there is a\npartial match (ports and vtags match but the source global IP does not).\nThis value is only useful if the\n.Nm nat\nis tracking global IP addresses.\n.It Cm 3\nErrorM is sent in response to all OOTB packets on both\nthe local and global side\n(DoS risk).\n.El\n.Pp\nAt the moment the default is 0, since the ErrorM packet is not yet\nsupported by most SCTP stacks.\nWhen it is supported, and if not tracking\nglobal addresses, we recommend setting this value to 1 to allow\nmulti-homed local hosts to function with the\n.Nm nat .\nTo track global addresses, we recommend setting this value to 2 to\nallow global hosts to be informed when they need to (re)send an\nASCONF-AddIP.\nValue 3 should never be chosen (except for debugging) as the\n.Nm nat\nwill respond to all OOTB global packets (a DoS risk).\n.It Va net.inet.ip.alias.sctp.hashtable_size: No 2003\nSize of hash tables used for\n.Nm nat\nlookups (100 < prime_number > 1000001).\nThis value sets the\n.Nm hash table\nsize for any future created\n.Nm nat\ninstance and therefore must be set prior to creating a\n.Nm nat\ninstance.\nThe table sizes may be changed to suit specific needs.\nIf there will be few\nconcurrent associations, and memory is scarce, you may make these smaller.\nIf there will be many thousands (or millions) of concurrent associations, you\nshould make these larger.\nA prime number is best for the table size.\nThe sysctl\nupdate function will adjust your input value to the next highest prime number.\n.It Va net.inet.ip.alias.sctp.holddown_time:  No 0\nHold association in table for this many seconds after receiving a\nSHUTDOWN-COMPLETE.\nThis allows endpoints to correct shutdown gracefully if a\nshutdown_complete is lost and retransmissions are required.\n.It Va net.inet.ip.alias.sctp.init_timer: No 15\nTimeout value while waiting for (INIT-ACK|AddIP-ACK).\nThis value cannot be 0.\n.It Va net.inet.ip.alias.sctp.initialising_chunk_proc_limit: No 2\nDefines the maximum number of chunks in an SCTP packet that will be parsed when\nno existing association exists that matches that packet.\nIdeally this packet\nwill only be an INIT or ASCONF-AddIP packet.\nA higher value may become a DoS\nrisk as malformed packets can consume processing resources.\n.It Va net.inet.ip.alias.sctp.param_proc_limit: No 25\nDefines the maximum number of parameters within a chunk that will be\nparsed in a\npacket.\nAs for other similar sysctl variables, larger values pose a DoS risk.\n.It Va net.inet.ip.alias.sctp.log_level: No 0\nLevel of detail in the system log messages (0 \\- minimal, 1 \\- event,\n2 \\- info, 3 \\- detail, 4 \\- debug, 5 \\- max debug).\nMay be a good\noption in high loss environments.\n.It Va net.inet.ip.alias.sctp.shutdown_time: No 15\nTimeout value while waiting for SHUTDOWN-COMPLETE.\nThis value cannot be 0.\n.It Va net.inet.ip.alias.sctp.track_global_addresses: No 0\nEnables/disables global IP address tracking within the\n.Nm nat\nand places an\nupper limit on the number of addresses tracked for each association:\n.Bl -tag -width indent\n.It Cm 0\nGlobal tracking is disabled\n.It Cm >1\nEnables tracking, the maximum number of addresses tracked for each\nassociation is limited to this value\n.El\n.Pp\nThis variable is fully dynamic, the new value will be adopted for all newly\narriving associations, existing associations are treated\nas they were previously.\nGlobal tracking will decrease the number of collisions within the\n.Nm nat\nat a cost\nof increased processing load, memory usage, complexity, and possible\n.Nm nat\nstate\nproblems in complex networks with multiple\n.Nm nats .\nWe recommend not tracking\nglobal IP addresses, this will still result in a fully functional\n.Nm nat .\n.It Va net.inet.ip.alias.sctp.up_timer: No 300\nTimeout value to keep an association up with no traffic.\nThis value cannot be 0.\n.It Va net.inet.ip.dummynet.expire : No 1\nLazily delete dynamic pipes/queue once they have no pending traffic.\nYou can disable this by setting the variable to 0, in which case\nthe pipes/queues will only be deleted when the threshold is reached.\n.It Va net.inet.ip.dummynet.hash_size : No 64\nDefault size of the hash table used for dynamic pipes/queues.\nThis value is used when no\n.Cm buckets\noption is specified when configuring a pipe/queue.\n.It Va net.inet.ip.dummynet.io_fast : No 0\nIf set to a non-zero value,\nthe\n.Dq fast\nmode of\n.Nm dummynet\noperation (see above) is enabled.\n.It Va net.inet.ip.dummynet.io_pkt\nNumber of packets passed to\n.Nm dummynet .\n.It Va net.inet.ip.dummynet.io_pkt_drop\nNumber of packets dropped by\n.Nm dummynet .\n.It Va net.inet.ip.dummynet.io_pkt_fast\nNumber of packets bypassed by the\n.Nm dummynet\nscheduler.\n.It Va net.inet.ip.dummynet.max_chain_len : No 16\nTarget value for the maximum number of pipes/queues in a hash bucket.\nThe product\n.Cm max_chain_len*hash_size\nis used to determine the threshold over which empty pipes/queues\nwill be expired even when\n.Cm net.inet.ip.dummynet.expire=0 .\n.It Va net.inet.ip.dummynet.red_lookup_depth : No 256\n.It Va net.inet.ip.dummynet.red_avg_pkt_size : No 512\n.It Va net.inet.ip.dummynet.red_max_pkt_size : No 1500\nParameters used in the computations of the drop probability\nfor the RED algorithm.\n.It Va net.inet.ip.dummynet.pipe_byte_limit : No 1048576\n.It Va net.inet.ip.dummynet.pipe_slot_limit : No 100\nThe maximum queue size that can be specified in bytes or packets.\nThese limits prevent accidental exhaustion of resources such as mbufs.\nIf you raise these limits,\nyou should make sure the system is configured so that sufficient resources\nare available.\n.It Va net.inet.ip.fw.autoinc_step : No 100\nDelta between rule numbers when auto-generating them.\nThe value must be in the range 1..1000.\n.It Va net.inet.ip.fw.curr_dyn_buckets : Va net.inet.ip.fw.dyn_buckets\nThe current number of buckets in the hash table for dynamic rules\n(readonly).\n.It Va net.inet.ip.fw.debug : No 1\nControls debugging messages produced by\n.Nm .\n.It Va net.inet.ip.fw.default_rule : No 65535\nThe default rule number (read-only).\nBy the design of\n.Nm , the default rule is the last one, so its number\ncan also serve as the highest number allowed for a rule.\n.It Va net.inet.ip.fw.dyn_buckets : No 256\nThe number of buckets in the hash table for dynamic rules.\nMust be a power of 2, up to 65536.\nIt only takes effect when all dynamic rules have expired, so you\nare advised to use a\n.Cm flush\ncommand to make sure that the hash table is resized.\n.It Va net.inet.ip.fw.dyn_count : No 3\nCurrent number of dynamic rules\n(read-only).\n.It Va net.inet.ip.fw.dyn_keepalive : No 1\nEnables generation of keepalive packets for\n.Cm keep-state\nrules on TCP sessions.\nA keepalive is generated to both\nsides of the connection every 5 seconds for the last 20\nseconds of the lifetime of the rule.\n.It Va net.inet.ip.fw.dyn_max : No 8192\nMaximum number of dynamic rules.\nWhen you hit this limit, no more dynamic rules can be\ninstalled until old ones expire.\n.It Va net.inet.ip.fw.dyn_ack_lifetime : No 300\n.It Va net.inet.ip.fw.dyn_syn_lifetime : No 20\n.It Va net.inet.ip.fw.dyn_fin_lifetime : No 1\n.It Va net.inet.ip.fw.dyn_rst_lifetime : No 1\n.It Va net.inet.ip.fw.dyn_udp_lifetime : No 5\n.It Va net.inet.ip.fw.dyn_short_lifetime : No 30\nThese variables control the lifetime, in seconds, of dynamic\nrules.\nUpon the initial SYN exchange the lifetime is kept short,\nthen increased after both SYN have been seen, then decreased\nagain during the final FIN exchange or when a RST is received.\nBoth\n.Em dyn_fin_lifetime\nand\n.Em dyn_rst_lifetime\nmust be strictly lower than 5 seconds, the period of\nrepetition of keepalives.\nThe firewall enforces that.\n.It Va net.inet.ip.fw.dyn_keep_states: No 0\nKeep dynamic states on rule/set deletion.\nStates are relinked to default rule (65535).\nThis can be handly for ruleset reload.\nTurned off by default.\n.It Va net.inet.ip.fw.enable : No 1\nEnables the firewall.\nSetting this variable to 0 lets you run your machine without\nfirewall even if compiled in.\n.It Va net.inet6.ip6.fw.enable : No 1\nprovides the same functionality as above for the IPv6 case.\n.It Va net.inet.ip.fw.one_pass : No 1\nWhen set, the packet exiting from the\n.Nm dummynet\npipe or from\n.Xr ng_ipfw 4\nnode is not passed though the firewall again.\nOtherwise, after an action, the packet is\nreinjected into the firewall at the next rule.\n.It Va net.inet.ip.fw.tables_max : No 128\nMaximum number of tables.\n.It Va net.inet.ip.fw.verbose : No 1\nEnables verbose messages.\n.It Va net.inet.ip.fw.verbose_limit : No 0\nLimits the number of messages produced by a verbose firewall.\n.It Va net.inet6.ip6.fw.deny_unknown_exthdrs : No 1\nIf enabled packets with unknown IPv6 Extension Headers will be denied.\n.It Va net.link.ether.ipfw : No 0\nControls whether layer-2 packets are passed to\n.Nm .\nDefault is no.\n.It Va net.link.bridge.ipfw : No 0\nControls whether bridged packets are passed to\n.Nm .\nDefault is no.\n.El\n.Sh EXAMPLES\nThere are far too many possible uses of\n.Nm\nso this Section will only give a small set of examples.\n.Pp\n.Ss BASIC PACKET FILTERING\nThis command adds an entry which denies all tcp packets from\n.Em cracker.evil.org\nto the telnet port of\n.Em wolf.tambov.su\nfrom being forwarded by the host:\n.Pp\n.Dl \"ipfw add deny tcp from cracker.evil.org to wolf.tambov.su telnet\"\n.Pp\nThis one disallows any connection from the entire cracker's\nnetwork to my host:\n.Pp\n.Dl \"ipfw add deny ip from 123.45.67.0/24 to my.host.org\"\n.Pp\nA first and efficient way to limit access (not using dynamic rules)\nis the use of the following rules:\n.Pp\n.Dl \"ipfw add allow tcp from any to any established\"\n.Dl \"ipfw add allow tcp from net1 portlist1 to net2 portlist2 setup\"\n.Dl \"ipfw add allow tcp from net3 portlist3 to net3 portlist3 setup\"\n.Dl \"...\"\n.Dl \"ipfw add deny tcp from any to any\"\n.Pp\nThe first rule will be a quick match for normal TCP packets,\nbut it will not match the initial SYN packet, which will be\nmatched by the\n.Cm setup\nrules only for selected source/destination pairs.\nAll other SYN packets will be rejected by the final\n.Cm deny\nrule.\n.Pp\nIf you administer one or more subnets, you can take advantage\nof the address sets and or-blocks and write extremely\ncompact rulesets which selectively enable services to blocks\nof clients, as below:\n.Pp\n.Dl \"goodguys=\\*q{ 10.1.2.0/24{20,35,66,18} or 10.2.3.0/28{6,3,11} }\\*q\"\n.Dl \"badguys=\\*q10.1.2.0/24{8,38,60}\\*q\"\n.Dl \"\"\n.Dl \"ipfw add allow ip from ${goodguys} to any\"\n.Dl \"ipfw add deny ip from ${badguys} to any\"\n.Dl \"... normal policies ...\"\n.Pp\nThe\n.Cm verrevpath\noption could be used to do automated anti-spoofing by adding the\nfollowing to the top of a ruleset:\n.Pp\n.Dl \"ipfw add deny ip from any to any not verrevpath in\"\n.Pp\nThis rule drops all incoming packets that appear to be coming to the\nsystem on the wrong interface.\nFor example, a packet with a source\naddress belonging to a host on a protected internal network would be\ndropped if it tried to enter the system from an external interface.\n.Pp\nThe\n.Cm antispoof\noption could be used to do similar but more restricted anti-spoofing\nby adding the following to the top of a ruleset:\n.Pp\n.Dl \"ipfw add deny ip from any to any not antispoof in\"\n.Pp\nThis rule drops all incoming packets that appear to be coming from another\ndirectly connected system but on the wrong interface.\nFor example, a packet with a source address of\n.Li 192.168.0.0/24 ,\nconfigured on\n.Li fxp0 ,\nbut coming in on\n.Li fxp1\nwould be dropped.\n.Pp\nThe\n.Cm setdscp\noption could be used to (re)mark user traffic,\nby adding the following to the appropriate place in ruleset:\n.Pp\n.Dl \"ipfw add setdscp be ip from any to any dscp af11,af21\"\n.Ss DYNAMIC RULES\nIn order to protect a site from flood attacks involving fake\nTCP packets, it is safer to use dynamic rules:\n.Pp\n.Dl \"ipfw add check-state\"\n.Dl \"ipfw add deny tcp from any to any established\"\n.Dl \"ipfw add allow tcp from my-net to any setup keep-state\"\n.Pp\nThis will let the firewall install dynamic rules only for\nthose connection which start with a regular SYN packet coming\nfrom the inside of our network.\nDynamic rules are checked when encountering the first\noccurrence of a\n.Cm check-state ,\n.Cm keep-state\nor\n.Cm limit\nrule.\nA\n.Cm check-state\nrule should usually be placed near the beginning of the\nruleset to minimize the amount of work scanning the ruleset.\nYour mileage may vary.\n.Pp\nTo limit the number of connections a user can open\nyou can use the following type of rules:\n.Pp\n.Dl \"ipfw add allow tcp from my-net/24 to any setup limit src-addr 10\"\n.Dl \"ipfw add allow tcp from any to me setup limit src-addr 4\"\n.Pp\nThe former (assuming it runs on a gateway) will allow each host\non a /24 network to open at most 10 TCP connections.\nThe latter can be placed on a server to make sure that a single\nclient does not use more than 4 simultaneous connections.\n.Pp\n.Em BEWARE :\nstateful rules can be subject to denial-of-service attacks\nby a SYN-flood which opens a huge number of dynamic rules.\nThe effects of such attacks can be partially limited by\nacting on a set of\n.Xr sysctl 8\nvariables which control the operation of the firewall.\n.Pp\nHere is a good usage of the\n.Cm list\ncommand to see accounting records and timestamp information:\n.Pp\n.Dl ipfw -at list\n.Pp\nor in short form without timestamps:\n.Pp\n.Dl ipfw -a list\n.Pp\nwhich is equivalent to:\n.Pp\n.Dl ipfw show\n.Pp\nNext rule diverts all incoming packets from 192.168.2.0/24\nto divert port 5000:\n.Pp\n.Dl ipfw divert 5000 ip from 192.168.2.0/24 to any in\n.Ss TRAFFIC SHAPING\nThe following rules show some of the applications of\n.Nm\nand\n.Nm dummynet\nfor simulations and the like.\n.Pp\nThis rule drops random incoming packets with a probability\nof 5%:\n.Pp\n.Dl \"ipfw add prob 0.05 deny ip from any to any in\"\n.Pp\nA similar effect can be achieved making use of\n.Nm dummynet\npipes:\n.Pp\n.Dl \"ipfw add pipe 10 ip from any to any\"\n.Dl \"ipfw pipe 10 config plr 0.05\"\n.Pp\nWe can use pipes to artificially limit bandwidth, e.g.\\& on a\nmachine acting as a router, if we want to limit traffic from\nlocal clients on 192.168.2.0/24 we do:\n.Pp\n.Dl \"ipfw add pipe 1 ip from 192.168.2.0/24 to any out\"\n.Dl \"ipfw pipe 1 config bw 300Kbit/s queue 50KBytes\"\n.Pp\nnote that we use the\n.Cm out\nmodifier so that the rule is not used twice.\nRemember in fact that\n.Nm\nrules are checked both on incoming and outgoing packets.\n.Pp\nShould we want to simulate a bidirectional link with bandwidth\nlimitations, the correct way is the following:\n.Pp\n.Dl \"ipfw add pipe 1 ip from any to any out\"\n.Dl \"ipfw add pipe 2 ip from any to any in\"\n.Dl \"ipfw pipe 1 config bw 64Kbit/s queue 10Kbytes\"\n.Dl \"ipfw pipe 2 config bw 64Kbit/s queue 10Kbytes\"\n.Pp\nThe above can be very useful, e.g.\\& if you want to see how\nyour fancy Web page will look for a residential user who\nis connected only through a slow link.\nYou should not use only one pipe for both directions, unless\nyou want to simulate a half-duplex medium (e.g.\\& AppleTalk,\nEthernet, IRDA).\nIt is not necessary that both pipes have the same configuration,\nso we can also simulate asymmetric links.\n.Pp\nShould we want to verify network performance with the RED queue\nmanagement algorithm:\n.Pp\n.Dl \"ipfw add pipe 1 ip from any to any\"\n.Dl \"ipfw pipe 1 config bw 500Kbit/s queue 100 red 0.002/30/80/0.1\"\n.Pp\nAnother typical application of the traffic shaper is to\nintroduce some delay in the communication.\nThis can significantly affect applications which do a lot of Remote\nProcedure Calls, and where the round-trip-time of the\nconnection often becomes a limiting factor much more than\nbandwidth:\n.Pp\n.Dl \"ipfw add pipe 1 ip from any to any out\"\n.Dl \"ipfw add pipe 2 ip from any to any in\"\n.Dl \"ipfw pipe 1 config delay 250ms bw 1Mbit/s\"\n.Dl \"ipfw pipe 2 config delay 250ms bw 1Mbit/s\"\n.Pp\nPer-flow queueing can be useful for a variety of purposes.\nA very simple one is counting traffic:\n.Pp\n.Dl \"ipfw add pipe 1 tcp from any to any\"\n.Dl \"ipfw add pipe 1 udp from any to any\"\n.Dl \"ipfw add pipe 1 ip from any to any\"\n.Dl \"ipfw pipe 1 config mask all\"\n.Pp\nThe above set of rules will create queues (and collect\nstatistics) for all traffic.\nBecause the pipes have no limitations, the only effect is\ncollecting statistics.\nNote that we need 3 rules, not just the last one, because\nwhen\n.Nm\ntries to match IP packets it will not consider ports, so we\nwould not see connections on separate ports as different\nones.\n.Pp\nA more sophisticated example is limiting the outbound traffic\non a net with per-host limits, rather than per-network limits:\n.Pp\n.Dl \"ipfw add pipe 1 ip from 192.168.2.0/24 to any out\"\n.Dl \"ipfw add pipe 2 ip from any to 192.168.2.0/24 in\"\n.Dl \"ipfw pipe 1 config mask src-ip 0x000000ff bw 200Kbit/s queue 20Kbytes\"\n.Dl \"ipfw pipe 2 config mask dst-ip 0x000000ff bw 200Kbit/s queue 20Kbytes\"\n.Ss LOOKUP TABLES\nIn the following example, we need to create several traffic bandwidth\nclasses and we need different hosts/networks to fall into different classes.\nWe create one pipe for each class and configure them accordingly.\nThen we create a single table and fill it with IP subnets and addresses.\nFor each subnet/host we set the argument equal to the number of the pipe\nthat it should use.\nThen we classify traffic using a single rule:\n.Pp\n.Dl \"ipfw pipe 1 config bw 1000Kbyte/s\"\n.Dl \"ipfw pipe 4 config bw 4000Kbyte/s\"\n.Dl \"...\"\n.Dl \"ipfw table 1 add 192.168.2.0/24 1\"\n.Dl \"ipfw table 1 add 192.168.0.0/27 4\"\n.Dl \"ipfw table 1 add 192.168.0.2 1\"\n.Dl \"...\"\n.Dl \"ipfw add pipe tablearg ip from table(1) to any\"\n.Pp\nUsing the\n.Cm fwd\naction, the table entries may include hostnames and IP addresses.\n.Pp\n.Dl \"ipfw table 1 add 192.168.2.0/24 10.23.2.1\"\n.Dl \"ipfw table 1 add 192.168.0.0/27 router1.dmz\"\n.Dl \"...\"\n.Dl \"ipfw add 100 fwd tablearg ip from any to table(1)\"\n.Pp\nIn the following example per-interface firewall is created:\n.Pp\n.Dl \"ipfw table 10 add vlan20 12000\"\n.Dl \"ipfw table 10 add vlan30 13000\"\n.Dl \"ipfw table 20 add vlan20 22000\"\n.Dl \"ipfw table 20 add vlan30 23000\"\n.Dl \"..\"\n.Dl \"ipfw add 100 ipfw skipto tablearg ip from any to any recv 'table(10)' in\"\n.Dl \"ipfw add 200 ipfw skipto tablearg ip from any to any xmit 'table(10)' out\"\n.Ss SETS OF RULES\nTo add a set of rules atomically, e.g.\\& set 18:\n.Pp\n.Dl \"ipfw set disable 18\"\n.Dl \"ipfw add NN set 18 ...         # repeat as needed\"\n.Dl \"ipfw set enable 18\"\n.Pp\nTo delete a set of rules atomically the command is simply:\n.Pp\n.Dl \"ipfw delete set 18\"\n.Pp\nTo test a ruleset and disable it and regain control if something goes wrong:\n.Pp\n.Dl \"ipfw set disable 18\"\n.Dl \"ipfw add NN set 18 ...         # repeat as needed\"\n.Dl \"ipfw set enable 18; echo done; sleep 30 && ipfw set disable 18\"\n.Pp\nHere if everything goes well, you press control-C before the \"sleep\"\nterminates, and your ruleset will be left active.\nOtherwise, e.g.\\& if\nyou cannot access your box, the ruleset will be disabled after\nthe sleep terminates thus restoring the previous situation.\n.Pp\nTo show rules of the specific set:\n.Pp\n.Dl \"ipfw set 18 show\"\n.Pp\nTo show rules of the disabled set:\n.Pp\n.Dl \"ipfw -S set 18 show\"\n.Pp\nTo clear a specific rule counters of the specific set:\n.Pp\n.Dl \"ipfw set 18 zero NN\"\n.Pp\nTo delete a specific rule of the specific set:\n.Pp\n.Dl \"ipfw set 18 delete NN\"\n.Ss NAT, REDIRECT AND LSNAT\nFirst redirect all the traffic to nat instance 123:\n.Pp\n.Dl \"ipfw add nat 123 all from any to any\"\n.Pp\nThen to configure nat instance 123 to alias all the outgoing traffic with ip\n192.168.0.123, blocking all incoming connections, trying to keep\nsame ports on both sides, clearing aliasing table on address change\nand keeping a log of traffic/link statistics:\n.Pp\n.Dl \"ipfw nat 123 config ip 192.168.0.123 log deny_in reset same_ports\"\n.Pp\nOr to change address of instance 123, aliasing table will be cleared (see\nreset option):\n.Pp\n.Dl \"ipfw nat 123 config ip 10.0.0.1\"\n.Pp\nTo see configuration of nat instance 123:\n.Pp\n.Dl \"ipfw nat 123 show config\"\n.Pp\nTo show logs of all the instances in range 111-999:\n.Pp\n.Dl \"ipfw nat 111-999 show\"\n.Pp\nTo see configurations of all instances:\n.Pp\n.Dl \"ipfw nat show config\"\n.Pp\nOr a redirect rule with mixed modes could looks like:\n.Pp\n.Dl \"ipfw nat 123 config redirect_addr 10.0.0.1 10.0.0.66\"\n.Dl \"\t\t\t redirect_port tcp 192.168.0.1:80 500\"\n.Dl \"\t\t\t redirect_proto udp 192.168.1.43 192.168.1.1\"\n.Dl \"\t\t\t redirect_addr 192.168.0.10,192.168.0.11\"\n.Dl \"\t\t\t \t    10.0.0.100\t# LSNAT\"\n.Dl \"\t\t\t redirect_port tcp 192.168.0.1:80,192.168.0.10:22\"\n.Dl \"\t\t\t \t    500\t\t# LSNAT\"\n.Pp\nor it could be split in:\n.Pp\n.Dl \"ipfw nat 1 config redirect_addr 10.0.0.1 10.0.0.66\"\n.Dl \"ipfw nat 2 config redirect_port tcp 192.168.0.1:80 500\"\n.Dl \"ipfw nat 3 config redirect_proto udp 192.168.1.43 192.168.1.1\"\n.Dl \"ipfw nat 4 config redirect_addr 192.168.0.10,192.168.0.11,192.168.0.12\"\n.Dl \"\t\t\t\t         10.0.0.100\"\n.Dl \"ipfw nat 5 config redirect_port tcp\"\n.Dl \"\t\t\t192.168.0.1:80,192.168.0.10:22,192.168.0.20:25 500\"\n.Sh SEE ALSO\n.Xr cpp 1 ,\n.Xr m4 1 ,\n.Xr altq 4 ,\n.Xr divert 4 ,\n.Xr dummynet 4 ,\n.Xr if_bridge 4 ,\n.Xr ip 4 ,\n.Xr ipfirewall 4 ,\n.Xr ng_ipfw 4 ,\n.Xr protocols 5 ,\n.Xr services 5 ,\n.Xr init 8 ,\n.Xr kldload 8 ,\n.Xr reboot 8 ,\n.Xr sysctl 8 ,\n.Xr syslogd 8\n.Sh HISTORY\nThe\n.Nm\nutility first appeared in\n.Fx 2.0 .\n.Nm dummynet\nwas introduced in\n.Fx 2.2.8 .\nStateful extensions were introduced in\n.Fx 4.0 .\n.Nm ipfw2\nwas introduced in Summer 2002.\n.Sh AUTHORS\n.An Ugen J. S. Antsilevich ,\n.An Poul-Henning Kamp ,\n.An Alex Nash ,\n.An Archie Cobbs ,\n.An Luigi Rizzo .\n.Pp\n.An -nosplit\nAPI based upon code written by\n.An Daniel Boulet\nfor BSDI.\n.Pp\nDummynet has been introduced by Luigi Rizzo in 1997-1998.\n.Pp\nSome early work (1999-2000) on the\n.Nm dummynet\ntraffic shaper supported by Akamba Corp.\n.Pp\nThe ipfw core (ipfw2) has been completely redesigned and\nreimplemented by Luigi Rizzo in summer 2002.\nFurther\nactions and\noptions have been added by various developer over the years.\n.Pp\n.An -nosplit\nIn-kernel NAT support written by\n.An Paolo Pisati Aq piso@FreeBSD.org\nas part of a Summer of Code 2005 project.\n.Pp\nSCTP\n.Nm nat\nsupport has been developed by\n.An The Centre for Advanced Internet Architectures (CAIA) Aq http://www.caia.swin.edu.au .\nThe primary developers and maintainers are David Hayes and Jason But.\nFor further information visit:\n.Aq http://www.caia.swin.edu.au/urp/SONATA\n.Pp\nDelay profiles have been developed by Alessandro Cerri and\nLuigi Rizzo, supported by the\nEuropean Commission within Projects Onelab and Onelab2.\n.Sh BUGS\nThe syntax has grown over the years and sometimes it might be confusing.\nUnfortunately, backward compatibility prevents cleaning up mistakes\nmade in the definition of the syntax.\n.Pp\n.Em !!! WARNING !!!\n.Pp\nMisconfiguring the firewall can put your computer in an unusable state,\npossibly shutting down network services and requiring console access to\nregain control of it.\n.Pp\nIncoming packet fragments diverted by\n.Cm divert\nare reassembled before delivery to the socket.\nThe action used on those packet is the one from the\nrule which matches the first fragment of the packet.\n.Pp\nPackets diverted to userland, and then reinserted by a userland process\nmay lose various packet attributes.\nThe packet source interface name\nwill be preserved if it is shorter than 8 bytes and the userland process\nsaves and reuses the sockaddr_in\n(as does\n.Xr natd 8 ) ;\notherwise, it may be lost.\nIf a packet is reinserted in this manner, later rules may be incorrectly\napplied, making the order of\n.Cm divert\nrules in the rule sequence very important.\n.Pp\nDummynet drops all packets with IPv6 link-local addresses.\n.Pp\nRules using\n.Cm uid\nor\n.Cm gid\nmay not behave as expected.\nIn particular, incoming SYN packets may\nhave no uid or gid associated with them since they do not yet belong\nto a TCP connection, and the uid/gid associated with a packet may not\nbe as expected if the associated process calls\n.Xr setuid 2\nor similar system calls.\n.Pp\nRule syntax is subject to the command line environment and some patterns\nmay need to be escaped with the backslash character\nor quoted appropriately.\n.Pp\nDue to the architecture of\n.Xr libalias 3 ,\nipfw nat is not compatible with the TCP segmentation offloading (TSO).\nThus, to reliably nat your network traffic, please disable TSO\non your NICs using\n.Xr ifconfig 8 .\n.Pp\nICMP error messages are not implicitly matched by dynamic rules\nfor the respective conversations.\nTo avoid failures of network error detection and path MTU discovery,\nICMP error messages may need to be allowed explicitly through static\nrules.\n.Pp\nRules using\n.Cm call\nand\n.Cm return\nactions may lead to confusing behaviour if ruleset has mistakes,\nand/or interaction with other subsystems (netgraph, dummynet, etc.) is used.\nOne possible case for this is packet leaving\n.Nm\nin subroutine on the input pass, while later on output encountering unpaired\n.Cm return\nfirst.\nAs the call stack is kept intact after input pass, packet will suddenly\nreturn to the rule number used on input pass, not on output one.\nOrder of processing should be checked carefully to avoid such mistakes.\n"
  },
  {
    "path": "ipfw/ipfw2.c",
    "content": "/*\n * Copyright (c) 2002-2003 Luigi Rizzo\n * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp\n * Copyright (c) 1994 Ugen J.S.Antsilevich\n *\n * Idea and grammar partially left from:\n * Copyright (c) 1993 Daniel Boulet\n *\n * Redistribution and use in source forms, with and without modification,\n * are permitted provided that this entire comment appears intact.\n *\n * Redistribution in binary form may occur without any restrictions.\n * Obviously, it would be nice if you gave credit where credit is due\n * but requiring it would be too onerous.\n *\n * This software is provided ``AS IS'' without any warranties of any kind.\n *\n * NEW command line interface for IP firewall facility\n *\n * $FreeBSD: head/sbin/ipfw/ipfw2.c 206843 2010-04-19 15:11:45Z luigi $\n */\n\n#include <sys/types.h>\n#include <sys/param.h>\n#include <sys/socket.h>\n#include <sys/sockio.h>\n#include <sys/sysctl.h>\n\n#include \"ipfw2.h\"\n\n#include <ctype.h>\n#include <err.h>\n#include <errno.h>\n#include <grp.h>\n#include <netdb.h>\n#include <pwd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sysexits.h>\n#include <time.h>\t/* ctime */\n#include <timeconv.h>\t/* _long_to_time */\n#include <unistd.h>\n#include <fcntl.h>\n#include <stddef.h>\t/* offsetof */\n\n#include <net/ethernet.h>\n#include <net/if.h>\t\t/* only IFNAMSIZ */\n#include <netinet/in.h>\n#include <netinet/in_systm.h>\t/* only n_short, n_long */\n#include <netinet/ip.h>\n#include <netinet/ip_icmp.h>\n#include <netinet/ip_fw.h>\n#include <netinet/tcp.h>\n#include <arpa/inet.h>\n\nstruct cmdline_opts co;\t/* global options */\n\nint resvd_set_number = RESVD_SET;\n\nint ipfw_socket = -1;\n\n#ifndef s6_addr32\n#define s6_addr32 __u6_addr.__u6_addr32\n#endif\n\n#define GET_UINT_ARG(arg, min, max, tok, s_x) do {\t\t\t\\\n\tif (!av[0])\t\t\t\t\t\t\t\\\n\t\terrx(EX_USAGE, \"%s: missing argument\", match_value(s_x, tok)); \\\n\tif (_substrcmp(*av, \"tablearg\") == 0) {\t\t\t\t\\\n\t\targ = IP_FW_TABLEARG;\t\t\t\t\t\\\n\t\tbreak;\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\\\n\tlong _xval;\t\t\t\t\t\t\t\\\n\tchar *end;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\t_xval = strtol(*av, &end, 10);\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\tif (!isdigit(**av) || *end != '\\0' || (_xval == 0 && errno == EINVAL)) \\\n\t\terrx(EX_DATAERR, \"%s: invalid argument: %s\",\t\t\\\n\t\t    match_value(s_x, tok), *av);\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\tif (errno == ERANGE || _xval < min || _xval > max)\t\t\\\n\t\terrx(EX_DATAERR, \"%s: argument is out of range (%u..%u): %s\", \\\n\t\t    match_value(s_x, tok), min, max, *av);\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\tif (_xval == IP_FW_TABLEARG)\t\t\t\t\t\\\n\t\terrx(EX_DATAERR, \"%s: illegal argument value: %s\",\t\\\n\t\t    match_value(s_x, tok), *av);\t\t\t\\\n\targ = _xval;\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n} while (0)\n\nstatic void\nPRINT_UINT_ARG(const char *str, uint32_t arg)\n{\n\tif (str != NULL)\n\t\tprintf(\"%s\",str);\n\tif (arg == IP_FW_TABLEARG)\n\t\tprintf(\"tablearg\");\n\telse\n\t\tprintf(\"%u\", arg);\n}\n\nstatic struct _s_x f_tcpflags[] = {\n\t{ \"syn\", TH_SYN },\n\t{ \"fin\", TH_FIN },\n\t{ \"ack\", TH_ACK },\n\t{ \"psh\", TH_PUSH },\n\t{ \"rst\", TH_RST },\n\t{ \"urg\", TH_URG },\n\t{ \"tcp flag\", 0 },\n\t{ NULL,\t0 }\n};\n\nstatic struct _s_x f_tcpopts[] = {\n\t{ \"mss\",\tIP_FW_TCPOPT_MSS },\n\t{ \"maxseg\",\tIP_FW_TCPOPT_MSS },\n\t{ \"window\",\tIP_FW_TCPOPT_WINDOW },\n\t{ \"sack\",\tIP_FW_TCPOPT_SACK },\n\t{ \"ts\",\t\tIP_FW_TCPOPT_TS },\n\t{ \"timestamp\",\tIP_FW_TCPOPT_TS },\n\t{ \"cc\",\t\tIP_FW_TCPOPT_CC },\n\t{ \"tcp option\",\t0 },\n\t{ NULL,\t0 }\n};\n\n/*\n * IP options span the range 0 to 255 so we need to remap them\n * (though in fact only the low 5 bits are significant).\n */\nstatic struct _s_x f_ipopts[] = {\n\t{ \"ssrr\",\tIP_FW_IPOPT_SSRR},\n\t{ \"lsrr\",\tIP_FW_IPOPT_LSRR},\n\t{ \"rr\",\t\tIP_FW_IPOPT_RR},\n\t{ \"ts\",\t\tIP_FW_IPOPT_TS},\n\t{ \"ip option\",\t0 },\n\t{ NULL,\t0 }\n};\n\nstatic struct _s_x f_iptos[] = {\n\t{ \"lowdelay\",\tIPTOS_LOWDELAY},\n\t{ \"throughput\",\tIPTOS_THROUGHPUT},\n\t{ \"reliability\", IPTOS_RELIABILITY},\n\t{ \"mincost\",\tIPTOS_MINCOST},\n\t{ \"congestion\",\tIPTOS_ECN_CE},\n\t{ \"ecntransport\", IPTOS_ECN_ECT0},\n\t{ \"ip tos option\", 0},\n\t{ NULL,\t0 }\n};\n\nstatic struct _s_x limit_masks[] = {\n\t{\"all\",\t\tDYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},\n\t{\"src-addr\",\tDYN_SRC_ADDR},\n\t{\"src-port\",\tDYN_SRC_PORT},\n\t{\"dst-addr\",\tDYN_DST_ADDR},\n\t{\"dst-port\",\tDYN_DST_PORT},\n\t{NULL,\t\t0}\n};\n\n/*\n * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines\n * This is only used in this code.\n */\n#define IPPROTO_ETHERTYPE\t0x1000\nstatic struct _s_x ether_types[] = {\n    /*\n     * Note, we cannot use \"-:&/\" in the names because they are field\n     * separators in the type specifications. Also, we use s = NULL as\n     * end-delimiter, because a type of 0 can be legal.\n     */\n\t{ \"ip\",\t\t0x0800 },\n\t{ \"ipv4\",\t0x0800 },\n\t{ \"ipv6\",\t0x86dd },\n\t{ \"arp\",\t0x0806 },\n\t{ \"rarp\",\t0x8035 },\n\t{ \"vlan\",\t0x8100 },\n\t{ \"loop\",\t0x9000 },\n\t{ \"trail\",\t0x1000 },\n\t{ \"at\",\t\t0x809b },\n\t{ \"atalk\",\t0x809b },\n\t{ \"aarp\",\t0x80f3 },\n\t{ \"pppoe_disc\",\t0x8863 },\n\t{ \"pppoe_sess\",\t0x8864 },\n\t{ \"ipx_8022\",\t0x00E0 },\n\t{ \"ipx_8023\",\t0x0000 },\n\t{ \"ipx_ii\",\t0x8137 },\n\t{ \"ipx_snap\",\t0x8137 },\n\t{ \"ipx\",\t0x8137 },\n\t{ \"ns\",\t\t0x0600 },\n\t{ NULL,\t\t0 }\n};\n\n\nstatic struct _s_x rule_actions[] = {\n\t{ \"accept\",\t\tTOK_ACCEPT },\n\t{ \"pass\",\t\tTOK_ACCEPT },\n\t{ \"allow\",\t\tTOK_ACCEPT },\n\t{ \"permit\",\t\tTOK_ACCEPT },\n\t{ \"count\",\t\tTOK_COUNT },\n\t{ \"pipe\",\t\tTOK_PIPE },\n\t{ \"queue\",\t\tTOK_QUEUE },\n\t{ \"divert\",\t\tTOK_DIVERT },\n\t{ \"tee\",\t\tTOK_TEE },\n\t{ \"netgraph\",\t\tTOK_NETGRAPH },\n\t{ \"ngtee\",\t\tTOK_NGTEE },\n\t{ \"fwd\",\t\tTOK_FORWARD },\n\t{ \"forward\",\t\tTOK_FORWARD },\n\t{ \"skipto\",\t\tTOK_SKIPTO },\n\t{ \"deny\",\t\tTOK_DENY },\n\t{ \"drop\",\t\tTOK_DENY },\n\t{ \"reject\",\t\tTOK_REJECT },\n\t{ \"reset6\",\t\tTOK_RESET6 },\n\t{ \"reset\",\t\tTOK_RESET },\n\t{ \"unreach6\",\t\tTOK_UNREACH6 },\n\t{ \"unreach\",\t\tTOK_UNREACH },\n\t{ \"check-state\",\tTOK_CHECKSTATE },\n\t{ \"//\",\t\t\tTOK_COMMENT },\n\t{ \"nat\",\t\tTOK_NAT },\n\t{ \"reass\",\t\tTOK_REASS },\n\t{ \"setfib\",\t\tTOK_SETFIB },\n\t{ \"call\",\t\tTOK_CALL },\n\t{ \"return\",\t\tTOK_RETURN },\n\t{ NULL, 0 }\t/* terminator */\n};\n\nstatic struct _s_x rule_action_params[] = {\n\t{ \"altq\",\t\tTOK_ALTQ },\n\t{ \"log\",\t\tTOK_LOG },\n\t{ \"tag\",\t\tTOK_TAG },\n\t{ \"untag\",\t\tTOK_UNTAG },\n\t{ NULL, 0 }\t/* terminator */\n};\n\n/*\n * The 'lookup' instruction accepts one of the following arguments.\n * -1 is a terminator for the list.\n * Arguments are passed as v[1] in O_DST_LOOKUP options.\n */\nstatic int lookup_key[] = {\n\tTOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT,\n\tTOK_UID, TOK_JAIL, TOK_DSCP, -1 };\n\nstatic struct _s_x rule_options[] = {\n\t{ \"tagged\",\t\tTOK_TAGGED },\n\t{ \"uid\",\t\tTOK_UID },\n\t{ \"gid\",\t\tTOK_GID },\n\t{ \"jail\",\t\tTOK_JAIL },\n\t{ \"in\",\t\t\tTOK_IN },\n\t{ \"limit\",\t\tTOK_LIMIT },\n\t{ \"keep-state\",\t\tTOK_KEEPSTATE },\n\t{ \"bridged\",\t\tTOK_LAYER2 },\n\t{ \"layer2\",\t\tTOK_LAYER2 },\n\t{ \"out\",\t\tTOK_OUT },\n\t{ \"diverted\",\t\tTOK_DIVERTED },\n\t{ \"diverted-loopback\",\tTOK_DIVERTEDLOOPBACK },\n\t{ \"diverted-output\",\tTOK_DIVERTEDOUTPUT },\n\t{ \"xmit\",\t\tTOK_XMIT },\n\t{ \"recv\",\t\tTOK_RECV },\n\t{ \"via\",\t\tTOK_VIA },\n\t{ \"fragment\",\t\tTOK_FRAG },\n\t{ \"frag\",\t\tTOK_FRAG },\n\t{ \"fib\",\t\tTOK_FIB },\n\t{ \"ipoptions\",\t\tTOK_IPOPTS },\n\t{ \"ipopts\",\t\tTOK_IPOPTS },\n\t{ \"iplen\",\t\tTOK_IPLEN },\n\t{ \"ipid\",\t\tTOK_IPID },\n\t{ \"ipprecedence\",\tTOK_IPPRECEDENCE },\n\t{ \"dscp\",\t\tTOK_DSCP },\n\t{ \"iptos\",\t\tTOK_IPTOS },\n\t{ \"ipttl\",\t\tTOK_IPTTL },\n\t{ \"ipversion\",\t\tTOK_IPVER },\n\t{ \"ipver\",\t\tTOK_IPVER },\n\t{ \"estab\",\t\tTOK_ESTAB },\n\t{ \"established\",\tTOK_ESTAB },\n\t{ \"setup\",\t\tTOK_SETUP },\n\t{ \"sockarg\",\t\tTOK_SOCKARG },\n\t{ \"tcpdatalen\",\t\tTOK_TCPDATALEN },\n\t{ \"tcpflags\",\t\tTOK_TCPFLAGS },\n\t{ \"tcpflgs\",\t\tTOK_TCPFLAGS },\n\t{ \"tcpoptions\",\t\tTOK_TCPOPTS },\n\t{ \"tcpopts\",\t\tTOK_TCPOPTS },\n\t{ \"tcpseq\",\t\tTOK_TCPSEQ },\n\t{ \"tcpack\",\t\tTOK_TCPACK },\n\t{ \"tcpwin\",\t\tTOK_TCPWIN },\n\t{ \"icmptype\",\t\tTOK_ICMPTYPES },\n\t{ \"icmptypes\",\t\tTOK_ICMPTYPES },\n\t{ \"dst-ip\",\t\tTOK_DSTIP },\n\t{ \"src-ip\",\t\tTOK_SRCIP },\n\t{ \"dst-port\",\t\tTOK_DSTPORT },\n\t{ \"src-port\",\t\tTOK_SRCPORT },\n\t{ \"proto\",\t\tTOK_PROTO },\n\t{ \"MAC\",\t\tTOK_MAC },\n\t{ \"mac\",\t\tTOK_MAC },\n\t{ \"mac-type\",\t\tTOK_MACTYPE },\n\t{ \"verrevpath\",\t\tTOK_VERREVPATH },\n\t{ \"versrcreach\",\tTOK_VERSRCREACH },\n\t{ \"antispoof\",\t\tTOK_ANTISPOOF },\n\t{ \"ipsec\",\t\tTOK_IPSEC },\n\t{ \"icmp6type\",\t\tTOK_ICMP6TYPES },\n\t{ \"icmp6types\",\t\tTOK_ICMP6TYPES },\n\t{ \"ext6hdr\",\t\tTOK_EXT6HDR},\n\t{ \"flow-id\",\t\tTOK_FLOWID},\n\t{ \"ipv6\",\t\tTOK_IPV6},\n\t{ \"ip6\",\t\tTOK_IPV6},\n\t{ \"ipv4\",\t\tTOK_IPV4},\n\t{ \"ip4\",\t\tTOK_IPV4},\n\t{ \"dst-ipv6\",\t\tTOK_DSTIP6},\n\t{ \"dst-ip6\",\t\tTOK_DSTIP6},\n\t{ \"src-ipv6\",\t\tTOK_SRCIP6},\n\t{ \"src-ip6\",\t\tTOK_SRCIP6},\n\t{ \"lookup\",\t\tTOK_LOOKUP},\n\t{ \"//\",\t\t\tTOK_COMMENT },\n\n\t{ \"not\",\t\tTOK_NOT },\t\t/* pseudo option */\n\t{ \"!\", /* escape ? */\tTOK_NOT },\t\t/* pseudo option */\n\t{ \"or\",\t\t\tTOK_OR },\t\t/* pseudo option */\n\t{ \"|\", /* escape */\tTOK_OR },\t\t/* pseudo option */\n\t{ \"{\",\t\t\tTOK_STARTBRACE },\t/* pseudo option */\n\t{ \"(\",\t\t\tTOK_STARTBRACE },\t/* pseudo option */\n\t{ \"}\",\t\t\tTOK_ENDBRACE },\t\t/* pseudo option */\n\t{ \")\",\t\t\tTOK_ENDBRACE },\t\t/* pseudo option */\n\t{ NULL, 0 }\t/* terminator */\n};\n\n/*\n * Helper routine to print a possibly unaligned uint64_t on\n * various platform. If width > 0, print the value with\n * the desired width, followed by a space;\n * otherwise, return the required width.\n */\nint\npr_u64(uint64_t *pd, int width)\n{\n#ifdef TCC\n#define U64_FMT \"I64\"\n#else\n#define U64_FMT \"llu\"\n#endif\n\tuint64_t u;\n\tunsigned long long d;\n\n\tbcopy (pd, &u, sizeof(u));\n\td = u;\n\treturn (width > 0) ?\n\t\tprintf(\"%*\" U64_FMT \" \", width, d) :\n\t\tsnprintf(NULL, 0, \"%\" U64_FMT, d) ;\n#undef U64_FMT\n}\n\nvoid *\nsafe_calloc(size_t number, size_t size)\n{\n\tvoid *ret = calloc(number, size);\n\n\tif (ret == NULL)\n\t\terr(EX_OSERR, \"calloc\");\n\treturn ret;\n}\n\nvoid *\nsafe_realloc(void *ptr, size_t size)\n{\n\tvoid *ret = realloc(ptr, size);\n\n\tif (ret == NULL)\n\t\terr(EX_OSERR, \"realloc\");\n\treturn ret;\n}\n\n/*\n * conditionally runs the command.\n * Selected options or negative -> getsockopt\n */\nint\ndo_cmd(int optname, void *optval, uintptr_t optlen)\n{\n\tint i;\n\n\tif (co.test_only)\n\t\treturn 0;\n\n\tif (ipfw_socket == -1)\n\t\tipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);\n\tif (ipfw_socket < 0)\n\t\terr(EX_UNAVAILABLE, \"socket\");\n\n\tif (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||\n\t    optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||\n\t    optname == IP_FW_TABLE_GETSIZE ||\n\t    optname == IP_FW_NAT_GET_CONFIG ||\n\t    optname < 0 ||\n\t    optname == IP_FW_NAT_GET_LOG) {\n\t\tif (optname < 0)\n\t\t\toptname = -optname;\n\t\ti = getsockopt(ipfw_socket, IPPROTO_IP, optname, optval,\n\t\t\t(socklen_t *)optlen);\n\t} else {\n\t\ti = setsockopt(ipfw_socket, IPPROTO_IP, optname, optval, optlen);\n\t}\n\treturn i;\n}\n\n#if 0 // XXX still unused\n/*\n * do_setcmd3 - pass ipfw control cmd to kernel\n * @optname: option name\n * @optval: pointer to option data\n * @optlen: option length\n *\n * Function encapsulates option value in IP_FW3 socket option\n * and calls setsockopt().\n * Function returns 0 on success or -1 otherwise.\n */\nstatic int\ndo_setcmd3(int optname, void *optval, socklen_t optlen)\n{\n\tsocklen_t len;\n\tip_fw3_opheader *op3;\n\n\tif (co.test_only)\n\t\treturn (0);\n\n\tif (ipfw_socket == -1)\n\t\tipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);\n\tif (ipfw_socket < 0)\n\t\terr(EX_UNAVAILABLE, \"socket\");\n\n\tlen = sizeof(ip_fw3_opheader) + optlen;\n\top3 = alloca(len);\n\t/* Zero reserved fields */\n\tmemset(op3, 0, sizeof(ip_fw3_opheader));\n\tmemcpy(op3 + 1, optval, optlen);\n\top3->opcode = optname;\n\n\treturn setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);\n}\n#endif // XXX still unused\n\n/**\n * match_token takes a table and a string, returns the value associated\n * with the string (-1 in case of failure).\n */\nint\nmatch_token(struct _s_x *table, char *string)\n{\n\tstruct _s_x *pt;\n\tuint i = strlen(string);\n\n\tfor (pt = table ; i && pt->s != NULL ; pt++)\n\t\tif (strlen(pt->s) == i && !bcmp(string, pt->s, i))\n\t\t\treturn pt->x;\n\treturn -1;\n}\n\n/**\n * match_value takes a table and a value, returns the string associated\n * with the value (NULL in case of failure).\n */\nchar const *\nmatch_value(struct _s_x *p, int value)\n{\n\tfor (; p->s != NULL; p++)\n\t\tif (p->x == value)\n\t\t\treturn p->s;\n\treturn NULL;\n}\n\n/*\n * _substrcmp takes two strings and returns 1 if they do not match,\n * and 0 if they match exactly or the first string is a sub-string\n * of the second.  A warning is printed to stderr in the case that the\n * first string is a sub-string of the second.\n *\n * This function will be removed in the future through the usual\n * deprecation process.\n */\nint\n_substrcmp(const char *str1, const char* str2)\n{\n\n\tif (strncmp(str1, str2, strlen(str1)) != 0)\n\t\treturn 1;\n\n\tif (strlen(str1) != strlen(str2))\n\t\twarnx(\"DEPRECATED: '%s' matched '%s' as a sub-string\",\n\t\t    str1, str2);\n\treturn 0;\n}\n\n/*\n * _substrcmp2 takes three strings and returns 1 if the first two do not match,\n * and 0 if they match exactly or the second string is a sub-string\n * of the first.  A warning is printed to stderr in the case that the\n * first string does not match the third.\n *\n * This function exists to warn about the bizarre construction\n * strncmp(str, \"by\", 2) which is used to allow people to use a shortcut\n * for \"bytes\".  The problem is that in addition to accepting \"by\",\n * \"byt\", \"byte\", and \"bytes\", it also excepts \"by_rabid_dogs\" and any\n * other string beginning with \"by\".\n *\n * This function will be removed in the future through the usual\n * deprecation process.\n */\nint\n_substrcmp2(const char *str1, const char* str2, const char* str3)\n{\n\n\tif (strncmp(str1, str2, strlen(str2)) != 0)\n\t\treturn 1;\n\n\tif (strcmp(str1, str3) != 0)\n\t\twarnx(\"DEPRECATED: '%s' matched '%s'\",\n\t\t    str1, str3);\n\treturn 0;\n}\n\n/*\n * prints one port, symbolic or numeric\n */\nstatic void\nprint_port(int proto, uint16_t port)\n{\n\n\tif (proto == IPPROTO_ETHERTYPE) {\n\t\tchar const *s;\n\n\t\tif (co.do_resolv && (s = match_value(ether_types, port)) )\n\t\t\tprintf(\"%s\", s);\n\t\telse\n\t\t\tprintf(\"0x%04x\", port);\n\t} else {\n\t\tstruct servent *se = NULL;\n\t\tif (co.do_resolv) {\n\t\t\tstruct protoent *pe = getprotobynumber(proto);\n\n\t\t\tse = getservbyport(htons(port), pe ? pe->p_name : NULL);\n\t\t}\n\t\tif (se)\n\t\t\tprintf(\"%s\", se->s_name);\n\t\telse\n\t\t\tprintf(\"%d\", port);\n\t}\n}\n\nstatic struct _s_x _port_name[] = {\n\t{\"dst-port\",\tO_IP_DSTPORT},\n\t{\"src-port\",\tO_IP_SRCPORT},\n\t{\"ipid\",\tO_IPID},\n\t{\"iplen\",\tO_IPLEN},\n\t{\"ipttl\",\tO_IPTTL},\n\t{\"mac-type\",\tO_MAC_TYPE},\n\t{\"tcpdatalen\",\tO_TCPDATALEN},\n\t{\"tcpwin\",\tO_TCPWIN},\n\t{\"tagged\",\tO_TAGGED},\n\t{NULL,\t\t0}\n};\n\n/*\n * Print the values in a list 16-bit items of the types above.\n * XXX todo: add support for mask.\n */\nstatic void\nprint_newports(ipfw_insn_u16 *cmd, int proto, int opcode)\n{\n\tuint16_t *p = cmd->ports;\n\tint i;\n\tchar const *sep;\n\n\tif (opcode != 0) {\n\t\tsep = match_value(_port_name, opcode);\n\t\tif (sep == NULL)\n\t\t\tsep = \"???\";\n\t\tprintf (\" %s\", sep);\n\t}\n\tsep = \" \";\n\tfor (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {\n\t\tprintf(\"%s\", sep);\n\t\tprint_port(proto, p[0]);\n\t\tif (p[0] != p[1]) {\n\t\t\tprintf(\"-\");\n\t\t\tprint_port(proto, p[1]);\n\t\t}\n\t\tsep = \",\";\n\t}\n}\n\n/*\n * Like strtol, but also translates service names into port numbers\n * for some protocols.\n * In particular:\n *\tproto == -1 disables the protocol check;\n *\tproto == IPPROTO_ETHERTYPE looks up an internal table\n *\tproto == <some value in /etc/protocols> matches the values there.\n * Returns *end == s in case the parameter is not found.\n */\nstatic int\nstrtoport(char *s, char **end, int base, int proto)\n{\n\tchar *p, *buf;\n\tchar *s1;\n\tint i;\n\n\t*end = s;\t\t/* default - not found */\n\tif (*s == '\\0')\n\t\treturn 0;\t/* not found */\n\n\tif (isdigit(*s))\n\t\treturn strtol(s, end, base);\n\n\t/*\n\t * find separator. '\\\\' escapes the next char.\n\t */\n\tfor (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\\\') ; s1++)\n\t\tif (*s1 == '\\\\' && s1[1] != '\\0')\n\t\t\ts1++;\n\n\tbuf = safe_calloc(s1 - s + 1, 1);\n\n\t/*\n\t * copy into a buffer skipping backslashes\n\t */\n\tfor (p = s, i = 0; p != s1 ; p++)\n\t\tif (*p != '\\\\')\n\t\t\tbuf[i++] = *p;\n\tbuf[i++] = '\\0';\n\n\tif (proto == IPPROTO_ETHERTYPE) {\n\t\ti = match_token(ether_types, buf);\n\t\tfree(buf);\n\t\tif (i != -1) {\t/* found */\n\t\t\t*end = s1;\n\t\t\treturn i;\n\t\t}\n\t} else {\n\t\tstruct protoent *pe = NULL;\n\t\tstruct servent *se;\n\n\t\tif (proto != 0)\n\t\t\tpe = getprotobynumber(proto);\n\t\tsetservent(1);\n\t\tse = getservbyname(buf, pe ? pe->p_name : NULL);\n\t\tfree(buf);\n\t\tif (se != NULL) {\n\t\t\t*end = s1;\n\t\t\treturn ntohs(se->s_port);\n\t\t}\n\t}\n\treturn 0;\t/* not found */\n}\n\n/*\n * Fill the body of the command with the list of port ranges.\n */\nstatic int\nfill_newports(ipfw_insn_u16 *cmd, char *av, int proto)\n{\n\tuint16_t a, b, *p = cmd->ports;\n\tint i = 0;\n\tchar *s = av;\n\n\twhile (*s) {\n\t\ta = strtoport(av, &s, 0, proto);\n\t\tif (s == av) \t\t\t/* empty or invalid argument */\n\t\t\treturn (0);\n\n\t\tswitch (*s) {\n\t\tcase '-':\t\t\t/* a range */\n\t\t\tav = s + 1;\n\t\t\tb = strtoport(av, &s, 0, proto);\n\t\t\t/* Reject expressions like '1-abc' or '1-2-3'. */\n\t\t\tif (s == av || (*s != ',' && *s != '\\0'))\n\t\t\t\treturn (0);\n\t\t\tp[0] = a;\n\t\t\tp[1] = b;\n\t\t\tbreak;\n\t\tcase ',':\t\t\t/* comma separated list */\n\t\tcase '\\0':\n\t\t\tp[0] = p[1] = a;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\twarnx(\"port list: invalid separator <%c> in <%s>\",\n\t\t\t\t*s, av);\n\t\t\treturn (0);\n\t\t}\n\n\t\ti++;\n\t\tp += 2;\n\t\tav = s + 1;\n\t}\n\tif (i > 0) {\n\t\tif (i + 1 > F_LEN_MASK)\n\t\t\terrx(EX_DATAERR, \"too many ports/ranges\\n\");\n\t\tcmd->o.len |= i + 1;\t/* leave F_NOT and F_OR untouched */\n\t}\n\treturn (i);\n}\n\nstatic struct _s_x icmpcodes[] = {\n      { \"net\",\t\t\tICMP_UNREACH_NET },\n      { \"host\",\t\t\tICMP_UNREACH_HOST },\n      { \"protocol\",\t\tICMP_UNREACH_PROTOCOL },\n      { \"port\",\t\t\tICMP_UNREACH_PORT },\n      { \"needfrag\",\t\tICMP_UNREACH_NEEDFRAG },\n      { \"srcfail\",\t\tICMP_UNREACH_SRCFAIL },\n      { \"net-unknown\",\t\tICMP_UNREACH_NET_UNKNOWN },\n      { \"host-unknown\",\t\tICMP_UNREACH_HOST_UNKNOWN },\n      { \"isolated\",\t\tICMP_UNREACH_ISOLATED },\n      { \"net-prohib\",\t\tICMP_UNREACH_NET_PROHIB },\n      { \"host-prohib\",\t\tICMP_UNREACH_HOST_PROHIB },\n      { \"tosnet\",\t\tICMP_UNREACH_TOSNET },\n      { \"toshost\",\t\tICMP_UNREACH_TOSHOST },\n      { \"filter-prohib\",\tICMP_UNREACH_FILTER_PROHIB },\n      { \"host-precedence\",\tICMP_UNREACH_HOST_PRECEDENCE },\n      { \"precedence-cutoff\",\tICMP_UNREACH_PRECEDENCE_CUTOFF },\n      { NULL, 0 }\n};\n\nstatic void\nfill_reject_code(u_short *codep, char *str)\n{\n\tint val;\n\tchar *s;\n\n\tval = strtoul(str, &s, 0);\n\tif (s == str || *s != '\\0' || val >= 0x100)\n\t\tval = match_token(icmpcodes, str);\n\tif (val < 0)\n\t\terrx(EX_DATAERR, \"unknown ICMP unreachable code ``%s''\", str);\n\t*codep = val;\n\treturn;\n}\n\nstatic void\nprint_reject_code(uint16_t code)\n{\n\tchar const *s = match_value(icmpcodes, code);\n\n\tif (s != NULL)\n\t\tprintf(\"unreach %s\", s);\n\telse\n\t\tprintf(\"unreach %u\", code);\n}\n\n/*\n * Returns the number of bits set (from left) in a contiguous bitmask,\n * or -1 if the mask is not contiguous.\n * XXX this needs a proper fix.\n * This effectively works on masks in big-endian (network) format.\n * when compiled on little endian architectures.\n *\n * First bit is bit 7 of the first byte -- note, for MAC addresses,\n * the first bit on the wire is bit 0 of the first byte.\n * len is the max length in bits.\n */\nint\ncontigmask(uint8_t *p, int len)\n{\n\tint i, n;\n\n\tfor (i=0; i<len ; i++)\n\t\tif ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */\n\t\t\tbreak;\n\tfor (n=i+1; n < len; n++)\n\t\tif ( (p[n/8] & (1 << (7 - (n%8)))) != 0)\n\t\t\treturn -1; /* mask not contiguous */\n\treturn i;\n}\n\n/*\n * print flags set/clear in the two bitmasks passed as parameters.\n * There is a specialized check for f_tcpflags.\n */\nstatic void\nprint_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)\n{\n\tchar const *comma = \"\";\n\tint i;\n\tuint8_t set = cmd->arg1 & 0xff;\n\tuint8_t clear = (cmd->arg1 >> 8) & 0xff;\n\n\tif (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {\n\t\tprintf(\" setup\");\n\t\treturn;\n\t}\n\n\tprintf(\" %s \", name);\n\tfor (i=0; list[i].x != 0; i++) {\n\t\tif (set & list[i].x) {\n\t\t\tset &= ~list[i].x;\n\t\t\tprintf(\"%s%s\", comma, list[i].s);\n\t\t\tcomma = \",\";\n\t\t}\n\t\tif (clear & list[i].x) {\n\t\t\tclear &= ~list[i].x;\n\t\t\tprintf(\"%s!%s\", comma, list[i].s);\n\t\t\tcomma = \",\";\n\t\t}\n\t}\n}\n\n/*\n * Print the ip address contained in a command.\n */\nstatic void\nprint_ip(ipfw_insn_ip *cmd, char const *s)\n{\n\tstruct hostent *he = NULL;\n\tuint32_t len = F_LEN((ipfw_insn *)cmd);\n\tuint32_t *a = ((ipfw_insn_u32 *)cmd)->d;\n\n\tif (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {\n\t\tuint32_t d = a[1];\n\t\tconst char *arg = \"<invalid>\";\n\n\t\tif (d < sizeof(lookup_key)/sizeof(lookup_key[0]))\n\t\t\targ = match_value(rule_options, lookup_key[d]);\n\t\tprintf(\"%s lookup %s %d\", cmd->o.len & F_NOT ? \" not\": \"\",\n\t\t\targ, cmd->o.arg1);\n\t\treturn;\n\t}\n\tprintf(\"%s%s \", cmd->o.len & F_NOT ? \" not\": \"\", s);\n\n\tif (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {\n\t\tprintf(\"me\");\n\t\treturn;\n\t}\n\tif (cmd->o.opcode == O_IP_SRC_LOOKUP ||\n\t    cmd->o.opcode == O_IP_DST_LOOKUP) {\n\t\tprintf(\"table(%u\", ((ipfw_insn *)cmd)->arg1);\n\t\tif (len == F_INSN_SIZE(ipfw_insn_u32))\n\t\t\tprintf(\",%u\", *a);\n\t\tprintf(\")\");\n\t\treturn;\n\t}\n\tif (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) {\n\t\tuint32_t x, *map = (uint32_t *)&(cmd->mask);\n\t\tint i, j;\n\t\tchar comma = '{';\n\n\t\tx = cmd->o.arg1 - 1;\n\t\tx = htonl( ~x );\n\t\tcmd->addr.s_addr = htonl(cmd->addr.s_addr);\n\t\tprintf(\"%s/%d\", inet_ntoa(cmd->addr),\n\t\t\tcontigmask((uint8_t *)&x, 32));\n\t\tx = cmd->addr.s_addr = htonl(cmd->addr.s_addr);\n\t\tx &= 0xff; /* base */\n\t\t/*\n\t\t * Print bits and ranges.\n\t\t * Locate first bit set (i), then locate first bit unset (j).\n\t\t * If we have 3+ consecutive bits set, then print them as a\n\t\t * range, otherwise only print the initial bit and rescan.\n\t\t */\n\t\tfor (i=0; i < cmd->o.arg1; i++)\n\t\t\tif (map[i/32] & (1<<(i & 31))) {\n\t\t\t\tfor (j=i+1; j < cmd->o.arg1; j++)\n\t\t\t\t\tif (!(map[ j/32] & (1<<(j & 31))))\n\t\t\t\t\t\tbreak;\n\t\t\t\tprintf(\"%c%d\", comma, i+x);\n\t\t\t\tif (j>i+2) { /* range has at least 3 elements */\n\t\t\t\t\tprintf(\"-%d\", j-1+x);\n\t\t\t\t\ti = j-1;\n\t\t\t\t}\n\t\t\t\tcomma = ',';\n\t\t\t}\n\t\tprintf(\"}\");\n\t\treturn;\n\t}\n\t/*\n\t * len == 2 indicates a single IP, whereas lists of 1 or more\n\t * addr/mask pairs have len = (2n+1). We convert len to n so we\n\t * use that to count the number of entries.\n\t */\n    for (len = len / 2; len > 0; len--, a += 2) {\n\tint mb =\t/* mask length */\n\t    (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ?\n\t\t32 : contigmask((uint8_t *)&(a[1]), 32);\n\tif (mb == 32 && co.do_resolv)\n\t\the = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET);\n\tif (he != NULL)\t\t/* resolved to name */\n\t\tprintf(\"%s\", he->h_name);\n\telse if (mb == 0)\t/* any */\n\t\tprintf(\"any\");\n\telse {\t\t/* numeric IP followed by some kind of mask */\n\t\tprintf(\"%s\", inet_ntoa( *((struct in_addr *)&a[0]) ) );\n\t\tif (mb < 0)\n\t\t\tprintf(\":%s\", inet_ntoa( *((struct in_addr *)&a[1]) ) );\n\t\telse if (mb < 32)\n\t\t\tprintf(\"/%d\", mb);\n\t}\n\tif (len > 1)\n\t\tprintf(\",\");\n    }\n}\n\n/*\n * prints a MAC address/mask pair\n */\nstatic void\nprint_mac(uint8_t *addr, uint8_t *mask)\n{\n\tint l = contigmask(mask, 48);\n\n\tif (l == 0)\n\t\tprintf(\" any\");\n\telse {\n\t\tprintf(\" %02x:%02x:%02x:%02x:%02x:%02x\",\n\t\t    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);\n\t\tif (l == -1)\n\t\t\tprintf(\"&%02x:%02x:%02x:%02x:%02x:%02x\",\n\t\t\t    mask[0], mask[1], mask[2],\n\t\t\t    mask[3], mask[4], mask[5]);\n\t\telse if (l < 48)\n\t\t\tprintf(\"/%d\", l);\n\t}\n}\n\nstatic void\nfill_icmptypes(ipfw_insn_u32 *cmd, char *av)\n{\n\tuint8_t type;\n\n\tcmd->d[0] = 0;\n\twhile (*av) {\n\t\tif (*av == ',')\n\t\t\tav++;\n\n\t\ttype = strtoul(av, &av, 0);\n\n\t\tif (*av != ',' && *av != '\\0')\n\t\t\terrx(EX_DATAERR, \"invalid ICMP type\");\n\n\t\tif (type > 31)\n\t\t\terrx(EX_DATAERR, \"ICMP type out of range\");\n\n\t\tcmd->d[0] |= 1 << type;\n\t}\n\tcmd->o.opcode = O_ICMPTYPE;\n\tcmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);\n}\n\nstatic void\nprint_icmptypes(ipfw_insn_u32 *cmd)\n{\n\tint i;\n\tchar sep= ' ';\n\n\tprintf(\" icmptypes\");\n\tfor (i = 0; i < 32; i++) {\n\t\tif ( (cmd->d[0] & (1 << (i))) == 0)\n\t\t\tcontinue;\n\t\tprintf(\"%c%d\", sep, i);\n\t\tsep = ',';\n\t}\n}\n\n/*\n * show_ipfw() prints the body of an ipfw rule.\n * Because the standard rule has at least proto src_ip dst_ip, we use\n * a helper function to produce these entries if not provided explicitly.\n * The first argument is the list of fields we have, the second is\n * the list of fields we want to be printed.\n *\n * Special cases if we have provided a MAC header:\n *   + if the rule does not contain IP addresses/ports, do not print them;\n *   + if the rule does not contain an IP proto, print \"all\" instead of \"ip\";\n *\n * Once we have 'have_options', IP header fields are printed as options.\n */\n#define\tHAVE_PROTO\t0x0001\n#define\tHAVE_SRCIP\t0x0002\n#define\tHAVE_DSTIP\t0x0004\n#define\tHAVE_PROTO4\t0x0008\n#define\tHAVE_PROTO6\t0x0010\n#define\tHAVE_IP\t\t0x0100\n#define\tHAVE_OPTIONS\t0x8000\n\nstatic void\nshow_prerequisites(int *flags, int want, int cmd)\n{\n\t(void)cmd;\t/* UNUSED */\n\tif (co.comment_only)\n\t\treturn;\n\tif ( (*flags & HAVE_IP) == HAVE_IP)\n\t\t*flags |= HAVE_OPTIONS;\n\n\tif ( !(*flags & HAVE_OPTIONS)) {\n\t\tif ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) {\n\t\t\tif ( (*flags & HAVE_PROTO4))\n\t\t\t\tprintf(\" ip4\");\n\t\t\telse if ( (*flags & HAVE_PROTO6))\n\t\t\t\tprintf(\" ip6\");\n\t\t\telse\n\t\t\t\tprintf(\" ip\");\n\t\t}\n\t\tif ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))\n\t\t\tprintf(\" from any\");\n\t\tif ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))\n\t\t\tprintf(\" to any\");\n\t}\n\t*flags |= want;\n}\n\nstatic void\nshow_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)\n{\n\tstatic int twidth = 0;\n\tint l;\n\tipfw_insn *cmd, *tagptr = NULL;\n\tconst char *comment = NULL;\t/* ptr to comment if we have one */\n\tint proto = 0;\t\t/* default */\n\tint flags = 0;\t/* prerequisites */\n\tipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */\n\tipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */\n\tint or_block = 0;\t/* we are in an or block */\n\tuint32_t set_disable;\n\n\tbcopy(&rule->next_rule, &set_disable, sizeof(set_disable));\n\n\tif (set_disable & (1 << rule->set)) { /* disabled */\n\t\tif (!co.show_sets)\n\t\t\treturn;\n\t\telse\n\t\t\tprintf(\"# DISABLED \");\n\t}\n\tprintf(\"%05u \", rule->rulenum);\n\n\tif (pcwidth > 0 || bcwidth > 0) {\n\t\tpr_u64(&rule->pcnt, pcwidth);\n\t\tpr_u64(&rule->bcnt, bcwidth);\n\t}\n\n\tif (co.do_time == 2)\n\t\tprintf(\"%10u \", rule->timestamp);\n\telse if (co.do_time == 1) {\n\t\tchar timestr[30];\n\t\ttime_t t = (time_t)0;\n\n\t\tif (twidth == 0) {\n\t\t\tstrcpy(timestr, ctime(&t));\n\t\t\t*strchr(timestr, '\\n') = '\\0';\n\t\t\ttwidth = strlen(timestr);\n\t\t}\n\t\tif (rule->timestamp) {\n\t\t\tt = _long_to_time(rule->timestamp);\n\n\t\t\tstrcpy(timestr, ctime(&t));\n\t\t\t*strchr(timestr, '\\n') = '\\0';\n\t\t\tprintf(\"%s \", timestr);\n\t\t} else {\n\t\t\tprintf(\"%*s\", twidth, \" \");\n\t\t}\n\t}\n\n\tif (co.show_sets)\n\t\tprintf(\"set %d \", rule->set);\n\n\t/*\n\t * print the optional \"match probability\"\n\t */\n\tif (rule->cmd_len > 0) {\n\t\tcmd = rule->cmd ;\n\t\tif (cmd->opcode == O_PROB) {\n\t\t\tipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd;\n\t\t\tdouble d = 1.0 * p->d[0];\n\n\t\t\td = (d / 0x7fffffff);\n\t\t\tprintf(\"prob %f \", d);\n\t\t}\n\t}\n\n\t/*\n\t * first print actions\n\t */\n\tfor (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);\n\t\t\tl > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {\n\t\tswitch(cmd->opcode) {\n\t\tcase O_CHECK_STATE:\n\t\t\tprintf(\"check-state\");\n\t\t\t/* avoid printing anything else */\n\t\t\tflags = HAVE_PROTO | HAVE_SRCIP |\n\t\t\t\tHAVE_DSTIP | HAVE_IP;\n\t\t\tbreak;\n\n\t\tcase O_ACCEPT:\n\t\t\tprintf(\"allow\");\n\t\t\tbreak;\n\n\t\tcase O_COUNT:\n\t\t\tprintf(\"count\");\n\t\t\tbreak;\n\n\t\tcase O_DENY:\n\t\t\tprintf(\"deny\");\n\t\t\tbreak;\n\n\t\tcase O_REJECT:\n\t\t\tif (cmd->arg1 == ICMP_REJECT_RST)\n\t\t\t\tprintf(\"reset\");\n\t\t\telse if (cmd->arg1 == ICMP_UNREACH_HOST)\n\t\t\t\tprintf(\"reject\");\n\t\t\telse\n\t\t\t\tprint_reject_code(cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_UNREACH6:\n\t\t\tif (cmd->arg1 == ICMP6_UNREACH_RST)\n\t\t\t\tprintf(\"reset6\");\n\t\t\telse\n\t\t\t\tprint_unreach6_code(cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_SKIPTO:\n\t\t\tPRINT_UINT_ARG(\"skipto \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_PIPE:\n\t\t\tPRINT_UINT_ARG(\"pipe \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_QUEUE:\n\t\t\tPRINT_UINT_ARG(\"queue \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_DIVERT:\n\t\t\tPRINT_UINT_ARG(\"divert \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_TEE:\n\t\t\tPRINT_UINT_ARG(\"tee \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_NETGRAPH:\n\t\t\tPRINT_UINT_ARG(\"netgraph \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_NGTEE:\n\t\t\tPRINT_UINT_ARG(\"ngtee \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_FORWARD_IP:\n\t\t    {\n\t\t\tipfw_insn_sa *s = (ipfw_insn_sa *)cmd;\n\n\t\t\tif (s->sa.sin_addr.s_addr == INADDR_ANY) {\n\t\t\t\tprintf(\"fwd tablearg\");\n\t\t\t} else {\n\t\t\t\tprintf(\"fwd %s\", inet_ntoa(s->sa.sin_addr));\n\t\t\t}\n\t\t\tif (s->sa.sin_port)\n\t\t\t\tprintf(\",%d\", s->sa.sin_port);\n\t\t    }\n\t\t\tbreak;\n\n#if 0 // XXX unused yet\n\t\tcase O_FORWARD_IP6:\n\t\t    {\n\t\t\tchar buf[4 + INET6_ADDRSTRLEN + 1];\n\t\t\tipfw_insn_sa6 *s = (ipfw_insn_sa6 *)cmd;\n\n\t\t\tprintf(\"fwd %s\", inet_ntop(AF_INET6, &s->sa.sin6_addr,\n\t\t\t    buf, sizeof(buf)));\n\t\t\tif (s->sa.sin6_port)\n\t\t\t\tprintf(\",%d\", s->sa.sin6_port);\n\t\t    }\n\t\t\tbreak;\n#endif // XXX unused yet\n\n\n\t\tcase O_LOG: /* O_LOG is printed last */\n\t\t\tlogptr = (ipfw_insn_log *)cmd;\n\t\t\tbreak;\n\n\t\tcase O_ALTQ: /* O_ALTQ is printed after O_LOG */\n\t\t\taltqptr = (ipfw_insn_altq *)cmd;\n\t\t\tbreak;\n\n\t\tcase O_TAG:\n\t\t\ttagptr = cmd;\n\t\t\tbreak;\n\n\t\tcase O_NAT:\n\t\t\tif (cmd->arg1 != 0)\n\t\t\t\tPRINT_UINT_ARG(\"nat \", cmd->arg1);\n\t\t\telse\n\t\t\t\tprintf(\"nat global\");\n\t\t\tbreak;\n\n\t\tcase O_SETFIB:\n\t\t\tPRINT_UINT_ARG(\"setfib \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_REASS:\n\t\t\tprintf(\"reass\");\n\t\t\tbreak;\n\n\t\tcase O_CALLRETURN:\n\t\t\tif (cmd->len & F_NOT)\n\t\t\t\tprintf(\"return\");\n\t\t\telse\n\t\t\t\tPRINT_UINT_ARG(\"call \", cmd->arg1);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tprintf(\"** unrecognized action %d len %d \",\n\t\t\t\tcmd->opcode, cmd->len);\n\t\t}\n\t}\n\tif (logptr) {\n\t\tif (logptr->max_log > 0)\n\t\t\tprintf(\" log logamount %d\", logptr->max_log);\n\t\telse\n\t\t\tprintf(\" log\");\n\t}\n#ifndef NO_ALTQ\n\tif (altqptr) {\n\t\tprint_altq_cmd(altqptr);\n\t}\n#endif\n\tif (tagptr) {\n\t\tif (tagptr->len & F_NOT)\n\t\t\tPRINT_UINT_ARG(\" untag \", tagptr->arg1);\n\t\telse\n\t\t\tPRINT_UINT_ARG(\" tag \", tagptr->arg1);\n\t}\n\n\t/*\n\t * then print the body.\n\t */\n\tfor (l = rule->act_ofs, cmd = rule->cmd ;\n\t\t\tl > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {\n\t\tif ((cmd->len & F_OR) || (cmd->len & F_NOT))\n\t\t\tcontinue;\n\t\tif (cmd->opcode == O_IP4) {\n\t\t\tflags |= HAVE_PROTO4;\n\t\t\tbreak;\n\t\t} else if (cmd->opcode == O_IP6) {\n\t\t\tflags |= HAVE_PROTO6;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (rule->_pad & 1) {\t/* empty rules before options */\n\t\tif (!co.do_compact) {\n\t\t\tshow_prerequisites(&flags, HAVE_PROTO, 0);\n\t\t\tprintf(\" from any to any\");\n\t\t}\n\t\tflags |= HAVE_IP | HAVE_OPTIONS | HAVE_PROTO |\n\t\t\t HAVE_SRCIP | HAVE_DSTIP;\n\t}\n\n\tif (co.comment_only)\n\t\tcomment = \"...\";\n\n\tfor (l = rule->act_ofs, cmd = rule->cmd ;\n\t\t\tl > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {\n\t\t/* useful alias */\n\t\tipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;\n\n\t\tif (co.comment_only) {\n\t\t\tif (cmd->opcode != O_NOP)\n\t\t\t\tcontinue;\n\t\t\tprintf(\" // %s\\n\", (char *)(cmd + 1));\n\t\t\treturn;\n\t\t}\n\n\t\tshow_prerequisites(&flags, 0, cmd->opcode);\n\n\t\tswitch(cmd->opcode) {\n\t\tcase O_PROB:\n\t\t\tbreak;\t/* done already */\n\n\t\tcase O_PROBE_STATE:\n\t\t\tbreak; /* no need to print anything here */\n\n\t\tcase O_IP_SRC:\n\t\tcase O_IP_SRC_LOOKUP:\n\t\tcase O_IP_SRC_MASK:\n\t\tcase O_IP_SRC_ME:\n\t\tcase O_IP_SRC_SET:\n\t\t\tshow_prerequisites(&flags, HAVE_PROTO, 0);\n\t\t\tif (!(flags & HAVE_SRCIP))\n\t\t\t\tprintf(\" from\");\n\t\t\tif ((cmd->len & F_OR) && !or_block)\n\t\t\t\tprintf(\" {\");\n\t\t\tprint_ip((ipfw_insn_ip *)cmd,\n\t\t\t\t(flags & HAVE_OPTIONS) ? \" src-ip\" : \"\");\n\t\t\tflags |= HAVE_SRCIP;\n\t\t\tbreak;\n\n\t\tcase O_IP_DST:\n\t\tcase O_IP_DST_LOOKUP:\n\t\tcase O_IP_DST_MASK:\n\t\tcase O_IP_DST_ME:\n\t\tcase O_IP_DST_SET:\n\t\t\tshow_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);\n\t\t\tif (!(flags & HAVE_DSTIP))\n\t\t\t\tprintf(\" to\");\n\t\t\tif ((cmd->len & F_OR) && !or_block)\n\t\t\t\tprintf(\" {\");\n\t\t\tprint_ip((ipfw_insn_ip *)cmd,\n\t\t\t\t(flags & HAVE_OPTIONS) ? \" dst-ip\" : \"\");\n\t\t\tflags |= HAVE_DSTIP;\n\t\t\tbreak;\n\n\t\tcase O_IP6_SRC:\n\t\tcase O_IP6_SRC_MASK:\n\t\tcase O_IP6_SRC_ME:\n\t\t\tshow_prerequisites(&flags, HAVE_PROTO, 0);\n\t\t\tif (!(flags & HAVE_SRCIP))\n\t\t\t\tprintf(\" from\");\n\t\t\tif ((cmd->len & F_OR) && !or_block)\n\t\t\t\tprintf(\" {\");\n\t\t\tprint_ip6((ipfw_insn_ip6 *)cmd,\n\t\t\t    (flags & HAVE_OPTIONS) ? \" src-ip6\" : \"\");\n\t\t\tflags |= HAVE_SRCIP | HAVE_PROTO;\n\t\t\tbreak;\n\n\t\tcase O_IP6_DST:\n\t\tcase O_IP6_DST_MASK:\n\t\tcase O_IP6_DST_ME:\n\t\t\tshow_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);\n\t\t\tif (!(flags & HAVE_DSTIP))\n\t\t\t\tprintf(\" to\");\n\t\t\tif ((cmd->len & F_OR) && !or_block)\n\t\t\t\tprintf(\" {\");\n\t\t\tprint_ip6((ipfw_insn_ip6 *)cmd,\n\t\t\t    (flags & HAVE_OPTIONS) ? \" dst-ip6\" : \"\");\n\t\t\tflags |= HAVE_DSTIP;\n\t\t\tbreak;\n\n\t\tcase O_FLOW6ID:\n\t\tprint_flow6id( (ipfw_insn_u32 *) cmd );\n\t\tflags |= HAVE_OPTIONS;\n\t\tbreak;\n\n\t\tcase O_IP_DSTPORT:\n\t\t\tshow_prerequisites(&flags,\n\t\t\t\tHAVE_PROTO | HAVE_SRCIP |\n\t\t\t\tHAVE_DSTIP | HAVE_IP, 0);\n\t\tcase O_IP_SRCPORT:\n\t\t\tif (flags & HAVE_DSTIP)\n\t\t\t\tflags |= HAVE_IP;\n\t\t\tshow_prerequisites(&flags,\n\t\t\t\tHAVE_PROTO | HAVE_SRCIP, 0);\n\t\t\tif ((cmd->len & F_OR) && !or_block)\n\t\t\t\tprintf(\" {\");\n\t\t\tif (cmd->len & F_NOT)\n\t\t\t\tprintf(\" not\");\n\t\t\tprint_newports((ipfw_insn_u16 *)cmd, proto,\n\t\t\t\t(flags & HAVE_OPTIONS) ? cmd->opcode : 0);\n\t\t\tbreak;\n\n\t\tcase O_PROTO: {\n\t\t\tstruct protoent *pe = NULL;\n\n\t\t\tif ((cmd->len & F_OR) && !or_block)\n\t\t\t\tprintf(\" {\");\n\t\t\tif (cmd->len & F_NOT)\n\t\t\t\tprintf(\" not\");\n\t\t\tproto = cmd->arg1;\n\t\t\tpe = getprotobynumber(cmd->arg1);\n\t\t\tif ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) &&\n\t\t\t    !(flags & HAVE_PROTO))\n\t\t\t\tshow_prerequisites(&flags,\n\t\t\t\t    HAVE_PROTO | HAVE_IP | HAVE_SRCIP |\n\t\t\t\t    HAVE_DSTIP | HAVE_OPTIONS, 0);\n\t\t\tif (flags & HAVE_OPTIONS)\n\t\t\t\tprintf(\" proto\");\n\t\t\tif (pe)\n\t\t\t\tprintf(\" %s\", pe->p_name);\n\t\t\telse\n\t\t\t\tprintf(\" %u\", cmd->arg1);\n\t\t\t}\n\t\t\tflags |= HAVE_PROTO;\n\t\t\tbreak;\n\n\t\tdefault: /*options ... */\n\t\t\tif (!(cmd->len & (F_OR|F_NOT)))\n\t\t\t\tif (((cmd->opcode == O_IP6) &&\n\t\t\t\t    (flags & HAVE_PROTO6)) ||\n\t\t\t\t    ((cmd->opcode == O_IP4) &&\n\t\t\t\t    (flags & HAVE_PROTO4)))\n\t\t\t\t\tbreak;\n\t\t\tshow_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP |\n\t\t\t\t    HAVE_DSTIP | HAVE_IP | HAVE_OPTIONS, 0);\n\t\t\tif ((cmd->len & F_OR) && !or_block)\n\t\t\t\tprintf(\" {\");\n\t\t\tif (cmd->len & F_NOT && cmd->opcode != O_IN)\n\t\t\t\tprintf(\" not\");\n\t\t\tswitch(cmd->opcode) {\n\t\t\tcase O_MACADDR2: {\n\t\t\t\tipfw_insn_mac *m = (ipfw_insn_mac *)cmd;\n\n\t\t\t\tprintf(\" MAC\");\n\t\t\t\tprint_mac(m->addr, m->mask);\n\t\t\t\tprint_mac(m->addr + 6, m->mask + 6);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_MAC_TYPE:\n\t\t\t\tprint_newports((ipfw_insn_u16 *)cmd,\n\t\t\t\t\t\tIPPROTO_ETHERTYPE, cmd->opcode);\n\t\t\t\tbreak;\n\n\n\t\t\tcase O_FRAG:\n\t\t\t\tprintf(\" frag\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_FIB:\n\t\t\t\tprintf(\" fib %u\", cmd->arg1 );\n\t\t\t\tbreak;\n\t\t\tcase O_SOCKARG:\n\t\t\t\tprintf(\" sockarg\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_IN:\n\t\t\t\tprintf(cmd->len & F_NOT ? \" out\" : \" in\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_DIVERTED:\n\t\t\t\tswitch (cmd->arg1) {\n\t\t\t\tcase 3:\n\t\t\t\t\tprintf(\" diverted\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tprintf(\" diverted-loopback\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tprintf(\" diverted-output\");\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tprintf(\" diverted-?<%u>\", cmd->arg1);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_LAYER2:\n\t\t\t\tprintf(\" layer2\");\n\t\t\t\tbreak;\n\t\t\tcase O_XMIT:\n\t\t\tcase O_RECV:\n\t\t\tcase O_VIA:\n\t\t\t    {\n\t\t\t\tchar const *s;\n\t\t\t\tipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;\n\n\t\t\t\tif (cmd->opcode == O_XMIT)\n\t\t\t\t\ts = \"xmit\";\n\t\t\t\telse if (cmd->opcode == O_RECV)\n\t\t\t\t\ts = \"recv\";\n\t\t\t\telse /* if (cmd->opcode == O_VIA) */\n\t\t\t\t\ts = \"via\";\n\t\t\t\tif (cmdif->name[0] == '\\0')\n\t\t\t\t\tprintf(\" %s %s\", s,\n\t\t\t\t\t    inet_ntoa(cmdif->p.ip));\n\t\t\t\telse\n\t\t\t\t\tprintf(\" %s %s\", s, cmdif->name);\n\n\t\t\t\tbreak;\n\t\t\t    }\n\t\t\tcase O_IPID:\n\t\t\t\tif (F_LEN(cmd) == 1)\n\t\t\t\t    printf(\" ipid %u\", cmd->arg1 );\n\t\t\t\telse\n\t\t\t\t    print_newports((ipfw_insn_u16 *)cmd, 0,\n\t\t\t\t\tO_IPID);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPTTL:\n\t\t\t\tif (F_LEN(cmd) == 1)\n\t\t\t\t    printf(\" ipttl %u\", cmd->arg1 );\n\t\t\t\telse\n\t\t\t\t    print_newports((ipfw_insn_u16 *)cmd, 0,\n\t\t\t\t\tO_IPTTL);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPVER:\n\t\t\t\tprintf(\" ipver %u\", cmd->arg1 );\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPPRECEDENCE:\n\t\t\t\tprintf(\" ipprecedence %u\", (cmd->arg1) >> 5 );\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPLEN:\n\t\t\t\tif (F_LEN(cmd) == 1)\n\t\t\t\t    printf(\" iplen %u\", cmd->arg1 );\n\t\t\t\telse\n\t\t\t\t    print_newports((ipfw_insn_u16 *)cmd, 0,\n\t\t\t\t\tO_IPLEN);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPOPT:\n\t\t\t\tprint_flags(\"ipoptions\", cmd, f_ipopts);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPTOS:\n\t\t\t\tprint_flags(\"iptos\", cmd, f_iptos);\n\t\t\t\tbreak;\n\n\t\t\tcase O_ICMPTYPE:\n\t\t\t\tprint_icmptypes((ipfw_insn_u32 *)cmd);\n\t\t\t\tbreak;\n\n\t\t\tcase O_ESTAB:\n\t\t\t\tprintf(\" established\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPDATALEN:\n\t\t\t\tif (F_LEN(cmd) == 1)\n\t\t\t\t    printf(\" tcpdatalen %u\", cmd->arg1 );\n\t\t\t\telse\n\t\t\t\t    print_newports((ipfw_insn_u16 *)cmd, 0,\n\t\t\t\t\tO_TCPDATALEN);\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPFLAGS:\n\t\t\t\tprint_flags(\"tcpflags\", cmd, f_tcpflags);\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPOPTS:\n\t\t\t\tprint_flags(\"tcpoptions\", cmd, f_tcpopts);\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPWIN:\n\t\t\t\tprintf(\" tcpwin %d\", ntohs(cmd->arg1));\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPACK:\n\t\t\t\tprintf(\" tcpack %d\", ntohl(cmd32->d[0]));\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPSEQ:\n\t\t\t\tprintf(\" tcpseq %d\", ntohl(cmd32->d[0]));\n\t\t\t\tbreak;\n\n\t\t\tcase O_UID:\n\t\t\t    {\n\t\t\t\tstruct passwd *pwd = getpwuid(cmd32->d[0]);\n\n\t\t\t\tif (pwd)\n\t\t\t\t\tprintf(\" uid %s\", pwd->pw_name);\n\t\t\t\telse\n\t\t\t\t\tprintf(\" uid %u\", cmd32->d[0]);\n\t\t\t    }\n\t\t\t\tbreak;\n\n\t\t\tcase O_GID:\n\t\t\t    {\n\t\t\t\tstruct group *grp = getgrgid(cmd32->d[0]);\n\n\t\t\t\tif (grp)\n\t\t\t\t\tprintf(\" gid %s\", grp->gr_name);\n\t\t\t\telse\n\t\t\t\t\tprintf(\" gid %u\", cmd32->d[0]);\n\t\t\t    }\n\t\t\t\tbreak;\n\n\t\t\tcase O_JAIL:\n\t\t\t\tprintf(\" jail %d\", cmd32->d[0]);\n\t\t\t\tbreak;\n\n\t\t\tcase O_VERREVPATH:\n\t\t\t\tprintf(\" verrevpath\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_VERSRCREACH:\n\t\t\t\tprintf(\" versrcreach\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_ANTISPOOF:\n\t\t\t\tprintf(\" antispoof\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPSEC:\n\t\t\t\tprintf(\" ipsec\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_NOP:\n\t\t\t\tcomment = (char *)(cmd + 1);\n\t\t\t\tbreak;\n\n\t\t\tcase O_KEEP_STATE:\n\t\t\t\tprintf(\" keep-state\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_LIMIT: {\n\t\t\t\tstruct _s_x *p = limit_masks;\n\t\t\t\tipfw_insn_limit *c = (ipfw_insn_limit *)cmd;\n\t\t\t\tuint8_t x = c->limit_mask;\n\t\t\t\tchar const *comma = \" \";\n\n\t\t\t\tprintf(\" limit\");\n\t\t\t\tfor (; p->x != 0 ; p++)\n\t\t\t\t\tif ((x & p->x) == p->x) {\n\t\t\t\t\t\tx &= ~p->x;\n\t\t\t\t\t\tprintf(\"%s%s\", comma, p->s);\n\t\t\t\t\t\tcomma = \",\";\n\t\t\t\t\t}\n\t\t\t\tPRINT_UINT_ARG(\" \", c->conn_limit);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase O_IP6:\n\t\t\t\tprintf(\" ip6\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP4:\n\t\t\t\tprintf(\" ip4\");\n\t\t\t\tbreak;\n\n\t\t\tcase O_ICMP6TYPE:\n\t\t\t\tprint_icmp6types((ipfw_insn_u32 *)cmd);\n\t\t\t\tbreak;\n\n\t\t\tcase O_EXT_HDR:\n\t\t\t\tprint_ext6hdr( (ipfw_insn *) cmd );\n\t\t\t\tbreak;\n\n\t\t\tcase O_TAGGED:\n\t\t\t\tif (F_LEN(cmd) == 1)\n\t\t\t\t\tPRINT_UINT_ARG(\" tagged \", cmd->arg1);\n\t\t\t\telse\n\t\t\t\t\tprint_newports((ipfw_insn_u16 *)cmd, 0,\n\t\t\t\t\t    O_TAGGED);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tprintf(\" [opcode %d len %d]\",\n\t\t\t\t    cmd->opcode, cmd->len);\n\t\t\t}\n\t\t}\n\t\tif (cmd->len & F_OR) {\n\t\t\tprintf(\" or\");\n\t\t\tor_block = 1;\n\t\t} else if (or_block) {\n\t\t\tprintf(\" }\");\n\t\t\tor_block = 0;\n\t\t}\n\t}\n\tshow_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP\n\t\t\t\t\t      | HAVE_IP, 0);\n\tif (comment)\n\t\tprintf(\" // %s\", comment);\n\tprintf(\"\\n\");\n}\n\nstatic void\nshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)\n{\n\tstruct protoent *pe;\n\tstruct in_addr a;\n\tuint16_t rulenum;\n\tchar buf[INET6_ADDRSTRLEN];\n\n\tif (!co.do_expired) {\n\t\tif (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))\n\t\t\treturn;\n\t}\n\tbcopy(&d->rule, &rulenum, sizeof(rulenum));\n\tprintf(\"%05d\", rulenum);\n\tif (pcwidth > 0 || bcwidth > 0) {\n\t\tprintf(\" \");\n\t\tpr_u64(&d->pcnt, pcwidth);\n\t\tpr_u64(&d->bcnt, bcwidth);\n\t\tprintf(\"(%ds)\", d->expire);\n\t}\n\tswitch (d->dyn_type) {\n\tcase O_LIMIT_PARENT:\n\t\tprintf(\" PARENT %d\", d->count);\n\t\tbreak;\n\tcase O_LIMIT:\n\t\tprintf(\" LIMIT\");\n\t\tbreak;\n\tcase O_KEEP_STATE: /* bidir, no mask */\n\t\tprintf(\" STATE\");\n\t\tbreak;\n\t}\n\n\tif ((pe = getprotobynumber(d->id.proto)) != NULL)\n\t\tprintf(\" %s\", pe->p_name);\n\telse\n\t\tprintf(\" proto %u\", d->id.proto);\n\n\tif (d->id.addr_type == 4) {\n\t\ta.s_addr = htonl(d->id.src_ip);\n\t\tprintf(\" %s %d\", inet_ntoa(a), d->id.src_port);\n\n\t\ta.s_addr = htonl(d->id.dst_ip);\n\t\tprintf(\" <-> %s %d\", inet_ntoa(a), d->id.dst_port);\n\t} else if (d->id.addr_type == 6) {\n\t\tprintf(\" %s %d\", inet_ntop(AF_INET6, &d->id.src_ip6, buf,\n\t\t    sizeof(buf)), d->id.src_port);\n\t\tprintf(\" <-> %s %d\", inet_ntop(AF_INET6, &d->id.dst_ip6, buf,\n\t\t    sizeof(buf)), d->id.dst_port);\n\t} else\n\t\tprintf(\" UNKNOWN <-> UNKNOWN\\n\");\n\n\tprintf(\"\\n\");\n}\n\n/*\n * This one handles all set-related commands\n * \tipfw set { show | enable | disable }\n * \tipfw set swap X Y\n * \tipfw set move X to Y\n * \tipfw set move rule X to Y\n */\nvoid\nipfw_sets_handler(char *av[])\n{\n\tuint32_t set_disable, masks[2];\n\tint i, nbytes;\n\tuint16_t rulenum;\n\tuint8_t cmd, new_set;\n\n\tav++;\n\n\tif (av[0] == NULL)\n\t\terrx(EX_USAGE, \"set needs command\");\n\tif (_substrcmp(*av, \"show\") == 0) {\n\t\tvoid *data = NULL;\n\t\tchar const *msg;\n\t\tint nalloc;\n\n\t\tnalloc = nbytes = sizeof(struct ip_fw);\n\t\twhile (nbytes >= nalloc) {\n\t\t\tif (data)\n\t\t\t\tfree(data);\n\t\t\tnalloc = nalloc * 2 + 200;\n\t\t\tnbytes = nalloc;\n\t\t\tdata = safe_calloc(1, nbytes);\n\t\t\tif (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0)\n\t\t\t\terr(EX_OSERR, \"getsockopt(IP_FW_GET)\");\n\t\t}\n\n\t\tbcopy(&((struct ip_fw *)data)->next_rule,\n\t\t\t&set_disable, sizeof(set_disable));\n\n\t\tfor (i = 0, msg = \"disable\" ; i < RESVD_SET; i++)\n\t\t\tif ((set_disable & (1<<i))) {\n\t\t\t\tprintf(\"%s %d\", msg, i);\n\t\t\t\tmsg = \"\";\n\t\t\t}\n\t\tmsg = (set_disable) ? \" enable\" : \"enable\";\n\t\tfor (i = 0; i < RESVD_SET; i++)\n\t\t\tif (!(set_disable & (1<<i))) {\n\t\t\t\tprintf(\"%s %d\", msg, i);\n\t\t\t\tmsg = \"\";\n\t\t\t}\n\t\tprintf(\"\\n\");\n\t} else if (_substrcmp(*av, \"swap\") == 0) {\n\t\tav++;\n\t\tif ( av[0] == NULL || av[1] == NULL )\n\t\t\terrx(EX_USAGE, \"set swap needs 2 set numbers\\n\");\n\t\trulenum = atoi(av[0]);\n\t\tnew_set = atoi(av[1]);\n\t\tif (!isdigit(*(av[0])) || rulenum > RESVD_SET)\n\t\t\terrx(EX_DATAERR, \"invalid set number %s\\n\", av[0]);\n\t\tif (!isdigit(*(av[1])) || new_set > RESVD_SET)\n\t\t\terrx(EX_DATAERR, \"invalid set number %s\\n\", av[1]);\n\t\tmasks[0] = (4 << 24) | (new_set << 16) | (rulenum);\n\t\ti = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));\n\t} else if (_substrcmp(*av, \"move\") == 0) {\n\t\tav++;\n\t\tif (av[0] && _substrcmp(*av, \"rule\") == 0) {\n\t\t\tcmd = 2;\n\t\t\tav++;\n\t\t} else\n\t\t\tcmd = 3;\n\t\tif (av[0] == NULL || av[1] == NULL || av[2] == NULL ||\n\t\t\t\tav[3] != NULL ||  _substrcmp(av[1], \"to\") != 0)\n\t\t\terrx(EX_USAGE, \"syntax: set move [rule] X to Y\\n\");\n\t\trulenum = atoi(av[0]);\n\t\tnew_set = atoi(av[2]);\n\t\tif (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) ||\n\t\t\t(cmd == 2 && rulenum == IPFW_DEFAULT_RULE) )\n\t\t\terrx(EX_DATAERR, \"invalid source number %s\\n\", av[0]);\n\t\tif (!isdigit(*(av[2])) || new_set > RESVD_SET)\n\t\t\terrx(EX_DATAERR, \"invalid dest. set %s\\n\", av[1]);\n\t\tmasks[0] = (cmd << 24) | (new_set << 16) | (rulenum);\n\t\ti = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));\n\t} else if (_substrcmp(*av, \"disable\") == 0 ||\n\t\t   _substrcmp(*av, \"enable\") == 0 ) {\n\t\tint which = _substrcmp(*av, \"enable\") == 0 ? 1 : 0;\n\n\t\tav++;\n\t\tmasks[0] = masks[1] = 0;\n\n\t\twhile (av[0]) {\n\t\t\tif (isdigit(**av)) {\n\t\t\t\ti = atoi(*av);\n\t\t\t\tif (i < 0 || i > RESVD_SET)\n\t\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t\t    \"invalid set number %d\\n\", i);\n\t\t\t\tmasks[which] |= (1<<i);\n\t\t\t} else if (_substrcmp(*av, \"disable\") == 0)\n\t\t\t\twhich = 0;\n\t\t\telse if (_substrcmp(*av, \"enable\") == 0)\n\t\t\t\twhich = 1;\n\t\t\telse\n\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t\t\"invalid set command %s\\n\", *av);\n\t\t\tav++;\n\t\t}\n\t\tif ( (masks[0] & masks[1]) != 0 )\n\t\t\terrx(EX_DATAERR,\n\t\t\t    \"cannot enable and disable the same set\\n\");\n\n\t\ti = do_cmd(IP_FW_DEL, masks, sizeof(masks));\n\t\tif (i)\n\t\t\twarn(\"set enable/disable: setsockopt(IP_FW_DEL)\");\n\t} else\n\t\terrx(EX_USAGE, \"invalid set command %s\\n\", *av);\n}\n\nvoid\nipfw_sysctl_handler(char *av[], int which)\n{\n\tav++;\n\n\tif (av[0] == NULL) {\n\t\twarnx(\"missing keyword to enable/disable\\n\");\n\t} else if (_substrcmp(*av, \"firewall\") == 0) {\n\t\tsysctlbyname(\"net.inet.ip.fw.enable\", NULL, 0,\n\t\t    &which, sizeof(which));\n\t\tsysctlbyname(\"net.inet6.ip6.fw.enable\", NULL, 0,\n\t\t    &which, sizeof(which));\n\t} else if (_substrcmp(*av, \"one_pass\") == 0) {\n\t\tsysctlbyname(\"net.inet.ip.fw.one_pass\", NULL, 0,\n\t\t    &which, sizeof(which));\n\t} else if (_substrcmp(*av, \"debug\") == 0) {\n\t\tsysctlbyname(\"net.inet.ip.fw.debug\", NULL, 0,\n\t\t    &which, sizeof(which));\n\t} else if (_substrcmp(*av, \"verbose\") == 0) {\n\t\tsysctlbyname(\"net.inet.ip.fw.verbose\", NULL, 0,\n\t\t    &which, sizeof(which));\n\t} else if (_substrcmp(*av, \"dyn_keepalive\") == 0) {\n\t\tsysctlbyname(\"net.inet.ip.fw.dyn_keepalive\", NULL, 0,\n\t\t    &which, sizeof(which));\n#ifndef NO_ALTQ\n\t} else if (_substrcmp(*av, \"altq\") == 0) {\n\t\taltq_set_enabled(which);\n#endif\n\t} else {\n\t\twarnx(\"unrecognize enable/disable keyword: %s\\n\", *av);\n\t}\n}\n\nvoid\nipfw_list(int ac, char *av[], int show_counters)\n{\n\tstruct ip_fw *r;\n\tipfw_dyn_rule *dynrules, *d;\n\n#define NEXT(r)\t((struct ip_fw *)((char *)r + RULESIZE(r)))\n\tchar *lim;\n\tvoid *data = NULL;\n\tint bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;\n\tint exitval = EX_OK;\n\tint lac;\n\tchar **lav;\n\tu_long rnum, last;\n\tchar *endptr;\n\tint seen = 0;\n\tuint8_t set;\n\n\tconst int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;\n\tint nalloc = 1024;\t/* start somewhere... */\n\n\tlast = 0;\n\n\tif (co.test_only) {\n\t\tfprintf(stderr, \"Testing only, list disabled\\n\");\n\t\treturn;\n\t}\n\tif (co.do_pipe) {\n\t\tdummynet_list(ac, av, show_counters);\n\t\treturn;\n\t}\n\n\tac--;\n\tav++;\n\n\t/* get rules or pipes from kernel, resizing array as necessary */\n\tnbytes = nalloc;\n\n\twhile (nbytes >= nalloc) {\n\t\tnalloc = nalloc * 2 + 200;\n\t\tnbytes = nalloc;\n\t\tdata = safe_realloc(data, nbytes);\n\t\tif (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0)\n\t\t\terr(EX_OSERR, \"getsockopt(IP_%s_GET)\",\n\t\t\t\tco.do_pipe ? \"DUMMYNET\" : \"FW\");\n\t}\n\n\t/*\n\t * Count static rules. They have variable size so we\n\t * need to scan the list to count them.\n\t */\n\tfor (nstat = 1, r = data, lim = (char *)data + nbytes;\n\t\t    r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim;\n\t\t    ++nstat, r = NEXT(r) )\n\t\t; /* nothing */\n\n\t/*\n\t * Count dynamic rules. This is easier as they have\n\t * fixed size.\n\t */\n\tr = NEXT(r);\n\tdynrules = (ipfw_dyn_rule *)r ;\n\tn = (char *)r - (char *)data;\n\tndyn = (nbytes - n) / sizeof *dynrules;\n\n\t/* if showing stats, figure out column widths ahead of time */\n\tbcwidth = pcwidth = 0;\n\tif (show_counters) {\n\t\tfor (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {\n\t\t\t/* skip rules from another set */\n\t\t\tif (co.use_set && r->set != co.use_set - 1)\n\t\t\t\tcontinue;\n\n\t\t\t/* packet counter */\n\t\t\twidth = pr_u64(&r->pcnt, 0);\n\t\t\tif (width > pcwidth)\n\t\t\t\tpcwidth = width;\n\n\t\t\t/* byte counter */\n\t\t\twidth = pr_u64(&r->bcnt, 0);\n\t\t\tif (width > bcwidth)\n\t\t\t\tbcwidth = width;\n\t\t}\n\t}\n\tif (co.do_dynamic && ndyn) {\n\t\tfor (n = 0, d = dynrules; n < ndyn; n++, d++) {\n\t\t\tif (co.use_set) {\n\t\t\t\t/* skip rules from another set */\n\t\t\t\tbcopy((char *)&d->rule + sizeof(uint16_t),\n\t\t\t\t      &set, sizeof(uint8_t));\n\t\t\t\tif (set != co.use_set - 1)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\twidth = pr_u64(&d->pcnt, 0);\n\t\t\tif (width > pcwidth)\n\t\t\t\tpcwidth = width;\n\n\t\t\twidth = pr_u64(&d->bcnt, 0);\n\t\t\tif (width > bcwidth)\n\t\t\t\tbcwidth = width;\n\t\t}\n\t}\n\t/* if no rule numbers were specified, list all rules */\n\tif (ac == 0) {\n\t\tfor (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {\n\t\t\tif (co.use_set && r->set != co.use_set - 1)\n\t\t\t\tcontinue;\n\t\t\tshow_ipfw(r, pcwidth, bcwidth);\n\t\t}\n\n\t\tif (co.do_dynamic && ndyn) {\n\t\t\tprintf(\"## Dynamic rules (%d):\\n\", ndyn);\n\t\t\tfor (n = 0, d = dynrules; n < ndyn; n++, d++) {\n\t\t\t\tif (co.use_set) {\n\t\t\t\t\tbcopy((char *)&d->rule + sizeof(uint16_t),\n\t\t\t\t\t      &set, sizeof(uint8_t));\n\t\t\t\t\tif (set != co.use_set - 1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tshow_dyn_ipfw(d, pcwidth, bcwidth);\n\t\t}\n\t\t}\n\t\tgoto done;\n\t}\n\n\t/* display specific rules requested on command line */\n\n\tfor (lac = ac, lav = av; lac != 0; lac--) {\n\t\t/* convert command line rule # */\n\t\tlast = rnum = strtoul(*lav++, &endptr, 10);\n\t\tif (*endptr == '-')\n\t\t\tlast = strtoul(endptr+1, &endptr, 10);\n\t\tif (*endptr) {\n\t\t\texitval = EX_USAGE;\n\t\t\twarnx(\"invalid rule number: %s\", *(lav - 1));\n\t\t\tcontinue;\n\t\t}\n\t\tfor (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) {\n\t\t\tif (r->rulenum > last)\n\t\t\t\tbreak;\n\t\t\tif (co.use_set && r->set != co.use_set - 1)\n\t\t\t\tcontinue;\n\t\t\tif (r->rulenum >= rnum && r->rulenum <= last) {\n\t\t\t\tshow_ipfw(r, pcwidth, bcwidth);\n\t\t\t\tseen = 1;\n\t\t\t}\n\t\t}\n\t\tif (!seen) {\n\t\t\t/* give precedence to other error(s) */\n\t\t\tif (exitval == EX_OK)\n\t\t\t\texitval = EX_UNAVAILABLE;\n\t\t\twarnx(\"rule %lu does not exist\", rnum);\n\t\t}\n\t}\n\n\tif (co.do_dynamic && ndyn) {\n\t\tprintf(\"## Dynamic rules:\\n\");\n\t\tfor (lac = ac, lav = av; lac != 0; lac--) {\n\t\t\tlast = rnum = strtoul(*lav++, &endptr, 10);\n\t\t\tif (*endptr == '-')\n\t\t\t\tlast = strtoul(endptr+1, &endptr, 10);\n\t\t\tif (*endptr)\n\t\t\t\t/* already warned */\n\t\t\t\tcontinue;\n\t\t\tfor (n = 0, d = dynrules; n < ndyn; n++, d++) {\n\t\t\t\tuint16_t rulenum;\n\n\t\t\t\tbcopy(&d->rule, &rulenum, sizeof(rulenum));\n\t\t\t\tif (rulenum > rnum)\n\t\t\t\t\tbreak;\n\t\t\t\tif (co.use_set) {\n\t\t\t\t\tbcopy((char *)&d->rule + sizeof(uint16_t),\n\t\t\t\t\t      &set, sizeof(uint8_t));\n\t\t\t\t\tif (set != co.use_set - 1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (r->rulenum >= rnum && r->rulenum <= last)\n\t\t\t\t\tshow_dyn_ipfw(d, pcwidth, bcwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tac = 0;\n\ndone:\n\tfree(data);\n\n\tif (exitval != EX_OK)\n\t\texit(exitval);\n#undef NEXT\n}\n\nstatic int\nlookup_host (char *host, struct in_addr *ipaddr)\n{\n\tstruct hostent *he;\n\n\tif (!inet_aton(host, ipaddr)) {\n\t\tif ((he = gethostbyname(host)) == NULL)\n\t\t\treturn(-1);\n\t\t*ipaddr = *(struct in_addr *)he->h_addr_list[0];\n\t}\n\treturn(0);\n}\n\n/*\n * fills the addr and mask fields in the instruction as appropriate from av.\n * Update length as appropriate.\n * The following formats are allowed:\n *\tme\treturns O_IP_*_ME\n *\t1.2.3.4\t\tsingle IP address\n *\t1.2.3.4:5.6.7.8\taddress:mask\n *\t1.2.3.4/24\taddress/mask\n *\t1.2.3.4/26{1,6,5,4,23}\tset of addresses in a subnet\n * We can have multiple comma-separated address/mask entries.\n */\nstatic void\nfill_ip(ipfw_insn_ip *cmd, char *av)\n{\n\tint len = 0;\n\tuint32_t *d = ((ipfw_insn_u32 *)cmd)->d;\n\n\tcmd->o.len &= ~F_LEN_MASK;\t/* zero len */\n\n\tif (_substrcmp(av, \"any\") == 0)\n\t\treturn;\n\n\tif (_substrcmp(av, \"me\") == 0) {\n\t\tcmd->o.len |= F_INSN_SIZE(ipfw_insn);\n\t\treturn;\n\t}\n\n\tif (strncmp(av, \"table(\", 6) == 0) {\n\t\tchar *p = strchr(av + 6, ',');\n\n\t\tif (p)\n\t\t\t*p++ = '\\0';\n\t\tcmd->o.opcode = O_IP_DST_LOOKUP;\n\t\tcmd->o.arg1 = strtoul(av + 6, NULL, 0);\n\t\tif (p) {\n\t\t\tcmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);\n\t\t\td[0] = strtoul(p, NULL, 0);\n\t\t} else\n\t\t\tcmd->o.len |= F_INSN_SIZE(ipfw_insn);\n\t\treturn;\n\t}\n\n    while (av) {\n\t/*\n\t * After the address we can have '/' or ':' indicating a mask,\n\t * ',' indicating another address follows, '{' indicating a\n\t * set of addresses of unspecified size.\n\t */\n\tchar *t = NULL, *p = strpbrk(av, \"/:,{\");\n\tint masklen;\n\tchar md, nd = '\\0';\n\n\tif (p) {\n\t\tmd = *p;\n\t\t*p++ = '\\0';\n\t\tif ((t = strpbrk(p, \",{\")) != NULL) {\n\t\t\tnd = *t;\n\t\t\t*t = '\\0';\n\t\t}\n\t} else\n\t\tmd = '\\0';\n\n\tif (lookup_host(av, (struct in_addr *)&d[0]) != 0)\n\t\terrx(EX_NOHOST, \"hostname ``%s'' unknown\", av);\n\tswitch (md) {\n\tcase ':':\n\t\tif (!inet_aton(p, (struct in_addr *)&d[1]))\n\t\t\terrx(EX_DATAERR, \"bad netmask ``%s''\", p);\n\t\tbreak;\n\tcase '/':\n\t\tmasklen = atoi(p);\n\t\tif (masklen == 0)\n\t\t\td[1] = htonl(0);\t/* mask */\n\t\telse if (masklen > 32)\n\t\t\terrx(EX_DATAERR, \"bad width ``%s''\", p);\n\t\telse\n\t\t\td[1] = htonl(~0 << (32 - masklen));\n\t\tbreak;\n\tcase '{':\t/* no mask, assume /24 and put back the '{' */\n\t\td[1] = htonl(~0 << (32 - 24));\n\t\t*(--p) = md;\n\t\tbreak;\n\n\tcase ',':\t/* single address plus continuation */\n\t\t*(--p) = md;\n\t\t/* FALLTHROUGH */\n\tcase 0:\t\t/* initialization value */\n\tdefault:\n\t\td[1] = htonl(~0);\t/* force /32 */\n\t\tbreak;\n\t}\n\td[0] &= d[1];\t\t/* mask base address with mask */\n\tif (t)\n\t\t*t = nd;\n\t/* find next separator */\n\tif (p)\n\t\tp = strpbrk(p, \",{\");\n\tif (p && *p == '{') {\n\t\t/*\n\t\t * We have a set of addresses. They are stored as follows:\n\t\t *   arg1\tis the set size (powers of 2, 2..256)\n\t\t *   addr\tis the base address IN HOST FORMAT\n\t\t *   mask..\tis an array of arg1 bits (rounded up to\n\t\t *\t\tthe next multiple of 32) with bits set\n\t\t *\t\tfor each host in the map.\n\t\t */\n\t\tuint32_t *map = (uint32_t *)&cmd->mask;\n\t\tint low, high;\n\t\tint i = contigmask((uint8_t *)&(d[1]), 32);\n\n\t\tif (len > 0)\n\t\t\terrx(EX_DATAERR, \"address set cannot be in a list\");\n\t\tif (i < 24 || i > 31)\n\t\t\terrx(EX_DATAERR, \"invalid set with mask %d\\n\", i);\n\t\tcmd->o.arg1 = 1<<(32-i);\t/* map length\t\t*/\n\t\td[0] = ntohl(d[0]);\t\t/* base addr in host format */\n\t\tcmd->o.opcode = O_IP_DST_SET;\t/* default */\n\t\tcmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32;\n\t\tfor (i = 0; i < (cmd->o.arg1+31)/32 ; i++)\n\t\t\tmap[i] = 0;\t/* clear map */\n\n\t\tav = p + 1;\n\t\tlow = d[0] & 0xff;\n\t\thigh = low + cmd->o.arg1 - 1;\n\t\t/*\n\t\t * Here, i stores the previous value when we specify a range\n\t\t * of addresses within a mask, e.g. 45-63. i = -1 means we\n\t\t * have no previous value.\n\t\t */\n\t\ti = -1;\t/* previous value in a range */\n\t\twhile (isdigit(*av)) {\n\t\t\tchar *s;\n\t\t\tint a = strtol(av, &s, 0);\n\n\t\t\tif (s == av) { /* no parameter */\n\t\t\t    if (*av != '}')\n\t\t\t\terrx(EX_DATAERR, \"set not closed\\n\");\n\t\t\t    if (i != -1)\n\t\t\t\terrx(EX_DATAERR, \"incomplete range %d-\", i);\n\t\t\t    break;\n\t\t\t}\n\t\t\tif (a < low || a > high)\n\t\t\t    errx(EX_DATAERR, \"addr %d out of range [%d-%d]\\n\",\n\t\t\t\ta, low, high);\n\t\t\ta -= low;\n\t\t\tif (i == -1)\t/* no previous in range */\n\t\t\t    i = a;\n\t\t\telse {\t\t/* check that range is valid */\n\t\t\t    if (i > a)\n\t\t\t\terrx(EX_DATAERR, \"invalid range %d-%d\",\n\t\t\t\t\ti+low, a+low);\n\t\t\t    if (*s == '-')\n\t\t\t\terrx(EX_DATAERR, \"double '-' in range\");\n\t\t\t}\n\t\t\tfor (; i <= a; i++)\n\t\t\t    map[i/32] |= 1<<(i & 31);\n\t\t\ti = -1;\n\t\t\tif (*s == '-')\n\t\t\t    i = a;\n\t\t\telse if (*s == '}')\n\t\t\t    break;\n\t\t\tav = s+1;\n\t\t}\n\t\treturn;\n\t}\n\tav = p;\n\tif (av)\t\t\t/* then *av must be a ',' */\n\t\tav++;\n\n\t/* Check this entry */\n\tif (d[1] == 0) { /* \"any\", specified as x.x.x.x/0 */\n\t\t/*\n\t\t * 'any' turns the entire list into a NOP.\n\t\t * 'not any' never matches, so it is removed from the\n\t\t * list unless it is the only item, in which case we\n\t\t * report an error.\n\t\t */\n\t\tif (cmd->o.len & F_NOT) {\t/* \"not any\" never matches */\n\t\t\tif (av == NULL && len == 0) /* only this entry */\n\t\t\t\terrx(EX_DATAERR, \"not any never matches\");\n\t\t}\n\t\t/* else do nothing and skip this entry */\n\t\treturn;\n\t}\n\t/* A single IP can be stored in an optimized format */\n\tif (d[1] == (uint32_t)~0 && av == NULL && len == 0) {\n\t\tcmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);\n\t\treturn;\n\t}\n\tlen += 2;\t/* two words... */\n\td += 2;\n    } /* end while */\n    if (len + 1 > F_LEN_MASK)\n\terrx(EX_DATAERR, \"address list too long\");\n    cmd->o.len |= len+1;\n}\n\n\n/* n2mask sets n bits of the mask */\nvoid\nn2mask(struct in6_addr *mask, int n)\n{\n\tstatic int\tminimask[9] =\n\t    { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };\n\tu_char\t\t*p;\n\n\tmemset(mask, 0, sizeof(struct in6_addr));\n\tp = (u_char *) mask;\n\tfor (; n > 0; p++, n -= 8) {\n\t\tif (n >= 8)\n\t\t\t*p = 0xff;\n\t\telse\n\t\t\t*p = minimask[n];\n\t}\n\treturn;\n}\n\n/*\n * helper function to process a set of flags and set bits in the\n * appropriate masks.\n */\nstatic void\nfill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,\n\tstruct _s_x *flags, char *p)\n{\n\tuint8_t set=0, clear=0;\n\n\twhile (p && *p) {\n\t\tchar *q;\t/* points to the separator */\n\t\tint val;\n\t\tuint8_t *which;\t/* mask we are working on */\n\n\t\tif (*p == '!') {\n\t\t\tp++;\n\t\t\twhich = &clear;\n\t\t} else\n\t\t\twhich = &set;\n\t\tq = strchr(p, ',');\n\t\tif (q)\n\t\t\t*q++ = '\\0';\n\t\tval = match_token(flags, p);\n\t\tif (val <= 0)\n\t\t\terrx(EX_DATAERR, \"invalid flag %s\", p);\n\t\t*which |= (uint8_t)val;\n\t\tp = q;\n\t}\n\tcmd->opcode = opcode;\n\tcmd->len =  (cmd->len & (F_NOT | F_OR)) | 1;\n\tcmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8);\n}\n\n\nvoid\nipfw_delete(char *av[])\n{\n\tuint32_t rulenum;\n\tint i;\n\tint exitval = EX_OK;\n\tint do_set = 0;\n\n\tav++;\n\tNEED1(\"missing rule specification\");\n\tif ( *av && _substrcmp(*av, \"set\") == 0) {\n\t\t/* Do not allow using the following syntax:\n\t\t *\tipfw set N delete set M\n\t\t */\n\t\tif (co.use_set)\n\t\t\terrx(EX_DATAERR, \"invalid syntax\");\n\t\tdo_set = 1;\t/* delete set */\n\t\tav++;\n\t}\n\n\t/* Rule number */\n\twhile (*av && isdigit(**av)) {\n\t\ti = atoi(*av); av++;\n\t\tif (co.do_nat) {\n\t\t\texitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i);\n\t\t\tif (exitval) {\n\t\t\t\texitval = EX_UNAVAILABLE;\n\t\t\t\twarn(\"rule %u not available\", i);\n\t\t\t}\n\t\t} else if (co.do_pipe) {\n\t\t\texitval = ipfw_delete_pipe(co.do_pipe, i);\n\t\t} else {\n\t\t\tif (co.use_set)\n\t\t\t\trulenum = (i & 0xffff) | (5 << 24) |\n\t\t\t\t    ((co.use_set - 1) << 16);\n\t\t\telse\n\t\t\trulenum =  (i & 0xffff) | (do_set << 24);\n\t\t\ti = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum);\n\t\t\tif (i) {\n\t\t\t\texitval = EX_UNAVAILABLE;\n\t\t\t\twarn(\"rule %u: setsockopt(IP_FW_DEL)\",\n\t\t\t\t    rulenum);\n\t\t\t}\n\t\t}\n\t}\n\tif (exitval != EX_OK)\n\t\texit(exitval);\n}\n\n\n/*\n * fill the interface structure. We do not check the name as we can\n * create interfaces dynamically, so checking them at insert time\n * makes relatively little sense.\n * Interface names containing '*', '?', or '[' are assumed to be shell\n * patterns which match interfaces.\n */\nstatic void\nfill_iface(ipfw_insn_if *cmd, char *arg)\n{\n\tcmd->name[0] = '\\0';\n\tcmd->o.len |= F_INSN_SIZE(ipfw_insn_if);\n\n\t/* Parse the interface or address */\n\tif (strcmp(arg, \"any\") == 0)\n\t\tcmd->o.len = 0;\t\t/* effectively ignore this command */\n\telse if (!isdigit(*arg)) {\n\t\tstrlcpy(cmd->name, arg, sizeof(cmd->name));\n\t\tcmd->p.glob = strpbrk(arg, \"*?[\") != NULL ? 1 : 0;\n\t} else if (!inet_aton(arg, &cmd->p.ip))\n\t\terrx(EX_DATAERR, \"bad ip address ``%s''\", arg);\n}\n\nstatic void\nget_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask)\n{\n\tint i;\n\tsize_t l;\n\tchar *ap, *ptr, *optr;\n\tstruct ether_addr *mac;\n\tconst char *macset = \"0123456789abcdefABCDEF:\";\n\n\tif (strcmp(p, \"any\") == 0) {\n\t\tfor (i = 0; i < ETHER_ADDR_LEN; i++)\n\t\t\taddr[i] = mask[i] = 0;\n\t\treturn;\n\t}\n\n\toptr = ptr = strdup(p);\n\tif ((ap = strsep(&ptr, \"&/\")) != NULL && *ap != 0) {\n\t\tl = strlen(ap);\n\t\tif (strspn(ap, macset) != l || (mac = ether_aton(ap)) == NULL)\n\t\t\terrx(EX_DATAERR, \"Incorrect MAC address\");\n\t\tbcopy(mac, addr, ETHER_ADDR_LEN);\n\t} else\n\t\terrx(EX_DATAERR, \"Incorrect MAC address\");\n\n\tif (ptr != NULL) { /* we have mask? */\n\t\tif (p[ptr - optr - 1] == '/') { /* mask len */\n\t\t\tlong ml = strtol(ptr, &ap, 10);\n\t\t\tif (*ap != 0 || ml > ETHER_ADDR_LEN * 8 || ml < 0)\n\t\t\t\terrx(EX_DATAERR, \"Incorrect mask length\");\n\t\t\tfor (i = 0; ml > 0 && i < ETHER_ADDR_LEN; ml -= 8, i++)\n\t\t\t\tmask[i] = (ml >= 8) ? 0xff: (~0) << (8 - ml);\n\t\t} else { /* mask */\n\t\t\tl = strlen(ptr);\n\t\t\tif (strspn(ptr, macset) != l ||\n\t\t\t    (mac = ether_aton(ptr)) == NULL)\n\t\t\t\terrx(EX_DATAERR, \"Incorrect mask\");\n\t\t\tbcopy(mac, mask, ETHER_ADDR_LEN);\n\t\t}\n\t} else { /* default mask: ff:ff:ff:ff:ff:ff */\n\t\tfor (i = 0; i < ETHER_ADDR_LEN; i++)\n\t\t\tmask[i] = 0xff;\n\t}\n\tfor (i = 0; i < ETHER_ADDR_LEN; i++)\n\t\taddr[i] &= mask[i];\n\n\tfree(optr);\n}\n\n/*\n * helper function, updates the pointer to cmd with the length\n * of the current command, and also cleans up the first word of\n * the new command in case it has been clobbered before.\n */\nstatic ipfw_insn *\nnext_cmd(ipfw_insn *cmd)\n{\n\tcmd += F_LEN(cmd);\n\tbzero(cmd, sizeof(*cmd));\n\treturn cmd;\n}\n\n/*\n * Takes arguments and copies them into a comment\n */\nstatic void\nfill_comment(ipfw_insn *cmd, char **av)\n{\n\tint i, l;\n\tchar *p = (char *)(cmd + 1);\n\n\tcmd->opcode = O_NOP;\n\tcmd->len =  (cmd->len & (F_NOT | F_OR));\n\n\t/* Compute length of comment string. */\n\tfor (i = 0, l = 0; av[i] != NULL; i++)\n\t\tl += strlen(av[i]) + 1;\n\tif (l == 0)\n\t\treturn;\n\tif (l > 84)\n\t\terrx(EX_DATAERR,\n\t\t    \"comment too long (max 80 chars)\");\n\tl = 1 + (l+3)/4;\n\tcmd->len =  (cmd->len & (F_NOT | F_OR)) | l;\n\tfor (i = 0; av[i] != NULL; i++) {\n\t\tstrcpy(p, av[i]);\n\t\tp += strlen(av[i]);\n\t\t*p++ = ' ';\n\t}\n\t*(--p) = '\\0';\n}\n\n/*\n * A function to fill simple commands of size 1.\n * Existing flags are preserved.\n */\nstatic void\nfill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg)\n{\n\tcmd->opcode = opcode;\n\tcmd->len =  ((cmd->len | flags) & (F_NOT | F_OR)) | 1;\n\tcmd->arg1 = arg;\n}\n\n/*\n * Fetch and add the MAC address and type, with masks. This generates one or\n * two microinstructions, and returns the pointer to the last one.\n */\nstatic ipfw_insn *\nadd_mac(ipfw_insn *cmd, char *av[])\n{\n\tipfw_insn_mac *mac;\n\n\tif ( ( av[0] == NULL ) || ( av[1] == NULL ) )\n\t\terrx(EX_DATAERR, \"MAC dst src\");\n\n\tcmd->opcode = O_MACADDR2;\n\tcmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);\n\n\tmac = (ipfw_insn_mac *)cmd;\n\tget_mac_addr_mask(av[0], mac->addr, mac->mask);\t/* dst */\n\tget_mac_addr_mask(av[1], &(mac->addr[ETHER_ADDR_LEN]),\n\t    &(mac->mask[ETHER_ADDR_LEN])); /* src */\n\treturn cmd;\n}\n\nstatic ipfw_insn *\nadd_mactype(ipfw_insn *cmd, char *av)\n{\n\tif (!av)\n\t\terrx(EX_DATAERR, \"missing MAC type\");\n\tif (strcmp(av, \"any\") != 0) { /* we have a non-null type */\n\t\tfill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);\n\t\tcmd->opcode = O_MAC_TYPE;\n\t\treturn cmd;\n\t} else\n\t\treturn NULL;\n}\n\nstatic ipfw_insn *\nadd_proto0(ipfw_insn *cmd, char *av, u_char *protop)\n{\n\tstruct protoent *pe;\n\tchar *ep;\n\tint proto;\n\n\tproto = strtol(av, &ep, 10);\n\tif (*ep != '\\0' || proto <= 0) {\n\t\tif ((pe = getprotobyname(av)) == NULL)\n\t\t\treturn NULL;\n\t\tproto = pe->p_proto;\n\t}\n\n\tfill_cmd(cmd, O_PROTO, 0, proto);\n\t*protop = proto;\n\treturn cmd;\n}\n\nstatic ipfw_insn *\nadd_proto(ipfw_insn *cmd, char *av, u_char *protop)\n{\n\tu_char proto = IPPROTO_IP;\n\n\tif (_substrcmp(av, \"all\") == 0 || strcmp(av, \"ip\") == 0)\n\t\t; /* do not set O_IP4 nor O_IP6 */\n\telse if (strcmp(av, \"ip4\") == 0)\n\t\t/* explicit \"just IPv4\" rule */\n\t\tfill_cmd(cmd, O_IP4, 0, 0);\n\telse if (strcmp(av, \"ip6\") == 0) {\n\t\t/* explicit \"just IPv6\" rule */\n\t\tproto = IPPROTO_IPV6;\n\t\tfill_cmd(cmd, O_IP6, 0, 0);\n\t} else\n\t\treturn add_proto0(cmd, av, protop);\n\n\t*protop = proto;\n\treturn cmd;\n}\n\nstatic ipfw_insn *\nadd_proto_compat(ipfw_insn *cmd, char *av, u_char *protop)\n{\n\tu_char proto = IPPROTO_IP;\n\n\tif (_substrcmp(av, \"all\") == 0 || strcmp(av, \"ip\") == 0)\n\t\t; /* do not set O_IP4 nor O_IP6 */\n\telse if (strcmp(av, \"ipv4\") == 0 || strcmp(av, \"ip4\") == 0)\n\t\t/* explicit \"just IPv4\" rule */\n\t\tfill_cmd(cmd, O_IP4, 0, 0);\n\telse if (strcmp(av, \"ipv6\") == 0 || strcmp(av, \"ip6\") == 0) {\n\t\t/* explicit \"just IPv6\" rule */\n\t\tproto = IPPROTO_IPV6;\n\t\tfill_cmd(cmd, O_IP6, 0, 0);\n\t} else\n\t\treturn add_proto0(cmd, av, protop);\n\n\t*protop = proto;\n\treturn cmd;\n}\n\nstatic ipfw_insn *\nadd_srcip(ipfw_insn *cmd, char *av)\n{\n\tfill_ip((ipfw_insn_ip *)cmd, av);\n\tif (cmd->opcode == O_IP_DST_SET)\t\t\t/* set */\n\t\tcmd->opcode = O_IP_SRC_SET;\n\telse if (cmd->opcode == O_IP_DST_LOOKUP)\t\t/* table */\n\t\tcmd->opcode = O_IP_SRC_LOOKUP;\n\telse if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))\t\t/* me */\n\t\tcmd->opcode = O_IP_SRC_ME;\n\telse if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))\t/* one IP */\n\t\tcmd->opcode = O_IP_SRC;\n\telse\t\t\t\t\t\t\t/* addr/mask */\n\t\tcmd->opcode = O_IP_SRC_MASK;\n\treturn cmd;\n}\n\nstatic ipfw_insn *\nadd_dstip(ipfw_insn *cmd, char *av)\n{\n\tfill_ip((ipfw_insn_ip *)cmd, av);\n\tif (cmd->opcode == O_IP_DST_SET)\t\t\t/* set */\n\t\t;\n\telse if (cmd->opcode == O_IP_DST_LOOKUP)\t\t/* table */\n\t\t;\n\telse if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))\t\t/* me */\n\t\tcmd->opcode = O_IP_DST_ME;\n\telse if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))\t/* one IP */\n\t\tcmd->opcode = O_IP_DST;\n\telse\t\t\t\t\t\t\t/* addr/mask */\n\t\tcmd->opcode = O_IP_DST_MASK;\n\treturn cmd;\n}\n\nstatic ipfw_insn *\nadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)\n{\n\t/* XXX \"any\" is trapped before. Perhaps \"to\" */\n\tif (_substrcmp(av, \"any\") == 0) {\n\t\treturn NULL;\n\t} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {\n\t\t/* XXX todo: check that we have a protocol with ports */\n\t\tcmd->opcode = opcode;\n\t\treturn cmd;\n\t}\n\treturn NULL;\n}\n\nstatic ipfw_insn *\nadd_src(ipfw_insn *cmd, char *av, u_char proto)\n{\n\tstruct in6_addr a;\n\tchar *host, *ch;\n\tipfw_insn *ret = NULL;\n\n\tif ((host = strdup(av)) == NULL)\n\t\treturn NULL;\n\tif ((ch = strrchr(host, '/')) != NULL)\n\t\t*ch = '\\0';\n\n\tif (proto == IPPROTO_IPV6  || strcmp(av, \"me6\") == 0 ||\n\t    inet_pton(AF_INET6, host, &a) == 1)\n\t\tret = add_srcip6(cmd, av);\n\t/* XXX: should check for IPv4, not !IPv6 */\n\tif (ret == NULL && (proto == IPPROTO_IP || strcmp(av, \"me\") == 0 ||\n\t    inet_pton(AF_INET6, host, &a) != 1))\n\t\tret = add_srcip(cmd, av);\n\tif (ret == NULL && strcmp(av, \"any\") != 0)\n\t\tret = cmd;\n\n\tfree(host);\n\treturn ret;\n}\n\nstatic ipfw_insn *\nadd_dst(ipfw_insn *cmd, char *av, u_char proto)\n{\n\tstruct in6_addr a;\n\tchar *host, *ch;\n\tipfw_insn *ret = NULL;\n\n\tif ((host = strdup(av)) == NULL)\n\t\treturn NULL;\n\tif ((ch = strrchr(host, '/')) != NULL)\n\t\t*ch = '\\0';\n\n\tif (proto == IPPROTO_IPV6  || strcmp(av, \"me6\") == 0 ||\n\t    inet_pton(AF_INET6, host, &a) == 1)\n\t\tret = add_dstip6(cmd, av);\n\t/* XXX: should check for IPv4, not !IPv6 */\n\tif (ret == NULL && (proto == IPPROTO_IP || strcmp(av, \"me\") == 0 ||\n\t    inet_pton(AF_INET6, host, &a) != 1))\n\t\tret = add_dstip(cmd, av);\n\tif (ret == NULL && strcmp(av, \"any\") != 0)\n\t\tret = cmd;\n\n\tfree(host);\n\treturn ret;\n}\n\n/*\n * Parse arguments and assemble the microinstructions which make up a rule.\n * Rules are added into the 'rulebuf' and then copied in the correct order\n * into the actual rule.\n *\n * The syntax for a rule starts with the action, followed by\n * optional action parameters, and the various match patterns.\n * In the assembled microcode, the first opcode must be an O_PROBE_STATE\n * (generated if the rule includes a keep-state option), then the\n * various match patterns, log/altq actions, and the actual action.\n *\n */\nvoid\nipfw_add(char *av[])\n{\n\t/*\n\t * rules are added into the 'rulebuf' and then copied in\n\t * the correct order into the actual rule.\n\t * Some things that need to go out of order (prob, action etc.)\n\t * go into actbuf[].\n\t */\n\tstatic uint32_t rulebuf[255], actbuf[255], cmdbuf[255];\n\n\tipfw_insn *src, *dst, *cmd, *action, *prev=NULL;\n\tipfw_insn *first_cmd;\t/* first match pattern */\n\n\tstruct ip_fw *rule;\n\n\t/*\n\t * various flags used to record that we entered some fields.\n\t */\n\tipfw_insn *have_state = NULL;\t/* check-state or keep-state */\n\tipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL;\n\tsize_t len;\n\n\tint i;\n\n\tint open_par = 0;\t/* open parenthesis ( */\n\n\t/* proto is here because it is used to fetch ports */\n\tu_char proto = IPPROTO_IP;\t/* default protocol */\n\n\tdouble match_prob = 1; /* match probability, default is always match */\n\n\tbzero(actbuf, sizeof(actbuf));\t\t/* actions go here */\n\tbzero(cmdbuf, sizeof(cmdbuf));\n\tbzero(rulebuf, sizeof(rulebuf));\n\n\trule = (struct ip_fw *)rulebuf;\n\tcmd = (ipfw_insn *)cmdbuf;\n\taction = (ipfw_insn *)actbuf;\n\n\tav++;\n\n\t/* [rule N]\t-- Rule number optional */\n\tif (av[0] && isdigit(**av)) {\n\t\trule->rulenum = atoi(*av);\n\t\tav++;\n\t}\n\n\t/* [set N]\t-- set number (0..RESVD_SET), optional */\n\tif (av[0] && av[1] && _substrcmp(*av, \"set\") == 0) {\n\t\tint set = strtoul(av[1], NULL, 10);\n\t\tif (set < 0 || set > RESVD_SET)\n\t\t\terrx(EX_DATAERR, \"illegal set %s\", av[1]);\n\t\trule->set = set;\n\t\tav += 2;\n\t}\n\n\t/* [prob D]\t-- match probability, optional */\n\tif (av[0] && av[1] && _substrcmp(*av, \"prob\") == 0) {\n\t\tmatch_prob = strtod(av[1], NULL);\n\n\t\tif (match_prob <= 0 || match_prob > 1)\n\t\t\terrx(EX_DATAERR, \"illegal match prob. %s\", av[1]);\n\t\tav += 2;\n\t}\n\n\t/* action\t-- mandatory */\n\tNEED1(\"missing action\");\n\ti = match_token(rule_actions, *av);\n\tav++;\n\taction->len = 1;\t/* default */\n\tswitch(i) {\n\tcase TOK_CHECKSTATE:\n\t\thave_state = action;\n\t\taction->opcode = O_CHECK_STATE;\n\t\tbreak;\n\n\tcase TOK_ACCEPT:\n\t\taction->opcode = O_ACCEPT;\n\t\tbreak;\n\n\tcase TOK_DENY:\n\t\taction->opcode = O_DENY;\n\t\taction->arg1 = 0;\n\t\tbreak;\n\n\tcase TOK_REJECT:\n\t\taction->opcode = O_REJECT;\n\t\taction->arg1 = ICMP_UNREACH_HOST;\n\t\tbreak;\n\n\tcase TOK_RESET:\n\t\taction->opcode = O_REJECT;\n\t\taction->arg1 = ICMP_REJECT_RST;\n\t\tbreak;\n\n\tcase TOK_RESET6:\n\t\taction->opcode = O_UNREACH6;\n\t\taction->arg1 = ICMP6_UNREACH_RST;\n\t\tbreak;\n\n\tcase TOK_UNREACH:\n\t\taction->opcode = O_REJECT;\n\t\tNEED1(\"missing reject code\");\n\t\tfill_reject_code(&action->arg1, *av);\n\t\tav++;\n\t\tbreak;\n\n\tcase TOK_UNREACH6:\n\t\taction->opcode = O_UNREACH6;\n\t\tNEED1(\"missing unreach code\");\n\t\tfill_unreach6_code(&action->arg1, *av);\n\t\tav++;\n\t\tbreak;\n\n\tcase TOK_COUNT:\n\t\taction->opcode = O_COUNT;\n\t\tbreak;\n\n\tcase TOK_NAT:\n\t\taction->opcode = O_NAT;\n\t\taction->len = F_INSN_SIZE(ipfw_insn_nat);\n\t\tgoto chkarg;\n\n\tcase TOK_QUEUE:\n\t\taction->opcode = O_QUEUE;\n\t\tgoto chkarg;\n\tcase TOK_PIPE:\n\t\taction->opcode = O_PIPE;\n\t\tgoto chkarg;\n\tcase TOK_SKIPTO:\n\t\taction->opcode = O_SKIPTO;\n\t\tgoto chkarg;\n\tcase TOK_NETGRAPH:\n\t\taction->opcode = O_NETGRAPH;\n\t\tgoto chkarg;\n\tcase TOK_NGTEE:\n\t\taction->opcode = O_NGTEE;\n\t\tgoto chkarg;\n\tcase TOK_DIVERT:\n\t\taction->opcode = O_DIVERT;\n\t\tgoto chkarg;\n\tcase TOK_TEE:\n\t\taction->opcode = O_TEE;\n\t\tgoto chkarg;\n\tcase TOK_CALL:\n\t\taction->opcode = O_CALLRETURN;\nchkarg:\n\t\tif (!av[0])\n\t\t\terrx(EX_USAGE, \"missing argument for %s\", *(av - 1));\n\t\tif (isdigit(**av)) {\n\t\t\taction->arg1 = strtoul(*av, NULL, 10);\n\t\t\tif (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG)\n\t\t\t\terrx(EX_DATAERR, \"illegal argument for %s\",\n\t\t\t\t    *(av - 1));\n\t\t} else if (_substrcmp(*av, \"tablearg\") == 0) {\n\t\t\taction->arg1 = IP_FW_TABLEARG;\n\t\t} else if (i == TOK_DIVERT || i == TOK_TEE) {\n\t\t\tstruct servent *s;\n\t\t\tsetservent(1);\n\t\t\ts = getservbyname(av[0], \"divert\");\n\t\t\tif (s != NULL)\n\t\t\t\taction->arg1 = ntohs(s->s_port);\n\t\t\telse\n\t\t\t\terrx(EX_DATAERR, \"illegal divert/tee port\");\n\t\t} else\n\t\t\terrx(EX_DATAERR, \"illegal argument for %s\", *(av - 1));\n\t\tav++;\n\t\tbreak;\n\n\tcase TOK_FORWARD: {\n\t\tipfw_insn_sa *p = (ipfw_insn_sa *)action;\n\t\tchar *s, *end;\n\n\t\tNEED1(\"missing forward address[:port]\");\n\n\t\taction->opcode = O_FORWARD_IP;\n\t\taction->len = F_INSN_SIZE(ipfw_insn_sa);\n\n\t\t/*\n\t\t * In the kernel we assume AF_INET and use only\n\t\t * sin_port and sin_addr. Remember to set sin_len as\n\t\t * the routing code seems to use it too.\n\t\t */\n\t\tp->sa.sin_family = AF_INET;\n\t\tp->sa.sin_len = sizeof(struct sockaddr_in);\n\t\tp->sa.sin_port = 0;\n\t\t/*\n\t\t * locate the address-port separator (':' or ',')\n\t\t */\n\t\ts = strchr(*av, ':');\n\t\tif (s == NULL)\n\t\t\ts = strchr(*av, ',');\n\t\tif (s != NULL) {\n\t\t\t*(s++) = '\\0';\n\t\t\ti = strtoport(s, &end, 0 /* base */, 0 /* proto */);\n\t\t\tif (s == end)\n\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t    \"illegal forwarding port ``%s''\", s);\n\t\t\tp->sa.sin_port = (u_short)i;\n\t\t}\n\t\tif (_substrcmp(*av, \"tablearg\") == 0)\n\t\t\tp->sa.sin_addr.s_addr = INADDR_ANY;\n\t\telse\n\t\t\tlookup_host(*av, &(p->sa.sin_addr));\n\t\tav++;\n\t\tbreak;\n\t    }\n\tcase TOK_COMMENT:\n\t\t/* pretend it is a 'count' rule followed by the comment */\n\t\taction->opcode = O_COUNT;\n\t\tav--;\t\t/* go back... */\n\t\tbreak;\n\n\tcase TOK_SETFIB:\n\t    {\n\t\tint numfibs;\n\t\tsize_t intsize = sizeof(int);\n\n\t\taction->opcode = O_SETFIB;\n\t\tNEED1(\"missing fib number\");\n\t        action->arg1 = strtoul(*av, NULL, 10);\n\t\tif (sysctlbyname(\"net.fibs\", &numfibs, &intsize, NULL, 0) == -1)\n\t\t\terrx(EX_DATAERR, \"fibs not suported.\\n\");\n\t\tif (action->arg1 >= numfibs)  /* Temporary */\n\t\t\terrx(EX_DATAERR, \"fib too large.\\n\");\n\t\tav++;\n\t\tbreak;\n\t    }\n\n\tcase TOK_REASS:\n\t\taction->opcode = O_REASS;\n\t\tbreak;\n\n\tcase TOK_RETURN:\n\t\tfill_cmd(action, O_CALLRETURN, F_NOT, 0);\n\t\tbreak;\n\n\tdefault:\n\t\terrx(EX_DATAERR, \"invalid action %s\\n\", av[-1]);\n\t}\n\taction = next_cmd(action);\n\n\t/*\n\t * [altq queuename] -- altq tag, optional\n\t * [log [logamount N]]\t-- log, optional\n\t *\n\t * If they exist, it go first in the cmdbuf, but then it is\n\t * skipped in the copy section to the end of the buffer.\n\t */\n\twhile (av[0] != NULL && (i = match_token(rule_action_params, *av)) != -1) {\n\t\tav++;\n\t\tswitch (i) {\n\t\tcase TOK_LOG:\n\t\t    {\n\t\t\tipfw_insn_log *c = (ipfw_insn_log *)cmd;\n\t\t\tint l;\n\n\t\t\tif (have_log)\n\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t    \"log cannot be specified more than once\");\n\t\t\thave_log = (ipfw_insn *)c;\n\t\t\tcmd->len = F_INSN_SIZE(ipfw_insn_log);\n\t\t\tcmd->opcode = O_LOG;\n\t\t\tif (av[0] && _substrcmp(*av, \"logamount\") == 0) {\n\t\t\t\tav++;\n\t\t\t\tNEED1(\"logamount requires argument\");\n\t\t\t\tl = atoi(*av);\n\t\t\t\tif (l < 0)\n\t\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t\t    \"logamount must be positive\");\n\t\t\t\tc->max_log = l;\n\t\t\t\tav++;\n\t\t\t} else {\n\t\t\t\tlen = sizeof(c->max_log);\n\t\t\t\tif (sysctlbyname(\"net.inet.ip.fw.verbose_limit\",\n\t\t\t\t    &c->max_log, &len, NULL, 0) == -1)\n\t\t\t\t\terrx(1, \"sysctlbyname(\\\"%s\\\")\",\n\t\t\t\t\t    \"net.inet.ip.fw.verbose_limit\");\n\t\t\t}\n\t\t    }\n\t\t\tbreak;\n\n#ifndef NO_ALTQ\n\t\tcase TOK_ALTQ:\n\t\t    {\n\t\t\tipfw_insn_altq *a = (ipfw_insn_altq *)cmd;\n\n\t\t\tNEED1(\"missing altq queue name\");\n\t\t\tif (have_altq)\n\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t    \"altq cannot be specified more than once\");\n\t\t\thave_altq = (ipfw_insn *)a;\n\t\t\tcmd->len = F_INSN_SIZE(ipfw_insn_altq);\n\t\t\tcmd->opcode = O_ALTQ;\n\t\t\ta->qid = altq_name_to_qid(*av);\n\t\t\tav++;\n\t\t    }\n\t\t\tbreak;\n#endif\n\n\t\tcase TOK_TAG:\n\t\tcase TOK_UNTAG: {\n\t\t\tuint16_t tag;\n\n\t\t\tif (have_tag)\n\t\t\t\terrx(EX_USAGE, \"tag and untag cannot be \"\n\t\t\t\t    \"specified more than once\");\n\t\t\tGET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, i,\n\t\t\t   rule_action_params);\n\t\t\thave_tag = cmd;\n\t\t\tfill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag);\n\t\t\tav++;\n\t\t\tbreak;\n\t\t}\n\n\t\tdefault:\n\t\t\tabort();\n\t\t}\n\t\tcmd = next_cmd(cmd);\n\t}\n\n\tif (have_state)\t/* must be a check-state, we are done */\n\t\tgoto done;\n\n#define OR_START(target)\t\t\t\t\t\\\n\tif (av[0] && (*av[0] == '(' || *av[0] == '{')) { \t\\\n\t\tif (open_par)\t\t\t\t\t\\\n\t\t\terrx(EX_USAGE, \"nested \\\"(\\\" not allowed\\n\"); \\\n\t\tprev = NULL;\t\t\t\t\t\\\n\t\topen_par = 1;\t\t\t\t\t\\\n\t\tif ( (av[0])[1] == '\\0') {\t\t\t\\\n\t\t\tav++;\t\t\t\t\t\\\n\t\t} else\t\t\t\t\t\t\\\n\t\t\t(*av)++;\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\\\n\ttarget:\t\t\t\t\t\t\t\\\n\n\n#define\tCLOSE_PAR\t\t\t\t\t\t\\\n\tif (open_par) {\t\t\t\t\t\t\\\n\t\tif (av[0] && (\t\t\t\t\t\\\n\t\t    strcmp(*av, \")\") == 0 ||\t\t\t\\\n\t\t    strcmp(*av, \"}\") == 0)) {\t\t\t\\\n\t\t\tprev = NULL;\t\t\t\t\\\n\t\t\topen_par = 0;\t\t\t\t\\\n\t\t\tav++;\t\t\t\t\t\\\n\t\t} else\t\t\t\t\t\t\\\n\t\t\terrx(EX_USAGE, \"missing \\\")\\\"\\n\");\t\\\n\t}\n\n#define NOT_BLOCK\t\t\t\t\t\t\\\n\tif (av[0] && _substrcmp(*av, \"not\") == 0) {\t\t\\\n\t\tif (cmd->len & F_NOT)\t\t\t\t\\\n\t\t\terrx(EX_USAGE, \"double \\\"not\\\" not allowed\\n\"); \\\n\t\tcmd->len |= F_NOT;\t\t\t\t\\\n\t\tav++;\t\t\t\t\t\t\\\n\t}\n\n#define OR_BLOCK(target)\t\t\t\t\t\\\n\tif (av[0] && _substrcmp(*av, \"or\") == 0) {\t\t\\\n\t\tif (prev == NULL || open_par == 0)\t\t\\\n\t\t\terrx(EX_DATAERR, \"invalid OR block\");\t\\\n\t\tprev->len |= F_OR;\t\t\t\t\\\n\t\tav++;\t\t\t\t\t\\\n\t\tgoto target;\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\\\n\tCLOSE_PAR;\n\n\tfirst_cmd = cmd;\n\n#if 0\n\t/*\n\t * MAC addresses, optional.\n\t * If we have this, we skip the part \"proto from src to dst\"\n\t * and jump straight to the option parsing.\n\t */\n\tNOT_BLOCK;\n\tNEED1(\"missing protocol\");\n\tif (_substrcmp(*av, \"MAC\") == 0 ||\n\t    _substrcmp(*av, \"mac\") == 0) {\n\t\tav++;\t\t\t/* the \"MAC\" keyword */\n\t\tadd_mac(cmd, av);\t/* exits in case of errors */\n\t\tcmd = next_cmd(cmd);\n\t\tav += 2;\t\t/* dst-mac and src-mac */\n\t\tNOT_BLOCK;\n\t\tNEED1(\"missing mac type\");\n\t\tif (add_mactype(cmd, av[0]))\n\t\t\tcmd = next_cmd(cmd);\n\t\tav++;\t\t\t/* any or mac-type */\n\t\tgoto read_options;\n\t}\n#endif\n\n\t/*\n\t * protocol, mandatory\n\t */\n    OR_START(get_proto);\n\tNOT_BLOCK;\n\tNEED1(\"missing protocol\");\n\tif (add_proto_compat(cmd, *av, &proto)) {\n\t\tav++;\n\t\tif (F_LEN(cmd) != 0) {\n\t\t\tprev = cmd;\n\t\t\tcmd = next_cmd(cmd);\n\t\t}\n\t} else if (first_cmd != cmd) {\n\t\terrx(EX_DATAERR, \"invalid protocol ``%s''\", *av);\n\t} else\n\t\tgoto read_options;\n    OR_BLOCK(get_proto);\n\n\t/*\n\t * \"from\", mandatory\n\t */\n\tif ((av[0] == NULL) || _substrcmp(*av, \"from\") != 0)\n\t\terrx(EX_USAGE, \"missing ``from''\");\n\tav++;\n\n\t/*\n\t * source IP, mandatory\n\t */\n    OR_START(source_ip);\n\tNOT_BLOCK;\t/* optional \"not\" */\n\tNEED1(\"missing source address\");\n\tif (add_src(cmd, *av, proto)) {\n\t\tav++;\n\t\tif (F_LEN(cmd) != 0) {\t/* ! any */\n\t\t\tprev = cmd;\n\t\t\tcmd = next_cmd(cmd);\n\t\t}\n\t} else\n\t\terrx(EX_USAGE, \"bad source address %s\", *av);\n    OR_BLOCK(source_ip);\n\n\t/*\n\t * source ports, optional\n\t */\n\tNOT_BLOCK;\t/* optional \"not\" */\n\tif ( av[0] != NULL ) {\n\t\tif (_substrcmp(*av, \"any\") == 0 ||\n\t\t    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {\n\t\t\tav++;\n\t\t\tif (F_LEN(cmd) != 0)\n\t\t\t\tcmd = next_cmd(cmd);\n\t\t}\n\t}\n\n\t/*\n\t * \"to\", mandatory\n\t */\n\tif ( (av[0] == NULL) || _substrcmp(*av, \"to\") != 0 )\n\t\terrx(EX_USAGE, \"missing ``to''\");\n\tav++;\n\n\t/*\n\t * destination, mandatory\n\t */\n    OR_START(dest_ip);\n\tNOT_BLOCK;\t/* optional \"not\" */\n\tNEED1(\"missing dst address\");\n\tif (add_dst(cmd, *av, proto)) {\n\t\tav++;\n\t\tif (F_LEN(cmd) != 0) {\t/* ! any */\n\t\t\tprev = cmd;\n\t\t\tcmd = next_cmd(cmd);\n\t\t}\n\t} else\n\t\terrx( EX_USAGE, \"bad destination address %s\", *av);\n    OR_BLOCK(dest_ip);\n\n\t/*\n\t * dest. ports, optional\n\t */\n\tNOT_BLOCK;\t/* optional \"not\" */\n\tif (av[0]) {\n\t\tif (_substrcmp(*av, \"any\") == 0 ||\n\t\t    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {\n\t\t\tav++;\n\t\t\tif (F_LEN(cmd) != 0)\n\t\t\t\tcmd = next_cmd(cmd);\n\t\t}\n\t}\n\nread_options:\n\tif (av[0] && first_cmd == cmd) {\n\t\t/*\n\t\t * nothing specified so far, store in the rule to ease\n\t\t * printout later.\n\t\t */\n\t\t rule->_pad = 1;\n\t}\n\tprev = NULL;\n\twhile ( av[0] != NULL ) {\n\t\tchar *s;\n\t\tipfw_insn_u32 *cmd32;\t/* alias for cmd */\n\n\t\ts = *av;\n\t\tcmd32 = (ipfw_insn_u32 *)cmd;\n\n\t\tif (*s == '!') {\t/* alternate syntax for NOT */\n\t\t\tif (cmd->len & F_NOT)\n\t\t\t\terrx(EX_USAGE, \"double \\\"not\\\" not allowed\\n\");\n\t\t\tcmd->len = F_NOT;\n\t\t\ts++;\n\t\t}\n\t\ti = match_token(rule_options, s);\n\t\tav++;\n\t\tswitch(i) {\n\t\tcase TOK_NOT:\n\t\t\tif (cmd->len & F_NOT)\n\t\t\t\terrx(EX_USAGE, \"double \\\"not\\\" not allowed\\n\");\n\t\t\tcmd->len = F_NOT;\n\t\t\tbreak;\n\n\t\tcase TOK_OR:\n\t\t\tif (open_par == 0 || prev == NULL)\n\t\t\t\terrx(EX_USAGE, \"invalid \\\"or\\\" block\\n\");\n\t\t\tprev->len |= F_OR;\n\t\t\tbreak;\n\n\t\tcase TOK_STARTBRACE:\n\t\t\tif (open_par)\n\t\t\t\terrx(EX_USAGE, \"+nested \\\"(\\\" not allowed\\n\");\n\t\t\topen_par = 1;\n\t\t\tbreak;\n\n\t\tcase TOK_ENDBRACE:\n\t\t\tif (!open_par)\n\t\t\t\terrx(EX_USAGE, \"+missing \\\")\\\"\\n\");\n\t\t\topen_par = 0;\n\t\t\tprev = NULL;\n\t\t\tbreak;\n\n\t\tcase TOK_IN:\n\t\t\tfill_cmd(cmd, O_IN, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_OUT:\n\t\t\tcmd->len ^= F_NOT; /* toggle F_NOT */\n\t\t\tfill_cmd(cmd, O_IN, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_DIVERTED:\n\t\t\tfill_cmd(cmd, O_DIVERTED, 0, 3);\n\t\t\tbreak;\n\n\t\tcase TOK_DIVERTEDLOOPBACK:\n\t\t\tfill_cmd(cmd, O_DIVERTED, 0, 1);\n\t\t\tbreak;\n\n\t\tcase TOK_DIVERTEDOUTPUT:\n\t\t\tfill_cmd(cmd, O_DIVERTED, 0, 2);\n\t\t\tbreak;\n\n\t\tcase TOK_FRAG:\n\t\t\tfill_cmd(cmd, O_FRAG, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_LAYER2:\n\t\t\tfill_cmd(cmd, O_LAYER2, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_XMIT:\n\t\tcase TOK_RECV:\n\t\tcase TOK_VIA:\n\t\t\tNEED1(\"recv, xmit, via require interface name\"\n\t\t\t\t\" or address\");\n\t\t\tfill_iface((ipfw_insn_if *)cmd, av[0]);\n\t\t\tav++;\n\t\t\tif (F_LEN(cmd) == 0)\t/* not a valid address */\n\t\t\t\tbreak;\n\t\t\tif (i == TOK_XMIT)\n\t\t\t\tcmd->opcode = O_XMIT;\n\t\t\telse if (i == TOK_RECV)\n\t\t\t\tcmd->opcode = O_RECV;\n\t\t\telse if (i == TOK_VIA)\n\t\t\t\tcmd->opcode = O_VIA;\n\t\t\tbreak;\n\n\t\tcase TOK_ICMPTYPES:\n\t\t\tNEED1(\"icmptypes requires list of types\");\n\t\t\tfill_icmptypes((ipfw_insn_u32 *)cmd, *av);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_ICMP6TYPES:\n\t\t\tNEED1(\"icmptypes requires list of types\");\n\t\t\tfill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_IPTTL:\n\t\t\tNEED1(\"ipttl requires TTL\");\n\t\t\tif (strpbrk(*av, \"-,\")) {\n\t\t\t    if (!add_ports(cmd, *av, 0, O_IPTTL))\n\t\t\t\terrx(EX_DATAERR, \"invalid ipttl %s\", *av);\n\t\t\t} else\n\t\t\t    fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_IPID:\n\t\t\tNEED1(\"ipid requires id\");\n\t\t\tif (strpbrk(*av, \"-,\")) {\n\t\t\t    if (!add_ports(cmd, *av, 0, O_IPID))\n\t\t\t\terrx(EX_DATAERR, \"invalid ipid %s\", *av);\n\t\t\t} else\n\t\t\t    fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_IPLEN:\n\t\t\tNEED1(\"iplen requires length\");\n\t\t\tif (strpbrk(*av, \"-,\")) {\n\t\t\t    if (!add_ports(cmd, *av, 0, O_IPLEN))\n\t\t\t\terrx(EX_DATAERR, \"invalid ip len %s\", *av);\n\t\t\t} else\n\t\t\t    fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_IPVER:\n\t\t\tNEED1(\"ipver requires version\");\n\t\t\tfill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0));\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_IPPRECEDENCE:\n\t\t\tNEED1(\"ipprecedence requires value\");\n\t\t\tfill_cmd(cmd, O_IPPRECEDENCE, 0,\n\t\t\t    (strtoul(*av, NULL, 0) & 7) << 5);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_IPOPTS:\n\t\t\tNEED1(\"missing argument for ipoptions\");\n\t\t\tfill_flags(cmd, O_IPOPT, f_ipopts, *av);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_IPTOS:\n\t\t\tNEED1(\"missing argument for iptos\");\n\t\t\tfill_flags(cmd, O_IPTOS, f_iptos, *av);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_UID:\n\t\t\tNEED1(\"uid requires argument\");\n\t\t    {\n\t\t\tchar *end;\n\t\t\tuid_t uid;\n\t\t\tstruct passwd *pwd;\n\n\t\t\tcmd->opcode = O_UID;\n\t\t\tuid = strtoul(*av, &end, 0);\n\t\t\tpwd = (*end == '\\0') ? getpwuid(uid) : getpwnam(*av);\n\t\t\tif (pwd == NULL)\n\t\t\t\terrx(EX_DATAERR, \"uid \\\"%s\\\" nonexistent\", *av);\n\t\t\tcmd32->d[0] = pwd->pw_uid;\n\t\t\tcmd->len |= F_INSN_SIZE(ipfw_insn_u32);\n\t\t\tav++;\n\t\t    }\n\t\t\tbreak;\n\n\t\tcase TOK_GID:\n\t\t\tNEED1(\"gid requires argument\");\n\t\t    {\n\t\t\tchar *end;\n\t\t\tgid_t gid;\n\t\t\tstruct group *grp;\n\n\t\t\tcmd->opcode = O_GID;\n\t\t\tgid = strtoul(*av, &end, 0);\n\t\t\tgrp = (*end == '\\0') ? getgrgid(gid) : getgrnam(*av);\n\t\t\tif (grp == NULL)\n\t\t\t\terrx(EX_DATAERR, \"gid \\\"%s\\\" nonexistent\", *av);\n\t\t\tcmd32->d[0] = grp->gr_gid;\n\t\t\tcmd->len |= F_INSN_SIZE(ipfw_insn_u32);\n\t\t\tav++;\n\t\t    }\n\t\t\tbreak;\n\n\t\tcase TOK_JAIL:\n\t\t\tNEED1(\"jail requires argument\");\n\t\t    {\n\t\t\tchar *end;\n\t\t\tint jid;\n\n\t\t\tcmd->opcode = O_JAIL;\n\t\t\tjid = (int)strtol(*av, &end, 0);\n\t\t\tif (jid < 0 || *end != '\\0')\n\t\t\t\terrx(EX_DATAERR, \"jail requires prison ID\");\n\t\t\tcmd32->d[0] = (uint32_t)jid;\n\t\t\tcmd->len |= F_INSN_SIZE(ipfw_insn_u32);\n\t\t\tav++;\n\t\t    }\n\t\t\tbreak;\n\n\t\tcase TOK_ESTAB:\n\t\t\tfill_cmd(cmd, O_ESTAB, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_SETUP:\n\t\t\tfill_cmd(cmd, O_TCPFLAGS, 0,\n\t\t\t\t(TH_SYN) | ( (TH_ACK) & 0xff) <<8 );\n\t\t\tbreak;\n\n\t\tcase TOK_TCPDATALEN:\n\t\t\tNEED1(\"tcpdatalen requires length\");\n\t\t\tif (strpbrk(*av, \"-,\")) {\n\t\t\t    if (!add_ports(cmd, *av, 0, O_TCPDATALEN))\n\t\t\t\terrx(EX_DATAERR, \"invalid tcpdata len %s\", *av);\n\t\t\t} else\n\t\t\t    fill_cmd(cmd, O_TCPDATALEN, 0,\n\t\t\t\t    strtoul(*av, NULL, 0));\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_TCPOPTS:\n\t\t\tNEED1(\"missing argument for tcpoptions\");\n\t\t\tfill_flags(cmd, O_TCPOPTS, f_tcpopts, *av);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_TCPSEQ:\n\t\tcase TOK_TCPACK:\n\t\t\tNEED1(\"tcpseq/tcpack requires argument\");\n\t\t\tcmd->len = F_INSN_SIZE(ipfw_insn_u32);\n\t\t\tcmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK;\n\t\t\tcmd32->d[0] = htonl(strtoul(*av, NULL, 0));\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_TCPWIN:\n\t\t\tNEED1(\"tcpwin requires length\");\n\t\t\tfill_cmd(cmd, O_TCPWIN, 0,\n\t\t\t    htons(strtoul(*av, NULL, 0)));\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_TCPFLAGS:\n\t\t\tNEED1(\"missing argument for tcpflags\");\n\t\t\tcmd->opcode = O_TCPFLAGS;\n\t\t\tfill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_KEEPSTATE:\n\t\t\tif (open_par)\n\t\t\t\terrx(EX_USAGE, \"keep-state cannot be part \"\n\t\t\t\t    \"of an or block\");\n\t\t\tif (have_state)\n\t\t\t\terrx(EX_USAGE, \"only one of keep-state \"\n\t\t\t\t\t\"and limit is allowed\");\n\t\t\thave_state = cmd;\n\t\t\tfill_cmd(cmd, O_KEEP_STATE, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_LIMIT: {\n\t\t\tipfw_insn_limit *c = (ipfw_insn_limit *)cmd;\n\t\t\tint val;\n\n\t\t\tif (open_par)\n\t\t\t\terrx(EX_USAGE,\n\t\t\t\t    \"limit cannot be part of an or block\");\n\t\t\tif (have_state)\n\t\t\t\terrx(EX_USAGE, \"only one of keep-state and \"\n\t\t\t\t    \"limit is allowed\");\n\t\t\thave_state = cmd;\n\n\t\t\tcmd->len = F_INSN_SIZE(ipfw_insn_limit);\n\t\t\tcmd->opcode = O_LIMIT;\n\t\t\tc->limit_mask = c->conn_limit = 0;\n\n\t\t\twhile ( av[0] != NULL ) {\n\t\t\t\tif ((val = match_token(limit_masks, *av)) <= 0)\n\t\t\t\t\tbreak;\n\t\t\t\tc->limit_mask |= val;\n\t\t\t\tav++;\n\t\t\t}\n\n\t\t\tif (c->limit_mask == 0)\n\t\t\t\terrx(EX_USAGE, \"limit: missing limit mask\");\n\n\t\t\tGET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX,\n\t\t\t    TOK_LIMIT, rule_options);\n\n\t\t\tav++;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase TOK_PROTO:\n\t\t\tNEED1(\"missing protocol\");\n\t\t\tif (add_proto(cmd, *av, &proto)) {\n\t\t\t\tav++;\n\t\t\t} else\n\t\t\t\terrx(EX_DATAERR, \"invalid protocol ``%s''\",\n\t\t\t\t    *av);\n\t\t\tbreak;\n\n\t\tcase TOK_SRCIP:\n\t\t\tNEED1(\"missing source IP\");\n\t\t\tif (add_srcip(cmd, *av)) {\n\t\t\t\tav++;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase TOK_DSTIP:\n\t\t\tNEED1(\"missing destination IP\");\n\t\t\tif (add_dstip(cmd, *av)) {\n\t\t\t\tav++;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase TOK_SRCIP6:\n\t\t\tNEED1(\"missing source IP6\");\n\t\t\tif (add_srcip6(cmd, *av)) {\n\t\t\t\tav++;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase TOK_DSTIP6:\n\t\t\tNEED1(\"missing destination IP6\");\n\t\t\tif (add_dstip6(cmd, *av)) {\n\t\t\t\tav++;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase TOK_SRCPORT:\n\t\t\tNEED1(\"missing source port\");\n\t\t\tif (_substrcmp(*av, \"any\") == 0 ||\n\t\t\t    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {\n\t\t\t\tav++;\n\t\t\t} else\n\t\t\t\terrx(EX_DATAERR, \"invalid source port %s\", *av);\n\t\t\tbreak;\n\n\t\tcase TOK_DSTPORT:\n\t\t\tNEED1(\"missing destination port\");\n\t\t\tif (_substrcmp(*av, \"any\") == 0 ||\n\t\t\t    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {\n\t\t\t\tav++;\n\t\t\t} else\n\t\t\t\terrx(EX_DATAERR, \"invalid destination port %s\",\n\t\t\t\t    *av);\n\t\t\tbreak;\n\n\t\tcase TOK_MAC:\n\t\t\tif (add_mac(cmd, av))\n\t\t\t\tav += 2;\n\t\t\tbreak;\n\n\t\tcase TOK_MACTYPE:\n\t\t\tNEED1(\"missing mac type\");\n\t\t\tif (!add_mactype(cmd, *av))\n\t\t\t\terrx(EX_DATAERR, \"invalid mac type %s\", *av);\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_VERREVPATH:\n\t\t\tfill_cmd(cmd, O_VERREVPATH, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_VERSRCREACH:\n\t\t\tfill_cmd(cmd, O_VERSRCREACH, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_ANTISPOOF:\n\t\t\tfill_cmd(cmd, O_ANTISPOOF, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_IPSEC:\n\t\t\tfill_cmd(cmd, O_IPSEC, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_IPV6:\n\t\t\tfill_cmd(cmd, O_IP6, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_IPV4:\n\t\t\tfill_cmd(cmd, O_IP4, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_EXT6HDR:\n\t\t\tfill_ext6hdr( cmd, *av );\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_FLOWID:\n\t\t\tif (proto != IPPROTO_IPV6 )\n\t\t\t\terrx( EX_USAGE, \"flow-id filter is active \"\n\t\t\t\t    \"only for ipv6 protocol\\n\");\n\t\t\tfill_flow6( (ipfw_insn_u32 *) cmd, *av );\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_COMMENT:\n\t\t\tfill_comment(cmd, av);\n\t\t\tav[0]=NULL;\n\t\t\tbreak;\n\n\t\tcase TOK_TAGGED:\n\t\t\tif (av[0] && strpbrk(*av, \"-,\")) {\n\t\t\t\tif (!add_ports(cmd, *av, 0, O_TAGGED))\n\t\t\t\t\terrx(EX_DATAERR, \"tagged: invalid tag\"\n\t\t\t\t\t    \" list: %s\", *av);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tuint16_t tag;\n\n\t\t\t\tGET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX,\n\t\t\t\t    TOK_TAGGED, rule_options);\n\t\t\t\tfill_cmd(cmd, O_TAGGED, 0, tag);\n\t\t\t}\n\t\t\tav++;\n\t\t\tbreak;\n\n\t\tcase TOK_FIB:\n\t\t\tNEED1(\"fib requires fib number\");\n\t\t\tfill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0));\n\t\t\tav++;\n\t\t\tbreak;\n\t\tcase TOK_SOCKARG:\n\t\t\tfill_cmd(cmd, O_SOCKARG, 0, 0);\n\t\t\tbreak;\n\n\t\tcase TOK_LOOKUP: {\n\t\t\tipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;\n\t\t\tchar *p;\n\t\t\tint j;\n\n\t\t\tif (!av[0] || !av[1])\n\t\t\t\terrx(EX_USAGE, \"format: lookup argument tablenum\");\n\t\t\tcmd->opcode = O_IP_DST_LOOKUP;\n\t\t\tcmd->len |= F_INSN_SIZE(ipfw_insn) + 2;\n\t\t\ti = match_token(rule_options, *av);\n\t\t\tfor (j = 0; lookup_key[j] >= 0 ; j++) {\n\t\t\t\tif (i == lookup_key[j])\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (lookup_key[j] <= 0)\n\t\t\t\terrx(EX_USAGE, \"format: cannot lookup on %s\", *av);\n\t\t\t__PAST_END(c->d, 1) = j; // i converted to option\n\t\t\tav++;\n\t\t\tcmd->arg1 = strtoul(*av, &p, 0);\n\t\t\tif (p && *p)\n\t\t\t\terrx(EX_USAGE, \"format: lookup argument tablenum\");\n\t\t\tav++;\n\t\t    }\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\terrx(EX_USAGE, \"unrecognised option [%d] %s\\n\", i, s);\n\t\t}\n\t\tif (F_LEN(cmd) > 0) {\t/* prepare to advance */\n\t\t\tprev = cmd;\n\t\t\tcmd = next_cmd(cmd);\n\t\t}\n\t}\n\ndone:\n\t/*\n\t * Now copy stuff into the rule.\n\t * If we have a keep-state option, the first instruction\n\t * must be a PROBE_STATE (which is generated here).\n\t * If we have a LOG option, it was stored as the first command,\n\t * and now must be moved to the top of the action part.\n\t */\n\tdst = (ipfw_insn *)rule->cmd;\n\n\t/*\n\t * First thing to write into the command stream is the match probability.\n\t */\n\tif (match_prob != 1) { /* 1 means always match */\n\t\tdst->opcode = O_PROB;\n\t\tdst->len = 2;\n\t\t*((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff);\n\t\tdst += dst->len;\n\t}\n\n\t/*\n\t * generate O_PROBE_STATE if necessary\n\t */\n\tif (have_state && have_state->opcode != O_CHECK_STATE) {\n\t\tfill_cmd(dst, O_PROBE_STATE, 0, 0);\n\t\tdst = next_cmd(dst);\n\t}\n\n\t/* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */\n\tfor (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {\n\t\ti = F_LEN(src);\n\n\t\tswitch (src->opcode) {\n\t\tcase O_LOG:\n\t\tcase O_KEEP_STATE:\n\t\tcase O_LIMIT:\n\t\tcase O_ALTQ:\n\t\tcase O_TAG:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbcopy(src, dst, i * sizeof(uint32_t));\n\t\t\tdst += i;\n\t\t}\n\t}\n\n\t/*\n\t * put back the have_state command as last opcode\n\t */\n\tif (have_state && have_state->opcode != O_CHECK_STATE) {\n\t\ti = F_LEN(have_state);\n\t\tbcopy(have_state, dst, i * sizeof(uint32_t));\n\t\tdst += i;\n\t}\n\t/*\n\t * start action section\n\t */\n\trule->act_ofs = dst - rule->cmd;\n\n\t/* put back O_LOG, O_ALTQ, O_TAG if necessary */\n\tif (have_log) {\n\t\ti = F_LEN(have_log);\n\t\tbcopy(have_log, dst, i * sizeof(uint32_t));\n\t\tdst += i;\n\t}\n\tif (have_altq) {\n\t\ti = F_LEN(have_altq);\n\t\tbcopy(have_altq, dst, i * sizeof(uint32_t));\n\t\tdst += i;\n\t}\n\tif (have_tag) {\n\t\ti = F_LEN(have_tag);\n\t\tbcopy(have_tag, dst, i * sizeof(uint32_t));\n\t\tdst += i;\n\t}\n\t/*\n\t * copy all other actions\n\t */\n\tfor (src = (ipfw_insn *)actbuf; src != action; src += i) {\n\t\ti = F_LEN(src);\n\t\tbcopy(src, dst, i * sizeof(uint32_t));\n\t\tdst += i;\n\t}\n\n\trule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd);\n\ti = (char *)dst - (char *)rule;\n\tif (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1)\n\t\terr(EX_UNAVAILABLE, \"getsockopt(%s)\", \"IP_FW_ADD\");\n\tif (!co.do_quiet)\n\t\tshow_ipfw(rule, 0, 0);\n}\n\n/*\n * clear the counters or the log counters.\n */\nvoid\nipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG */)\n{\n\tuint32_t arg, saved_arg;\n\tint failed = EX_OK;\n\tchar const *errstr;\n\tchar const *name = optname ? \"RESETLOG\" : \"ZERO\";\n\n\toptname = optname ? IP_FW_RESETLOG : IP_FW_ZERO;\n\n\tav++; ac--;\n\n\tif (!ac) {\n\t\t/* clear all entries */\n\t\tif (do_cmd(optname, NULL, 0) < 0)\n\t\t\terr(EX_UNAVAILABLE, \"setsockopt(IP_FW_%s)\", name);\n\t\tif (!co.do_quiet)\n\t\t\tprintf(\"%s.\\n\", optname == IP_FW_ZERO ?\n\t\t\t    \"Accounting cleared\":\"Logging counts reset\");\n\n\t\treturn;\n\t}\n\n\twhile (ac) {\n\t\t/* Rule number */\n\t\tif (isdigit(**av)) {\n\t\t\targ = strtonum(*av, 0, 0xffff, &errstr);\n\t\t\tif (errstr)\n\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t    \"invalid rule number %s\\n\", *av);\n\t\t\tsaved_arg = arg;\n\t\t\tif (co.use_set)\n\t\t\t\targ |= (1 << 24) | ((co.use_set - 1) << 16);\n\t\t\tav++;\n\t\t\tac--;\n\t\t\tif (do_cmd(optname, &arg, sizeof(arg))) {\n\t\t\t\twarn(\"rule %u: setsockopt(IP_FW_%s)\",\n\t\t\t\t    saved_arg, name);\n\t\t\t\tfailed = EX_UNAVAILABLE;\n\t\t\t} else if (!co.do_quiet)\n\t\t\t\tprintf(\"Entry %d %s.\\n\", saved_arg,\n\t\t\t\t    optname == IP_FW_ZERO ?\n\t\t\t\t\t\"cleared\" : \"logging count reset\");\n\t\t} else {\n\t\t\terrx(EX_USAGE, \"invalid rule number ``%s''\", *av);\n\t\t}\n\t}\n\tif (failed != EX_OK)\n\t\texit(failed);\n}\n\nvoid\nipfw_flush(int force)\n{\n\tint cmd = co.do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH;\n\n\tif (!force && !co.do_quiet) { /* need to ask user */\n\t\tint c;\n\n\t\tprintf(\"Are you sure? [yn] \");\n\t\tfflush(stdout);\n\t\tdo {\n\t\t\tc = toupper(getc(stdin));\n\t\t\twhile (c != '\\n' && getc(stdin) != '\\n')\n\t\t\t\tif (feof(stdin))\n\t\t\t\t\treturn; /* and do not flush */\n\t\t} while (c != 'Y' && c != 'N');\n\t\tprintf(\"\\n\");\n\t\tif (c == 'N')\t/* user said no */\n\t\t\treturn;\n\t}\n\tif (co.do_pipe) {\n\t\tdummynet_flush();\n\t\treturn;\n\t}\n\t/* `ipfw set N flush` - is the same that `ipfw delete set N` */\n\tif (co.use_set) {\n\t\tuint32_t arg = ((co.use_set - 1) & 0xffff) | (1 << 24);\n\t\tif (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0)\n\t\t\terr(EX_UNAVAILABLE, \"setsockopt(IP_FW_DEL)\");\n\t} else if (do_cmd(cmd, NULL, 0) < 0)\n\t\terr(EX_UNAVAILABLE, \"setsockopt(IP_%s_FLUSH)\",\n\t\t    co.do_pipe ? \"DUMMYNET\" : \"FW\");\n\tif (!co.do_quiet)\n\t\tprintf(\"Flushed all %s.\\n\", co.do_pipe ? \"pipes\" : \"rules\");\n}\n\n\nstatic void table_list(ipfw_table_entry ent, int need_header);\n\n/*\n * This one handles all table-related commands\n * \tipfw table N add addr[/masklen] [value]\n * \tipfw table N delete addr[/masklen]\n * \tipfw table {N | all} flush\n * \tipfw table {N | all} list\n */\nvoid\nipfw_table_handler(int ac, char *av[])\n{\n\tipfw_table_entry ent;\n\tint do_add;\n\tint is_all;\n\tsize_t len;\n\tchar *p;\n\tuint32_t a;\n\tuint32_t tables_max;\n\n\tlen = sizeof(tables_max);\n\tif (sysctlbyname(\"net.inet.ip.fw.tables_max\", &tables_max, &len,\n\t\tNULL, 0) == -1) {\n#ifdef IPFW_TABLES_MAX\n\t\twarn(\"Warn: Failed to get the max tables number via sysctl. \"\n\t\t     \"Using the compiled in defaults. \\nThe reason was\");\n\t\ttables_max = IPFW_TABLES_MAX;\n#else\n\t\terrx(1, \"Failed sysctlbyname(\\\"net.inet.ip.fw.tables_max\\\")\");\n#endif\n\t}\n\n\tac--; av++;\n\tif (ac && isdigit(**av)) {\n\t\tent.tbl = atoi(*av);\n\t\tis_all = 0;\n\t\tac--; av++;\n\t} else if (ac && _substrcmp(*av, \"all\") == 0) {\n\t\tent.tbl = 0;\n\t\tis_all = 1;\n\t\tac--; av++;\n\t} else\n\t\terrx(EX_USAGE, \"table number or 'all' keyword required\");\n\tif (ent.tbl >= tables_max)\n\t\terrx(EX_USAGE, \"The table number exceeds the maximum allowed \"\n\t\t\t\"value (%d)\", tables_max - 1);\n\tNEED1(\"table needs command\");\n\tif (is_all && _substrcmp(*av, \"list\") != 0\n\t\t   && _substrcmp(*av, \"flush\") != 0)\n\t\terrx(EX_USAGE, \"table number required\");\n\n\tif (_substrcmp(*av, \"add\") == 0 ||\n\t    _substrcmp(*av, \"delete\") == 0) {\n\t\tdo_add = **av == 'a';\n\t\tac--; av++;\n\t\tif (!ac)\n\t\t\terrx(EX_USAGE, \"IP address required\");\n\t\tp = strchr(*av, '/');\n\t\tif (p) {\n\t\t\t*p++ = '\\0';\n\t\t\tent.masklen = atoi(p);\n\t\t\tif (ent.masklen > 32)\n\t\t\t\terrx(EX_DATAERR, \"bad width ``%s''\", p);\n\t\t} else\n\t\t\tent.masklen = 32;\n\t\tif (lookup_host(*av, (struct in_addr *)&ent.addr) != 0)\n\t\t\terrx(EX_NOHOST, \"hostname ``%s'' unknown\", *av);\n\t\tac--; av++;\n\t\tif (do_add && ac) {\n\t\t\tunsigned int tval;\n\t\t\t/* isdigit is a bit of a hack here.. */\n\t\t\tif (strchr(*av, (int)'.') == NULL && isdigit(**av))  {\n\t\t\t\tent.value = strtoul(*av, NULL, 0);\n\t\t\t} else {\n\t\t        \tif (lookup_host(*av, (struct in_addr *)&tval) == 0) {\n\t\t\t\t\t/* The value must be stored in host order\t *\n\t\t\t\t\t * so that the values < 65k can be distinguished */\n\t\t       \t\t\tent.value = ntohl(tval);\n\t\t\t\t} else {\n\t\t\t\t\terrx(EX_NOHOST, \"hostname ``%s'' unknown\", *av);\n\t\t\t\t}\n\t\t\t}\n\t\t} else\n\t\t\tent.value = 0;\n\t\tif (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL,\n\t\t    &ent, sizeof(ent)) < 0) {\n\t\t\t/* If running silent, don't bomb out on these errors. */\n\t\t\tif (!(co.do_quiet && (errno == (do_add ? EEXIST : ESRCH))))\n\t\t\t\terr(EX_OSERR, \"setsockopt(IP_FW_TABLE_%s)\",\n\t\t\t\t    do_add ? \"ADD\" : \"DEL\");\n\t\t\t/* In silent mode, react to a failed add by deleting */\n\t\t\tif (do_add) {\n\t\t\t\tdo_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent));\n\t\t\t\tif (do_cmd(IP_FW_TABLE_ADD,\n\t\t\t\t    &ent, sizeof(ent)) < 0)\n\t\t\t\t\terr(EX_OSERR,\n\t\t\t\t            \"setsockopt(IP_FW_TABLE_ADD)\");\n\t\t\t}\n\t\t}\n\t} else if (_substrcmp(*av, \"flush\") == 0) {\n\t\ta = is_all ? tables_max : (uint32_t)(ent.tbl + 1);\n\t\tdo {\n\t\t\tif (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl,\n\t\t\t    sizeof(ent.tbl)) < 0)\n\t\t\t\terr(EX_OSERR, \"setsockopt(IP_FW_TABLE_FLUSH)\");\n\t\t} while (++ent.tbl < a);\n\t} else if (_substrcmp(*av, \"list\") == 0) {\n\t\ta = is_all ? tables_max : (uint32_t)(ent.tbl + 1);\n\t\tdo {\n\t\t\ttable_list(ent, is_all);\n\t\t} while (++ent.tbl < a);\n\t} else\n\t\terrx(EX_USAGE, \"invalid table command %s\", *av);\n}\n\nstatic void\ntable_list(ipfw_table_entry ent, int need_header)\n{\n\tipfw_table *tbl;\n\tsocklen_t l;\n\tuint32_t a;\n\n\ta = ent.tbl;\n\tl = sizeof(a);\n\tif (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0)\n\t\terr(EX_OSERR, \"getsockopt(IP_FW_TABLE_GETSIZE)\");\n\n\t/* If a is zero we have nothing to do, the table is empty. */\n\tif (a == 0)\n\t\treturn;\n\n\tl = sizeof(*tbl) + a * sizeof(ipfw_table_entry);\n\ttbl = safe_calloc(1, l);\n\ttbl->tbl = ent.tbl;\n\tif (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0)\n\t\terr(EX_OSERR, \"getsockopt(IP_FW_TABLE_LIST)\");\n\tif (tbl->cnt && need_header)\n\t\tprintf(\"---table(%d)---\\n\", tbl->tbl);\n\tfor (a = 0; a < tbl->cnt; a++) {\n\t\tunsigned int tval;\n\t\ttval = tbl->ent[a].value;\n\t\tif (co.do_value_as_ip) {\n\t\t\tchar tbuf[128];\n\t\t\tstrncpy(tbuf, inet_ntoa(*(struct in_addr *)\n\t\t\t\t&tbl->ent[a].addr), 127);\n\t\t\t/* inet_ntoa expects network order */\n\t\t\ttval = htonl(tval);\n\t\t\tprintf(\"%s/%u %s\\n\", tbuf, tbl->ent[a].masklen,\n\t\t\t\tinet_ntoa(*(struct in_addr *)&tval));\n\t\t} else {\n\t\t\tprintf(\"%s/%u %u\\n\",\n\t\t\t\tinet_ntoa(*(struct in_addr *)&tbl->ent[a].addr),\n\t\t\t\ttbl->ent[a].masklen, tval);\n\t\t}\n\t}\n\tfree(tbl);\n}\n"
  },
  {
    "path": "ipfw/ipfw2.h",
    "content": "/*\n * Copyright (c) 2002-2003 Luigi Rizzo\n * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp\n * Copyright (c) 1994 Ugen J.S.Antsilevich\n *\n * Idea and grammar partially left from:\n * Copyright (c) 1993 Daniel Boulet\n *\n * Redistribution and use in source forms, with and without modification,\n * are permitted provided that this entire comment appears intact.\n *\n * Redistribution in binary form may occur without any restrictions.\n * Obviously, it would be nice if you gave credit where credit is due\n * but requiring it would be too onerous.\n *\n * This software is provided ``AS IS'' without any warranties of any kind.\n *\n * NEW command line interface for IP firewall facility\n *\n * $FreeBSD: head/sbin/ipfw/ipfw2.h 206843 2010-04-19 15:11:45Z luigi $\n */\n\n/*\n * Options that can be set on the command line.\n * When reading commands from a file, a subset of the options can also\n * be applied globally by specifying them before the file name.\n * After that, each line can contain its own option that changes\n * the global value.\n * XXX The context is not restored after each line.\n */\n\nstruct cmdline_opts {\n\t/* boolean options: */\n\tint\tdo_value_as_ip;\t/* show table value as IP */\n\tint\tdo_resolv;\t/* try to resolve all ip to names */\n\tint\tdo_time;\t/* Show time stamps */\n\tint\tdo_quiet;\t/* Be quiet in add and flush */\n\tint\tdo_pipe;\t/* this cmd refers to a pipe/queue/sched */\n\tint\tdo_nat; \t/* this cmd refers to a nat config */\n\tint\tdo_dynamic;\t/* display dynamic rules */\n\tint\tdo_expired;\t/* display expired dynamic rules */\n\tint\tdo_compact;\t/* show rules in compact mode */\n\tint\tdo_force;\t/* do not ask for confirmation */\n\tint\tshow_sets;\t/* display the set each rule belongs to */\n\tint\ttest_only;\t/* only check syntax */\n\tint\tcomment_only;\t/* only print action and comment */\n\tint\tverbose;\t/* be verbose on some commands */\n\n\t/* The options below can have multiple values. */\n\n\tint\tdo_sort;\t/* field to sort results (0 = no) */\n\t\t/* valid fields are 1 and above */\n\n\tint\tuse_set;\t/* work with specified set number */\n\t\t/* 0 means all sets, otherwise apply to set use_set - 1 */\n\n};\n\nextern struct cmdline_opts co;\n\n/*\n * _s_x is a structure that stores a string <-> token pairs, used in\n * various places in the parser. Entries are stored in arrays,\n * with an entry with s=NULL as terminator.\n * The search routines are match_token() and match_value().\n * Often, an element with x=0 contains an error string.\n *\n */\nstruct _s_x {\n\tchar const *s;\n\tint x;\n};\n\nenum tokens {\n\tTOK_NULL=0,\n\n\tTOK_OR,\n\tTOK_NOT,\n\tTOK_STARTBRACE,\n\tTOK_ENDBRACE,\n\n\tTOK_ACCEPT,\n\tTOK_COUNT,\n\tTOK_PIPE,\n\tTOK_LINK,\n\tTOK_QUEUE,\n\tTOK_FLOWSET,\n\tTOK_SCHED,\n\tTOK_DIVERT,\n\tTOK_TEE,\n\tTOK_NETGRAPH,\n\tTOK_NGTEE,\n\tTOK_FORWARD,\n\tTOK_SKIPTO,\n\tTOK_DENY,\n\tTOK_REJECT,\n\tTOK_RESET,\n\tTOK_UNREACH,\n\tTOK_CHECKSTATE,\n\tTOK_NAT,\n\tTOK_REASS,\n\tTOK_CALL,\n\tTOK_RETURN,\n\n\tTOK_ALTQ,\n\tTOK_LOG,\n\tTOK_TAG,\n\tTOK_UNTAG,\n\n\tTOK_TAGGED,\n\tTOK_UID,\n\tTOK_GID,\n\tTOK_JAIL,\n\tTOK_IN,\n\tTOK_LIMIT,\n\tTOK_KEEPSTATE,\n\tTOK_LAYER2,\n\tTOK_OUT,\n\tTOK_DIVERTED,\n\tTOK_DIVERTEDLOOPBACK,\n\tTOK_DIVERTEDOUTPUT,\n\tTOK_XMIT,\n\tTOK_RECV,\n\tTOK_VIA,\n\tTOK_FRAG,\n\tTOK_IPOPTS,\n\tTOK_IPLEN,\n\tTOK_IPID,\n\tTOK_IPPRECEDENCE,\n\tTOK_DSCP,\n\tTOK_IPTOS,\n\tTOK_IPTTL,\n\tTOK_IPVER,\n\tTOK_ESTAB,\n\tTOK_SETUP,\n\tTOK_TCPDATALEN,\n\tTOK_TCPFLAGS,\n\tTOK_TCPOPTS,\n\tTOK_TCPSEQ,\n\tTOK_TCPACK,\n\tTOK_TCPWIN,\n\tTOK_ICMPTYPES,\n\tTOK_MAC,\n\tTOK_MACTYPE,\n\tTOK_VERREVPATH,\n\tTOK_VERSRCREACH,\n\tTOK_ANTISPOOF,\n\tTOK_IPSEC,\n\tTOK_COMMENT,\n\n\tTOK_PLR,\n\tTOK_NOERROR,\n\tTOK_BUCKETS,\n\tTOK_DSTIP,\n\tTOK_SRCIP,\n\tTOK_DSTPORT,\n\tTOK_SRCPORT,\n\tTOK_ALL,\n\tTOK_MASK,\n\tTOK_FLOW_MASK,\n\tTOK_SCHED_MASK,\n\tTOK_BW,\n\tTOK_DELAY,\n\tTOK_PROFILE,\n\tTOK_BURST,\n\tTOK_RED,\n\tTOK_GRED,\n\tTOK_DROPTAIL,\n\tTOK_PROTO,\n\t/* dummynet tokens */\n\tTOK_WEIGHT,\n\tTOK_LMAX,\n\tTOK_PRI,\n\tTOK_TYPE,\n\tTOK_SLOTSIZE,\n\n\tTOK_IP,\n\tTOK_IF,\n \tTOK_ALOG,\n \tTOK_DENY_INC,\n \tTOK_SAME_PORTS,\n \tTOK_UNREG_ONLY,\n\tTOK_SKIP_GLOBAL,\n \tTOK_RESET_ADDR,\n \tTOK_ALIAS_REV,\n \tTOK_PROXY_ONLY,\n\tTOK_REDIR_ADDR,\n\tTOK_REDIR_PORT,\n\tTOK_REDIR_PROTO,\n\n\tTOK_IPV6,\n\tTOK_FLOWID,\n\tTOK_ICMP6TYPES,\n\tTOK_EXT6HDR,\n\tTOK_DSTIP6,\n\tTOK_SRCIP6,\n\n\tTOK_IPV4,\n\tTOK_UNREACH6,\n\tTOK_RESET6,\n\n\tTOK_FIB,\n\tTOK_SETFIB,\n\tTOK_LOOKUP,\n\tTOK_SOCKARG,\n};\n/*\n * the following macro returns an error message if we run out of\n * arguments.\n */\n#define NEED(_p, msg)      {if (!_p) errx(EX_USAGE, msg);}\n#define NEED1(msg)      {if (!(*av)) errx(EX_USAGE, msg);}\n\nint pr_u64(uint64_t *pd, int width);\n\n/* memory allocation support */\nvoid *safe_calloc(size_t number, size_t size);\nvoid *safe_realloc(void *ptr, size_t size);\n\n/* string comparison functions used for historical compatibility */\nint _substrcmp(const char *str1, const char* str2);\nint _substrcmp2(const char *str1, const char* str2, const char* str3);\n\n/* utility functions */\nint match_token(struct _s_x *table, char *string);\nchar const *match_value(struct _s_x *p, int value);\n\nint do_cmd(int optname, void *optval, uintptr_t optlen);\n\nstruct in6_addr;\nvoid n2mask(struct in6_addr *mask, int n);\nint contigmask(uint8_t *p, int len);\n\n/*\n * Forward declarations to avoid include way too many headers.\n * C does not allow duplicated typedefs, so we use the base struct\n * that the typedef points to.\n * Should the typedefs use a different type, the compiler will\n * still detect the change when compiling the body of the\n * functions involved, so we do not lose error checking.\n */\nstruct _ipfw_insn;\nstruct _ipfw_insn_altq;\nstruct _ipfw_insn_u32;\nstruct _ipfw_insn_ip6;\nstruct _ipfw_insn_icmp6;\n\n/*\n * The reserved set numer. This is a constant in ip_fw.h\n * but we store it in a variable so other files do not depend\n * in that header just for one constant.\n */\nextern int resvd_set_number;\n\n/* first-level command handlers */\nvoid ipfw_add(char *av[]);\nvoid ipfw_show_nat(int ac, char **av);\nvoid ipfw_config_pipe(int ac, char **av);\nvoid ipfw_config_nat(int ac, char **av);\nvoid ipfw_sets_handler(char *av[]);\nvoid ipfw_table_handler(int ac, char *av[]);\nvoid ipfw_sysctl_handler(char *av[], int which);\nvoid ipfw_delete(char *av[]);\nvoid ipfw_flush(int force);\nvoid ipfw_zero(int ac, char *av[], int optname);\nvoid ipfw_list(int ac, char *av[], int show_counters);\n\n/* altq.c */\nvoid altq_set_enabled(int enabled);\nu_int32_t altq_name_to_qid(const char *name);\n\nvoid print_altq_cmd(struct _ipfw_insn_altq *altqptr);\n\n/* dummynet.c */\nvoid dummynet_list(int ac, char *av[], int show_counters);\nvoid dummynet_flush(void);\nint ipfw_delete_pipe(int pipe_or_queue, int n);\n\n/* ipv6.c */\nvoid print_unreach6_code(uint16_t code);\nvoid print_ip6(struct _ipfw_insn_ip6 *cmd, char const *s);\nvoid print_flow6id(struct _ipfw_insn_u32 *cmd);\nvoid print_icmp6types(struct _ipfw_insn_u32 *cmd);\nvoid print_ext6hdr(struct _ipfw_insn *cmd );\n\nstruct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av);\nstruct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av);\n\nvoid fill_flow6(struct _ipfw_insn_u32 *cmd, char *av );\nvoid fill_unreach6_code(u_short *codep, char *str);\nvoid fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av);\nint fill_ext6hdr(struct _ipfw_insn *cmd, char *av);\n"
  },
  {
    "path": "ipfw/ipv6.c",
    "content": "/*\n * Copyright (c) 2002-2003 Luigi Rizzo\n * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp\n * Copyright (c) 1994 Ugen J.S.Antsilevich\n *\n * Idea and grammar partially left from:\n * Copyright (c) 1993 Daniel Boulet\n *\n * Redistribution and use in source forms, with and without modification,\n * are permitted provided that this entire comment appears intact.\n *\n * Redistribution in binary form may occur without any restrictions.\n * Obviously, it would be nice if you gave credit where credit is due\n * but requiring it would be too onerous.\n *\n * This software is provided ``AS IS'' without any warranties of any kind.\n *\n * NEW command line interface for IP firewall facility\n *\n * $FreeBSD: user/luigi/ipfw3-head/sbin/ipfw/ipv6.c 187770 2009-01-27 12:01:30Z luigi $\n *\n * ipv6 support\n */\n\n#include <sys/types.h>\n#include <sys/socket.h>\n\n#include \"ipfw2.h\"\n\n#include <err.h>\n#include <netdb.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sysexits.h>\n\n#include <net/if.h>\n#include <netinet/in.h>\n#include <netinet/in_systm.h>\n#include <netinet/ip.h>\n#include <netinet/icmp6.h>\n#include <netinet/ip_fw.h>\n#include <arpa/inet.h>\n\nstatic struct _s_x icmp6codes[] = {\n      { \"no-route\",\t\tICMP6_DST_UNREACH_NOROUTE },\n      { \"admin-prohib\",\t\tICMP6_DST_UNREACH_ADMIN },\n      { \"address\",\t\tICMP6_DST_UNREACH_ADDR },\n      { \"port\",\t\t\tICMP6_DST_UNREACH_NOPORT },\n      { NULL, 0 }\n};\n\nvoid\nfill_unreach6_code(u_short *codep, char *str)\n{\n\tint val;\n\tchar *s;\n\n\tval = strtoul(str, &s, 0);\n\tif (s == str || *s != '\\0' || val >= 0x100)\n\t\tval = match_token(icmp6codes, str);\n\tif (val < 0)\n\t\terrx(EX_DATAERR, \"unknown ICMPv6 unreachable code ``%s''\", str);\n\t*codep = val;\n\treturn;\n}\n\nvoid\nprint_unreach6_code(uint16_t code)\n{\n\tchar const *s = match_value(icmp6codes, code);\n\n\tif (s != NULL)\n\t\tprintf(\"unreach6 %s\", s);\n\telse\n\t\tprintf(\"unreach6 %u\", code);\n}\n\n/*\n * Print the ip address contained in a command.\n */\nvoid\nprint_ip6(ipfw_insn_ip6 *cmd, char const *s)\n{\n       struct hostent *he = NULL;\n       int len = F_LEN((ipfw_insn *) cmd) - 1;\n       struct in6_addr *a = &(cmd->addr6);\n       char trad[255];\n\n       printf(\"%s%s \", cmd->o.len & F_NOT ? \" not\": \"\", s);\n\n       if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {\n\t\tprintf(\"me6\");\n\t\treturn;\n       }\n       if (cmd->o.opcode == O_IP6) {\n\t\tprintf(\" ip6\");\n\t\treturn;\n       }\n\n\t/*\n\t * len == 4 indicates a single IP, whereas lists of 1 or more\n\t * addr/mask pairs have len = (2n+1). We convert len to n so we\n\t * use that to count the number of entries.\n\t */\n\n\tfor (len = len / 4; len > 0; len -= 2, a += 2) {\n           int mb =        /* mask length */\n               (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ?\n               128 : contigmask((uint8_t *)&(a[1]), 128);\n\n           if (mb == 128 && co.do_resolv)\n               he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);\n           if (he != NULL)             /* resolved to name */\n               printf(\"%s\", he->h_name);\n           else if (mb == 0)           /* any */\n               printf(\"any\");\n           else {          /* numeric IP followed by some kind of mask */\n               if (inet_ntop(AF_INET6,  a, trad, sizeof( trad ) ) == NULL)\n                   printf(\"Error ntop in print_ip6\\n\");\n               printf(\"%s\",  trad );\n               if (mb < 0)     /* XXX not really legal... */\n                   printf(\":%s\",\n                       inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));\n               else if (mb < 128)\n                   printf(\"/%d\", mb);\n           }\n           if (len > 2)\n               printf(\",\");\n       }\n}\n\nvoid\nfill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)\n{\n       uint8_t type;\n\n       bzero(cmd, sizeof(*cmd));\n\twhile (*av) {\n\tif (*av == ',')\n\t    av++;\n           type = strtoul(av, &av, 0);\n           if (*av != ',' && *av != '\\0')\n               errx(EX_DATAERR, \"invalid ICMP6 type\");\n\t   /*\n\t    * XXX: shouldn't this be 0xFF?  I can't see any reason why\n\t    * we shouldn't be able to filter all possiable values\n\t    * regardless of the ability of the rest of the kernel to do\n\t    * anything useful with them.\n\t    */\n           if (type > ICMP6_MAXTYPE)\n               errx(EX_DATAERR, \"ICMP6 type out of range\");\n           cmd->d[type / 32] |= ( 1 << (type % 32));\n       }\n       cmd->o.opcode = O_ICMP6TYPE;\n       cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);\n}\n\n\nvoid\nprint_icmp6types(ipfw_insn_u32 *cmd)\n{\n       int i, j;\n       char sep= ' ';\n\n       printf(\" ip6 icmp6types\");\n       for (i = 0; i < 7; i++)\n               for (j=0; j < 32; ++j) {\n                       if ( (cmd->d[i] & (1 << (j))) == 0)\n                               continue;\n                       printf(\"%c%d\", sep, (i*32 + j));\n                       sep = ',';\n               }\n}\n\nvoid\nprint_flow6id( ipfw_insn_u32 *cmd)\n{\n       uint16_t i, limit = cmd->o.arg1;\n       char sep = ',';\n\n       printf(\" flow-id \");\n       for( i=0; i < limit; ++i) {\n               if (i == limit - 1)\n                       sep = ' ';\n               printf(\"%d%c\", cmd->d[i], sep);\n       }\n}\n\n/* structure and define for the extension header in ipv6 */\nstatic struct _s_x ext6hdrcodes[] = {\n       { \"frag\",       EXT_FRAGMENT },\n       { \"hopopt\",     EXT_HOPOPTS },\n       { \"route\",      EXT_ROUTING },\n       { \"dstopt\",     EXT_DSTOPTS },\n       { \"ah\",\t\tEXT_AH },\n       { \"esp\",        EXT_ESP },\n       { \"rthdr0\",     EXT_RTHDR0 },\n       { \"rthdr2\",     EXT_RTHDR2 },\n       { NULL,         0 }\n};\n\n/* fills command for the extension header filtering */\nint\nfill_ext6hdr( ipfw_insn *cmd, char *av)\n{\n       int tok;\n       char *s = av;\n\n       cmd->arg1 = 0;\n\n       while(s) {\n\t   av = strsep( &s, \",\") ;\n           tok = match_token(ext6hdrcodes, av);\n           switch (tok) {\n           case EXT_FRAGMENT:\n               cmd->arg1 |= EXT_FRAGMENT;\n               break;\n\n           case EXT_HOPOPTS:\n               cmd->arg1 |= EXT_HOPOPTS;\n               break;\n\n           case EXT_ROUTING:\n               cmd->arg1 |= EXT_ROUTING;\n               break;\n\n           case EXT_DSTOPTS:\n               cmd->arg1 |= EXT_DSTOPTS;\n               break;\n\n           case EXT_AH:\n               cmd->arg1 |= EXT_AH;\n               break;\n\n           case EXT_ESP:\n               cmd->arg1 |= EXT_ESP;\n               break;\n\n           case EXT_RTHDR0:\n               cmd->arg1 |= EXT_RTHDR0;\n               break;\n\n           case EXT_RTHDR2:\n               cmd->arg1 |= EXT_RTHDR2;\n               break;\n\n           default:\n               errx( EX_DATAERR, \"invalid option for ipv6 exten header\" );\n               break;\n           }\n       }\n       if (cmd->arg1 == 0 )\n\t    return 0;\n       cmd->opcode = O_EXT_HDR;\n       cmd->len |= F_INSN_SIZE( ipfw_insn );\n       return 1;\n}\n\nvoid\nprint_ext6hdr( ipfw_insn *cmd )\n{\n       char sep = ' ';\n\n       printf(\" extension header:\");\n       if (cmd->arg1 & EXT_FRAGMENT ) {\n\t    printf(\"%cfragmentation\", sep);\n           sep = ',';\n       }\n       if (cmd->arg1 & EXT_HOPOPTS ) {\n           printf(\"%chop options\", sep);\n           sep = ',';\n       }\n       if (cmd->arg1 & EXT_ROUTING ) {\n           printf(\"%crouting options\", sep);\n           sep = ',';\n       }\n       if (cmd->arg1 & EXT_RTHDR0 ) {\n           printf(\"%crthdr0\", sep);\n           sep = ',';\n       }\n       if (cmd->arg1 & EXT_RTHDR2 ) {\n           printf(\"%crthdr2\", sep);\n           sep = ',';\n       }\n       if (cmd->arg1 & EXT_DSTOPTS ) {\n           printf(\"%cdestination options\", sep);\n           sep = ',';\n       }\n       if (cmd->arg1 & EXT_AH ) {\n           printf(\"%cauthentication header\", sep);\n           sep = ',';\n       }\n       if (cmd->arg1 & EXT_ESP ) {\n           printf(\"%cencapsulated security payload\", sep);\n       }\n}\n\n/* Try to find ipv6 address by hostname */\nstatic int\nlookup_host6 (char *host, struct in6_addr *ip6addr)\n{\n\tstruct hostent *he;\n\n\tif (!inet_pton(AF_INET6, host, ip6addr)) {\n\t\tif ((he = gethostbyname2(host, AF_INET6)) == NULL)\n\t\t\treturn(-1);\n\t\tmemcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));\n\t}\n\treturn(0);\n}\n\n\n/*\n * fill the addr and mask fields in the instruction as appropriate from av.\n * Update length as appropriate.\n * The following formats are allowed:\n *     any     matches any IP6. Actually returns an empty instruction.\n *     me      returns O_IP6_*_ME\n *\n *     03f1::234:123:0342                single IP6 addres\n *     03f1::234:123:0342/24            address/mask\n *     03f1::234:123:0342/24,03f1::234:123:0343/               List of address\n *\n * Set of address (as in ipv6) not supported because ipv6 address\n * are typically random past the initial prefix.\n * Return 1 on success, 0 on failure.\n */\nstatic int\nfill_ip6(ipfw_insn_ip6 *cmd, char *av)\n{\n\tint len = 0;\n\tstruct in6_addr *d = &(cmd->addr6);\n\t/*\n\t * Needed for multiple address.\n\t * Note d[1] points to struct in6_add r mask6 of cmd\n\t */\n\n       cmd->o.len &= ~F_LEN_MASK;\t/* zero len */\n\n       if (strcmp(av, \"any\") == 0)\n\t       return (1);\n\n\n       if (strcmp(av, \"me\") == 0) {\t/* Set the data for \"me\" opt*/\n\t       cmd->o.len |= F_INSN_SIZE(ipfw_insn);\n\t       return (1);\n       }\n\n       if (strcmp(av, \"me6\") == 0) {\t/* Set the data for \"me\" opt*/\n\t       cmd->o.len |= F_INSN_SIZE(ipfw_insn);\n\t       return (1);\n       }\n\n       av = strdup(av);\n       while (av) {\n\t\t/*\n\t\t * After the address we can have '/' indicating a mask,\n\t\t * or ',' indicating another address follows.\n\t\t */\n\n\t\tchar *p;\n\t\tint masklen;\n\t\tchar md = '\\0';\n\n\t\tif ((p = strpbrk(av, \"/,\")) ) {\n\t\t\tmd = *p;\t/* save the separator */\n\t\t\t*p = '\\0';\t/* terminate address string */\n\t\t\tp++;\t\t/* and skip past it */\n\t\t}\n\t\t/* now p points to NULL, mask or next entry */\n\n\t\t/* lookup stores address in *d as a side effect */\n\t\tif (lookup_host6(av, d) != 0) {\n\t\t\t/* XXX: failed. Free memory and go */\n\t\t\terrx(EX_DATAERR, \"bad address \\\"%s\\\"\", av);\n\t\t}\n\t\t/* next, look at the mask, if any */\n\t\tmasklen = (md == '/') ? atoi(p) : 128;\n\t\tif (masklen > 128 || masklen < 0)\n\t\t\terrx(EX_DATAERR, \"bad width \\\"%s\\''\", p);\n\t\telse\n\t\t\tn2mask(&d[1], masklen);\n\n\t\tAPPLY_MASK(d, &d[1])   /* mask base address with mask */\n\n\t\t/* find next separator */\n\n\t\tif (md == '/') {\t/* find separator past the mask */\n\t\t\tp = strpbrk(p, \",\");\n\t\t\tif (p != NULL)\n\t\t\t\tp++;\n\t\t}\n\t\tav = p;\n\n\t\t/* Check this entry */\n\t\tif (masklen == 0) {\n\t\t\t/*\n\t\t\t * 'any' turns the entire list into a NOP.\n\t\t\t * 'not any' never matches, so it is removed from the\n\t\t\t * list unless it is the only item, in which case we\n\t\t\t * report an error.\n\t\t\t */\n\t\t\tif (cmd->o.len & F_NOT && av == NULL && len == 0)\n\t\t\t\terrx(EX_DATAERR, \"not any never matches\");\n\t\t\tcontinue;\n\t\t}\n\n\t\t/*\n\t\t * A single IP can be stored alone\n\t\t */\n\t\tif (masklen == 128 && av == NULL && len == 0) {\n\t\t\tlen = F_INSN_SIZE(struct in6_addr);\n\t\t\tbreak;\n\t\t}\n\n\t\t/* Update length and pointer to arguments */\n\t\tlen += F_INSN_SIZE(struct in6_addr)*2;\n\t\td += 2;\n\t} /* end while */\n\n\t/*\n\t * Total length of the command, remember that 1 is the size of\n\t * the base command.\n\t */\n\tif (len + 1 > F_LEN_MASK)\n\t\terrx(EX_DATAERR, \"address list too long\");\n\tcmd->o.len |= len+1;\n\tfree(av);\n\treturn (1);\n}\n\n/*\n * fills command for ipv6 flow-id filtering\n * note that the 20 bit flow number is stored in a array of u_int32_t\n * it's supported lists of flow-id, so in the o.arg1 we store how many\n * additional flow-id we want to filter, the basic is 1\n */\nvoid\nfill_flow6( ipfw_insn_u32 *cmd, char *av )\n{\n\tu_int32_t type;\t /* Current flow number */\n\tu_int16_t nflow = 0;    /* Current flow index */\n\tchar *s = av;\n\tcmd->d[0] = 0;\t  /* Initializing the base number*/\n\n\twhile (s) {\n\t\tav = strsep( &s, \",\") ;\n\t\ttype = strtoul(av, &av, 0);\n\t\tif (*av != ',' && *av != '\\0')\n\t\t\terrx(EX_DATAERR, \"invalid ipv6 flow number %s\", av);\n\t\tif (type > 0xfffff)\n\t\t\terrx(EX_DATAERR, \"flow number out of range %s\", av);\n\t\tcmd->d[nflow] |= type;\n\t\tnflow++;\n\t}\n\tif( nflow > 0 ) {\n\t\tcmd->o.opcode = O_FLOW6ID;\n\t\tcmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;\n\t\tcmd->o.arg1 = nflow;\n\t}\n\telse {\n\t\terrx(EX_DATAERR, \"invalid ipv6 flow number %s\", av);\n\t}\n}\n\nipfw_insn *\nadd_srcip6(ipfw_insn *cmd, char *av)\n{\n\n\tfill_ip6((ipfw_insn_ip6 *)cmd, av);\n\tif (F_LEN(cmd) == 0) {\t\t\t\t/* any */\n\t} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) {\t/* \"me\" */\n\t\tcmd->opcode = O_IP6_SRC_ME;\n\t} else if (F_LEN(cmd) ==\n\t    (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {\n\t\t/* single IP, no mask*/\n\t\tcmd->opcode = O_IP6_SRC;\n\t} else {\t\t\t\t\t/* addr/mask opt */\n\t\tcmd->opcode = O_IP6_SRC_MASK;\n\t}\n\treturn cmd;\n}\n\nipfw_insn *\nadd_dstip6(ipfw_insn *cmd, char *av)\n{\n\n\tfill_ip6((ipfw_insn_ip6 *)cmd, av);\n\tif (F_LEN(cmd) == 0) {\t\t\t\t/* any */\n\t} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) {\t/* \"me\" */\n\t\tcmd->opcode = O_IP6_DST_ME;\n\t} else if (F_LEN(cmd) ==\n\t    (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {\n\t\t/* single IP, no mask*/\n\t\tcmd->opcode = O_IP6_DST;\n\t} else {\t\t\t\t\t/* addr/mask opt */\n\t\tcmd->opcode = O_IP6_DST_MASK;\n\t}\n\treturn cmd;\n}\n"
  },
  {
    "path": "ipfw/main.c",
    "content": "/*\n * Copyright (c) 2002-2003,2010 Luigi Rizzo\n * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp\n * Copyright (c) 1994 Ugen J.S.Antsilevich\n *\n * Idea and grammar partially left from:\n * Copyright (c) 1993 Daniel Boulet\n *\n * Redistribution and use in source forms, with and without modification,\n * are permitted provided that this entire comment appears intact.\n *\n * Redistribution in binary form may occur without any restrictions.\n * Obviously, it would be nice if you gave credit where credit is due\n * but requiring it would be too onerous.\n *\n * This software is provided ``AS IS'' without any warranties of any kind.\n *\n * Command line interface for IP firewall facility\n *\n * $FreeBSD: head/sbin/ipfw/main.c 206494 2010-04-12 08:27:53Z luigi $\n */\n\n#include <sys/wait.h>\n#include <ctype.h>\n#include <err.h>\n#include <errno.h>\n#include <signal.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sysexits.h>\n#include <unistd.h>\n\n#include \"ipfw2.h\"\n\nstatic void\nhelp(void)\n{\n\tfprintf(stderr,\n\"ipfw syntax summary (but please do read the ipfw(8) manpage):\\n\\n\"\n\"\\tipfw [-abcdefhnNqStTv] <command>\\n\\n\"\n\"where <command> is one of the following:\\n\\n\"\n\"add [num] [set N] [prob x] RULE-BODY\\n\"\n\"{pipe|queue} N config PIPE-BODY\\n\"\n\"[pipe|queue] {zero|delete|show} [N{,N}]\\n\"\n\"nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|reset|\\n\"\n\"\t\treverse|proxy_only|redirect_addr linkspec|\\n\"\n\"\t\tredirect_port linkspec|redirect_proto linkspec}\\n\"\n\"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\\n\"\n\"set N {show|list|zero|resetlog|delete} [N{,N}] | flush\\n\"\n\"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\\n\"\n\"table all {flush | list}\\n\"\n\"\\n\"\n\"RULE-BODY:\tcheck-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\\n\"\n\"ACTION:\tcheck-state | allow | count | deny | unreach{,6} CODE |\\n\"\n\"               skipto N | {divert|tee} PORT | forward ADDR |\\n\"\n\"               pipe N | queue N | nat N | setfib FIB | reass\\n\"\n\"PARAMS: \t[log [logamount LOGLIMIT]] [altq QUEUE_NAME]\\n\"\n\"ADDR:\t\t[ MAC dst src ether_type ] \\n\"\n\"\t\t[ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\\n\"\n\"\t\t[ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\\n\"\n\"IPADDR:\t[not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\\n\"\n\"IP6ADDR:\t[not] { any | me | me6 | ip6/bits | IP6LIST }\\n\"\n\"IP6LIST:\t{ ip6 | ip6/bits }[,IP6LIST]\\n\"\n\"IPLIST:\t{ ip | ip/bits | ip:mask }[,IPLIST]\\n\"\n\"OPTION_LIST:\tOPTION [OPTION_LIST]\\n\"\n\"OPTION:\tbridged | diverted | diverted-loopback | diverted-output |\\n\"\n\"\t{dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\\n\"\n\"\t{dst-port|src-port} LIST |\\n\"\n\"\testab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\\n\"\n\"\tiplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\\n\"\n\"\tipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\\n\"\n\"\ticmp6types LIST | ext6hdr LIST | flow-id N[,N] | fib FIB |\\n\"\n\"\tmac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\\n\"\n\"\tsetup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\\n\"\n\"\ttcpdatalen LIST | verrevpath | versrcreach | antispoof\\n\"\n);\n\n\texit(0);\n}\n\n/*\n * Called with the arguments, including program name because getopt\n * wants it to be present.\n * Returns 0 if successful, 1 if empty command, errx() in case of errors.\n * First thing we do is process parameters creating an argv[] array\n * which includes the program name and a NULL entry at the end.\n * If we are called with a single string, we split it on whitespace.\n * Also, arguments with a trailing ',' are joined to the next one.\n * The pointers (av[]) and data are in a single chunk of memory.\n * av[0] points to the original program name, all other entries\n * point into the allocated chunk.\n */\nstatic int\nipfw_main(int oldac, char **oldav)\n{\n\tint ch, ac;\n\tconst char *errstr;\n\tchar **av, **save_av;\n\tint do_acct = 0;\t\t/* Show packet/byte count */\n\tint try_next = 0;\t\t/* set if pipe cmd not found */\n\tint av_size;\t\t\t/* compute the av size */\n\tchar *av_p;\t\t\t/* used to build the av list */\n\n#define WHITESP\t\t\" \\t\\f\\v\\n\\r\"\n\tif (oldac < 2)\n\t\treturn 1;\t/* need at least one argument */\n\n\tif (oldac == 2) {\n\t\t/*\n\t\t * If we are called with one argument, try to split it into\n\t\t * words for subsequent parsing. Spaces after a ',' are\n\t\t * removed by copying the string in-place.\n\t\t */\n\t\tchar *arg = oldav[1];\t/* The string is the first arg. */\n\t\tint l = strlen(arg);\n\t\tint copy = 0;\t\t/* 1 if we need to copy, 0 otherwise */\n\t\tint i, j;\n\n\t\tfor (i = j = 0; i < l; i++) {\n\t\t\tif (arg[i] == '#')\t/* comment marker */\n\t\t\t\tbreak;\n\t\t\tif (copy) {\n\t\t\t\targ[j++] = arg[i];\n\t\t\t\tcopy = !strchr(\",\" WHITESP, arg[i]);\n\t\t\t} else {\n\t\t\t\tcopy = !strchr(WHITESP, arg[i]);\n\t\t\t\tif (copy)\n\t\t\t\t\targ[j++] = arg[i];\n\t\t\t}\n\t\t}\n\t\tif (!copy && j > 0)\t/* last char was a 'blank', remove it */\n\t\t\tj--;\n\t\tl = j;\t\t\t/* the new argument length */\n\t\targ[j++] = '\\0';\n\t\tif (l == 0)\t\t/* empty string! */\n\t\t\treturn 1;\n\n\t\t/*\n\t\t * First, count number of arguments. Because of the previous\n\t\t * processing, this is just the number of blanks plus 1.\n\t\t */\n\t\tfor (i = 0, ac = 1; i < l; i++)\n\t\t\tif (strchr(WHITESP, arg[i]) != NULL)\n\t\t\t\tac++;\n\n\t\t/*\n\t\t * Allocate the argument list structure as a single block\n\t\t * of memory, containing pointers and the argument\n\t\t * strings. We include one entry for the program name\n\t\t * because getopt expects it, and a NULL at the end\n\t\t * to simplify further parsing.\n\t\t */\n\t\tac++;\t\t/* add 1 for the program name */\n\t\tav_size = (ac+1) * sizeof(char *) + l + 1;\n\t\tav = safe_calloc(av_size, 1);\n\n\t\t/*\n\t\t * Init the argument pointer to the end of the array\n\t\t * and copy arguments from arg[] to av[]. For each one,\n\t\t * j is the initial character, i is the one past the end.\n\t\t */\n\t\tav_p = (char *)&av[ac+1];\n\t\tfor (ac = 1, i = j = 0; i < l; i++) {\n\t\t\tif (strchr(WHITESP, arg[i]) != NULL || i == l-1) {\n\t\t\t\tif (i == l-1)\n\t\t\t\t\ti++;\n\t\t\t\tbcopy(arg+j, av_p, i-j);\n\t\t\t\tav[ac] = av_p;\n\t\t\t\tav_p += i-j;\t/* the length of the string */\n\t\t\t\t*av_p++ = '\\0';\n\t\t\t\tac++;\n\t\t\t\tj = i + 1;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t/*\n\t\t * If an argument ends with ',' join with the next one.\n\t\t */\n\t\tint first, i, l=0;\n\n\t\t/*\n\t\t * Allocate the argument list structure as a single block\n\t\t * of memory, containing both pointers and the argument\n\t\t * strings. We include some space for the program name\n\t\t * because getopt expects it.\n\t\t * We add an extra pointer to the end of the array,\n\t\t * to make simpler further parsing.\n\t\t */\n\t\tfor (i=0; i<oldac; i++)\n\t\t\tl += strlen(oldav[i]);\n\n\t\tav_size = (oldac+1) * sizeof(char *) + l + oldac;\n\t\tav = safe_calloc(av_size, 1);\n\n\t\t/*\n\t\t * Init the argument pointer to the end of the array\n\t\t * and copy arguments from arg[] to av[]\n\t\t */\n\t\tav_p = (char *)&av[oldac+1];\n\t\tfor (first = i = ac = 1, l = 0; i < oldac; i++) {\n\t\t\tchar *arg = oldav[i];\n\t\t\tint k = strlen(arg);\n\n\t\t\tl += k;\n\t\t\tif (arg[k-1] != ',' || i == oldac-1) {\n\t\t\t\t/* Time to copy. */\n\t\t\t\tav[ac] = av_p;\n\t\t\t\tfor (l=0; first <= i; first++) {\n\t\t\t\t\tstrcat(av_p, oldav[first]);\n\t\t\t\t\tav_p += strlen(oldav[first]);\n\t\t\t\t}\n\t\t\t\t*av_p++ = '\\0';\n\t\t\t\tac++;\n\t\t\t\tl = 0;\n\t\t\t\tfirst = i+1;\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * set the progname pointer to the original string\n\t * and terminate the array with null\n\t */\n\tav[0] = oldav[0];\n\tav[ac] = NULL;\n\n\t/* Set the force flag for non-interactive processes */\n\tif (!co.do_force)\n\t\tco.do_force = !isatty(STDIN_FILENO);\n\n#ifdef EMULATE_SYSCTL /* sysctl emulation */\n\tif ( ac >= 2 && !strcmp(av[1], \"sysctl\")) {\n\t\tchar *s;\n\t\tint i;\n\n\t\tif (ac != 3) {\n\t\t\tprintf(\t\"sysctl emulation usage:\\n\"\n\t\t\t\t\"\tipfw sysctl name[=value]\\n\"\n\t\t\t\t\"\tipfw sysctl -a\\n\");\n\t\t\treturn 0;\n\t\t}\n\t\ts = strchr(av[2], '=');\n\t\tif (s == NULL) {\n\t\t\ts = !strcmp(av[2], \"-a\") ? NULL : av[2];\n\t\t\tsysctlbyname(s, NULL, NULL, NULL, 0);\n\t\t} else {\t/* ipfw sysctl x.y.z=value */\n\t\t\t/* assume an INT value, will extend later */\n\t\t\tif (s[1] == '\\0') {\n\t\t\t\tprintf(\"ipfw sysctl: missing value\\n\\n\");\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t*s = '\\0';\n\t\t\ti = strtol(s+1, NULL, 0);\n\t\t\tsysctlbyname(av[2], NULL, NULL, &i, sizeof(int));\n\t\t}\n\t\treturn 0;\n\t}\n#endif\n\n\t/* Save arguments for final freeing of memory. */\n\tsave_av = av;\n\n\toptind = optreset = 1;\t/* restart getopt() */\n\twhile ((ch = getopt(ac, av, \"abcdefhinNp:qs:STtv\")) != -1)\n\t\tswitch (ch) {\n\t\tcase 'a':\n\t\t\tdo_acct = 1;\n\t\t\tbreak;\n\n\t\tcase 'b':\n\t\t\tco.comment_only = 1;\n\t\t\tco.do_compact = 1;\n\t\t\tbreak;\n\n\t\tcase 'c':\n\t\t\tco.do_compact = 1;\n\t\t\tbreak;\n\n\t\tcase 'd':\n\t\t\tco.do_dynamic = 1;\n\t\t\tbreak;\n\n\t\tcase 'e':\n\t\t\tco.do_expired = 1;\n\t\t\tbreak;\n\n\t\tcase 'f':\n\t\t\tco.do_force = 1;\n\t\t\tbreak;\n\n\t\tcase 'h': /* help */\n\t\t\tfree(save_av);\n\t\t\thelp();\n\t\t\tbreak;\t/* NOTREACHED */\n\n\t\tcase 'i':\n\t\t\tco.do_value_as_ip = 1;\n\t\t\tbreak;\n\n\t\tcase 'n':\n\t\t\tco.test_only = 1;\n\t\t\tbreak;\n\n\t\tcase 'N':\n\t\t\tco.do_resolv = 1;\n\t\t\tbreak;\n\n\t\tcase 'q':\n\t\t\tco.do_quiet = 1;\n\t\t\tbreak;\n\n\t\tcase 'p':\n\t\t\terrx(EX_USAGE, \"An absolute pathname must be used \"\n\t\t\t    \"with -p option.\");\n\t\t\t/* NOTREACHED */\n\n\t\tcase 's': /* sort */\n\t\t\tco.do_sort = atoi(optarg);\n\t\t\tbreak;\n\n\t\tcase 'S':\n\t\t\tco.show_sets = 1;\n\t\t\tbreak;\n\n\t\tcase 't':\n\t\t\tco.do_time = 1;\n\t\t\tbreak;\n\n\t\tcase 'T':\n\t\t\tco.do_time = 2;\t/* numeric timestamp */\n\t\t\tbreak;\n\n\t\tcase 'v': /* verbose */\n\t\t\tco.verbose = 1;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tfree(save_av);\n\t\t\treturn 1;\n\t\t}\n\n\tac -= optind;\n\tav += optind;\n\tNEED1(\"bad arguments, for usage summary ``ipfw''\");\n\n\t/*\n\t * An undocumented behaviour of ipfw1 was to allow rule numbers first,\n\t * e.g. \"100 add allow ...\" instead of \"add 100 allow ...\".\n\t * In case, swap first and second argument to get the normal form.\n\t */\n\tif (ac > 1 && isdigit(*av[0])) {\n\t\tchar *p = av[0];\n\n\t\tav[0] = av[1];\n\t\tav[1] = p;\n\t}\n\n\t/*\n\t * Optional: pipe, queue or nat.\n\t */\n\tco.do_nat = 0;\n\tco.do_pipe = 0;\n\tco.use_set = 0;\n\tif (!strncmp(*av, \"nat\", strlen(*av)))\n\t        co.do_nat = 1;\n\telse if (!strncmp(*av, \"pipe\", strlen(*av)))\n\t\tco.do_pipe = 1;\n\telse if (_substrcmp(*av, \"queue\") == 0)\n\t\tco.do_pipe = 2;\n\telse if (_substrcmp(*av, \"flowset\") == 0)\n\t\tco.do_pipe = 2;\n\telse if (_substrcmp(*av, \"sched\") == 0)\n\t\tco.do_pipe = 3;\n\telse if (!strncmp(*av, \"set\", strlen(*av))) {\n\t\tif (ac > 1 && isdigit(av[1][0])) {\n\t\t\tco.use_set = strtonum(av[1], 0, resvd_set_number,\n\t\t\t\t\t&errstr);\n\t\t\tif (errstr)\n\t\t\t\terrx(EX_DATAERR,\n\t\t\t\t    \"invalid set number %s\\n\", av[1]);\n\t\t\tac -= 2; av += 2; co.use_set++;\n\t\t}\n\t}\n\n\tif (co.do_pipe || co.do_nat) {\n\t\tac--;\n\t\tav++;\n\t}\n\tNEED1(\"missing command\");\n\n\t/*\n\t * For pipes, queues and nats we normally say 'nat|pipe NN config'\n\t * but the code is easier to parse as 'nat|pipe config NN'\n\t * so we swap the two arguments.\n\t */\n\tif ((co.do_pipe || co.do_nat) && ac > 1 && isdigit(*av[0])) {\n\t\tchar *p = av[0];\n\n\t\tav[0] = av[1];\n\t\tav[1] = p;\n\t}\n\n\tif (co.use_set == 0) {\n\t\tif (_substrcmp(*av, \"add\") == 0)\n\t\t\tipfw_add(av);\n\t\telse if (co.do_nat && _substrcmp(*av, \"show\") == 0)\n\t\t\tipfw_show_nat(ac, av);\n\t\telse if (co.do_pipe && _substrcmp(*av, \"config\") == 0)\n\t\t\tipfw_config_pipe(ac, av);\n\t\telse if (co.do_nat && _substrcmp(*av, \"config\") == 0)\n\t\t\tipfw_config_nat(ac, av);\n\t\telse if (_substrcmp(*av, \"set\") == 0)\n\t\t\tipfw_sets_handler(av);\n\t\telse if (_substrcmp(*av, \"table\") == 0)\n\t\t\tipfw_table_handler(ac, av);\n\t\telse if (_substrcmp(*av, \"enable\") == 0)\n\t\t\tipfw_sysctl_handler(av, 1);\n\t\telse if (_substrcmp(*av, \"disable\") == 0)\n\t\t\tipfw_sysctl_handler(av, 0);\n\t\telse\n\t\t\ttry_next = 1;\n\t}\n\n\tif (co.use_set || try_next) {\n\t\tif (_substrcmp(*av, \"delete\") == 0)\n\t\t\tipfw_delete(av);\n\t\telse if (_substrcmp(*av, \"flush\") == 0)\n\t\t\tipfw_flush(co.do_force);\n\t\telse if (_substrcmp(*av, \"zero\") == 0)\n\t\t\tipfw_zero(ac, av, 0 /* IP_FW_ZERO */);\n\t\telse if (_substrcmp(*av, \"resetlog\") == 0)\n\t\t\tipfw_zero(ac, av, 1 /* IP_FW_RESETLOG */);\n\t\telse if (_substrcmp(*av, \"print\") == 0 ||\n\t\t         _substrcmp(*av, \"list\") == 0)\n\t\t\tipfw_list(ac, av, do_acct);\n\t\telse if (_substrcmp(*av, \"show\") == 0)\n\t\t\tipfw_list(ac, av, 1 /* show counters */);\n\t\telse\n\t\t\terrx(EX_USAGE, \"bad command `%s'\", *av);\n\t}\n\n\t/* Free memory allocated in the argument parsing. */\n\tfree(save_av);\n\treturn 0;\n}\n\n\nstatic void\nipfw_readfile(int ac, char *av[])\n{\n#define MAX_ARGS\t32\n\tchar buf[4096];\n\tchar *progname = av[0];\t\t/* original program name */\n\tconst char *cmd = NULL;\t\t/* preprocessor name, if any */\n\tconst char *filename = av[ac-1]; /* file to read */\n\tint\tc, lineno=0;\n\tFILE\t*f = NULL;\n\tpid_t\tpreproc = 0;\n\n\twhile ((c = getopt(ac, av, \"cfNnp:qS\")) != -1) {\n\t\tswitch(c) {\n\t\tcase 'c':\n\t\t\tco.do_compact = 1;\n\t\t\tbreak;\n\n\t\tcase 'f':\n\t\t\tco.do_force = 1;\n\t\t\tbreak;\n\n\t\tcase 'N':\n\t\t\tco.do_resolv = 1;\n\t\t\tbreak;\n\n\t\tcase 'n':\n\t\t\tco.test_only = 1;\n\t\t\tbreak;\n\n\t\tcase 'p':\n\t\t\t/*\n\t\t\t * ipfw -p cmd [args] filename\n\t\t\t *\n\t\t\t * We are done with getopt(). All arguments\n\t\t\t * except the filename go to the preprocessor,\n\t\t\t * so we need to do the following:\n\t\t\t * - check that a filename is actually present;\n\t\t\t * - advance av by optind-1 to skip arguments\n\t\t\t *   already processed;\n\t\t\t * - decrease ac by optind, to remove the args\n\t\t\t *   already processed and the final filename;\n\t\t\t * - set the last entry in av[] to NULL so\n\t\t\t *   popen() can detect the end of the array;\n\t\t\t * - set optind=ac to let getopt() terminate.\n\t\t\t */\n\t\t\tif (optind == ac)\n\t\t\t\terrx(EX_USAGE, \"no filename argument\");\n\t\t\tcmd = optarg;\n\t\t\tav[ac-1] = NULL;\n\t\t\tav += optind - 1;\n\t\t\tac -= optind;\n\t\t\toptind = ac;\n\t\t\tbreak;\n\n\t\tcase 'q':\n\t\t\tco.do_quiet = 1;\n\t\t\tbreak;\n\n\t\tcase 'S':\n\t\t\tco.show_sets = 1;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\terrx(EX_USAGE, \"bad arguments, for usage\"\n\t\t\t     \" summary ``ipfw''\");\n\t\t}\n\n\t}\n\n\tif (cmd == NULL && ac != optind + 1)\n\t\terrx(EX_USAGE, \"extraneous filename arguments %s\", av[ac-1]);\n\n\tif ((f = fopen(filename, \"r\")) == NULL)\n\t\terr(EX_UNAVAILABLE, \"fopen: %s\", filename);\n\n\tif (cmd != NULL) {\t\t\t/* pipe through preprocessor */\n\t\tint pipedes[2];\n\n\t\tif (pipe(pipedes) == -1)\n\t\t\terr(EX_OSERR, \"cannot create pipe\");\n\n\t\tpreproc = fork();\n\t\tif (preproc == -1)\n\t\t\terr(EX_OSERR, \"cannot fork\");\n\n\t\tif (preproc == 0) {\n\t\t\t/*\n\t\t\t * Child, will run the preprocessor with the\n\t\t\t * file on stdin and the pipe on stdout.\n\t\t\t */\n\t\t\tif (dup2(fileno(f), 0) == -1\n\t\t\t    || dup2(pipedes[1], 1) == -1)\n\t\t\t\terr(EX_OSERR, \"dup2()\");\n\t\t\tfclose(f);\n\t\t\tclose(pipedes[1]);\n\t\t\tclose(pipedes[0]);\n\t\t\texecvp(cmd, av);\n\t\t\terr(EX_OSERR, \"execvp(%s) failed\", cmd);\n\t\t} else { /* parent, will reopen f as the pipe */\n\t\t\tfclose(f);\n\t\t\tclose(pipedes[1]);\n\t\t\tif ((f = fdopen(pipedes[0], \"r\")) == NULL) {\n\t\t\t\tint savederrno = errno;\n\n\t\t\t\t(void)kill(preproc, SIGTERM);\n\t\t\t\terrno = savederrno;\n\t\t\t\terr(EX_OSERR, \"fdopen()\");\n\t\t\t}\n\t\t}\n\t}\n\n\twhile (fgets(buf, sizeof(buf), f)) {\t\t/* read commands */\n\t\tchar linename[20];\n\t\tchar *args[2];\n\n\t\tlineno++;\n\t\tsnprintf(linename, sizeof(linename), \"Line %d\", lineno);\n\t\tsetprogname(linename); /* XXX */\n\t\targs[0] = progname;\n\t\targs[1] = buf;\n\t\tipfw_main(2, args);\n\t}\n\tfclose(f);\n\tif (cmd != NULL) {\n\t\tint status;\n\n\t\tif (waitpid(preproc, &status, 0) == -1)\n\t\t\terrx(EX_OSERR, \"waitpid()\");\n\t\tif (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)\n\t\t\terrx(EX_UNAVAILABLE,\n\t\t\t    \"preprocessor exited with status %d\",\n\t\t\t    WEXITSTATUS(status));\n\t\telse if (WIFSIGNALED(status))\n\t\t\terrx(EX_UNAVAILABLE,\n\t\t\t    \"preprocessor exited with signal %d\",\n\t\t\t    WTERMSIG(status));\n\t}\n}\n\nint\nmain(int ac, char *av[])\n{\n#if defined(_WIN32) && defined(TCC)\n\t{\n\t\tWSADATA wsaData;\n\t\tint ret=0;\n\t\tunsigned short wVersionRequested = MAKEWORD(2, 2);\n\t\tret = WSAStartup(wVersionRequested, &wsaData);\n\t\tif (ret != 0) {\n\t\t\t/* Tell the user that we could not find a usable */\n\t\t\t/* Winsock DLL.                                  */\n\t\t\tprintf(\"WSAStartup failed with error: %d\\n\", ret);\n\t\t\treturn 1;\n\t\t}\n\t}\n#endif\n\t/*\n\t * If the last argument is an absolute pathname, interpret it\n\t * as a file to be preprocessed.\n\t */\n\n\tif (ac > 1 && av[ac - 1][0] == '/') {\n\t\tif (access(av[ac - 1], R_OK) == 0)\n\t\t\tipfw_readfile(ac, av);\n\t\telse\n\t\t\terr(EX_USAGE, \"pathname: %s\", av[ac - 1]);\n\t} else {\n\t\tif (ipfw_main(ac, av)) {\n\t\t\terrx(EX_USAGE,\n\t\t\t    \"usage: ipfw [options]\\n\"\n\t\t\t    \"do \\\"ipfw -h\\\" or \\\"man ipfw\\\" for details\");\n\t\t}\n\t}\n\treturn EX_OK;\n}\n"
  },
  {
    "path": "ipfw/qsort.c",
    "content": "/*-\n * Copyright (c) 1992, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#if defined(LIBC_SCCS) && !defined(lint)\nstatic char sccsid[] = \"@(#)qsort.c\t8.1 (Berkeley) 6/4/93\";\n#endif /* LIBC_SCCS and not lint */\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.15 2008/01/14 09:21:34 das Exp $\");\n\n#include <stdlib.h>\n\n#ifdef I_AM_QSORT_R\ntypedef int\t\t cmp_t(void *, const void *, const void *);\n#else\ntypedef int\t\t cmp_t(const void *, const void *);\n#endif\nstatic inline char\t*med3(char *, char *, char *, cmp_t *, void *);\nstatic inline void\t swapfunc(char *, char *, int, int);\n\n#define min(a, b)\t(a) < (b) ? a : b\n\n/*\n * Qsort routine from Bentley & McIlroy's \"Engineering a Sort Function\".\n */\n#define swapcode(TYPE, parmi, parmj, n) { \t\t\\\n\tlong i = (n) / sizeof (TYPE); \t\t\t\\\n\tTYPE *pi = (TYPE *) (parmi); \t\t\\\n\tTYPE *pj = (TYPE *) (parmj); \t\t\\\n\tdo { \t\t\t\t\t\t\\\n\t\tTYPE\tt = *pi;\t\t\\\n\t\t*pi++ = *pj;\t\t\t\t\\\n\t\t*pj++ = t;\t\t\t\t\\\n        } while (--i > 0);\t\t\t\t\\\n}\n\n#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \\\n\tes % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;\n\nstatic inline void\nswapfunc(a, b, n, swaptype)\n\tchar *a, *b;\n\tint n, swaptype;\n{\n\tif(swaptype <= 1)\n\t\tswapcode(long, a, b, n)\n\telse\n\t\tswapcode(char, a, b, n)\n}\n\n#define swap(a, b)\t\t\t\t\t\\\n\tif (swaptype == 0) {\t\t\t\t\\\n\t\tlong t = *(long *)(a);\t\t\t\\\n\t\t*(long *)(a) = *(long *)(b);\t\t\\\n\t\t*(long *)(b) = t;\t\t\t\\\n\t} else\t\t\t\t\t\t\\\n\t\tswapfunc(a, b, es, swaptype)\n\n#define vecswap(a, b, n) \tif ((n) > 0) swapfunc(a, b, n, swaptype)\n\n#ifdef I_AM_QSORT_R\n#define\tCMP(t, x, y) (cmp((t), (x), (y)))\n#else\n#define\tCMP(t, x, y) (cmp((x), (y)))\n#endif\n\nstatic inline char *\nmed3(char *a, char *b, char *c, cmp_t *cmp, void *thunk\n#ifndef I_AM_QSORT_R\n__unused // XXX what ?\n#endif\n)\n{\n\treturn CMP(thunk, a, b) < 0 ?\n\t       (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))\n              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));\n}\n\n#ifdef I_AM_QSORT_R\nvoid\nqsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)\n#else\n#define thunk NULL\nvoid\nqsort(void *a, size_t n, size_t es, cmp_t *cmp)\n#endif\n{\n\tchar *pa, *pb, *pc, *pd, *pl, *pm, *pn;\n\tsize_t d, r;\n\tint cmp_result;\n\tint swaptype, swap_cnt;\n\nloop:\tSWAPINIT(a, es);\n\tswap_cnt = 0;\n\tif (n < 7) {\n\t\tfor (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)\n\t\t\tfor (pl = pm;\n\t\t\t     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;\n\t\t\t     pl -= es)\n\t\t\t\tswap(pl, pl - es);\n\t\treturn;\n\t}\n\tpm = (char *)a + (n / 2) * es;\n\tif (n > 7) {\n\t\tpl = a;\n\t\tpn = (char *)a + (n - 1) * es;\n\t\tif (n > 40) {\n\t\t\td = (n / 8) * es;\n\t\t\tpl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);\n\t\t\tpm = med3(pm - d, pm, pm + d, cmp, thunk);\n\t\t\tpn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);\n\t\t}\n\t\tpm = med3(pl, pm, pn, cmp, thunk);\n\t}\n\tswap(a, pm);\n\tpa = pb = (char *)a + es;\n\n\tpc = pd = (char *)a + (n - 1) * es;\n\tfor (;;) {\n\t\twhile (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {\n\t\t\tif (cmp_result == 0) {\n\t\t\t\tswap_cnt = 1;\n\t\t\t\tswap(pa, pb);\n\t\t\t\tpa += es;\n\t\t\t}\n\t\t\tpb += es;\n\t\t}\n\t\twhile (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {\n\t\t\tif (cmp_result == 0) {\n\t\t\t\tswap_cnt = 1;\n\t\t\t\tswap(pc, pd);\n\t\t\t\tpd -= es;\n\t\t\t}\n\t\t\tpc -= es;\n\t\t}\n\t\tif (pb > pc)\n\t\t\tbreak;\n\t\tswap(pb, pc);\n\t\tswap_cnt = 1;\n\t\tpb += es;\n\t\tpc -= es;\n\t}\n\tif (swap_cnt == 0) {  /* Switch to insertion sort */\n\t\tfor (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)\n\t\t\tfor (pl = pm;\n\t\t\t     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;\n\t\t\t     pl -= es)\n\t\t\t\tswap(pl, pl - es);\n\t\treturn;\n\t}\n\n\tpn = (char *)a + n * es;\n\tr = min(pa - (char *)a, pb - pa);\n\tvecswap(a, pb - r, r);\n\tr = min(pd - pc, pn - pd - es);\n\tvecswap(pb, pn - r, r);\n\tif ((r = pb - pa) > es)\n#ifdef I_AM_QSORT_R\n\t\tqsort_r(a, r / es, es, thunk, cmp);\n#else\n\t\tqsort(a, r / es, es, cmp);\n#endif\n\tif ((r = pd - pc) > es) {\n\t\t/* Iterate rather than recurse to save stack space */\n\t\ta = pn - r;\n\t\tn = r / es;\n\t\tgoto loop;\n\t}\n/*\t\tqsort(pn - r, r / es, es, cmp);*/\n}\n"
  },
  {
    "path": "ipfw/qsort_r.c",
    "content": "/*\n * This file is in the public domain.  Originally written by Garrett\n * A. Wollman.\n *\n * $FreeBSD: src/lib/libc/stdlib/qsort_r.c,v 1.1 2002/09/10 02:04:49 wollman Exp $\n */\n#define I_AM_QSORT_R\n#include \"qsort.c\"\n"
  },
  {
    "path": "ipfw/rule_test.sh",
    "content": "#/bin/bash\n\nCOMMAND=ipfw\n\n\necho .########## Set $COMMAND mode .##########\n$COMMAND add allow ip from any to any\n$COMMAND -q flush\n\necho .########## empty rules .##########\n$COMMAND list\n$COMMAND add allow ip from any to any\n$COMMAND add allow ip from any to { 1.2.3.4 or 2.3.4.5 }\n$COMMAND add allow { dst-ip 1.2.3.4 or dst-ip 2.3.4.5 }\n\necho .########## listing 3 rules .##########\n$COMMAND list\n\n$COMMAND delete 200\necho .########## listing 2 rules .##########\n$COMMAND list\n\n$COMMAND table 10 add 1.2.3.4\n$COMMAND table 10 add 1.2.3.5\n$COMMAND table 10 add 1.2.3.6\n$COMMAND table 10 add 1.2.3.7/13\n$COMMAND table 10 add 1.2.3.7/20\n$COMMAND table 10 add 1.2.3.7/28\n\necho .########## listing table 10 with 6 elements .##########\n$COMMAND table 10 list\n$COMMAND table 10 delete 1.2.3.6\n\necho .########## listing table 10 with 5 elements .##########\n$COMMAND table 10 list\n$COMMAND table 10 flush\n\necho .########## table 10 empty .##########\n$COMMAND table 10 list\n\necho .########## move rule 100 to set 1 300 to 3 .##########\n$COMMAND set move rule 100 to 1\n$COMMAND set move rule 300 to 3\n$COMMAND -S show\n\necho .########## move rule 200 to 2 but 200 do not exist .######\n$COMMAND set move rule 200 to 2\n\necho .########## add some rules .##########\n$COMMAND add 200 queue 2 proto ip\n$COMMAND add 300 queue 5 proto ip\n$COMMAND add 400 queue 40 proto ip\n$COMMAND add 400 queue 50 proto ip\n\necho .########## move rule 200 to 2 .######\n$COMMAND set move rule 200 to 2\n\necho .########## move rule 400 to 5 .######\n$COMMAND set move rule 400 to 5\n\necho .########## set 5 show 2 rules .######\n$COMMAND set 5 show\n\necho .########## flush set 5 .######\n$COMMAND -q set 5 flush\n\necho .########## set 5 show 0 rule .######\n$COMMAND set 5 show\n\necho .########## disable set 1 .######\n$COMMAND set disable 1\n\necho .########## show all rules except set 1 .######\n$COMMAND -S show\n\necho .########## enable set 1 .######\n$COMMAND set enable 1\n\necho .########## show all rules .######\n$COMMAND -S show\n\n\n\n"
  },
  {
    "path": "ipfw/ws2_32.def",
    "content": "LIBRARY ws2_32.dll\r\n\r\nEXPORTS\r\nFreeAddrInfoW\r\nGetAddrInfoW\r\nGetNameInfoW\r\nWEP\r\nWPUCompleteOverlappedRequest\r\nWSAAccept\r\nWSAAddressToStringA\r\nWSAAddressToStringW\r\nWSAAsyncGetHostByAddr\r\nWSAAsyncGetHostByName\r\nWSAAsyncGetProtoByName\r\nWSAAsyncGetProtoByNumber\r\nWSAAsyncGetServByName\r\nWSAAsyncGetServByPort\r\nWSAAsyncSelect\r\nWSACancelAsyncRequest\r\nWSACancelBlockingCall\r\nWSACleanup\r\nWSACloseEvent\r\nWSAConnect\r\nWSACreateEvent\r\nWSADuplicateSocketA\r\nWSADuplicateSocketW\r\nWSAEnumNameSpaceProvidersA\r\nWSAEnumNameSpaceProvidersW\r\nWSAEnumNetworkEvents\r\nWSAEnumProtocolsA\r\nWSAEnumProtocolsW\r\nWSAEventSelect\r\nWSAGetLastError\r\nWSAGetOverlappedResult\r\nWSAGetQOSByName\r\nWSAGetServiceClassInfoA\r\nWSAGetServiceClassInfoW\r\nWSAGetServiceClassNameByClassIdA\r\nWSAGetServiceClassNameByClassIdW\r\nWSAHtonl\r\nWSAHtons\r\nWSAInstallServiceClassA\r\nWSAInstallServiceClassW\r\nWSAIoctl\r\nWSAIsBlocking\r\nWSAJoinLeaf\r\nWSALookupServiceBeginA\r\nWSALookupServiceBeginW\r\nWSALookupServiceEnd\r\nWSALookupServiceNextA\r\nWSALookupServiceNextW\r\nWSANSPIoctl\r\nWSANtohl\r\nWSANtohs\r\nWSAProviderConfigChange\r\nWSARecv\r\nWSARecvDisconnect\r\nWSARecvFrom\r\nWSARemoveServiceClass\r\nWSAResetEvent\r\nWSASend\r\nWSASendDisconnect\r\nWSASendTo\r\nWSASetBlockingHook\r\nWSASetEvent\r\nWSASetLastError\r\nWSASetServiceA\r\nWSASetServiceW\r\nWSASocketA\r\nWSASocketW\r\nWSAStartup\r\nWSAStringToAddressA\r\nWSAStringToAddressW\r\nWSAUnhookBlockingHook\r\nWSAWaitForMultipleEvents\r\nWSApSetPostRoutine\r\nWSCDeinstallProvider\r\nWSCEnableNSProvider\r\nWSCEnumProtocols\r\nWSCGetProviderPath\r\nWSCInstallNameSpace\r\nWSCInstallProvider\r\nWSCUnInstallNameSpace\r\nWSCUpdateProvider\r\nWSCWriteNameSpaceOrder\r\nWSCWriteProviderOrder\r\n__WSAFDIsSet\r\naccept\r\nbind\r\nclosesocket\r\nconnect\r\nfreeaddrinfo\r\ngetaddrinfo\r\ngethostbyaddr\r\ngethostbyname\r\ngethostname\r\ngetnameinfo\r\ngetpeername\r\ngetprotobyname\r\ngetprotobynumber\r\ngetservbyname\r\ngetservbyport\r\ngetsockname\r\ngetsockopt\r\nhtonl\r\nhtons\r\ninet_addr\r\ninet_ntoa\r\nioctlsocket\r\nlisten\r\nntohl\r\nntohs\r\nrecv\r\nrecvfrom\r\nselect\r\nsend\r\nsendto\r\nsetsockopt\r\nshutdown\r\nsocket\r\n"
  },
  {
    "path": "kipfw/Makefile",
    "content": "# $Id: Makefile 12257 2013-04-26 21:13:24Z luigi $\n# gnu Makefile to build linux/Windows module for ipfw+dummynet.\n#\n# The defaults are set to build without modifications on PlanetLab\n# and possibly 2.6 versions.\n# On Windows, we use gnu-make and MSC\n\n# Some variables need to have specific names, because they are used\n# by the build infrastructure on Linux and OpenWrt. They are:\n# \n#   ccflags-y\tadditional $(CC) flags\n#   M\t\tused by Kbuild, we must set it to `pwd`\n#   obj-m\tlist of .o modules to build\n#   $(MOD)-y\tfor each $MOD in obj-m, the list of objects\n#   obj-y\tsame as above, for openwrt\n#   O_TARGET\tthe link target, for openwrt\n#   EXTRA_CFLAGS as the name says... in openwrt\n#   EXTRA_CFLAGS is used in 2.6.22 module kernel compilation too\n#   KERNELPATH\tthe path to the kernel sources or headers\n#\t(on planetlab it is set already by the build system,\n#\tfor other systems we take KSRC which is either guessed\n#\tor taken from the command line.\n#\n# Not sure about this (the name might be reserved)\n#   ipfw-cflags\t\tour flags for building the module\n#\n# Other variables are only private and can be renamed. They include:\n#\n#   VER\t\tlinux version we are building for (2.4 2.6 or openwrt)\n#\n#---\n#\n# The windows files (passthru etc.) are modified version of the\n# examples found in the $(DDK)/src/network/ndis/passthru/driver/\n# They can be re-created using the 'ndis-glue' target in the \n\nIPFW3_ROOT ?= $(PWD)/..\ninclude $(IPFW3_ROOT)/Makefile.inc\n\nTARGET = kipfw\n\n# lets default for 2.6 for planetlab builds\nVER ?= 2.6\n\n# $(warning ########## linux dir is $(LINUX_DIR) ###########)\n# $(warning ########## KERNELPATH is $(KERNELPATH) ###########)\n#--- General values for all types of build ---\n# obj-m is the target module\nobj-m := ipfw_mod.o\n\n#-- the list of source files. IPFW_SRCS is our own name.\n# Original ipfw and dummynet sources + FreeBSD stuff,\nIPFW_SRCS := ip_fw2.c ip_fw_pfil.c ip_fw_sockopt.c\nIPFW_SRCS += ip_fw_dynamic.c ip_fw_table.c ip_fw_log.c\nIPFW_SRCS += radix.c in_cksum.c\nIPFW_SRCS += ip_dummynet.c ip_dn_io.c ip_dn_glue.c\nIPFW_SRCS += dn_heap.c\nIPFW_SRCS += dn_sched_fifo.c dn_sched_wf2q.c\nIPFW_SRCS += dn_sched_rr.c dn_sched_qfq.c\nIPFW_SRCS += dn_sched_prio.c\n# Module glue and functions missing in linux\nIPFW_SRCS += ipfw2_mod.c bsd_compat.c\n\n# generic cflags used on all systems\n#ipfw-cflags += -DIPFW_HASHTABLES\nipfw-cflags += -DIPFIREWALL_DEFAULT_TO_ACCEPT\n# _BSD_SOURCE enables __FAVOR_BSD (udp/tcp bsd structs instead of posix)\nipfw-cflags += -D_BSD_SOURCE\nipfw-cflags += -DKERNEL_MODULE\t# build linux kernel module\n# the two header trees for empty and override files\nipfw-cflags += -I $(M)/include_e\nipfw-cflags += -I $(M)/../sys\nipfw-cflags += -include $(M)/../glue.h\t# headers\nipfw-cflags += -include $(M)/missing.h\t# headers\n\n$(warning ------ arch $(OSARCH) goals $(MAKECMDGOALS) -----------)\n\nifeq ($(OSARCH),Windows)\t#--- {  Windows block\n  ifeq ($(VER),win64)\n    $(warning ---- building for 64-bit windows ---)\n    win_arch= -DAMD64=1\n  else\n    win_arch= -Di386=1\n  endif\n    M ?= $(shell pwd)\n    WIN_SRCS += md_win.c\n    WIN_SRCS += miniport.c protocol.c passthru.c debug.c\n    #compiler, linker, target, sources and objects\n    #DDK is exported from the root makefile\n    #DDK = C:/WinDDK/7600.16385.1\n\n    CSOURCES = $(IPFW_SRCS) $(WIN_SRCS)\n\n    COBJS := $(CSOURCES:.c=.obj)\n    COBJS := $(addprefix $(OBJDIR)/,$(COBJS))\n\n    #include paths\n    INCLUDE_PATHS = -Ii386 -I../sys -Iinclude_e -I.\n    # INCLUDE_PATHS += -I$(OBJDIR)\n    INCLUDE_PATHS += -I$(DDK)/inc/api\n    INCLUDE_PATHS += -I$(DDK)/inc/ddk\n    INCLUDE_PATHS += -I$(DDK)/inc/crt\n\n    # #preprocessor MS defines\n    PREPROC  = -D_X86_=1 -Di386=1 -DSTD_CALL -DCONDITION_HANDLING=1\n    PREPROC += -DNT_UP=0 -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 -DWINNT=1\n    PREPROC += -D_WIN32_WINNT=0x0501 -DWINVER=0x0501 -D_WIN32_IE=0x0603\n    PREPROC += -DWIN32_LEAN_AND_MEAN=1 \n    PREPROC += -D__BUILDMACHINE__=WinDDK -DFPO=0 -D_DLL=1\n    PREPROC += -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1\n    PREPROC += -DNDIS51_MINIPORT=1 -DNDIS51=1\n    PREPROC += -DMSC_NOOPT -DNTDDI_VERSION=0x05010200\n    PREPROC += -DKMDF_MAJOR_VERSION_STRING=01 -DKMDF_MINOR_VERSION_STRING=009\n    #PREPROC += -DDBG=1 #debug\n    PREPROC += -DNDEBUG #always up, seems no effect, possibly no debug?\n    PREPROC += -DDEVL=1 #always up, seems no effect\n    #macroing module name, WARNING: must match the one in .inf files\n    PREPROC += -DMODULENAME=Ipfw \n\n    #our defines\n    OUR_PREPROC  = -D_KERNEL -DKERNEL_MODULE -DKLD_MODULE\n    OUR_PREPROC += -D__BSD_VISIBLE -DIPFIREWALL_DEFAULT_TO_ACCEPT\n    OUR_PREPROC += -D__LITTLE_ENDIAN -DSYSCTL_NODE -DEMULATE_SYSCTL\n\n  ifeq ($(TCC),)\t# Microsoft C compiler\n    CC = $(DDK)/bin/x86/x86/cl.exe\n    LD = $(DDK)/bin/x86/x86/link.exe\n    # #complier options\n    CFLAGS  = -Fo$(OBJDIR)/  -c -FC -Zc:wchar_t-\n    CFLAGS += -Zl -Zp8 -Gy -Gm- -GF -cbstring -Gz -hotpatch -EHs-c-\n    CFLAGS += -W2 # -W3 gives too many conversion errors\n    CFLAGS += -GR- -GF -GS -Zi\t# XXX do we need this ?\n    CFLAGS += -Fd$(OBJDIR)/\n    CFLAGS += -wd4603 -wd4627 -typedil-\n    CFLAGS += -FI $(DDK)/inc/api/warning.h\n    CFLAGS += -FI winmissing.h\n    CFLAGS += -FI missing.h\t# headers\n    CFLAGS += -FI ../glue.h\t# headers\n\n    #optimization options\n    OPTIMIZE = -Od -Oi -Oy-\n\n    #linker options\n    LDFLAGS  = /MERGE:_PAGE=PAGE /MERGE:_TEXT=.text\n    LDFLAGS += /SECTION:INIT,d /OPT:REF /OPT:ICF\n    LDFLAGS += /IGNORE:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221\n    LDFLAGS += /INCREMENTAL:NO /release /NODEFAULTLIB /WX\n    LDFLAGS += /debug /debugtype:cv,fixup,pdata\n    LDFLAGS += /version:6.1 /osversion:6.1 /functionpadmin:5\n    LDFLAGS += /safeseh /pdbcompress\n    LDFLAGS += /STACK:0x40000,0x1000 /driver /base:0x10000 /align:0x80\n    LDFLAGS += /stub:$(DDK)\\\\lib\\\\wxp\\\\stub512.com\n    LDFLAGS += /subsystem:native,5.01 /entry:GsDriverEntry@8\n    LDFLAGS += /out:$(OBJDIR)/ipfw.sys\n\n    #libraries to build against\n    LIBS  = $(DDK)/lib/wxp/i386/BufferOverflowK.lib\n    LIBS += $(DDK)/lib/wxp/i386/ntoskrnl.lib\n    LIBS += $(DDK)/lib/wxp/i386/hal.lib\n    LIBS += $(DDK)/lib/wxp/i386/wmilib.lib\n    LIBS += $(DDK)/lib/wxp/i386/ndis.lib\n    LIBS += $(DDK)/lib/wxp/i386/sehupd.lib\n  else\t# use tcc. not working yet for the kernel module.\n    # TCC points to the root of tcc tree\n    CC=$(TCC)/bin/wintcc\n    EXTRA_CFLAGS += -DTCC -I..\n    EXTRA_CFLAGS += -I$(TCC)/include/winapi -I$(TCC)/include\n    EXTRA_CFLAGS += -nostdinc\n\n    CFLAGS += -include winmissing.h -include missing.h -include ../glue.h\n    CFLAGS += -I../../inc/api -I../../inc/ddk -I../../inc/crt\n    CFLAGS += -DRC_INVOKED\n  endif # use tcc\n\n    #empty include directory to be built\n    M ?= $(shell pwd)\n    EFILES_asm += div64.h\n    EFILES_linux += if.h random.h errno.h\n    EFILES_net += if_types.h inet_hashtables.h route.h\n\n    #targets\nall: $(TARGET)\n\n$(TARGET): include_e\n\t# XXX dangerous rm -rf $(OBJDIR)\n\tmkdir -p $(OBJDIR)\n\t$(MSG) \"  CC [$(CC)] $(CSOURCES)\"\n\t$(HIDE) $(CC) $(INCLUDE_PATHS) $(PREPROC) $(OUR_PREPROC) $(CFLAGS) $(OPTIMIZE) $(CSOURCES)\n\t$(MSG) \"  LD [$(LD)] $(COBJS)\"\n\t$(HIDE) $(LD) $(LDFLAGS) $(COBJS) $(LIBS)\n\nelse # } { linux variables and targets\n\n  # extract version number (hex, aXXYY). Newer linuxes have a different dir\n  # if not set, use the version from the installed system\n  KERNELPATH ?= $(KSRC)\n  LIN_VER := $(shell V=linux/version.h; G=. ; \\\n        [ -f $(KERNELPATH)/include/$${V} ] || G=generated/uapi ;\\\n        grep LINUX_VERSION_CODE $(KERNELPATH)/include/$${G}/linux/version.h | \\\n        awk '{printf \"%03x%02x\", $$3/256, $$3%256} ')\n\n  $(warning ------------- linux version $(LIN_VER) (hex) ------------)\n# We have three sections: OpenWrt, Linux 2.4 and Linux 2.6\n\nifeq ($(LIN_VER),openwrt)\t#--- { The Makefile section for openwrt ---\n  # this was used on openwrt, but not anymore\n  $(error ------ build on openwrt ---------- )\n  # We do not include a dependency on include_e as it is called\n  # by Makefile.openwrt in Build/Prepare\n  M=.\n  obj-y := $(IPFW_SRCS:%.c=%.o)\n  O_TARGET := $(obj-m)\n\n  # xcflags-y is a temporary variable where we store build options\n  xcflags-y += -O1 -DLINUX_24\n  xcflags-y += -g\n\n  EXTRA_CFLAGS := $(xcflags-y) $(ipfw-cflags) -DSYSCTL_NODE -DEMULATE_SYSCTL\n\n  # we should not export anything\n  #export-objs := ipfw2_mod.o\n-include $(TOPDIR)/Rules.make\nendif # ---- } end openwrt version\n\n\nifneq ($(shell echo $(LIN_VER)|grep '2.4'),)\t#--- {\n  # Makefile section for the linux 2.4 version\n  # tested on linux-2.4.35.4, does not work with 2.4.37\n  #\n  # guess the kernel path -- or is it under /lib/modules ?\n  KERNELPATH ?= $(KSRC)\n\n  # We need to figure out the gcc include directory, if not\n  # set by the user through MYGCC_INCLUDE\n  # Find compiler version (3rd field in last line returned by gcc -v)\n  # e.g.\tgcc version 4.3.2 (Debian 4.3.2-1.1)\n  MYGCC_VER ?= $(shell $(CC) -v 2>&1 |tail -n 1 | cut -d \" \" -f 3)\n  # We don't know the exact directory under /usr/lib/gcc so we guess\n  MYGCC_INCLUDE ?= $(shell echo /usr/lib/gcc/*/$(MYGCC_VER) | cut -d \" \" -f 1)/include\n  $(warning \"---- gcc includes guessed to $(MYGCC_INCLUDE)\")\n\n  # additional warning\n  WARN += -Wall -Wundef\n  WARN += -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing\n  WARN += -fno-common -Werror-implicit-function-declaration\n  # WARN += -O2  -fno-stack-protector -m32 -msoft-float -mregparm=3\n  # -mregparm=3 gives a printk error\n  WARN += -m32 -msoft-float # -mregparm=3\n  #WARN += -freg-struct-return -mpreferred-stack-boundary=2\n  WARN += -Wno-sign-compare\n  WARN += -Wdeclaration-after-statement\n  ifneq ($(MYGCC_VER),3.4.6)\n        WARN += -Wno-pointer-sign\n  endif\n\n  ccflags-y += -O1 -DLINUX_24\n  CFLAGS = -DMODULE -D__KERNEL__ -nostdinc \\\n\t-isystem ${KERNELPATH}/include -isystem $(MYGCC_INCLUDE) \\\n\t${ccflags-y}\n  # The Main target\nall: mod24\n\nelse # --- } {  linux 2.6 and newer\n  $(warning --- build 2.6 and newer target $(TARGET) ----)\n\n  # This is the Makefile section for Linux 2.6.x including planetlab\n\n  ifeq ($(IPFW_PLANETLAB),1)\n    $(warning \"---- Building for PlanetLab\")\n    ipfw-cflags += -DIPFW_PLANETLAB        # PlanetLab compilation\n  endif\n\n  WARN := -O1 -Wall -Werror -DDEBUG_SPINLOCK -DDEBUG_MUTEXES\n  # The main target\n\n  # Required by GCC 4.6\n  ccflags-y += -Wno-unused-but-set-variable\n\n\n  ifeq ($(shell if [ -z $(LIN_VER) ] ; then echo \"true\"; fi),true)\n    $(warning \"---- Perhaps you miss a (cd $(KERNELPATH); make oldconfig; make prepare; make scripts)\");\n  endif\n\n  # Required by kernel < 2.6.23, ccflags-y is used on newer version\n  ifeq ($(shell [ \"$(LIN_VER)\" \\< \"20617\" ] && echo \"true\"),true)\n    EXTRA_CFLAGS += $(ccflags-y)\n  endif\n\n  $(warning $(shell [ \"$(LIN_VER)\" \\< \"2061c\" ] && \\\n\t[ `$(MAKE) -version | head -1 | cut -d \" \" -f 3` != '3.81' ] && \\\n\techo \"****   need make 3.81 *****\") )\n  # $(warning make is $(MAKE) version is $(shell $(MAKE) -version | head -1) )\n\n  #--- openwrt ?\n  ifeq ($(_VER),xx-openwrt)\n    $(warning ----------------------- compiling for openwrt -----)\n    M=.\n    obj-y := $(IPFW_SRCS:%.c=%.o)\n    O_TARGET := $(obj-m)\n\n    # xcflags-y is a temporary variable where we store build options\n    xcflags-y += -O1\n    xcflags-y += -g\n\n    EXTRA_CFLAGS := $(xcflags-y) $(ipfw-cflags) -DSYSCTL_NODE -DEMULATE_SYSCTL\n  endif #---- end openwrt\n\nall: $(TARGET)\n$(TARGET):\tinclude_e\n\techo \"xxxxxxxxxxxxx $(MAKE) -C $(KERNELPATH) V=$(V) M=`pwd` modules\"\n\t$(MAKE) -C $(KERNELPATH) V=$(V) M=`pwd` modules\n\n\nendif # } --- linux 2.6 and newer\n\n#-- back to the common section for linux\n\n# the list of objects used to build the module\nipfw_mod-y = $(IPFW_SRCS:%.c=%.o)\n\n# additional $(CC) flags\nccflags-y += $(WARN)\nccflags-y += $(ipfw-cflags)\n# if we really want debug symbols...\nccflags-y += -g\n\nmod24: include_e $(obj-m)\n\n$(obj-m): $(ipfw_mod-y)\n\t$(LD) $(LDFLAGS) -m elf_i386 -r -o $@ $^\n\n# M is the current directory, used in recursive builds\n# so we allow it to be overridden\nM ?= $(shell pwd)\n\nendif # } ----- end of the non-Windows block\n\nifneq ($(OBJDIR),mia)\n    $(error objdir set to $(OBJDIR))\nendif\n\n#--- various common targets\nclean:\n\t-@rm -f *.o *.ko Module.symvers *.mod.c\n\t-@# rm -rf $(OBJDIR)\n\t-@rm -rf include_e\n\ndistclean: clean\n\t-@rm -f .*cmd modules.order opt_*\n\t-@rm -rf .tmp_versions .*.o.d _CL_*\n\n# support to create empty dirs and files in include_e/\n# EFILES_foo/bar is the list of files to be created in foo/bar\n# (/ and . are allowed in gmake variable names)\n\nEFILES_. += opt_inet.h opt_inet6.h opt_ipfw.h opt_ipsec.h opt_mpath.h\nEFILES_. += opt_mbuf_stress_test.h opt_param.h opt_ipdivert.h\n\nEFILES_altq += if_altq.h\nEFILES_arpa += inet.h\nEFILES_machine += in_cksum.h\nEFILES_net += ethernet.h netisr.h pf_mtag.h bpf.h if_types.h vnet.h\n\nEFILES_netinet += ether.h icmp6.h if_ether.h in.h in_pcb.h in_var.h\nEFILES_netinet += in_systm.h ip_carp.h ip_var.h pim.h\nEFILES_netinet += sctp.h tcp_timer.h tcpip.h udp_var.h\nEFILES_netinet6 += ip6_var.h\n\nEFILES_sys += _lock.h _rwlock.h rmlock.h _mutex.h jail.h\nEFILES_sys += condvar.h eventhandler.h domain.h\nEFILES_sys += limits.h lock.h mutex.h priv.h\nEFILES_sys += proc.h rwlock.h socket.h socketvar.h\nEFILES_sys += sysctl.h time.h ucred.h\n\n# first make a list of directories from variable names\nEDIRS= $(subst EFILES_,,$(filter EFILES_%,$(.VARIABLES)))\n# then prepend the directory name to individual files.\n#       $(empty) serves to interpret the following space literally,\n#       and the \":  = \" substitution packs spaces into one.\nEFILES = $(foreach i,$(EDIRS),$(subst $(empty) , $(i)/, $(EFILES_$(i):  = )))\n\ninclude_e:\n\t-@rm -rf $(M)/include_e opt_*\n\t-@mkdir -p $(M)/include_e\n\t-@(cd $(M)/include_e; mkdir -p $(EDIRS); touch $(EFILES) )\n\n#--- some other targets for testing purposes\ntest_radix: test_radix.o radix.o\ntest_lookup: ip_fw_lookup.o\ntest_radix test_lookup: CFLAGS=-Wall -Werror -O1\n"
  },
  {
    "path": "kipfw/bsd_compat.c",
    "content": "/*\n * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: bsd_compat.c 11530 2012-08-01 10:29:32Z luigi $\n *\n * kernel variables and functions that are not available in linux.\n */\n\n#include <sys/cdefs.h>\n#include <asm/div64.h>\t/* do_div on 2.4 */\n#include <linux/random.h>\t/* get_random_bytes on 2.4 */\n#include <netinet/ip_fw.h>\n#include <netinet/ip_dummynet.h>\n#include <sys/malloc.h>\n\n/*\n * gettimeofday would be in sys/time.h but it is not\n * visible if _KERNEL is defined\n */\nint gettimeofday(struct timeval *, struct timezone *);\n\nint ticks;\t\t/* kernel ticks counter */\nint hz = 1000;\t\t/* default clock time */\nlong tick = 1000;\t/* XXX is this 100000/hz ? */\nint bootverbose = 0;\nstruct timeval boottime;\n\nint     ip_defttl = 64;\t/* XXX set default value */\nint\tmax_linkhdr = 16;\nint fw_one_pass = 1;\nu_long  in_ifaddrhmask;                         /* mask for hash table */\nstruct  in_ifaddrhashhead *in_ifaddrhashtbl;    /* inet addr hash table  */\n\nu_int rt_numfibs = RT_NUMFIBS;\n\n/*\n * pfil hook support.\n * We make pfil_head_get return a non-null pointer, which is then ignored\n * in our 'add-hook' routines.\n */\nstruct pfil_head;\ntypedef int (pfil_hook_t)\n\t(void *, struct mbuf **, struct ifnet *, int, struct inpcb *);\n\nstruct pfil_head *\npfil_head_get(int proto, u_long flags)\n{\n\tstatic int dummy;\n\treturn (struct pfil_head *)&dummy;\n}\n \nint\npfil_add_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)\n{\n\treturn 0;\n}\n\nint\npfil_remove_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)\n{\n\treturn 0;\n}\n\n/* define empty body for kernel function */\nint\npriv_check(struct thread *td, int priv)\n{\n\treturn 0;\n}\n\nint\nsecurelevel_ge(struct ucred *cr, int level)\n{\n\treturn 0;\n}\n\nint\nsysctl_handle_int(SYSCTL_HANDLER_ARGS)\n{\n\treturn 0;\n}\n\nint\nsysctl_handle_long(SYSCTL_HANDLER_ARGS)\n{\n\treturn 0;\n}\n\nvoid\nether_demux(struct ifnet *ifp, struct mbuf *m)\n{\n\treturn;\n}\n\nint\nether_output_frame(struct ifnet *ifp, struct mbuf *m)\n{\n\treturn 0;\n}\n\nvoid\nin_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum)\n{\n\treturn;\n}\n\nvoid\nicmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu)\n{\n\treturn;\n}\n\nu_short\nin_cksum_skip(struct mbuf *m, int len, int skip)\n{\n\treturn 0;\n}\n\nu_short\nin_cksum_hdr(struct ip *ip)\n{\n\treturn 0;\n}\n\n/*\n * we don't really reassemble, just return whatever we had.\n */\nstruct mbuf *\nip_reass(struct mbuf *clone)\n{\n\treturn clone;\n}\n#ifdef INP_LOCK_ASSERT\n#undef INP_LOCK_ASSERT\n#define INP_LOCK_ASSERT(a)\n#endif\n\n/* credentials check */\n#include <netinet/ip_fw.h>\n#ifdef __linux__\nint\ncred_check(void *_insn,  int proto, struct ifnet *oif,\n    struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,\n    u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,\n    struct sk_buff *skb)\n{\n\tint match = 0;\n\tipfw_insn_u32 *insn = (ipfw_insn_u32 *)_insn;\n\n\tif (*ugid_lookupp == 0) {        /* actively lookup and copy in cache */\n\t\t/* returns null if any element of the chain up to file is null.\n\t\t * if sk != NULL then we also have a reference\n\t\t */\n\t\t*ugid_lookupp = linux_lookup(proto,\n\t\t\tsrc_ip.s_addr, htons(src_port),\n\t\t\tdst_ip.s_addr, htons(dst_port),\n\t\t\tskb, oif ? 1 : 0, u);\n\t}\n\tif (*ugid_lookupp < 0)\n\t\treturn 0;\n\n\tif (insn->o.opcode == O_UID)\n\t\tmatch = (u->uid == (uid_t)insn->d[0]);\n\telse if (insn->o.opcode == O_JAIL)\n\t\tmatch = (u->xid == (uid_t)insn->d[0]);\n\telse if (insn->o.opcode == O_GID)\n\t\tmatch = (u->gid == (uid_t)insn->d[0]);\n\treturn match;\n}\n#endif\t/* __linux__ */\n\nint\njailed(struct ucred *cred)\n{\n\treturn 0;\n}\n\n/*\n* Return 1 if an internet address is for a ``local'' host\n* (one to which we have a connection).  If subnetsarelocal\n* is true, this includes other subnets of the local net.\n* Otherwise, it includes only the directly-connected (sub)nets.\n*/\nint\nin_localaddr(struct in_addr in)\n{\n\treturn 1;\n}\n\nint\nsooptcopyout(struct sockopt *sopt, const void *buf, size_t len)\n{\n\tsize_t valsize = sopt->sopt_valsize;\n\n\tif (len < valsize)\n\t\tsopt->sopt_valsize = valsize = len;\n\t//printf(\"copyout buf = %p, sopt = %p, soptval = %p, len = %d \\n\", buf, sopt, sopt->sopt_val, len);\n\tbcopy(buf, sopt->sopt_val, valsize);\n\treturn 0;\n}\n\n/*\n * copy data from userland to kernel\n */\nint\nsooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)\n{\n\tsize_t valsize = sopt->sopt_valsize;\n\n\tif (valsize < minlen)\n\t\treturn EINVAL;\n\tif (valsize > len)\n\t\tsopt->sopt_valsize = valsize = len;\n\t//printf(\"copyin buf = %p, sopt = %p, soptval = %p, len = %d \\n\", buf, sopt, sopt->sopt_val, len);\n\tbcopy(sopt->sopt_val, buf, valsize);\n\treturn 0;\n}\n\nvoid\ngetmicrouptime(struct timeval *tv)\n{\n\tdo_gettimeofday(tv);\n}\n\n\n#include <arpa/inet.h>\n\nchar *\ninet_ntoa_r(struct in_addr ina, char *buf)\n{\n#ifdef _WIN32\n#else\n\tunsigned char *ucp = (unsigned char *)&ina;\n\n\tsprintf(buf, \"%d.%d.%d.%d\",\n\tucp[0] & 0xff,\n\tucp[1] & 0xff,\n\tucp[2] & 0xff,\n\tucp[3] & 0xff);\n#endif\n\treturn buf;\n}\n\nchar *\ninet_ntoa(struct in_addr ina)\n{\n\tstatic char buf[16];\n\treturn inet_ntoa_r(ina, buf);\n}\n\nint\nrandom(void)\n{\n#ifdef _WIN32\n\tstatic unsigned long seed;\n\tif (seed == 0) {\n\t\tLARGE_INTEGER tm;\n\t\tKeQuerySystemTime(&tm);\n\t\tseed = tm.LowPart;\n\t}\n\treturn RtlRandomEx(&seed) & 0x7fffffff;\n#else\n\tint r;\n\tget_random_bytes(&r, sizeof(r));\n\treturn r & 0x7fffffff; \n#endif\n}\n\n\n/*\n * do_div really does a u64 / u32 bit division.\n * we save the sign and convert to uint befor calling.\n * We are safe just because we always call it with small operands.\n */\nint64_t\ndiv64(int64_t a, int64_t b)\n{\n#ifdef _WIN32\n        int a1 = a, b1 = b;\n\treturn a1/b1;\n#else\n\tuint64_t ua, ub;\n\tint sign = ((a>0)?1:-1) * ((b>0)?1:-1);\n\n\tua = ((a>0)?a:-a);\n\tub = ((b>0)?b:-b);\n        do_div(ua, ub);\n\treturn sign*ua;\n#endif\n}\n\n#ifdef __MIPSEL__\nsize_t\nstrlcpy(char *dst, const char *src, size_t siz)\n{\n        char *d = dst;\n        const char *s = src;\n        size_t n = siz;\n \n        /* Copy as many bytes as will fit */\n        if (n != 0 && --n != 0) {\n                do {\n                        if ((*d++ = *s++) == 0)\n                                break;\n                } while (--n != 0);\n        }\n\n        /* Not enough room in dst, add NUL and traverse rest of src */\n        if (n == 0) {\n                if (siz != 0)\n                        *d = '\\0';              /* NUL-terminate dst */\n                while (*s++)\n                        ;\n        }\n\n        return(s - src - 1);    /* count does not include NUL */\n}\n#endif // __MIPSEL__\n\n/*\n * compact version of fnmatch.\n */\nint\nfnmatch(const char *pattern, const char *string, int flags)\n{\n\tchar s;\n\n\tif (!string || !pattern)\n\t\treturn 1;\t/* no match */\n\twhile ( (s = *string++) ) {\n\t\tchar p = *pattern++;\n\t\tif (p == '\\0')\t\t/* pattern is over, no match */\n\t\t\treturn 1;\n\t\tif (p == '*')\t\t/* wildcard, match */\n\t\t\treturn 0;\n\t\tif (p == '.' || p == s)\t/* char match, continue */\n\t\t\tcontinue;\n\t\treturn 1;\t\t/* no match */\n\t}\n\t/* end of string, make sure the pattern is over too */\n\tif (*pattern == '\\0' || *pattern == '*')\n\t\treturn 0;\n\treturn 1;\t/* no match */\n}\n\n\n/*\n * linux 2.6.33 defines these functions to access to\n * skbuff internal structures. Define the missing\n * function for the previous versions too.\n */\n#ifdef linux\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)\ninline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)\n{\n        skb->dst = dst;\n}\n\ninline struct dst_entry *skb_dst(const struct sk_buff *skb)\n{\n        return (struct dst_entry *)skb->dst;\n}\n#endif /* < 2.6.31 */\n#endif /* linux */\n\n\n/* support for sysctl emulation.\n * XXX this is actually MI code that should be enabled also on openwrt\n */\n#ifdef EMULATE_SYSCTL\nstatic struct sysctltable GST;\n\nint\nkesysctl_emu_get(struct sockopt* sopt)\n{\n\tstruct dn_id* oid = sopt->sopt_val;\n\tstruct sysctlhead* entry;\n\tint sizeneeded = sizeof(struct dn_id) + GST.totalsize +\n\t\tsizeof(struct sysctlhead);\n\tunsigned char* pstring;\n\tunsigned char* pdata;\n\tint i;\n\t\n\tif (sopt->sopt_valsize < sizeneeded) {\n\t\t// this is a probe to retrieve the space needed for\n\t\t// a dump of the sysctl table\n\t\toid->id = sizeneeded;\n\t\tsopt->sopt_valsize = sizeof(struct dn_id);\n\t\treturn 0;\n\t}\n\t\n\tentry = (struct sysctlhead*)(oid+1);\n\tfor( i=0; i<GST.count; i++) {\n\t\tentry->blocklen = GST.entry[i].head.blocklen;\n\t\tentry->namelen = GST.entry[i].head.namelen;\n\t\tentry->flags = GST.entry[i].head.flags;\n\t\tentry->datalen = GST.entry[i].head.datalen;\n\t\tpdata = (unsigned char*)(entry+1);\n\t\tpstring = pdata+GST.entry[i].head.datalen;\n\t\tbcopy(GST.entry[i].data, pdata, GST.entry[i].head.datalen);\n\t\tbcopy(GST.entry[i].name, pstring, GST.entry[i].head.namelen);\n\t\tentry = (struct sysctlhead*)\n\t\t\t((unsigned char*)(entry) + GST.entry[i].head.blocklen);\n\t}\n\tsopt->sopt_valsize = sizeneeded;\n\treturn 0;\n}\n\nint\nkesysctl_emu_set(void* p, int l)\n{\n\tstruct sysctlhead* entry;\n\tunsigned char* pdata;\n\tunsigned char* pstring;\n\tint i = 0;\n\t\n\tentry = (struct sysctlhead*)(((struct dn_id*)p)+1);\n\tpdata = (unsigned char*)(entry+1);\n\tpstring = pdata + entry->datalen;\n\t\n\tfor (i=0; i<GST.count; i++) {\n\t\tif (strcmp(GST.entry[i].name, pstring) != 0)\n\t\t\tcontinue;\n\t\tprintf(\"%s: match found! %s\\n\",__FUNCTION__,pstring);\n\t\t//sanity check on len, not really useful now since\n\t\t//we only accept int32\n\t\tif (entry->datalen != GST.entry[i].head.datalen) {\n\t\t\tprintf(\"%s: len mismatch, user %d vs kernel %d\\n\",\n\t\t\t\t__FUNCTION__, entry->datalen,\n\t\t\t\tGST.entry[i].head.datalen);\n\t\t\treturn -1;\n\t\t}\n\t\t// check access (at the moment flags handles only the R/W rights\n\t\t//later on will be type + access\n\t\tif( (GST.entry[i].head.flags & 3) == CTLFLAG_RD) {\n\t\t\tprintf(\"%s: the entry %s is read only\\n\",\n\t\t\t\t__FUNCTION__,GST.entry[i].name);\n\t\t\treturn -1;\n\t\t}\n\t\tbcopy(pdata, GST.entry[i].data, GST.entry[i].head.datalen);\n\t\treturn 0;\n\t}\n\tprintf(\"%s: match not found\\n\",__FUNCTION__);\n\treturn 0;\n}\n\n/* convert all _ to . until the first . */\nstatic void\nunderscoretopoint(char* s)\n{\n\tfor (; *s && *s != '.'; s++)\n\t\tif (*s == '_')\n\t\t\t*s = '.';\n}\n\nstatic int\nformatnames()\n{\n\tint i;\n\tint size=0;\n\tchar* name;\n\n\tfor (i=0; i<GST.count; i++)\n\t\tsize += GST.entry[i].head.namelen;\n\tGST.namebuffer = malloc(size, 0, 0);\n\tif (GST.namebuffer == NULL)\n\t\treturn -1;\n\tname = GST.namebuffer;\n\tfor (i=0; i<GST.count; i++) {\n\t\tbcopy(GST.entry[i].name, name, GST.entry[i].head.namelen);\n\t\tunderscoretopoint(name);\n\t\tGST.entry[i].name = name;\n\t\tname += GST.entry[i].head.namelen;\n\t}\n\treturn 0;\n}\n\nstatic void\ndumpGST()\n{\n\tint i;\n\n\tfor (i=0; i<GST.count; i++) {\n\t\tprintf(\"SYSCTL: entry %i\\n\", i);\n\t\tprintf(\"name %s\\n\", GST.entry[i].name);\n\t\tprintf(\"namelen %i\\n\", GST.entry[i].head.namelen);\n\t\tprintf(\"type %i access %i\\n\",\n\t\t\tGST.entry[i].head.flags >> 2,\n\t\t\tGST.entry[i].head.flags & 0x00000003);\n\t\tprintf(\"data %i\\n\", *(int*)(GST.entry[i].data));\n\t\tprintf(\"datalen %i\\n\", GST.entry[i].head.datalen);\n\t\tprintf(\"blocklen %i\\n\", GST.entry[i].head.blocklen);\n\t}\n}\n\nvoid sysctl_addgroup_f1();\nvoid sysctl_addgroup_f2();\nvoid sysctl_addgroup_f3();\nvoid sysctl_addgroup_f4();\n\nvoid\nkeinit_GST()\n{\n\tint ret;\n\n\tsysctl_addgroup_f1();\n\tsysctl_addgroup_f2();\n\tsysctl_addgroup_f3();\n\tsysctl_addgroup_f4();\n\tret = formatnames();\n\tif (ret != 0)\n\t\tprintf(\"conversion of names failed for some reason\\n\");\n\t//dumpGST();\n\tprintf(\"*** Global Sysctl Table entries = %i, total size = %i ***\\n\",\n\t\tGST.count, GST.totalsize);\n}\n\nvoid\nkeexit_GST()\n{\n\tif (GST.namebuffer != NULL)\n\t\tfree(GST.namebuffer,0);\n\tbzero(&GST, sizeof(GST));\n}\n\nvoid\nsysctl_pushback(char* name, int flags, int datalen, void* data)\n{\n\tif (GST.count >= GST_HARD_LIMIT) {\n\t\tprintf(\"WARNING: global sysctl table full, this entry will not be added,\"\n\t\t\t\t\"please recompile the module increasing the table size\\n\");\n\t\treturn;\n\t}\n\tGST.entry[GST.count].head.namelen = strlen(name)+1; //add space for '\\0'\n\tGST.entry[GST.count].name = name;\n\tGST.entry[GST.count].head.flags = flags;\n\tGST.entry[GST.count].data = data;\n\tGST.entry[GST.count].head.datalen = datalen;\n\tGST.entry[GST.count].head.blocklen =\n\t\t((sizeof(struct sysctlhead) + GST.entry[GST.count].head.namelen +\n\t\t\tGST.entry[GST.count].head.datalen)+3) & ~3;\n\tGST.totalsize += GST.entry[GST.count].head.blocklen;\n\tGST.count++;\n}\n#endif /* EMULATE_SYSCTL */\n"
  },
  {
    "path": "kipfw/debug.c",
    "content": "#include <ntddk.h>\n\nconst char* texify_cmd(int i)\n{\n\tif (i==110)\n\t\treturn(\"IP_FW_ADD\");\n\tif (i==111)\n\t\treturn(\"IP_FW_DEL\");\n\tif (i==112)\n\t\treturn(\"IP_FW_FLUSH\");\n\tif (i==113)\n\t\treturn(\"IP_FW_ZERO\");\n\tif (i==114)\n\t\treturn(\"IP_FW_GET\");\n\tif (i==115)\n\t\treturn(\"IP_FW_RESETLOG\");\n\tif (i==116)\n\t\treturn(\"IP_FW_NAT_CFG\");\n\tif (i==117)\n\t\treturn(\"IP_FW_NAT_DEL\");\n\tif (i==118)\n\t\treturn(\"IP_FW_NAT_GET_CONFIG\");\n\tif (i==119)\n\t\treturn(\"IP_FW_NAT_GET_LOG\");\n\tif (i==120)\n\t\treturn(\"IP_DUMMYNET_CONFIGURE\");\n\tif (i==121)\n\t\treturn(\"IP_DUMMYNET_DEL\");\n\tif (i==122)\n\t\treturn(\"IP_DUMMYNET_FLUSH\");\n\tif (i==124)\n\t\treturn(\"IP_DUMMYNET_GET\");\n\tif (i==108)\n\t\treturn(\"IP_FW3\");\n\tif (i==109)\n\t\treturn(\"IP_DUMMYNET3\");\n\treturn (\"BOH\");\n}\n\nconst char* texify_proto(unsigned int p)\n{\n\tif (p==1)\n\t\treturn(\"ICMP\");\n\tif (p==6)\n\t\treturn(\"TCP\");\n\tif (p==17)\n\t\treturn(\"UDP\");\n\treturn(\"OTHER\");\n}\n\nvoid hexdump(unsigned char* addr, int len, const char *msg)\n{\n\tint i;\n\tconst  int cicli = len/8;\n\tconst int resto = len%8;\n\tunsigned char d[8];\n\n\tDbgPrint(\"%s at %p len %d\\n\", msg, addr, len);\n\tfor (i=0; i<=cicli; i++) {\n\t\tbzero(d, 8);\n\t\tbcopy(addr+i*8, d, i < cicli ? 8 : resto);\n\t\tDbgPrint(\"%04X %02X %02X %02X %02X %02X %02X %02X %02X\\n\",\n\t\t\ti*8, d[0], d[1], d[2], d[3], d[4],\n\t\t\td[5], d[6], d[7]);\n\t}\n\tDbgPrint(\"\\n\");\n}\n"
  },
  {
    "path": "kipfw/ipfw2_mod.c",
    "content": "/*\n * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: ipfw2_mod.c 12501 2014-01-10 01:09:14Z luigi $\n *\n * The main interface to build ipfw+dummynet as a linux module.\n * (and possibly as a windows module as well, though that part\n * is not complete yet).\n *\n * The control interface uses the sockopt mechanism\n * on a socket(AF_INET, SOCK_RAW, IPPROTO_RAW).\n *\n * The data interface uses the netfilter interface, at the moment\n * hooked to the PRE_ROUTING and POST_ROUTING hooks.\n * Unfortunately the netfilter interface is a moving target,\n * so we need a set of macros to adapt to the various cases.\n *\n * In the netfilter hook we just mark packet as 'QUEUE' and then\n * let the queue handler to do the whole work (filtering and\n * possibly emulation).\n * As we receive packets, we wrap them with an mbuf descriptor\n * so the existing ipfw+dummynet code runs unmodified.\n */\n\n#include <sys/cdefs.h>\n#include <sys/mbuf.h>\t\t\t/* sizeof struct mbuf */\n#include <sys/param.h>\t\t\t/* NGROUPS */\n\n#ifndef D\n#define ND(fmt, ...) do {} while (0)\n#define D1(fmt, ...) do {} while (0)\n#define D(fmt, ...) printf(\"%-10s \" fmt \"\\n\",      \\\n        __FUNCTION__, ## __VA_ARGS__)\n#endif\n\n#ifdef __linux__\n#include <linux/module.h>\n#include <linux/kernel.h>\n\n#ifndef CONFIG_NETFILTER\n#error should configure netfilter (broken on 2.6.26 and below ?)\n#endif\n\n#include <linux/netfilter.h>\n#include <linux/netfilter_ipv4.h>\t/* NF_IP_PRI_FILTER */\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)\n#include <net/netfilter/nf_queue.h>\t/* nf_queue */\n#endif\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)\n#define __read_mostly\n#endif\n\n#endif /* !__linux__ */\n\n#include <netinet/in.h>\t\t\t/* in_addr */\n#include <netinet/ip_fw.h>\t\t/* ip_fw_ctl_t, ip_fw_chk_t */\n#include <netinet/ipfw/ip_fw_private.h>\t\t/* ip_fw_ctl_t, ip_fw_chk_t */\n#include <netinet/ip_dummynet.h>\t/* ip_dn_ctl_t, ip_dn_io_t */\n#include <net/pfil.h>\t\t\t/* PFIL_IN, PFIL_OUT */\n\n#ifdef __linux__\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)\n/* XXX was < 2.6.0:  inet_hashtables.h is introduced in 2.6.14 */\n// #warning --- inet_hashtables not present on 2.4\n#include <linux/tcp.h>\n#include <net/route.h>\n#include <net/sock.h>\nstatic inline int inet_iif(const struct sk_buff *skb)\n{\n        return ((struct rtable *)skb->dst)->rt_iif;\n}\n\n#else\n#include <net/inet_hashtables.h>\t/* inet_lookup */\n#endif\n#endif /* __linux__ */\n\n#include <net/route.h>\t\t\t/* inet_iif */\n\n/*\n * Here we allocate some global variables used in the firewall.\n */\n//ip_dn_ctl_t    *ip_dn_ctl_ptr;\nint (*ip_dn_ctl_ptr)(struct sockopt *);\n\nip_fw_ctl_t    *ip_fw_ctl_ptr;\n\nint\t(*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);\nip_fw_chk_t    *ip_fw_chk_ptr;\n\nvoid\t\t(*bridge_dn_p)(struct mbuf *, struct ifnet *);\n\n/* Divert hooks. */\nvoid (*ip_divert_ptr)(struct mbuf *m, int incoming);\n\n/* ng_ipfw hooks. */\nng_ipfw_input_t *ng_ipfw_input_p = NULL;\n\n/*---\n * Glue code to implement the registration of children with the parent.\n * Each child should call my_mod_register() when linking, so that\n * module_init() and module_exit() can call init_children() and\n * fini_children() to provide the necessary initialization.\n * We use the same mechanism for MODULE_ and SYSINIT_.\n * The former only get a pointer to the moduledata,\n * the latter have two function pointers (init/uninit)\n */\n#include <sys/module.h>\nstruct mod_args {\n        const char *name;\n        int order;\n        struct moduledata *mod;\n\tvoid (*init)(void), (*uninit)(void);\n};\n\nstatic unsigned int mod_idx;\nstatic struct mod_args mods[10];\t/* hard limit to 10 modules */\n\nint\nmy_mod_register(const char *name, int order,\n\tstruct moduledata *mod, void *init, void *uninit);\n/*\n * my_mod_register should be called automatically as the init\n * functions in the submodules. Unfortunately this compiler/linker\n * trick is not supported yet so we call it manually.\n */\nint\nmy_mod_register(const char *name, int order,\n\tstruct moduledata *mod, void *init, void *uninit)\n{\n\tstruct mod_args m;\n\n\tm.name = name;\n\tm.order = order;\n\tm.mod = mod;\n\tm.init = init;\n\tm.uninit = uninit;\n\n\tprintf(\"%s %s called\\n\", __FUNCTION__, name);\n\tif (mod_idx < sizeof(mods) / sizeof(mods[0]))\n\t\tmods[mod_idx++] = m;\n\treturn 0;\n}\n\nstatic void\ninit_children(void)\n{\n\tunsigned int i;\n\n        /* Call the functions registered at init time. */\n\tprintf(\"%s mod_idx value %d\\n\", __FUNCTION__, mod_idx);\n        for (i = 0; i < mod_idx; i++) {\n\t\tstruct mod_args *m = &mods[i];\n                printf(\"+++ start module %d %s %s at %p order 0x%x\\n\",\n                        i, m->name, m->mod ? m->mod->name : \"SYSINIT\",\n                        m->mod, m->order);\n\t\tif (m->mod && m->mod->evhand)\n\t\t\tm->mod->evhand(NULL, MOD_LOAD, m->mod->priv);\n\t\telse if (m->init)\n\t\t\tm->init();\n        }\n}\n\nstatic void\nfini_children(void)\n{\n\tint i;\n\n        /* Call the functions registered at init time. */\n        for (i = mod_idx - 1; i >= 0; i--) {\n\t\tstruct mod_args *m = &mods[i];\n                printf(\"+++ end module %d %s %s at %p order 0x%x\\n\",\n                        i, m->name, m->mod ? m->mod->name : \"SYSINIT\",\n                        m->mod, m->order);\n\t\tif (m->mod && m->mod->evhand)\n\t\t\tm->mod->evhand(NULL, MOD_UNLOAD, m->mod->priv);\n\t\telse if (m->uninit)\n\t\t\tm->uninit();\n        }\n}\n/*--- end of module binding helper functions ---*/\n\n/*---\n * Control hooks:\n * ipfw_ctl_h() is a wrapper for linux to FreeBSD sockopt call convention.\n * then call the ipfw handler in order to manage requests.\n * In turn this is called by the linux set/get handlers.\n */\nstatic int\nipfw_ctl_h(struct sockopt *s, int cmd, int dir, int len, void __user *user)\n{\n\tstruct thread t;\n\tint ret = EINVAL;\n\n\tmemset(s, 0, sizeof(*s));\n\ts->sopt_name = cmd;\n\ts->sopt_dir = dir;\n\ts->sopt_valsize = len;\n\ts->sopt_val = user;\n\n\t/* sopt_td is not used but it is referenced */\n\tmemset(&t, 0, sizeof(t));\n\ts->sopt_td = &t;\n\t\n\t//printf(\"%s called with cmd %d len %d sopt %p user %p\\n\", __FUNCTION__, cmd, len, s, user);\n\n\tif (ip_fw_ctl_ptr && cmd != IP_DUMMYNET3 && (cmd == IP_FW3 ||\n\t    cmd < IP_DUMMYNET_CONFIGURE))\n\t\tret = ip_fw_ctl_ptr(s);\n\telse if (ip_dn_ctl_ptr && (cmd == IP_DUMMYNET3 ||\n\t    cmd >= IP_DUMMYNET_CONFIGURE))\n\t\tret = ip_dn_ctl_ptr(s);\n\t\n\treturn -ret;\t/* errors are < 0 on linux */\n}\n\n#ifdef linux\n/*\n * Convert an mbuf into an skbuff\n * At the moment this only works for ip packets fully contained\n * in a single mbuf. We assume that on entry ip_len and ip_off are\n * in host format, and the ip checksum is not computed.\n */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* check boundary */\nint dst_output(struct skbuff *s)\n{\n\treturn 0;\n}\n\nstruct sk_buff *\nmbuf2skbuff(struct mbuf* m)\n{\n\treturn NULL;\n}\n#else\nstruct sk_buff *\nmbuf2skbuff(struct mbuf* m)\n{\n\tstruct sk_buff *skb;\n\tsize_t len = m->m_pkthdr.len;\n\n\t/* used to lookup the routing table */\n\tstruct rtable *r;\n\tstruct flowi fl;\n\tint ret = 0;\t/* success for ip_route_output_key() */\n\n\tstruct ip *ip = mtod(m, struct ip *);\n\n\t/* XXX ip_output has ip_len and ip_off in network format,\n\t * linux expects host format */\n\tip->ip_len = ntohs(ip->ip_len);\n\tip->ip_off = ntohs(ip->ip_off);\n\n\tip->ip_sum = 0;\n\tip->ip_sum = in_cksum(m, ip->ip_hl<<2);\n\n\t/* fill flowi struct, we need just the dst addr, see XXX */\n\tbzero(&fl, sizeof(fl));\n\tflow_daddr.daddr = ip->ip_dst.s_addr;\n\n\t/*\n\t * ip_route_output_key() should increment\n\t * r->u.dst.__use and call a dst_hold(dst)\n\t * XXX verify how we release the resources.\n\t */\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38) /* check boundary */\n\tr = ip_route_output_key(&init_net, &fl.u.ip4);\n#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) /* check boundary */\n\tret = ip_route_output_key(&init_net, &r, &fl);\n#else\n\tret = ip_route_output_key(&r, &fl);\n#endif\n\tif (ret != 0 || r == NULL ) {\n\t\tprintf(\"NO ROUTE FOUND\\n\");\n\t\treturn NULL;\n\t}\n\n\t/* allocate the skbuff and the data */\n\tskb = alloc_skb(len + sizeof(struct ethhdr), GFP_ATOMIC);\n\tif (skb == NULL) {\n\t\tprintf(\"%s: can not allocate SKB buffers.\\n\", __FUNCTION__);\n\t\treturn NULL;\n\t}\n\n\tskb->protocol = htons(ETH_P_IP); // XXX 8 or 16 bit ?\n\t/* sk_dst_set XXX take the lock (?) */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)\n\tskb_dst_set(skb, &r->u.dst);\n#else\n\tskb_dst_set(skb, &r->dst);\n#endif\n\tskb->dev = skb_dst(skb)->dev;\n\n\t/* reserve space for ethernet header */\n\tskb_reserve(skb, sizeof(struct ethhdr));\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)\n\tskb_reset_network_header(skb); // skb->network_header = skb->data - skb->head\n#else\n\tskb->nh.raw = skb->data;\n#endif\n\t/* set skbuff tail pointers and copy content */\n\tskb_put(skb, len);\n\tmemcpy(skb->data, m->m_data, len);\n\n\treturn skb;\n}\n#endif /* linux 2.6+ */\n#endif /* linux */\n\n\n/*\n * This function is called to reinject packets to the\n * kernel stack within the linux netfilter system\n * or to send a new created mbuf.\n * In the first case we have a valid sk_buff pointer\n * encapsulated within the fake mbuf, so we can call\n * the reinject function trough netisr_dispatch.\n * In the last case we need to build a sk_buff from scratch,\n * before sending out the packet.\n */\nint\nip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,\n    struct ip_moptions *imo, struct inpcb *inp)\n{\n\t(void)opt; (void)ro; (void)flags; (void)imo; (void)inp;\t/* UNUSED */\n\tif ( m->m_skb != NULL ) { /* reinjected packet, just call dispatch */\n\t\tND(\"sending... \");\n\t\tnetisr_dispatch(0, m);\n\t} else {\n\t\t/* self-generated packet, wrap as appropriate and send */\n#ifdef __linux__\n\t\tstruct sk_buff *skb = mbuf2skbuff(m);\n\n\t\tif (skb != NULL)\n\t\t\tdst_output(skb);\n#else /* Windows */\n\t\tD(\"unimplemented.\");\n#endif\n\t\tFREE_PKT(m);\n\t}\n\treturn 0;\n}\n\n/*\n * setsockopt hook has no return value other than the error code.\n */\nint\ndo_ipfw_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)\n{\n\tstruct sockopt s;\t/* pass arguments */\n\t(void)sk;\t\t/* UNUSED */\n\treturn ipfw_ctl_h(&s, cmd, SOPT_SET, len, user);\n}\n\n/*\n * getsockopt can can return a block of data in response.\n */\nint\ndo_ipfw_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)\n{\n\tstruct sockopt s;\t/* pass arguments */\n\tint ret = ipfw_ctl_h(&s, cmd, SOPT_GET, *len, user);\n\n\t(void)sk;\t\t/* UNUSED */\n\t*len = s.sopt_valsize;\t/* return length back to the caller */\n\treturn ret;\n}\n\n#ifdef __linux__\n\n/*\n * declare our [get|set]sockopt hooks\n */\nstatic struct nf_sockopt_ops ipfw_sockopts = {\n\t.pf\t\t= PF_INET,\n\t.set_optmin\t= _IPFW_SOCKOPT_BASE,\n\t.set_optmax\t= _IPFW_SOCKOPT_END,\n\t.set\t\t= do_ipfw_set_ctl,\n\t.get_optmin\t= _IPFW_SOCKOPT_BASE,\n\t.get_optmax\t= _IPFW_SOCKOPT_END,\n\t.get\t\t= do_ipfw_get_ctl,\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)\n\t.owner\t\t= THIS_MODULE,\n#endif\n};\n\n/*----\n * We need a number of macros to adapt to the various APIs in\n * different linux versions. Among them:\n *\n * - the hook names change between macros (NF_IP*) and enum NF_INET_*\n *\n * - the second argument to the netfilter hook is\n *\tstruct sk_buff **\tin kernels <= 2.6.22\n *\tstruct sk_buff *\tin kernels > 2.6.22\n *\n * - NF_STOP is not defined before 2.6 so we remap it to NF_ACCEPT\n *\n * - the packet descriptor passed to the queue handler is\n *\tstruct nf_info\t\tin kernels <= 2.6.24\n *\tstruct nf_queue_entry\tin kernels <= 2.6.24\n *\n * - the arguments to the queue handler also change;\n */\n\n/*\n * declare hook to grab packets from the netfilter interface.\n * The NF_* names change in different versions of linux, in some\n * cases they are #defines, in others they are enum, so we\n * need to adapt.\n */\n#ifndef NF_IP_PRE_ROUTING\n#define NF_IP_PRE_ROUTING\tNF_INET_PRE_ROUTING\n#endif\n#ifndef NF_IP_POST_ROUTING\n#define NF_IP_POST_ROUTING\tNF_INET_POST_ROUTING\n#endif\n\n/*\n * ipfw hooks into the POST_ROUTING and the PRE_ROUTING chains.\n * PlanetLab sets skb_tag to the slice id in the LOCAL_INPUT and\n * POST_ROUTING chains, so if we want to use that information we\n * need to hook the LOCAL_INPUT chain instead of the PRE_ROUTING.\n * However at the moment the skb_tag info is not reliable so\n * we stay with the standard hooks.\n */\n#if 0 // defined(IPFW_PLANETLAB)\n#define IPFW_HOOK_IN NF_IP_LOCAL_IN\n#else\n#define IPFW_HOOK_IN NF_IP_PRE_ROUTING\n#endif\n\n/*\n * The main netfilter hook.\n * To make life simple, we queue everything and then do all the\n * decision in the queue handler.\n *\n * XXX note that in 2.4 and up to 2.6.22 the skbuf is passed as sk_buff**\n * so we have an #ifdef to set the proper argument type.\n */\nstatic unsigned int\ncall_ipfw(\n#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)\n\tunsigned int hooknum,\n#else\n\tconst struct nf_hook_ops *hooknum,\n#endif\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) // in 2.6.22 we have **\n\tstruct sk_buff  **skb,\n#else\n\tstruct sk_buff  *skb,\n#endif\n\tconst struct net_device *in, const struct net_device *out,\n\tint (*okfn)(struct sk_buff *))\n{\n\t(void)hooknum; (void)skb; (void)in; (void)out; (void)okfn; /* UNUSED */\n\treturn NF_QUEUE;\n}\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)\t/* XXX was 2.6.0 */\n#define\tNF_STOP\t\tNF_ACCEPT\n#endif\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)\n\n/*\n * nf_queue_entry is a recent addition, in previous versions\n * of the code the struct is called nf_info.\n */\n#define nf_queue_entry\tnf_info\t/* for simplicity */\n\n/* also, 2.4 and perhaps something else have different arguments */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)\t/* XXX unsure */\n/* on 2.4 we use nf_info */\n#define QH_ARGS\t\tstruct sk_buff *skb, struct nf_info *info, void *data\n#else\t/* 2.6.14. 2.6.24 */\n#define QH_ARGS\t\tstruct sk_buff *skb, struct nf_info *info, unsigned int qnum, void *data\n#endif\n\n#define DEFINE_SKB\t/* nothing, already an argument */\n#define\tREINJECT(_inf, _verd)\tnf_reinject(skb, _inf, _verd)\n\n#else\t/* 2.6.25 and above */\n\n#define QH_ARGS\t\tstruct nf_queue_entry *info, unsigned int queuenum\n#define DEFINE_SKB\tstruct sk_buff *skb = info->skb;\n#define\tREINJECT(_inf, _verd)\tnf_reinject(_inf, _verd)\n#endif\n\n/*\n * used by dummynet when dropping packets\n * XXX use dummynet_send()\n */\nvoid\nreinject_drop(struct mbuf* m)\n{\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)\t/* unsure on the exact boundary */\n\tstruct sk_buff *skb = (struct sk_buff *)m;\n#endif\n\tREINJECT(m->queue_entry, NF_DROP);\n}\n\n/*\n * The real call to the firewall. nf_queue_entry points to the skbuf,\n * and eventually we need to return both through nf_reinject().\n */\nstatic int\nipfw2_queue_handler(QH_ARGS)\n{\n\tDEFINE_SKB\t/* no semicolon here, goes in the macro */\n\tint ret = 0;\t/* return value */\n\tstruct mbuf *m;\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)\n\tif (skb->nh.iph == NULL) {\n\t\tprintf(\"null dp, len %d reinject now\\n\", skb->len);\n\t\tREINJECT(info, NF_ACCEPT);\n\t\treturn 0;\n\t}\n#endif\n\tm = malloc(sizeof(*m), 0, 0);\n\tif (m == NULL) {\n\t\tprintf(\"malloc fail, len %d reinject now\\n\", skb->len);\n\t\tREINJECT(info, NF_ACCEPT);\n\t\treturn 0;\n\t}\n\n\tm->m_skb = skb;\n\tm->m_len = skb->len;\t\t/* len from ip header to end */\n\tm->m_pkthdr.len = skb->len;\t/* total packet len */\n\tm->m_pkthdr.rcvif = info->indev;\n\tm->queue_entry = info;\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)\t/* XXX was 2.6.0 */\n\tm->m_data = (char *)skb->nh.iph;\n#else\n\tm->m_data = (char *)skb_network_header(skb);\t// XXX unsigned ? */\n#endif\n\n\t/* XXX add the interface */\n\tif (info->hook == IPFW_HOOK_IN) {\n\t\tret = ipfw_check_hook(NULL, &m, info->indev, PFIL_IN, NULL);\n\t} else {\n\t\tret = ipfw_check_hook(NULL, &m, info->outdev, PFIL_OUT, NULL);\n\t}\n\n\tif (m != NULL) {\t/* Accept. reinject and free the mbuf */\n\t\tREINJECT(info, NF_ACCEPT);\n\t\tm_freem(m);\n\t} else if (ret == 0) {\n\t\t/* dummynet has kept the packet, will reinject later. */\n\t} else {\n\t\t/*\n\t\t * Packet dropped by ipfw or dummynet. Nothing to do as\n\t\t * FREE_PKT already did a reinject as NF_DROP\n\t\t */\n\t}\n\treturn 0;\n}\n\nstruct route;\nstruct ip_moptions;\nstruct inpcb;\n\n/* XXX should include prototypes for netisr_dispatch and ip_output */\n/*\n * The reinjection routine after a packet comes out from dummynet.\n * We must update the skb timestamp so ping reports the right time.\n * This routine is also used (with num == -1) as FREE_PKT. XXX\n */\nvoid\nnetisr_dispatch(int num, struct mbuf *m)\n{\n\tstruct nf_queue_entry *info = m->queue_entry;\n\tstruct sk_buff *skb = m->m_skb;\t/* always used */\n\n\t/*\n\t * This function can be called by the FREE_PKT()\n\t * used when ipfw generate their own mbuf packets\n\t * or by the mbuf2skbuff() function.\n\t */\n\tm_freem(m);\n\n\t/* XXX check\n\t * info is null in the case of a real mbuf\n\t * (one created by the ipfw code without a\n\t * valid sk_buff pointer\n\t */\n\tif (info == NULL)\n\t\treturn;\n\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)\t// XXX above 2.6.x ?\n\t__net_timestamp(skb);\t/* update timestamp */\n#endif\n\n\t/* XXX to obey one-pass, possibly call the queue handler here */\n\tREINJECT(info, ((num == -1)?NF_DROP:NF_STOP));\t/* accept but no more firewall */\n}\n\n/*\n * socket lookup function for linux.\n * This code is used to associate uid, gid, jail/xid to packets,\n * and store the info in a cache *ugp where they can be accessed quickly.\n * The function returns 1 if the info is found, -1 otherwise.\n *\n * We do this only on selected protocols: TCP, ...\n *\n * The chain is the following\n *   sk_buff*  sock*  socket*    file*\n *\tskb  ->  sk ->sk_socket->file ->f_owner    ->pid\n *\tskb  ->  sk ->sk_socket->file ->f_uid (direct)\n *\tskb  ->  sk ->sk_socket->file ->f_cred->fsuid (2.6.29+)\n *\n * Related headers:\n * linux/skbuff.h\tstruct skbuff\n * net/sock.h\t\tstruct sock\n * linux/net.h\t\tstruct socket\n * linux/fs.h\t\tstruct file\n *\n * With vserver we may have sk->sk_xid and sk->sk_nid that\n * which we store in fw_groups[1] (matches O_JAIL) and fw_groups[2]\n * (no matches yet)\n *\n * Note- for locally generated, outgoing packets we should not need\n * need a lookup because the sk_buff already points to the socket where\n * the info is.\n */\nextern struct inet_hashinfo tcp_hashinfo;\nint\nlinux_lookup(const int proto, const __be32 saddr, const __be16 sport,\n\t\tconst __be32 daddr, const __be16 dport,\n\t\tstruct sk_buff *skb, int dir, struct bsd_ucred *u)\n{\n#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) \t/* XXX was 2.6.0 */\n\treturn -1;\n#else\n\tstruct sock *sk;\n\tint ret = -1;\t/* default return value */\n\tint st = -1;\t/* state */\n\n\n\tif (proto != IPPROTO_TCP)\t/* XXX extend for UDP */\n\t\treturn -1;\n\n\tif ((dir ? (void *)skb_dst(skb) : (void *)skb->dev) == NULL) {\n\t\tpanic(\" -- this should not happen\\n\");\n\t\treturn -1;\n\t}\n\n\tif (skb->sk) {\n\t\tsk = skb->sk;\n\t} else {\n\t\t/*\n\t\t * Try a lookup. On a match, sk has a refcount that we must\n\t\t * release on exit (we know it because skb->sk = NULL).\n\t\t *\n\t\t * inet_lookup above 2.6.24 has an additional 'net' parameter\n\t\t * so we use a macro to conditionally supply it.\n\t\t * swap dst and src depending on the direction.\n\t\t */\n#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)\n#define _OPT_NET_ARG\n#else\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)\n/* there is no dev_net() on 2.6.25 */\n#define _OPT_NET_ARG (skb->dev->nd_net),\n#else\t/* 2.6.26 and above */\n#define _OPT_NET_ARG dev_net(skb->dev),\n#endif\n#endif\n\t\tsk =  (dir) ? /* dir != 0 on output */\n\t\t    inet_lookup(_OPT_NET_ARG &tcp_hashinfo,\n\t\t\tdaddr, dport, saddr, sport,\t// match outgoing\n\t\t\tinet_iif(skb)) :\n\t\t    inet_lookup(_OPT_NET_ARG &tcp_hashinfo,\n\t\t\tsaddr, sport, daddr, dport,\t// match incoming\n\t\t\tskb->dev->ifindex);\n#undef _OPT_NET_ARG\n\n\t\tif (sk == NULL) /* no match, nothing to be done */\n\t\t\treturn -1;\n\t}\n\tret = 1;\t/* retrying won't make things better */\n\tst = sk->sk_state;\n#ifdef CONFIG_VSERVER\n\tu->xid = sk->sk_xid;\n\tu->nid = sk->sk_nid;\n#else\n\tu->xid = u->nid = 0;\n#endif\n\t/*\n\t * Exclude tcp states where sk points to a inet_timewait_sock which\n\t * has no sk_socket field (surely TCP_TIME_WAIT, perhaps more).\n\t * To be safe, use a whitelist and not a blacklist.\n\t * Before dereferencing sk_socket grab a lock on sk_callback_lock.\n\t *\n\t * Once again we need conditional code because the UID and GID\n\t * location changes between kernels.\n\t */\n#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)\n/* use the current's real uid/gid */\n#define _CURR_UID f_uid\n#define _CURR_GID f_gid\n#else /* 2.6.29 and above */\n/* use the current's file access real uid/gid */\n#define _CURR_UID f_cred->fsuid\n#define _CURR_GID f_cred->fsgid\n#endif\n\n#define GOOD_STATES (\t\\\n\t(1<<TCP_LISTEN) | (1<<TCP_SYN_RECV)   | (1<<TCP_SYN_SENT)   | \\\n\t(1<<TCP_ESTABLISHED)  | (1<<TCP_FIN_WAIT1) | (1<<TCP_FIN_WAIT2) )\n\t// surely exclude TCP_CLOSE, TCP_TIME_WAIT, TCP_LAST_ACK\n\t// uncertain TCP_CLOSE_WAIT and TCP_CLOSING\n\n\tif ((1<<st) & GOOD_STATES) {\n\t\tread_lock_bh(&sk->sk_callback_lock);\n\t\tif (sk->sk_socket && sk->sk_socket->file) {\n\t\t\t//u->uid = sk->sk_socket->file->_CURR_UID;\n\t\t\t//u->gid = sk->sk_socket->file->_CURR_GID;\n\t\t}\n\t\tread_unlock_bh(&sk->sk_callback_lock);\n\t} else {\n\t\tu->uid = u->gid = 0;\n\t}\n\tif (!skb->sk) /* return the reference that came from the lookup */\n\t\tsock_put(sk);\n#undef GOOD_STATES\n#undef _CURR_UID\n#undef _CURR_GID\n\treturn ret;\n\n#endif /* LINUX > 2.4 */\n}\n\n/*\n * Now prepare to hook the various functions.\n * Linux 2.4 has a different API so we need some adaptation\n * for register and unregister hooks\n *\n * the unregister function changed arguments between 2.6.22 and 2.6.24\n */\n#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)\nstruct nf_queue_handler ipfw2_queue_handler_desc = {\n        .outfn = ipfw2_queue_handler,\n#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)\n        .name = \"ipfw2 dummynet queue\",\n#endif\n};\n#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)\n#define REG_QH_ARG(pf, fn)\tpf, &(fn ## _desc)\n#else\n#define REG_QH_ARG(pf, fn)\t&(fn ## _desc)\n#endif\n#endif\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) /* XXX was 2.6.0 */\nstatic int\nnf_register_hooks(struct nf_hook_ops *ops, int n)\n{\n\tint i, ret = 0;\n\tfor (i = 0; i < n; i++) {\n\t\tret = nf_register_hook(ops + i);\n\t\tif (ret < 0)\n\t\t\tbreak;\n\t}\n\treturn ret;\n}\n\nstatic void\nnf_unregister_hooks(struct nf_hook_ops *ops, int n)\n{\n\tint i;\n\tfor (i = 0; i < n; i++) {\n\t\tnf_unregister_hook(ops + i);\n\t}\n}\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) /* XXX was 2.6.0 */\n#define REG_QH_ARG(pf, fn)\tpf, fn, NULL\n#endif\n#define UNREG_QH_ARG(pf, fn) //fn\t/* argument for nf_[un]register_queue_handler */\n#define SET_MOD_OWNER\n\n#else /* linux > 2.6.17 */\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)\n#define UNREG_QH_ARG(pf, fn) //fn\n#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)\n#define UNREG_QH_ARG(pf, fn)\tpf, &(fn ## _desc)\n#else\n#define UNREG_QH_ARG(pf, fn)\n#endif /* 2.6.0 < LINUX > 2.6.24 */\n\n#define SET_MOD_OWNER\t.owner = THIS_MODULE,\n\n#endif\t/* !LINUX < 2.6.0 */\n\nstatic struct nf_hook_ops ipfw_ops[] __read_mostly = {\n        {\n                .hook           = call_ipfw,\n                .pf             = PF_INET,\n                .hooknum        = IPFW_HOOK_IN,\n                .priority       = NF_IP_PRI_FILTER,\n                SET_MOD_OWNER\n        },\n        {\n                .hook           = call_ipfw,\n                .pf             = PF_INET,\n                .hooknum        = NF_IP_POST_ROUTING,\n                .priority       = NF_IP_PRI_FILTER,\n\t\tSET_MOD_OWNER\n        },\n};\n#endif /* __linux__ */\n\n/* descriptors for the children, until i find a way for the\n * linker to produce them\n */\nextern moduledata_t *moddesc_ipfw;\nextern moduledata_t *moddesc_dummynet;\nextern moduledata_t *moddesc_dn_fifo;\nextern moduledata_t *moddesc_dn_wf2qp;\nextern moduledata_t *moddesc_dn_rr;\nextern moduledata_t *moddesc_dn_qfq;\nextern moduledata_t *moddesc_dn_prio;\nextern void *sysinit_ipfw_init;\nextern void *sysuninit_ipfw_destroy;\nextern void *sysinit_vnet_ipfw_init;\nextern void *sysuninit_vnet_ipfw_uninit;\n\n/*\n * Module glue - init and exit function.\n */\nint __init\nipfw_module_init(void)\n{\n\tint ret = 0;\n#ifdef _WIN32\n\tunsigned long resolution;\n#endif\n\n\trn_init(64);\n\tmy_mod_register(\"ipfw\",  1, moddesc_ipfw, NULL, NULL);\n\tmy_mod_register(\"sy_ipfw\",  2, NULL,\n\t\tsysinit_ipfw_init, sysuninit_ipfw_destroy);\n\tmy_mod_register(\"sy_Vnet_ipfw\",  3, NULL,\n\t\tsysinit_vnet_ipfw_init, sysuninit_vnet_ipfw_uninit);\n\tmy_mod_register(\"dummynet\",  4, moddesc_dummynet, NULL, NULL);\n\tmy_mod_register(\"dn_fifo\",  5, moddesc_dn_fifo, NULL, NULL);\n\tmy_mod_register(\"dn_wf2qp\",  6, moddesc_dn_wf2qp, NULL, NULL);\n\tmy_mod_register(\"dn_rr\",  7, moddesc_dn_rr, NULL, NULL);\n\tmy_mod_register(\"dn_qfq\",  8, moddesc_dn_qfq, NULL, NULL);\n\tmy_mod_register(\"dn_prio\",  9, moddesc_dn_prio, NULL, NULL);\n\tinit_children();\n\n#ifdef _WIN32\n\tresolution = ExSetTimerResolution(1, TRUE);\n\tprintf(\"*** ExSetTimerResolution: resolution set to %d n-sec ***\\n\",resolution);\n#endif\n#ifdef EMULATE_SYSCTL\n\tkeinit_GST();\n#endif \n\n#ifdef __linux__\n\t/* sockopt register, in order to talk with user space */\n\tret = nf_register_sockopt(&ipfw_sockopts);\n        if (ret < 0) {\n\t\tprintf(\"error %d in nf_register_sockopt\\n\", ret);\n\t\tgoto clean_modules;\n\t}\n\n\t/* queue handler registration, in order to get network\n\t * packet under a private queue */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)\n\tret =\n#endif\n\t    nf_register_queue_handler(REG_QH_ARG(PF_INET, ipfw2_queue_handler) );\n        if (ret < 0)\t/* queue busy */\n\t\tgoto unregister_sockopt;\n\n        ret = nf_register_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));\n        if (ret < 0)\n\t\tgoto unregister_sockopt;\n\n\tprintf(\"%s loaded\\n\", __FUNCTION__);\n\treturn 0;\n\n\n/* handle errors on load */\nunregister_sockopt:\n\tnf_unregister_queue_handler(UNREG_QH_ARG(PF_INET, ipfw2_queue_handler) );\n\tnf_unregister_sockopt(&ipfw_sockopts);\n\nclean_modules:\n\tfini_children();\n\tprintf(\"%s error\\n\", __FUNCTION__);\n\n#endif\t/* __linux__ */\n\treturn ret;\n}\n\n/* module shutdown */\nvoid __exit\nipfw_module_exit(void)\n{\n#ifdef EMULATE_SYSCTL\n\tkeexit_GST();\n#endif\n#ifdef _WIN32\n\tExSetTimerResolution(0,FALSE);\n\n#else  /* linux hook */\n        nf_unregister_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));\n\t/* maybe drain the queue before unregistering ? */\n\tnf_unregister_queue_handler(UNREG_QH_ARG(PF_INET, ipfw2_queue_handler) );\n\tnf_unregister_sockopt(&ipfw_sockopts);\n#endif\t/* __linux__ */\n\n\tfini_children();\n\n\tprintf(\"%s unloaded\\n\", __FUNCTION__);\n}\n\n#ifdef __linux__\nmodule_init(ipfw_module_init)\nmodule_exit(ipfw_module_exit)\nMODULE_LICENSE(\"Dual BSD/GPL\"); /* the code here is all BSD. */\n#endif\n"
  },
  {
    "path": "kipfw/md_win.c",
    "content": "/*\n * Copyright (C) 2010 Luigi Rizzo, Francesco Magno, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * kernel variables and functions that are not available in Windows.\n */\n\n#include <net/pfil.h> /* provides PFIL_IN and PFIL_OUT */\n#include <arpa/inet.h>\n#include <netinet/in.h>\t\t\t/* in_addr */\n#include <ndis.h>\n#include <sys/mbuf.h>\n#include <passthru.h>\n\n/* credentials check */\nint\ncred_check(void *_insn,  int proto, struct ifnet *oif,\n    struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,\n    u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,\n    struct sk_buff *skb)\n{\n\treturn 0;\n}\n\n/*\n * as good as anywhere, place here the missing calls\n */\n\nvoid *\nmy_alloc(int size)\n{\n\tvoid *_ret = ExAllocatePoolWithTag(NonPagedPool, size, 'wfpi');\n\tif (_ret)\n\t\tmemset(_ret, 0, size);\n\treturn _ret;\n}\n\nvoid\npanic(const char *fmt, ...)\n{\n\tprintf(\"%s\", fmt);\n\tfor (;;);\n}\n\nint securelevel = 0;\n\nint ffs(int bits)\n{\n\tint i;\n\tif (bits == 0)\n\t\treturn (0);\n\tfor (i = 1; ; i++, bits >>= 1) {\n\t\tif (bits & 1)\n\t\t\tbreak;\n\t}\n\treturn (i);\n}\n\nvoid\ndo_gettimeofday(struct timeval *tv)\n{\n\tstatic LARGE_INTEGER prevtime; //system time in 100-nsec resolution\n\tstatic LARGE_INTEGER prevcount; //RTC counter value\n\tstatic LARGE_INTEGER freq; //frequency\n\n\tLARGE_INTEGER currtime;\n\tLARGE_INTEGER currcount;\n\tif (prevtime.QuadPart == 0) { //first time we ask for system time\n\t\tKeQuerySystemTime(&prevtime);\n\t\tprevcount = KeQueryPerformanceCounter(&freq);\n\t\tcurrtime.QuadPart = prevtime.QuadPart;\n\t} else {\n\t\tKeQuerySystemTime(&currtime);\n\t\tcurrcount = KeQueryPerformanceCounter(&freq);\n\t\tif (currtime.QuadPart == prevtime.QuadPart) {\n\t\t\t//time has NOT changed, calculate time using ticks and DO NOT update\n\t\t\tLONGLONG difftime = 0; //difference in 100-nsec\n\t\t\tLONGLONG diffcount = 0; //clock count difference\n\t\t\t//printf(\"time has NOT changed\\n\");\n\t\t\tdiffcount = currcount.QuadPart - prevcount.QuadPart;\n\t\t\tdiffcount *= 10000000;\n\t\t\tdifftime = diffcount / freq.QuadPart;\n\t\t\tcurrtime.QuadPart += difftime;\n\t\t} else {\t\n\t\t\t//time has changed, update and return SystemTime\n\t\t\t//printf(\"time has changed\\n\");\n\t\t\tprevtime.QuadPart = currtime.QuadPart;\n\t\t\tprevcount.QuadPart = currcount.QuadPart;\n\t\t}\n\t}\n\tcurrtime.QuadPart /= 10; //convert in usec\n\ttv->tv_sec = currtime.QuadPart / (LONGLONG)1000000;\n\ttv->tv_usec = currtime.QuadPart % (LONGLONG)1000000;\n\t//printf(\"sec %d usec %d\\n\",tv->tv_sec, tv->tv_usec);\n}\n\nint time_uptime_w32()\n{\n\tint ret;\n\tLARGE_INTEGER tm;\n\tKeQuerySystemTime(&tm);\n\tret = (int)(tm.QuadPart / (LONGLONG)1000000);\n\treturn ret;\n}\n\n\n/*\n * Windows version of firewall hook. We receive a partial copy of\n * the packet which points to the original buffers. In output,\n * the refcount has been already incremented.\n * The function reconstructs\n * the whole packet in a contiguous memory area, builds a fake mbuf,\n * calls the firewall, does the eventual cleaning and returns\n * to MiniportSend or ProtocolReceive, which will silently return\n * (dropping packet) or continue its execution (allowing packet).\n * The memory area contains:\n * - the fake mbuf, filled with data needed by ipfw, and information\n *   for reinjection\n * - the packet data\n */\nvoid hexdump(PUCHAR,int, const char *);\nstatic char _if_in[] = \"incoming\";\nstatic char _if_out[] = \"outgoing\";\n\nint\nipfw2_qhandler_w32(PNDIS_PACKET pNdisPacket, int direction,\n\tNDIS_HANDLE Context)\n{\t\n\tunsigned int\t\tBufferCount = 0;\n\tunsigned\t\t\tTotalPacketLength = 0;\n\tPNDIS_BUFFER\t\tpCurrentBuffer = NULL;\n\tPNDIS_BUFFER\t\tpNextBuffer = NULL;\n\tstruct mbuf*\t\tm;\n\tunsigned char*\t\tpayload = NULL;\n\tunsigned int\t\tofs, l;\n\tunsigned short\t\tEtherType = 0;\n\tunsigned int\t\ti = 0;\n\tint\t\t\t\t\tret = 0;\n\tPNDIS_BUFFER\t\tpNdisBuffer, old_head, old_tail;\n\tNDIS_HANDLE\t\t\tPacketPool;\n\tPADAPT\t\t\t\tpAdapt;\n\tNDIS_STATUS\t\t\tStatus;\n\n\t/* In NDIS, packets are a chain of NDIS_BUFFER. We query\n\t * the packet to get a pointer of chain's head, the length\n\t * of the chain, and the length of the packet itself.\n\t * Then allocate a buffer for the mbuf and the payload.\n\t */\n\tNdisQueryPacket(pNdisPacket, NULL, &BufferCount,\n\t\t&pCurrentBuffer, &TotalPacketLength);\n\tm = malloc(sizeof(struct mbuf) + TotalPacketLength, 0, 0 );\n\tif (m == NULL) //resource shortage, drop the packet\n\t\tgoto drop_pkt;\n\n\t/* set mbuf fields to point past the MAC header.\n\t * Also set additional W32 info\n\t */\n\tpayload = (unsigned char*)(m + 1);\n\tm->m_len = m->m_pkthdr.len = TotalPacketLength-14;\n\tm->m_pkthdr.rcvif = (void *)((direction==INCOMING) ? _if_in : NULL);\n\tm->m_data = payload + 14; /* past the MAC header */\n\tm->direction = direction;\n\tm->context = Context;\n\tm->pkt = pNdisPacket;\n\n\t/* m_skb != NULL is used in the ip_output routine to check\n\t * for packets that come from the stack and differentiate\n\t * from those internally generated by ipfw.\n\t * The pointer is not used, just needs to be non-null.\n\t */\n\tm->m_skb = (void *)pNdisPacket;\n\t/*\n\t * Now copy the data from the Windows buffers to the mbuf.\n\t */\n\tfor (i=0, ofs = 0; i < BufferCount; i++) {\n\t\tunsigned char* src;\n\t\tNdisQueryBufferSafe(pCurrentBuffer, &src, &l,\n\t\t\tNormalPagePriority);\n\t\tbcopy(src, payload + ofs, l);\n\t\tofs += l;\n\t\tNdisGetNextBuffer(pCurrentBuffer, &pNextBuffer);\n\t\tpCurrentBuffer = pNextBuffer;\n\t}\n\t/*\n\t * Identify EtherType. If the packet is not IP, simply allow\n\t * and don't bother the firewall. XXX should be done before.\n\t */\n\tEtherType = *(unsigned short*)(payload + 12);\n\tEtherType = RtlUshortByteSwap(EtherType);\n\tif (EtherType != 0x0800) {\n\t\t//DbgPrint(\"ethertype = %X, skipping ipfw\\n\",EtherType);\n\t\tfree(m, 0);\n\t\treturn PASS;\n\t}\n\n\t/*\n\t * Now build a buffer descriptor to replace the original chain.\n\t */\n\tpAdapt = Context;\n\tPacketPool = direction == OUTGOING ?\n\t\tpAdapt->SendPacketPoolHandle : pAdapt->RecvPacketPoolHandle;\n        NdisAllocateBuffer(&Status, &pNdisBuffer,\n                PacketPool, payload, m->m_pkthdr.len+14);\n        if (Status != NDIS_STATUS_SUCCESS)\n                goto drop_pkt;\n        /*\n\t * Save the old buffer pointers, and put the new one\n\t * into the chain.\n         */\n        pNdisBuffer->Next = NULL;\n\told_head = NDIS_PACKET_FIRST_NDIS_BUFFER(pNdisPacket);\n\told_tail = NDIS_PACKET_LAST_NDIS_BUFFER(pNdisPacket);\n\tNdisReinitializePacket(pNdisPacket);\n\tNdisChainBufferAtFront(pNdisPacket, pNdisBuffer);\n#if 0\n\tif (direction == INCOMING) {\n\t\tDBGPRINT((\"incoming: proto %u (%s), src %08X, dst %08X, sport %u, dport %u, len %u\\n\", *(payload+14+9), texify_proto(*(payload+14+9)), *(unsigned int*)(payload+14+12), *(unsigned int*)(payload+14+16), ntohs((*((unsigned short int*)(payload+14+20)))), ntohs((*((unsigned short int*)(payload+14+22)))), TotalPacketLength));\n\t} else {\n\t\tDBGPRINT((\"outgoing: proto %u (%s), src %08X, dst %08X, sport %u, dport %u, len %u\\n\", *(payload+14+9), texify_proto(*(payload+14+9)), *(unsigned int*)(payload+14+12), *(unsigned int*)(payload+14+16), ntohs((*((unsigned short int*)(payload+14+20)))), ntohs((*((unsigned short int*)(payload+14+22)))), TotalPacketLength));\n\t}\n#endif\n\tif (direction == INCOMING)\n\t\tret = ipfw_check_hook(NULL, &m, NULL, PFIL_IN, NULL);\n\telse\n\t\tret = ipfw_check_hook(NULL, &m, (struct ifnet*)_if_out, PFIL_OUT, NULL);\n\n\tif (m != NULL) {\n\t\t/* Accept. Restore the old buffer chain, free\n\t\t * the mbuf and return PASS.\n\t\t */\n\t\t//DBGPRINT((\"accepted\\n\"));\n\t\tNdisReinitializePacket(pNdisPacket);\n\t\tNDIS_PACKET_FIRST_NDIS_BUFFER(pNdisPacket) = old_head;\n\t\tNDIS_PACKET_LAST_NDIS_BUFFER(pNdisPacket) = old_tail;\n\t\tNdisFreeBuffer(pNdisBuffer);\n\t\tm_freem(m);\n\t\treturn PASS;\n\t} else if (ret == 0) {\n\t\t/* dummynet has kept the packet, will reinject later. */\n\t\t//DBGPRINT((\"kept by dummynet\\n\"));\n\t\treturn DUMMYNET;\n\t} else {\n\t\t/*\n\t\t * Packet dropped by ipfw or dummynet. Nothing to do as\n\t\t * FREE_PKT already freed the fake mbuf\n\t\t */\n\t\t//DBGPRINT((\"dropped by dummynet, ret = %i\\n\", ret));\n\t\treturn DROP;\n\t}\ndrop_pkt:\n\t/* for some reason we cannot proceed. Free any resources\n\t * including those received from above, and return\n\t * faking success. XXX this must be fixed later.\n\t */\n\tNdisFreePacket(pNdisPacket);\n\treturn DROP;\n}\n\n/*\n * Windows reinjection function.\n * The packet is already available as m->pkt, so we only\n * need to send it to the right place.\n * Normally a ndis intermediate driver allocates\n * a fresh descriptor, while the actual data's ownership is\n * retained by the protocol, or the miniport below.\n * Since an intermediate driver behaves as a miniport driver\n * at the upper edge (towards the protocol), and as a protocol\n * driver at the lower edge (towards the NIC), when we handle a\n * packet we have a reserved area in both directions (we can use\n * only one for each direction at our own discretion).\n * Normally this area is used to save a pointer to the original\n * packet, so when the driver is done with it, the original descriptor\n * can be retrieved, and the resources freed (packet descriptor,\n * buffer descriptor(s) and the actual data). In our driver this\n * area is used to mark the reinjected packets as 'orphan', because\n * the original descriptor is gone long ago. This way we can handle\n * correctly the resource freeing when the callback function\n * is called by NDIS.\n */\n\nvoid \nnetisr_dispatch(int num, struct mbuf *m)\n{\n\tunsigned char*\t\tpayload = (unsigned char*)(m+1);\n\tPADAPT\t\t\t\tpAdapt = m->context;\n\tNDIS_STATUS\t\t\tStatus;\n\tPNDIS_PACKET\t\tpPacket = m->pkt;\n\tPNDIS_BUFFER\t\tpNdisBuffer;\n\tNDIS_HANDLE\t\t\tPacketPool;\n\n\tif (num < 0)\n\t\tgoto drop_pkt;\n\n\t//debug print\n#if 0\n\tDbgPrint(\"reinject %s\\n\", m->direction == OUTGOING ?\n\t\t\"outgoing\" : \"incoming\");\n#endif\n\tNdisAcquireSpinLock(&pAdapt->Lock);\n\tif (m->direction == OUTGOING) {\n\t\t//we must first check if the adapter is going down,\n\t\t// in this case abort the reinjection\n\t\tif (pAdapt->PTDeviceState > NdisDeviceStateD0) {\n\t\t\tpAdapt->OutstandingSends--;\n\t\t\t// XXX should we notify up ?\n\t\t\tNdisReleaseSpinLock(&pAdapt->Lock);\n\t\t\tgoto drop_pkt;\n\t\t}\n\t} else {\n\t\t/* if the upper miniport edge is not initialized or\n\t\t * the miniport edge is in low power state, abort\n\t\t * XXX we should notify the error.\n\t\t */\n\t\tif (!pAdapt->MiniportHandle ||\n\t\t    pAdapt->MPDeviceState > NdisDeviceStateD0) {\n\t\t\tNdisReleaseSpinLock(&pAdapt->Lock);\n\t\t\tgoto drop_pkt;\n\t\t}\n\t}\n\tNdisReleaseSpinLock(&pAdapt->Lock);\n\n\tif (m->direction == OUTGOING) {\n\t\tPSEND_RSVD\tSendRsvd;\n\t\t/* use the 8-bytes protocol reserved area, the first\n\t\t * field is used to mark/the packet as 'orphan', the\n\t\t * second stores the pointer to the mbuf, so in the\n\t\t * the SendComplete handler we know that this is a\n\t\t * reinjected packet and can free correctly.\n\t\t */\n\t\tSendRsvd = (PSEND_RSVD)(pPacket->ProtocolReserved);\n\t\tSendRsvd->OriginalPkt = NULL;\n\t\tSendRsvd->pMbuf = m;\n\t\t//do the actual send\n\t\tNdisSend(&Status, pAdapt->BindingHandle, pPacket);\n\t\tif (Status != NDIS_STATUS_PENDING) {\n\t\t\t/* done, call the callback now */\n\t\t\tPtSendComplete(m->context, m->pkt, Status);\n\t\t}\n\t\treturn; /* unconditional return here. */\n\t} else {\n\t\t/* There's no need to check the 8-bytes miniport \n\t\t * reserved area since the path going up will be always\n\t\t * syncronous, and all the cleanup will be done inline.\n\t\t * If the reinjected packed comes from a PtReceivePacket, \n\t\t * there will be no callback.\n\t\t * Otherwise PtReceiveComplete will be called but will just\n\t\t * return since all the cleaning is alreqady done */\n\t\t// do the actual receive. \n\t\tULONG Proc = KeGetCurrentProcessorNumber();\n\t\tpAdapt->ReceivedIndicationFlags[Proc] = TRUE;\n\t\tNdisMEthIndicateReceive(pAdapt->MiniportHandle, NULL, payload, 14, payload+14, m->m_len, m->m_len);\n\t\tNdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);\n\t\tpAdapt->ReceivedIndicationFlags[Proc] = FALSE;\n\t}\ndrop_pkt:\n\t/* NDIS_PACKET exists and must be freed only if\n\t * the packet come from a PtReceivePacket, oherwise\n\t * m->pkt will ne null.\n\t */\n\tif (m->pkt != NULL)\n\t{\n\t\tNdisUnchainBufferAtFront(m->pkt, &pNdisBuffer);\n\t\tNdisFreeBuffer(pNdisBuffer);\n\t\tNdisFreePacket(m->pkt);\n\t}\n\tm_freem(m);\n}\n\nvoid win_freem(void *);\t/* wrapper for m_freem() for protocol.c */\nvoid\nwin_freem(void *_m)\n{\n\tstruct mbuf *m = _m;\n\tm_freem(m);\n}\n\n/*\n * not implemented in linux.\n * taken from /usr/src/lib/libc/string/strlcpy.c\n */\nsize_t\nstrlcpy(char *dst, const char *src, size_t siz)\n{\n        char *d = dst;\n        const char *s = src;\n        size_t n = siz;\n \n        /* Copy as many bytes as will fit */\n        if (n != 0 && --n != 0) {\n                do {\n                        if ((*d++ = *s++) == 0)\n                                break;\n                } while (--n != 0);\n        }\n\n        /* Not enough room in dst, add NUL and traverse rest of src */\n        if (n == 0) {\n                if (siz != 0)\n                        *d = '\\0';              /* NUL-terminate dst */\n                while (*s++)\n                        ;\n        }\n\n        return(s - src - 1);    /* count does not include NUL */\n}\n\nvoid CleanupReinjected(PNDIS_PACKET Packet, struct mbuf* m, PADAPT pAdapt)\n{\n\tPNDIS_BUFFER pNdisBuffer;\n\n\tNdisQueryPacket(Packet, NULL, NULL, &pNdisBuffer, NULL);\n\tNdisUnchainBufferAtFront(Packet, &pNdisBuffer);\n\tNdisFreeBuffer(pNdisBuffer);\n\twin_freem(m);\n\tNdisFreePacket(Packet);\n\tADAPT_DECR_PENDING_SENDS(pAdapt);\n}\n\nint\nipfw2_qhandler_w32_oldstyle(int direction,\n\tNDIS_HANDLE         ProtocolBindingContext,\n    unsigned char*      HeaderBuffer,\n    unsigned int        HeaderBufferSize,\n    unsigned char*      LookAheadBuffer,\n    unsigned int        LookAheadBufferSize,\n    unsigned int        PacketSize)\n{\n\tstruct mbuf* m;\n\tunsigned char*\t\tpayload = NULL;\n\tunsigned short\t\tEtherType = 0;\n\tint\t\t\t\t\tret = 0;\n\t\n\t/* We are in a special case when NIC signals an incoming\n\t * packet using old style calls. This is done passing\n\t * a pointer to the MAC header and a pointer to the\n\t * rest of the packet.\n\t * We simply allocate space for the mbuf and the\n\t * subsequent payload section.\n\t */\n\tm = malloc(sizeof(struct mbuf) + HeaderBufferSize + LookAheadBufferSize, 0, 0 );\n\tif (m == NULL) //resource shortage, drop the packet\n\t\treturn DROP;\n\t\n\t/* set mbuf fields to point past the MAC header.\n\t * Also set additional W32 info.\n\t * m->pkt here is set to null because the notification\n\t * from the NIC has come with a header+loolahead buffer,\n\t * no NDIS_PACKET has been provided.\n\t */\n\tpayload = (unsigned char*)(m + 1);\n\tm->m_len = m->m_pkthdr.len = HeaderBufferSize+LookAheadBufferSize-14;\n\tm->m_data = payload + 14; /* past the MAC header */\n\tm->direction = direction;\n\tm->context = ProtocolBindingContext;\n\tm->pkt = NULL;\n\t\n\t/*\n\t * Now copy the data from the Windows buffers to the mbuf.\n\t */\n\tbcopy(HeaderBuffer, payload, HeaderBufferSize);\n\tbcopy(LookAheadBuffer, payload+HeaderBufferSize, LookAheadBufferSize);\n\t//hexdump(payload,HeaderBufferSize+LookAheadBufferSize,\"qhandler\");\n\t/*\n\t * Identify EtherType. If the packet is not IP, simply allow\n\t * and don't bother the firewall. XXX should be done before.\n\t */\n\tEtherType = *(unsigned short*)(payload + 12);\n\tEtherType = RtlUshortByteSwap(EtherType);\n\tif (EtherType != 0x0800) {\n\t\t//DbgPrint(\"ethertype = %X, skipping ipfw\\n\",EtherType);\n\t\tfree(m, 0);\n\t\treturn PASS;\n\t}\n\n\t//DbgPrint(\"incoming_raw: proto %u (%s), src %08X, dst %08X, sport %u, dport %u, len %u\\n\", *(payload+14+9), texify_proto(*(payload+14+9)), *(unsigned int*)(payload+14+12), *(unsigned int*)(payload+14+16), ntohs((*((unsigned short int*)(payload+14+20)))), ntohs((*((unsigned short int*)(payload+14+22)))), HeaderBufferSize+LookAheadBufferSize);\n\t\n\t/* Query the firewall */\n\tret = ipfw_check_hook(NULL, &m, NULL, PFIL_IN, NULL);\n\n\tif (m != NULL) {\n\t\t/* Accept. Free the mbuf and return PASS. */\n\t\t//DbgPrint(\"accepted\\n\");\n\t\tm_freem(m);\n\t\treturn PASS;\n\t} else if (ret == 0) {\n\t\t/* dummynet has kept the packet, will reinject later. */\n\t\t//DbgPrint(\"kept by dummynet\\n\");\n\t\treturn DUMMYNET;\n\t} else {\n\t\t/*\n\t\t * Packet dropped by ipfw or dummynet. Nothing to do as\n\t\t * FREE_PKT already freed the fake mbuf\n\t\t */\n\t\t//DbgPrint(\"dropped by dummynet, ret = %i\\n\", ret);\n\t\treturn DROP;\n\t}\n}\n\n/* forward declaration because those functions are used only here,\n * no point to make them visible in passthru/protocol/miniport */\nint do_ipfw_set_ctl(struct sock *sk, int cmd,\n\tvoid __user *user, unsigned int len);\nint do_ipfw_get_ctl(struct sock *sk, int cmd,\n\tvoid __user *user, int *len);\n\nNTSTATUS\nDevIoControl(\n    IN PDEVICE_OBJECT    pDeviceObject,\n    IN PIRP              pIrp\n    )\n/*++\n\nRoutine Description:\n\n    This is the dispatch routine for handling device ioctl requests.\n\nArguments:\n\n    pDeviceObject - Pointer to the device object.\n\n    pIrp - Pointer to the request packet.\n\nReturn Value:\n\n    Status is returned.\n\n--*/\n{\n    PIO_STACK_LOCATION  pIrpSp;\n    NTSTATUS            NtStatus = STATUS_SUCCESS;\n    unsigned long       BytesReturned = 0;\n    unsigned long       FunctionCode;\n    unsigned long       len;\n    struct sockopt\t\t*sopt;\n    int\t\t\t\t\tret = 0;\n    \n    UNREFERENCED_PARAMETER(pDeviceObject);\n    \n    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);\n    \n    /*\n     * Using METHOD_BUFFERED as communication method, the userland\n     * side calls DeviceIoControl passing an input buffer and an output\n     * and their respective length (ipfw uses the same length for both).\n     * The system creates a single I/O buffer, with len=max(inlen,outlen).\n     * In the kernel we can read information from this buffer (which is\n     * directly accessible), overwrite it with our results, and set\n     * IoStatus.Information with the number of bytes that the system must\n     * copy back to userland.\n     * In our sockopt emulation, the initial part of the buffer contains\n     * a struct sockopt, followed by the data area.\n     */\n\n    len = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;\n    if (len < sizeof(struct sockopt))\n    {\n\treturn STATUS_NOT_SUPPORTED; // XXX find better value\n    }\n    sopt = pIrp->AssociatedIrp.SystemBuffer;\n\n    FunctionCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;\n\n    len = sopt->sopt_valsize;\n\n    switch (FunctionCode)\n    {\n\t\tcase IP_FW_SETSOCKOPT:\n\t\t\tret = do_ipfw_set_ctl(NULL, sopt->sopt_name, sopt+1, len);\n\t\t\tbreak;\n\t\t\t\n\t\tcase IP_FW_GETSOCKOPT:\n\t\t\tret = do_ipfw_get_ctl(NULL, sopt->sopt_name, sopt+1, &len);\n\t\t\tsopt->sopt_valsize = len;\n\t\t\t//sanity check on len\n\t\t\tif (len + sizeof(struct sockopt) <= pIrpSp->Parameters.DeviceIoControl.InputBufferLength)\n\t\t\t\tBytesReturned = len + sizeof(struct sockopt);\n\t\t\telse\n\t\t\t\tBytesReturned = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\t\tNtStatus = STATUS_NOT_SUPPORTED;\n\t\t\t\tbreak;\n    }\n    \n    pIrp->IoStatus.Information = BytesReturned;\n    pIrp->IoStatus.Status = NtStatus;\n    IoCompleteRequest(pIrp, IO_NO_INCREMENT);\n\n    return NtStatus;\n} \n\nvoid dummynet(void * unused);\nvoid ipfw_tick(void * vnetx);\n\nVOID dummynet_dpc(\n    __in struct _KDPC  *Dpc,\n    __in_opt PVOID  DeferredContext,\n    __in_opt PVOID  SystemArgument1,\n    __in_opt PVOID  SystemArgument2\n    )\n{\n\tdummynet(NULL);\n}\n\nVOID ipfw_dpc(\n    __in struct _KDPC  *Dpc,\n    __in_opt PVOID  DeferredContext,\n    __in_opt PVOID  SystemArgument1,\n    __in_opt PVOID  SystemArgument2\n    )\n{\n\tipfw_tick(DeferredContext);\n}\n"
  },
  {
    "path": "kipfw/missing.h",
    "content": "/*\n * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: missing.h 12256 2013-04-26 21:12:44Z luigi $\n *\n * Header for kernel variables and functions that are not available in\n * userland.\n */\n\n#ifndef _MISSING_H_\n#define _MISSING_H_\n\n#include <sys/cdefs.h>\n#ifdef linux\n#include <linux/sysctl.h>\n#include <linux/module.h>\n#include <linux/moduleparam.h>\n#endif /* linux */\n\n/* portability features, to be set before the rest: */\n#define HAVE_NET_IPLEN\t\t/* iplen/ipoff in net format */\n#define WITHOUT_BPF\t\t/* do not use bpf logging */\n\n#ifdef _WIN32\n\n#ifndef DEFINE_SPINLOCK\n#define DEFINE_SPINLOCK(x)\tFAST_MUTEX x\n#endif\n/* spinlock --> Guarded Mutex KGUARDED_MUTEX */\n/* http://www.reactos.org/wiki/index.php/Guarded_Mutex */\n#define spin_lock_init(_l)\n#define spin_lock_bh(_l)\n#define spin_unlock_bh(_l)\n\n#include <sys/socket.h>\t\t/* bsd-compat.c */\n#include <netinet/in.h>\t\t/* bsd-compat.c */\n#include <netinet/ip.h>\t\t/* local version */\n#define INADDR_TO_IFP(a, b) b = NULL\n\n#else\t/* __linux__ */\n\n#define MALLOC_DECLARE(x)\t/* nothing */\n#include <linux/time.h>\t\t/* do_gettimeofday */\n#include <netinet/ip.h>\t\t/* local version */\nstruct inpcb;\n\n/*\n * Kernel locking support.\n * FreeBSD uses mtx in dummynet.c and struct rwlock ip_fw2.c\n *\n * In linux we use spinlock_bh to implement both.\n * For 'struct rwlock' we need an #ifdef to change it to spinlock_t\n */\n\n#ifndef DEFINE_SPINLOCK\t/* this is for linux 2.4 */\n#define DEFINE_SPINLOCK(x)   spinlock_t x = SPIN_LOCK_UNLOCKED\n#endif\n\n\n#define rw_assert(a, b)\n#define rw_destroy(_l)\n#define rw_init(_l, msg)\tspin_lock_init(_l)\n#define rw_rlock(_l)\t\tspin_lock_bh(_l)\n#define rw_runlock(_l)\t\tspin_unlock_bh(_l)\n#define rw_wlock(_l)\t\tspin_lock_bh(_l)\n#define rw_wunlock(_l)\t\tspin_unlock_bh(_l)\n#define rw_init_flags(_l, s, v)\n\n#define mtx_assert(a, b)\n#define\tmtx_destroy(m)\n#define mtx_init(m, a,b,c) \tspin_lock_init(m)\n#define mtx_lock(_l)\t\tspin_lock_bh(_l)\n#define mtx_unlock(_l)\t\tspin_unlock_bh(_l)\n\n#endif\t/* __linux__ */\n/* end of locking support */\n\n/*\n * Reference to an ipfw rule that can be carried outside critical sections.\n * A rule is identified by rulenum:rule_id which is ordered.\n * In version chain_id the rule can be found in slot 'slot', so\n * we don't need a lookup if chain_id == chain->id.\n *\n * On exit from the firewall this structure refers to the rule after\n * the matching one (slot points to the new rule; rulenum:rule_id-1\n * is the matching rule), and additional info (e.g. info often contains\n * the insn argument or tablearg in the low 16 bits, in host format).\n * On entry, the structure is valid if slot>0, and refers to the starting\n * rules. 'info' contains the reason for reinject, e.g. divert port,\n * divert direction, and so on.\n */\nstruct ipfw_rule_ref {\n\tuint32_t\tslot;\t\t/* slot for matching rule\t*/\n\tuint32_t\trulenum;\t/* matching rule number\t\t*/\n\tuint32_t\trule_id;\t/* matching rule id\t\t*/\n\tuint32_t\tchain_id;\t/* ruleset id\t\t\t*/\n\tuint32_t\tinfo;\t\t/* see below\t\t\t*/\n};\n\nenum {\n\tIPFW_INFO_MASK\t= 0x0000ffff,\n\tIPFW_INFO_OUT\t= 0x00000000,\t/* outgoing, just for convenience */\n\tIPFW_INFO_IN\t= 0x80000000,\t/* incoming, overloads dir */\n\tIPFW_ONEPASS\t= 0x40000000,\t/* One-pass, do not reinject */\n\tIPFW_IS_MASK\t= 0x30000000,\t/* which source ? */\n\tIPFW_IS_DIVERT\t= 0x20000000,\n\tIPFW_IS_DUMMYNET =0x10000000,\n\tIPFW_IS_PIPE\t= 0x08000000,\t/* pipe=1, queue = 0 */\n};\n\n/* in netinet/in.h */\n#define        in_nullhost(x)  ((x).s_addr == INADDR_ANY)\n\n/* bzero not present on linux, but this should go in glue.h */\n#define bzero(s, n) memset(s, 0, n)\n#define bcmp(p1, p2, n) memcmp(p1, p2, n)\n\n/* ethernet stuff */\n#define\tETHERTYPE_IP\t\t0x0800\t/* IP protocol */\n//#define\tETHER_ADDR_LEN\t\t6\t/* length of an Ethernet address */\nstruct ether_header {\n        u_char  ether_dhost[ETHER_ADDR_LEN];\n        u_char  ether_shost[ETHER_ADDR_LEN];\n        u_short ether_type;\n};\n\n#define ETHER_TYPE_LEN          2       /* length of the Ethernet type field */\n#define ETHER_HDR_LEN           (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN)\n\n/*\n * Historically, BSD keeps ip_len and ip_off in host format\n * when doing layer 3 processing, and this often requires\n * to translate the format back and forth.\n * To make the process explicit, we define a couple of macros\n * that also take into account the fact that at some point\n * we may want to keep those fields always in net format.\n */\n\n#if (BYTE_ORDER == BIG_ENDIAN) || defined(HAVE_NET_IPLEN)\n#define SET_NET_IPLEN(p)        do {} while (0)\n#define SET_HOST_IPLEN(p)       do {} while (0)\n#else /* never on linux */\n#define SET_NET_IPLEN(p)        do {            \\\n        struct ip *h_ip = (p);                  \\\n        h_ip->ip_len = htons(h_ip->ip_len);     \\\n        h_ip->ip_off = htons(h_ip->ip_off);     \\\n        } while (0)\n\n#define SET_HOST_IPLEN(p)       do {            \\\n        struct ip *h_ip = (p);                  \\\n        h_ip->ip_len = ntohs(h_ip->ip_len);     \\\n        h_ip->ip_off = ntohs(h_ip->ip_off);     \\\n        } while (0)\n#endif /* !HAVE_NET_IPLEN */\n\n/* ip_dummynet.c */\n#define __FreeBSD_version 500035\n\n#ifdef __linux__\nstruct moduledata;\nint my_mod_register(const char *name,\n\tint order, struct moduledata *mod, void *init, void *uninit);\n\n/* define some macro for ip_dummynet */\n\nstruct malloc_type {\n};\n\n#define MALLOC_DEFINE(type, shortdesc, longdesc) \t\\\n\tstruct malloc_type type[1]; void *md_dummy_ ## type = type\n\n#define CTASSERT(x)\n\n/* log... does not use the first argument */\n#define\tLOG_ERR\t\t0x100\n#define\tLOG_INFO\t0x200\n#define log(_level, fmt, arg...)  do {\t\t\t\\\n\tint _qwerty=_level;(void)_qwerty; printk(KERN_ERR fmt, ##arg); } while (0)\n\n/*\n * gettimeofday would be in sys/time.h but it is not\n * visible if _KERNEL is defined\n */\nint gettimeofday(struct timeval *, struct timezone *);\n\n#else  /* _WIN32 */\n#define MALLOC_DEFINE(a,b,c)\n#endif /* _WIN32 */\n\nextern int\thz;\nextern long\ttick;\t\t/* exists in 2.4 but not in 2.6 */\nextern int\tbootverbose;\nextern struct timeval boottime;\n\n/* The time_uptime a FreeBSD variable increased each second */\n#ifdef __linux__\n#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,37) /* revise boundaries */\n#define time_uptime get_seconds()\n#else /* OpenWRT */\n#define time_uptime CURRENT_TIME\n#endif\n#else /* WIN32 */\n#define time_uptime time_uptime_w32()\n#endif\n\nextern int\tmax_linkhdr;\nextern int\tip_defttl;\nextern u_long\tin_ifaddrhmask;                         /* mask for hash table */\nextern struct in_ifaddrhashhead *in_ifaddrhashtbl;    /* inet addr hash table  */\n\n/*-------------------------------------------------*/\n\n/* define, includes and functions missing in linux */\n/* include and define */\n#include <arpa/inet.h>\t\t/* inet_ntoa */\n\nstruct mbuf;\n\n/* used by ip_dummynet.c */\nvoid reinject_drop(struct mbuf* m);\n\n#include <linux/errno.h>\t/* error define */\n#include <linux/if.h>\t\t/* IFNAMESIZ */\n\nvoid rn_init(int);\n/*\n * some network structure can be defined in the bsd way\n * by using the _FAVOR_BSD definition. This is not true\n * for icmp structure.\n * XXX struct icmp contains bsd names in \n * /usr/include/netinet/ip_icmp.h\n */\n#ifdef __linux__\n#define icmp_code code\n#define icmp_type type\n\n/* linux in6_addr has no member __u6_addr\n * replace the whole structure ?\n */\n#define __u6_addr       in6_u\n#define __u6_addr32     u6_addr32\n#endif /* __linux__ */\n\n/* defined in linux/sctp.h with no bsd definition */\nstruct sctphdr {\n        uint16_t src_port;      /* source port */\n        uint16_t dest_port;     /* destination port */\n        uint32_t v_tag;         /* verification tag of packet */\n        uint32_t checksum;      /* Adler32 C-Sum */\n        /* chunks follow... */\n};\n\n/* missing definition */\n#define TH_FIN  0x01\n#define TH_SYN  0x02\n#define TH_RST  0x04\n#define TH_ACK  0x10\n\n#define RTF_CLONING\t0x100\t\t/* generate new routes on use */\n\n#define IPPROTO_OSPFIGP         89              /* OSPFIGP */\n#define IPPROTO_CARP            112             /* CARP */\n#ifndef _WIN32\n#define IPPROTO_IPV4            IPPROTO_IPIP    /* for compatibility */\n#endif\n\n#define\tCARP_VERSION\t\t2\n#define\tCARP_ADVERTISEMENT\t0x01\n\n#define PRIV_NETINET_IPFW       491     /* Administer IPFW firewall. */\n\n#define IP_FORWARDING           0x1             /* most of ip header exists */\n\n#define NETISR_IP       2               /* same as AF_INET */\n\n#define PRIV_NETINET_DUMMYNET   494     /* Administer DUMMYNET. */\n\nextern int securelevel;\n\nstruct carp_header {\n#if BYTE_ORDER == LITTLE_ENDIAN\n        u_int8_t        carp_type:4,\n                        carp_version:4;\n#endif\n#if BYTE_ORDER == BIG_ENDIAN\n        u_int8_t        carp_version:4,\n                        carp_type:4;\n#endif\n};\n\nstruct pim {\n\tint dummy;      /* windows compiler does not like empty definition */\n};\n\n#ifndef _WIN32\nstruct route {\n\tstruct  rtentry *ro_rt;\n\tstruct  sockaddr ro_dst;\n};\n#endif\n\nstruct ifaltq {\n\tvoid *ifq_head;\n};\n\n/*\n * ifnet->if_snd is used in ip_dummynet.c to take the transmission\n * clock.\n */\n#if defined( __linux__)\n#define\tif_xname\tname\n#define\tif_snd\t\tXXX\n/* search local the ip addresses, used for the \"me\" keyword */\n#include <linux/inetdevice.h>\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)\n#define INADDR_TO_IFP(ip, b)\t\\\n\tb = ip_dev_find(ip.s_addr)\n#else\n#define INADDR_TO_IFP(ip, b)\t\\\n\tb = ip_dev_find((struct net *)&init_net, ip.s_addr)\n#endif\n\n#elif defined( _WIN32 )\n/* used in ip_dummynet.c */\nstruct ifnet {\n\tchar    if_xname[IFNAMSIZ];     /* external name (name + unit) */\n//        struct ifaltq if_snd;          /* output queue (includes altq) */\n};\n\nstruct net_device {\n\tchar    if_xname[IFNAMSIZ];     /* external name (name + unit) */\n};\n#endif\n\n/* involves mbufs */\nint in_cksum(struct mbuf *m, int len);\n#define divert_cookie(mtag) 0\n#define divert_info(mtag) 0\n#define pf_find_mtag(a) NULL\n#define pf_get_mtag(a) NULL\n#ifndef _WIN32\n#define AF_LINK AF_ASH\t/* ? our sys/socket.h */\n#endif\n\n/* we don't pullup, either success or free and fail */\n#define m_pullup(m, x)\t\t\t\t\t\\\n\t((m)->m_len >= x ? (m) : (FREE_PKT(m), NULL))\n\nstruct pf_mtag {\n\tvoid            *hdr;           /* saved hdr pos in mbuf, for ECN */\n\tsa_family_t      af;            /* for ECN */\n        u_int32_t        qid;           /* queue id */\n};\n\n#if 0 // ndef radix\n/* radix stuff in radix.h and radix.c */\nstruct radix_node {\n\tcaddr_t rn_key;         /* object of search */\n\tcaddr_t rn_mask;        /* netmask, if present */\n};\n#endif /* !radix */\n\n/* missing kernel functions */\nchar *inet_ntoa(struct in_addr ina);\nint random(void);\n\n/*\n * Return the risult of a/b\n *\n * this is used in linux kernel space,\n * since the 64bit division needs to\n * be done using a macro\n */\nint64_t\ndiv64(int64_t a, int64_t b);\n\nchar *\ninet_ntoa_r(struct in_addr ina, char *buf);\n\n/* from bsd sys/queue.h */\n#define TAILQ_FOREACH_SAFE(var, head, field, tvar)                      \\\n        for ((var) = TAILQ_FIRST((head));                               \\\n            (var) && ((tvar) = TAILQ_NEXT((var), field), 1);            \\\n            (var) = (tvar))\n\n#define SLIST_FOREACH_SAFE(var, head, field, tvar)                      \\\n        for ((var) = SLIST_FIRST((head));                               \\\n            (var) && ((tvar) = SLIST_NEXT((var), field), 1);            \\\n            (var) = (tvar))\n\n/* depending of linux version */\n#ifndef ETHERTYPE_IPV6\n#define ETHERTYPE_IPV6          0x86dd          /* IP protocol version 6 */\n#endif\n\n/*-------------------------------------------------*/\n#define RT_NUMFIBS 1\nextern u_int rt_numfibs;\n\n/* involves kernel locking function */\n#ifdef RTFREE\n#undef RTFREE\n#define RTFREE(a) fprintf(stderr, \"RTFREE: commented out locks\\n\");\n#endif\n\nvoid getmicrouptime(struct timeval *tv);\n\n/* from sys/netinet/ip_output.c */\nstruct ip_moptions;\nstruct route;\nstruct ip;\n\nstruct mbuf *ip_reass(struct mbuf *);\nu_short in_cksum_hdr(struct ip *);\nint ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,\n    struct ip_moptions *imo, struct inpcb *inp);\n\n/* from net/netisr.c */\nvoid netisr_dispatch(int num, struct mbuf *m);\n\n/* definition moved in missing.c */\nint sooptcopyout(struct sockopt *sopt, const void *buf, size_t len);\n\nint sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen);\n\n/* defined in session.c */\nint priv_check(struct thread *td, int priv);\n\n/* struct ucred is in linux/socket.h and has pid, uid, gid.\n * We need a 'bsd_ucred' to store also the extra info\n */\n\nstruct bsd_ucred {\n\tuid_t\t\tuid;\n\tgid_t\t\tgid;\n\tuint32_t\txid;\n\tuint32_t\tnid;\n};\n\nint\ncred_check(void *insn, int proto, struct ifnet *oif,\n    struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,\n    u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,\n    struct sk_buff *skb);\n\nint securelevel_ge(struct ucred *cr, int level);\n\nstruct sysctl_oid;\nstruct sysctl_req;\n\n#ifdef _WIN32\n#define module_param_named(_name, _var, _ty, _perm)\n#else /* !_WIN32 */\n\n/* Linux 2.4 is mostly for openwrt */\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)\n#include <linux/bitops.h>\t /* generic_ffs() used in ip_fw2.c */\ntypedef uint32_t __be32;\ntypedef uint16_t __be16;\nstruct sock;\nstruct net;\nstruct inet_hashinfo;\nstruct sock *inet_lookup(\n\tstruct inet_hashinfo *hashinfo,\n        const __be32 saddr, const __be16 sport,\n        const __be32 daddr, const __be16 dport,\n        const int dif);\nstruct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);\n#endif /* Linux < 2.6 */\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) &&\t\\\n\tLINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)\t/* XXX NOT sure, in 2.6.9 give an error */\n#define module_param_named(_name, _var, _ty, _perm)\t\\\n\t//module_param(_name, _ty, 0644)\n#endif\n\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)\ntypedef unsigned long uintptr_t;\n\n#ifdef __i386__\nstatic inline unsigned long __fls(unsigned long word)\n{\n        asm(\"bsr %1,%0\"\n            : \"=r\" (word)\n            : \"rm\" (word));\n        return word;\n}\n#endif\n\n#endif /* LINUX < 2.6.25 */\n\n#endif /* !_WIN32 so maybe __linux__ */\n\n#if defined (__linux__) && !defined (EMULATE_SYSCTL)\n#define SYSCTL_DECL(_1)\n#define SYSCTL_OID(_1, _2, _3, _4, _5, _6, _7, _8)\n#define SYSCTL_NODE(_1, _2, _3, _4, _5, _6)\n#define _SYSCTL_BASE(_name, _var, _ty, _perm)\t\t\\\n\tmodule_param_named(_name, *(_var), _ty, \t\\\n\t\t( (_perm) == CTLFLAG_RD) ? 0444: 0644 )\n#define SYSCTL_PROC(_base, _oid, _name, _mode, _var, _val, _desc, _a, _b)\n\n#define SYSCTL_INT(_base, _oid, _name, _mode, _var, _val, _desc)\t\\\n\t_SYSCTL_BASE(_name, _var, int, _mode)\n\n#define SYSCTL_LONG(_base, _oid, _name, _mode, _var, _val, _desc)\t\\\n\t_SYSCTL_BASE(_name, _var, long, _mode)\n\n#define SYSCTL_ULONG(_base, _oid, _name, _mode, _var, _val, _desc)\t\\\n\t_SYSCTL_BASE(_name, _var, ulong, _mode)\n\n#define SYSCTL_UINT(_base, _oid, _name, _mode, _var, _val, _desc)\t\\\n\t _SYSCTL_BASE(_name, _var, uint, _mode)\n\n#define TUNABLE_INT(_name, _ptr)\n\n#define SYSCTL_VNET_PROC\t\tSYSCTL_PROC\n#define SYSCTL_VNET_INT\t\t\tSYSCTL_INT\n#define SYSCTL_VNET_UINT\t\tSYSCTL_UINT\n\n#endif\n\n#define SYSCTL_HANDLER_ARGS \t\t\\\n\tstruct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req\nint sysctl_handle_int(SYSCTL_HANDLER_ARGS);\nint sysctl_handle_long(SYSCTL_HANDLER_ARGS); \n\n\nvoid ether_demux(struct ifnet *ifp, struct mbuf *m);\n\nint ether_output_frame(struct ifnet *ifp, struct mbuf *m);\n\nvoid in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum);\n\nvoid icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu);\n\nvoid rtfree(struct rtentry *rt);\n\nu_short in_cksum_skip(struct mbuf *m, int len, int skip);\n\n#ifdef INP_LOCK_ASSERT\n#undef INP_LOCK_ASSERT\n#define INP_LOCK_ASSERT(a)\n#endif\n\nint jailed(struct ucred *cred);\n\n/*\n* Return 1 if an internet address is for a ``local'' host\n* (one to which we have a connection).  If subnetsarelocal\n* is true, this includes other subnets of the local net.\n* Otherwise, it includes only the directly-connected (sub)nets.\n*/\nint in_localaddr(struct in_addr in);\n\n/* the prototype is already in the headers */\n//int ipfw_chg_hook(SYSCTL_HANDLER_ARGS); \n\nint fnmatch(const char *pattern, const char *string, int flags);\n\nint\nlinux_lookup(const int proto, const __be32 saddr, const __be16 sport,\n\tconst __be32 daddr, const __be16 dport,\n\tstruct sk_buff *skb, int dir, struct bsd_ucred *u);\n\n/* vnet wrappers, in vnet.h and ip_var.h */\n//int ipfw_init(void);\n//void ipfw_destroy(void);\n\n#define\tMTAG_IPFW\t1148380143\t/* IPFW-tagged cookie */\n#define\tMTAG_IPFW_RULE\t1262273568\t/* rule reference */\n\nstruct ip_fw_args;\nextern int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);\n\n#define curvnet                 NULL\n#define\tCURVNET_SET(_v)\n#define\tCURVNET_RESTORE()\n#define VNET_ASSERT(condition)\n\n#define VNET_NAME(n)            n\n#define VNET_DECLARE(t, n)      extern t n\n#define VNET_DEFINE(t, n)       t n\n#define _VNET_PTR(b, n)         &VNET_NAME(n)\n/*\n * Virtualized global variable accessor macros.\n */\n#define VNET_VNET_PTR(vnet, n)          (&(n))\n#define VNET_VNET(vnet, n)              (n)\n\n#define VNET_PTR(n)             (&(n))\n#define VNET(n)                 (n)\n\nVNET_DECLARE(int, ip_defttl);\n#define V_ip_defttl    VNET(ip_defttl);\n\nint ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp,\n\tint dir, struct inpcb *inp);\n\n/* hooks for divert */\nextern void (*ip_divert_ptr)(struct mbuf *m, int incoming);\n\nextern int (*ip_dn_ctl_ptr)(struct sockopt *);\ntypedef int ip_fw_ctl_t(struct sockopt *);\nextern ip_fw_ctl_t *ip_fw_ctl_ptr;\n\n/* netgraph prototypes */\ntypedef int ng_ipfw_input_t(struct mbuf **, int, struct ip_fw_args *, int);\nextern  ng_ipfw_input_t *ng_ipfw_input_p;\n\n/* For kernel ipfw_ether and ipfw_bridge. */\nstruct ip_fw_args;\ntypedef int ip_fw_chk_t(struct ip_fw_args *args);\nextern  ip_fw_chk_t     *ip_fw_chk_ptr;\n\n#define V_ip_fw_chk_ptr         VNET(ip_fw_chk_ptr)\n#define V_ip_fw_ctl_ptr         VNET(ip_fw_ctl_ptr)\n#define\tV_tcbinfo\t\tVNET(tcbinfo)\n#define\tV_udbinfo\t\tVNET(udbinfo)\n\n#endif /* !_MISSING_H_ */\n"
  },
  {
    "path": "kipfw/mysetenv.sh",
    "content": "#!/bin/bash\n\n# bash script to set a suitable environment to call MSVC's build\n# to build a 64-bit version of the kernel.\n#\n# inspired by C:/winddk/7600.16385.1/bin/setenv.bat\n# see http://www.osronline.com/ddkx/ddtools/build_ref_0kqb.htm\n\n#############################################################\n#  edit theese variables to meet your configuration         #\n#  - DRIVE is the hard drive letter where DDK is installed  #\n#  - DDK is the path to the DDK's root directory            #\n#  - CYGDDK is the complete cygwin path to DDK              #\n#############################################################\nif [ $# -ne 3 ]; then\necho \"invalid params\" && exit 1\nfi\nDRIVE=$1\nDDK=$2\nCYGDDK=/cygdrive/c/${DDK}\nTARGETOS=$3\nMYDIR=`pwd`\t# XXX luigi\n\nif [ \"$TARGETOS\" = \"wnet\" ]; then\nexport DDK_TARGET_OS=WinNET\nexport _NT_TARGET_VERSION=0x502\nfi\n\nif [ \"$TARGETOS\" = \"wlh\" ]; then\nexport DDK_TARGET_OS=WinLH\nexport _NT_TARGET_VERSION=0x600\nfi\n\nif [ \"$TARGETOS\" = \"win7\" ]; then\nexport DDK_TARGET_OS=Win7\nexport _NT_TARGET_VERSION=0x601\nfi\n\n\n#############################################################\n#  don't edit anything else below this point                #\n#############################################################\n\nD=${DRIVE}${DDK}\nDB=${D}/bin\nDI=${D}/inc\nDL=${D}/lib\n\n\nexport AMD64=1\nexport ATL_INC_PATH=$DI\t\t\t\t# defaults to DDKROOT/inc\nexport ATL_INC_ROOT=$DI\t\t\t\t# XXX redundant ?\nexport ATL_LIB_PATH=${DL}/atl/*\nexport BASEDIR=$D\t\t\t\t# default\nexport BUFFER_OVERFLOW_CHECKS=1\nexport BUILD_ALLOW_COMPILER_WARNINGS=1\nexport BUILD_ALT_DIR=chk_${TARGETOS}_AMD64\nexport BUILD_DEFAULT=\"-ei -nmake -i -nosqm\"\t# can go on the command line\nexport BUILD_DEFAULT_TARGETS=\"-amd64\"\t\t# can also go on the command line\nexport BUILD_MAKE_PROGRAM=nmake.exe\t\t# default to nmake\nexport BUILD_MULTIPROCESSOR=1\t\t\t# parallel make, same as -M\nexport BUILD_OPTIONS=\" ~imca ~toastpkg\"\nexport COFFBASE_TXT_FILE=${DB}/coffbase.txt\nexport CPU=AMD64\nexport CRT_INC_PATH=${DI}/crt\t\t\t# default\nexport CRT_LIB_PATH=${DL}/crt/*\t\t\t# not default, it seems uses lib/{wnet,win7}/*\nexport DDKBUILDENV=chk\t\t\t\t# checked or free\nexport DDK_INC_PATH=${DI}/ddk\nexport DDK_LIB_DEST=${DL}/${TARGETOS}\nexport DDK_LIB_PATH=${DL}/${TARGETOS}/*\nexport DEPRECATE_DDK_FUNCTIONS=1\nexport DRIVER_INC_PATH=${DI}/ddk\nexport HALKIT_INC_PATH=${DI}/ddk\nexport HALKIT_LIB_PATH=${DL}/${TARGETOS}/*\nexport IFSKIT_INC_PATH=${DI}/ddk\nexport IFSKIT_LIB_DEST=${DL}/${TARGETOS}\nexport IFSKIT_LIB_PATH=${DL}/${TARGETOS}/*\nexport Include=${DI}/api\nexport KMDF_INC_PATH=${DI}/wdf/kmdf\nexport KMDF_LIB_PATH=${DL}/wdf/kmdf/*\nexport LANGUAGE_NEUTRAL=0\nexport Lib=${DL}\nexport LINK_LIB_IGNORE=4198\nexport MFC_INC_PATH=${DI}/mfc42\nexport MFC_LIB_PATH=${DL}/mfc/*\nexport MSC_OPTIMIZATION=\"/Od /Oi\" \nexport NEW_CRTS=1\nexport NO_BINPLACE=TRUE\nexport NO_BROWSER_FILE=TRUE\nexport NTDBGFILES=1\nexport NTDEBUG=ntsd\nexport NTDEBUGTYPE=both\n# need NTMAKEENV to point to the binary dir\nexport NTMAKEENV=${DB}\nexport OAK_INC_PATH=${DI}/api\n\nexport PATH=\"${CYGDDK}/bin/amd64:${CYGDDK}/tools/sdv/bin:${CYGDDK}/tools/pfd/bin/bin/x86_AMD64\\\n:${CYGDDK}/bin/SelfSign:${CYGDDK}/bin/x86/amd64:${CYGDDK}/bin/x86\\\n:${CYGDDK}/tools/pfd/bin/bin/AMD64:${CYGDDK}/tools/tracing/amd64:$PATH\"\n\nexport PATHEXT=\".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC\"\nexport PROJECT_ROOT=${D}/src\nexport PUBLIC_ROOT=${D}\nexport RAZZLETOOLPATH=${DB}\nexport RCNOFONTMAP=1\nexport SDK_INC_PATH=${DI}/api\nexport SDK_LIB_DEST=${DL}/${TARGETOS}\nexport SDK_LIB_PATH=${DL}/${TARGETOS}/*\nexport SDV=${D}/tools/sdv\nexport separate_object_root=FALSE\nexport TEMP=tmpbuild\nexport TMP=tmpbuild\nexport UMDF_INC_PATH=${DI}/wdf/umdf\nexport USE_OBJECT_ROOT=1\nexport WDM_INC_PATH=${DI}/ddk\nexport WPP_CONFIG_PATH=${DB}/wppconfig\nexport _AMD64bit=true\nexport _BUILDARCH=AMD64\nexport _BuildType=chk\nexport _NTDRIVE=${DRIVE}\nexport _NTROOT=${DDK}\n#\n# --- XXX note, it spams  C:/winddk/7600.16385.1/build.dat\n# -c: delete objs, -e: generare build.* logfiles, -f rescan sources, -g color errors\nunset MAKEFLAGS\necho \"emv ${MAKE} flags ${MAKEFLAGS}\"\ncd kipfw-mod && build -cefg \necho \"done\"\n#cp objchk_${TARGETOS}_amd64/amd64/ipfw.sys ../binary/ipfw.sys\n"
  },
  {
    "path": "kipfw/netipfw.inf",
    "content": "; version section\r\n[Version]\r\nSignature  = \"$Windows NT$\"\r\nClass      = NetService\r\nClassGUID  = {4D36E974-E325-11CE-BFC1-08002BE10318}\r\nProvider   = %Unipi%\r\nDriverVer  = 08/12/2012,3.0.1.1\r\n\r\n; manufacturer section\r\n[Manufacturer]\r\n%Unipi% = UNIPI,NTx86,NTamd64\r\n\r\n; control flags section\r\n; optional, unused in netipfw.inf inf, used in netipfw_m.inf\r\n[ControlFlags]\r\n\r\n; models section\r\n[UNIPI] ; Win2k\r\n%Desc% = Ipfw.ndi, unipi_ipfw\r\n[UNIPI.NTx86] ;For WinXP and later\r\n%Desc% = Ipfw.ndi, unipi_ipfw\r\n[UNIPI.NTamd64] ;For x64\r\n%Desc% = Ipfw.ndi, unipi_ipfw\r\n\r\n; ddinstall section\r\n[Ipfw.ndi]\r\nAddReg          = Ipfw.ndi.AddReg, Ipfw.AddReg\r\nCharacteristics = 0x4410 ;  NCF_FILTER | NCF_NDIS_PROTOCOL !--Filter Specific--!!\r\nCopyFiles       = Ipfw.Files.Sys\r\nCopyInf         = netipfw_m.inf\r\n\r\n; remove section\r\n[Ipfw.ndi.Remove]\r\nDelFiles = Ipfw.Files.Sys\r\n\r\n;ddinstall.services section\r\n[Ipfw.ndi.Services]\r\nAddService = Ipfw,,Ipfw.AddService\r\n\r\n[Ipfw.AddService]\r\nDisplayName    = %ServiceDesc%\r\nServiceType    = 1 ;SERVICE_KERNEL_DRIVER\r\nStartType      = 3 ;SERVICE_DEMAND_START\r\nErrorControl   = 1 ;SERVICE_ERROR_NORMAL\r\nServiceBinary  = %12%\\ipfw.sys\r\nAddReg         = Ipfw.AddService.AddReg\r\n\r\n[Ipfw.AddService.AddReg]\r\n\r\n;file copy related sections\r\n[SourceDisksNames]\r\n1=%DiskDescription%,\"\",,\r\n\r\n[SourceDisksFiles]\r\nipfw.sys=1\r\n\r\n[DestinationDirs]\r\nDefaultDestDir = 12\r\nIpfw.Files.Sys   = 12   ; %windir%\\System32\\drivers\r\n\r\n; ddinstall->copyfiles points here\r\n[Ipfw.Files.Sys]\r\nipfw.sys,,,2\r\n\r\n; ddinstall->addreg points here\r\n[Ipfw.ndi.AddReg]\r\nHKR, Ndi,            HelpText,            , %HELP% ; this is displayed at the bottom of the General page of the Connection Properties dialog box\r\nHKR, Ndi,            FilterClass,         , failover\r\nHKR, Ndi,            FilterDeviceInfId,   , unipi_ipfwmp\r\nHKR, Ndi,            Service,             , Ipfw\r\nHKR, Ndi\\Interfaces, UpperRange,          , noupper\r\nHKR, Ndi\\Interfaces, LowerRange,          , nolower\r\nHKR, Ndi\\Interfaces, FilterMediaTypes,    , \"ethernet, tokenring, fddi, wan\"\r\n\r\n;strings section\r\n[Strings]\r\nUnipi = \"Unipi\"\r\nDiskDescription = \"Ipfw Driver Disk\"\r\nDesc = \"ipfw+dummynet\"\r\nHELP = \"This is ipfw and dummynet network emulator, developed by unipi.it\"\r\nServiceDesc = \"ipfw service\"\r\n"
  },
  {
    "path": "kipfw/netipfw_m.inf",
    "content": "; version section\r\n[Version]\r\nSignature  = \"$Windows NT$\"\r\nClass      = Net\r\nClassGUID  = {4D36E972-E325-11CE-BFC1-08002BE10318}\r\nProvider   = %Unipi%\r\nDriverVer  = 08/12/2012,3.0.1.1\r\n\r\n; control flags section\r\n; optional, unused in netipfw.inf inf, used in netipfw_m.inf\r\n[ControlFlags]\r\nExcludeFromSelect = unipi_ipfwmp\r\n\r\n; destinationdirs section, optional\r\n[DestinationDirs]\r\nDefaultDestDir=12\r\n; No files to copy \r\n\r\n; manufacturer section\r\n[Manufacturer]\r\n%Unipi% = UNIPI,NTx86,NTamd64\r\n\r\n; models section\r\n[UNIPI] ; Win2k\r\n%Desc% = IpfwMP.ndi, unipi_ipfwmp\r\n[UNIPI.NTx86] ;For WinXP and later\r\n%Desc% = IpfwMP.ndi, unipi_ipfwmp\r\n[UNIPI.NTamd64] ;For x64\r\n%Desc% = IpfwMP.ndi, unipi_ipfwmp\r\n\r\n; ddinstall section\r\n[IpfwMP.ndi]\r\nAddReg  = IpfwMP.ndi.AddReg\r\nCharacteristics = 0x29 ;NCF_NOT_USER_REMOVABLE | NCF_VIRTUAL | NCF_HIDDEN\r\n\r\n; ddinstall->addreg points here\r\n[IpfwMP.ndi.AddReg]\r\nHKR, Ndi, Service,  0,  IpfwMP\r\n\r\n;ddinstall.services section\r\n[IpfwMP.ndi.Services]\r\nAddService = IpfwMP,0x2, IpfwMP.AddService\r\n\r\n[IpfwMP.AddService]\r\nServiceType    = 1 ;SERVICE_KERNEL_DRIVER\r\nStartType      = 3 ;SERVICE_DEMAND_START\r\nErrorControl   = 1 ;SERVICE_ERROR_NORMAL\r\nServiceBinary  = %12%\\ipfw.sys\r\nAddReg         = IpfwMP.AddService.AddReg\r\n\r\n[IpfwMP.AddService.AddReg]\r\n; None\r\n\r\n[Strings]\r\nUnipi = \"Unipi\"\r\nDesc = \"Ipfw Miniport\"\n"
  },
  {
    "path": "kipfw/sources",
    "content": "TARGETNAME=ipfw\r\nTARGETTYPE=DRIVER\r\n\r\nC_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DNDIS_WDM=1\r\n\r\nMSC_WARNING_LEVEL=/W2\r\n\r\n# The driver is built in the XP or .NET build environment\r\n# So let us build NDIS 5.1 version.\r\nC_DEFINES=$(C_DEFINES) -DNDIS51_MINIPORT=1\r\nC_DEFINES=$(C_DEFINES) -DNDIS51=1\r\n\r\n# Enable dummynet preprocessing macros\r\nC_DEFINES=$(C_DEFINES) /D_WIN32 /DMODULENAME=Ipfw /D_BSD_SOURCE /DKERNEL_MODULE /D_KERNEL /DKLD_MODULE /D__BSD_VISIBLE /DIPFIREWALL_DEFAULT_TO_ACCEPT /D__LITTLE_ENDIAN /DSYSCTL_NODE /DEMULATE_SYSCTL -FIwinmissing.h -FImissing.h -FI../glue.h /DWIN32_LEAN_AND_MEAN=1\r\n\r\nTARGETLIBS=$(DDK_LIB_PATH)\\ndis.lib\r\n\r\nINCLUDES= include_e ; ../sys\r\n\r\nSOURCES= ip_fw2.c ip_fw_pfil.c ip_fw_sockopt.c ip_fw_dynamic.c ip_fw_table.c ip_fw_log.c radix.c in_cksum.c ip_dummynet.c ip_dn_io.c ip_dn_glue.c dn_heap.c dn_sched_fifo.c dn_sched_wf2q.c dn_sched_rr.c dn_sched_qfq.c dn_sched_prio.c ipfw2_mod.c bsd_compat.c md_win.c miniport.c protocol.c passthru.c debug.c\r\n"
  },
  {
    "path": "kipfw/win-passthru.diff",
    "content": "diff -ubwrp original_passthru/miniport.c kipfw/miniport.c\n--- original_passthru/miniport.c\t2012-08-01 14:34:15.096679600 +0200\n+++ kipfw/miniport.c\t2012-08-01 14:34:11.377929600 +0200\n@@ -223,6 +223,7 @@ Return Value:\n     //\r\n     // Use NDIS 5.1 packet stacking:\r\n     //\r\n+    if (0)\t// XXX IPFW - make sure we don't go in here\n     {\r\n         PNDIS_PACKET_STACK        pStack;\r\n         BOOLEAN                   Remaining;\r\n@@ -347,6 +348,25 @@ Return Value:\n                                                 MediaSpecificInfo,\r\n                                                 MediaSpecificInfoSize);\r\n         }\r\n+#if 1\t/* IPFW: query the firewall */\n+\t/* if dummynet keeps the packet, we mimic success.\n+\t * otherwise continue as usual.\n+\t */\n+\t\t{\n+\t\t\tint ret = ipfw2_qhandler_w32(MyPacket, OUTGOING,\n+\t\t\t\t\tMiniportAdapterContext);\n+\t\t\tif (ret != PASS) {\n+\t\t\t\tif (ret == DROP)\n+\t\t\t\t\treturn NDIS_STATUS_FAILURE;\n+\t\t\t\telse {  //dummynet kept the packet\n+#ifndef WIN9X\n+\t\t\t\t\tNdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);\n+#endif\n+\t\t\t\t\treturn NDIS_STATUS_SUCCESS; //otherwise simply continue\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+#endif\t/* end of IPFW code */\n \r\n         NdisSend(&Status,\r\n                  pAdapt->BindingHandle,\r\ndiff -ubwrp original_passthru/passthru.c kipfw/passthru.c\n--- original_passthru/passthru.c\t2012-08-01 14:34:15.268554600 +0200\n+++ kipfw/passthru.c\t2012-08-01 14:34:11.534179600 +0200\n@@ -47,8 +47,15 @@ NDIS_HANDLE        NdisWrapperHandle;\n // To support ioctls from user-mode:\r\n //\r\n \r\n-#define LINKNAME_STRING     L\"\\\\DosDevices\\\\Passthru\"\r\n-#define NTDEVICE_STRING     L\"\\\\Device\\\\Passthru\"\r\n+#define STR2(x) #x\n+#define STR(x) STR2(x)\n+#define DOSPREFIX \"\\\\DosDevices\\\\\"\n+#define NTPREFIX \"\\\\Device\\\\\"\n+#define WIDEN2(x) L ## x\n+#define WIDEN(x) WIDEN2(x)\n+#define LINKNAME_STRING\t\t\tWIDEN(DOSPREFIX) WIDEN(STR(MODULENAME))\n+#define NTDEVICE_STRING\t\t\tWIDEN(NTPREFIX) WIDEN(STR(MODULENAME))\n+#define PROTOCOLNAME_STRING\t\tWIDEN(STR(MODULENAME))\n \r\n NDIS_HANDLE     NdisDeviceHandle = NULL;\r\n PDEVICE_OBJECT  ControlDeviceObject = NULL;\r\n@@ -136,8 +143,8 @@ Return Value:\n         // Either the Send or the SendPackets handler should be specified.\r\n         // If SendPackets handler is specified, SendHandler is ignored\r\n         //\r\n-        MChars.SendHandler = NULL;    // MPSend;\r\n-        MChars.SendPacketsHandler = MPSendPackets;\r\n+        MChars.SendHandler = MPSend;    // IPFW: use MPSend, not SendPackets\n+        MChars.SendPacketsHandler = NULL;\n \r\n         Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,\r\n                                                   &MChars,\r\n@@ -165,7 +172,7 @@ Return Value:\n         // This is needed to ensure that NDIS can correctly determine\r\n         // the binding and call us to bind to miniports below.\r\n         //\r\n-        NdisInitUnicodeString(&Name, L\"Passthru\");    // Protocol name\r\n+        NdisInitUnicodeString(&Name, PROTOCOLNAME_STRING);    // Protocol name\n         PChars.Name = Name;\r\n         PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;\r\n         PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;\r\n@@ -205,6 +212,8 @@ Return Value:\n         NdisTerminateWrapper(NdisWrapperHandle, NULL);\r\n     }\r\n \r\n+    ipfw_module_init();\t// IPFW - start the system\n+\n     return(Status);\r\n }\r\n \r\n@@ -276,7 +285,8 @@ Return Value:\n         DispatchTable[IRP_MJ_CREATE] = PtDispatch;\r\n         DispatchTable[IRP_MJ_CLEANUP] = PtDispatch;\r\n         DispatchTable[IRP_MJ_CLOSE] = PtDispatch;\r\n-        DispatchTable[IRP_MJ_DEVICE_CONTROL] = PtDispatch;\r\n+\t// IPFW we use DevIoControl ?\n+        DispatchTable[IRP_MJ_DEVICE_CONTROL] = DevIoControl;\n         \r\n \r\n         NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);\r\n@@ -453,6 +463,7 @@ PtUnload(\n     \r\n     NdisFreeSpinLock(&GlobalLock);\r\n \r\n+    ipfw_module_exit(); // IPFW unloading dummynet\n+\n     DBGPRINT((\"PtUnload: done!\\n\"));\r\n }\r\n-\r\ndiff -ubwrp original_passthru/passthru.h kipfw/passthru.h\n--- original_passthru/passthru.h\t2012-08-01 14:34:15.049804600 +0200\n+++ kipfw/passthru.h\t2012-08-01 14:34:11.362304600 +0200\n@@ -61,6 +61,13 @@ PtDispatch(\n     IN PIRP                      Irp\r\n     );\r\n \r\n+DRIVER_DISPATCH DevIoControl;\r\n+NTSTATUS\r\n+DevIoControl(\r\n+    IN PDEVICE_OBJECT            pDeviceObject,\r\n+    IN PIRP                      pIrp\r\n+    );\r\n+\r\n NDIS_STATUS\r\n PtRegisterDevice(\r\n     VOID\r\n@@ -366,6 +373,7 @@ PtDereferenceAdapt(\n typedef struct _SEND_RSVD\r\n {\r\n     PNDIS_PACKET    OriginalPkt;\r\n+    struct mbuf*    pMbuf; // IPFW extension, reference to the mbuf\r\n } SEND_RSVD, *PSEND_RSVD;\r\n \r\n //\r\n@@ -376,6 +384,7 @@ typedef struct _SEND_RSVD\n typedef struct _RECV_RSVD\r\n {\r\n     PNDIS_PACKET    OriginalPkt;\r\n+    struct mbuf*    pMbuf; // IPFW extension, reference to the mbuf\r\n } RECV_RSVD, *PRECV_RSVD;\r\n \r\n C_ASSERT(sizeof(RECV_RSVD) <= sizeof(((PNDIS_PACKET)0)->MiniportReserved));\r\n@@ -475,3 +484,17 @@ IsIMDeviceStateOn(\n */\r\n #define IsIMDeviceStateOn(_pP)        ((_pP)->MPDeviceState == NdisDeviceStateD0 && (_pP)->PTDeviceState == NdisDeviceStateD0 ) \r\n \r\n+#include \"winmissing.h\"\r\n+\r\n+int ipfw_module_init(void);\r\n+void ipfw_module_exit(void);\r\n+int ipfw2_qhandler_w32(PNDIS_PACKET pNdisPacket, int direction,\r\n+\tNDIS_HANDLE Context);\r\n+int ipfw2_qhandler_w32_oldstyle(int direction, NDIS_HANDLE ProtocolBindingContext,\r\n+\t\tunsigned char* HeaderBuffer, unsigned int HeaderBufferSize,\r\n+\t\tunsigned char* LookAheadBuffer, unsigned int LookAheadBufferSize,\r\n+\t    unsigned int PacketSize);\r\n+void CleanupReinjected(PNDIS_PACKET Packet, struct mbuf* m, PADAPT pAdapt);\r\n+void hexdump(PUCHAR,int, const char *);\r\n+void my_init();\r\n+void my_exit();\n\\ Manca newline alla fine del file\nSolo in original_passthru: passthru.htm\nSolo in original_passthru: passthru.rc\ndiff -ubwrp original_passthru/protocol.c kipfw/protocol.c\n--- original_passthru/protocol.c\t2012-08-01 14:34:15.112304600 +0200\n+++ kipfw/protocol.c\t2012-08-01 14:34:11.409179600 +0200\n@@ -841,6 +841,14 @@ Return Value:\n         SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);\r\n         Pkt = SendRsvd->OriginalPkt;\r\n     \r\n+#if 1\t// IPFW - new code\n+\t//DbgPrint(\"SendComplete: packet %p pkt %p\\n\", Packet, Pkt);\n+\tif (Pkt == NULL) { //this is a reinjected packet, with no 'father'\n+\t\tCleanupReinjected(Packet, SendRsvd->pMbuf, pAdapt);\n+\t\treturn;\n+\t}\n+#endif /* IPFW */\n+    \n #ifndef WIN9X\r\n         NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);\r\n #endif\r\n@@ -1021,6 +1029,13 @@ Return Value:\n \r\n                 if (pAdapt->MiniportHandle != NULL)\r\n                 {\r\n+#if 1\t/* IPFW: query the firewall */\n+\t\t\t\t\tint\tret;\n+\t\t\t\t\tret = ipfw2_qhandler_w32(MyPacket, INCOMING,\n+\t\t\t\t\t\tProtocolBindingContext);\n+\t\t\t\t\tif (ret != PASS)\n+\t\t\t\t\treturn 0; //otherwise simply continue\n+#endif /* end of IPFW code */\n                     NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);\r\n                 }\r\n \r\n@@ -1055,6 +1070,13 @@ Return Value:\n         {\r\n             case NdisMedium802_3:\r\n             case NdisMediumWan:\r\n+\t\t\t\t//DbgPrint(\"EthIndicateReceive context %p, header at %p len %u, lookahead at %p len %u, packetsize %u\\n\",ProtocolBindingContext,HeaderBuffer,HeaderBufferSize,LookAheadBuffer,LookAheadBufferSize,PacketSize);\n+\t\t\t\t//hexdump(HeaderBuffer,HeaderBufferSize+LookAheadBufferSize,\"EthIndicateReceive\");\n+\t\t\t{\n+\t\t\t\tint ret = ipfw2_qhandler_w32_oldstyle(INCOMING, ProtocolBindingContext, HeaderBuffer, HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize, PacketSize);\n+\t\t\t\tif (ret != PASS)\n+\t\t\t\t\treturn NDIS_STATUS_SUCCESS;\n+\t\t\t}\n                 NdisMEthIndicateReceive(pAdapt->MiniportHandle,\r\n                                              MacReceiveContext,\r\n                                              HeaderBuffer,\r\n@@ -1120,6 +1142,21 @@ Return Value:\n     PADAPT        pAdapt =(PADAPT)ProtocolBindingContext;\r\n     ULONG         Proc = KeGetCurrentProcessorNumber();      \r\n \r\n+\t/* Warning: this is a poor implementation of the PtReceiveComplete\n+\t * made by MS, and it's a well known (but never fixed) issue.\n+\t * Since the ProcessorNumber here can be different from the one\n+\t * that processed the PtReceive, sometimes NdisMEthIndicateReceiveComplete\n+\t * will not be called, causing poor performance in the incoming traffic.\n+\t * In our driver, PtReceive is called for IP packets ONLY by particulary \n+\t * old NIC drivers, and the poor performance can be seen even \n+\t * in traffic not handled by ipfw or dummynet.\n+\t * Fortunately, this is quite rare, all the incoming IP packets\n+\t * will arrive through PtReceivePacket, and this callback will never\n+\t * be called. For reinjected traffic, a workaround is done\n+\t * commuting the ReceivedIndicationFlag and calling\n+\t * NdisMEthIndicateReceiveComplete manually for each packet.\n+\t */\n+\n     if (((pAdapt->MiniportHandle != NULL)\r\n                 && (pAdapt->MPDeviceState == NdisDeviceStateD0))\r\n                 && (pAdapt->ReceivedIndicationFlags[Proc]))\r\n@@ -1199,7 +1236,7 @@ Return Value:\n     // See also: PtReceive(). \r\n     //\r\n     (VOID)NdisIMGetCurrentPacketStack(Packet, &Remaining);\r\n-    if (Remaining)\r\n+    if (0 && Remaining)\n     {\r\n         //\r\n         // We can reuse \"Packet\". Indicate it up and be done with it.\r\n@@ -1247,6 +1284,13 @@ Return Value:\n \r\n         if (pAdapt->MiniportHandle != NULL)\r\n         {\r\n+#if 1\t/* IPFW: query the firewall */\n+\t    int\tret;\n+\t    ret = ipfw2_qhandler_w32(MyPacket, INCOMING,\n+\t\t\tProtocolBindingContext);\n+\t    if (ret != PASS)\n+\t\t\treturn 0; //otherwise simply continue\n+#endif /* end of IPFW code */\n             NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);\r\n         }\r\n \r\n"
  },
  {
    "path": "kipfw/winmissing.h",
    "content": "/*\n * Copyright (c) 2010 Francesco Magno, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: winmissing.h 11647 2012-08-06 23:20:21Z luigi $\n * definitions and other things needed to build freebsd kernel\n * modules in Windows (with the MSVC compiler)\n */\n\n#ifndef _WINMISSING_H_\n#define _WINMISSING_H_\n\n#include <ntifs.h>\n#include <ntddk.h>\n#include <basetsd.h>\n#include <windef.h>\n#include <stdio.h>\n#include <ndis.h>\n\ntypedef UCHAR\tu_char;\ntypedef UCHAR\tu_int8_t;\ntypedef UCHAR\tuint8_t;\ntypedef USHORT\tu_short;\ntypedef USHORT\tu_int16_t;\ntypedef USHORT\tuint16_t;\ntypedef USHORT\tn_short;\ntypedef UINT\tu_int;\ntypedef INT32\tint32_t;\ntypedef UINT32\tu_int32_t;\ntypedef UINT32\tuint32_t;\ntypedef ULONG\tu_long;\ntypedef ULONG\tn_long;\ntypedef UINT64\tuint64_t;\ntypedef UINT64\tu_int64_t;\ntypedef INT64\tint64_t;\n\ntypedef UINT32\tin_addr_t;\ntypedef UCHAR\tsa_family_t;\ntypedef\tUSHORT\tin_port_t;\ntypedef UINT32\t__gid_t;\ntypedef UINT32\tgid_t;\ntypedef UINT32\t__uid_t;\ntypedef UINT32\tuid_t;\ntypedef ULONG\tn_time;\ntypedef char*\tcaddr_t;\n\n/* linux_lookup uses __be32 and __be16 in the prototype */\ntypedef uint32_t __be32; /* XXX __u32 __bitwise __be32 */\ntypedef uint16_t __be16; /* XXX */\n\n//*** DEBUG STUFF ***\n/*\n * To see the debugging messages you need DbgView\nhttp://technet.microsoft.com/en-us/sysinternals/bb896647.aspx\n */\n#define printf\t\tDbgPrint\n#define log(lev, ...)\tDbgPrint(__VA_ARGS__)\nconst char* texify_cmd(int i);\nconst char* texify_proto(unsigned int p);\n//*** end DEBUG STUFF ***\n\n#define snprintf _snprintf\n#define timespec timeval\nstruct timeval {\n\tlong tv_sec;\n\tlong tv_usec;\n};\n\nstruct in_addr {\n\tin_addr_t s_addr;\n};\n\nstruct sockaddr_in {\n\tuint8_t\tsin_len;\n\tsa_family_t\tsin_family;\n\tin_port_t\tsin_port;\n\tstruct\tin_addr sin_addr;\n\tchar\tsin_zero[8];\n};\n\n/* XXX watch out, windows names are actually longer */\n#define IFNAMSIZ\t16\n#define IF_NAMESIZE\t16\n\n#define ETHER_ADDR_LEN 6\n\n/* we do not include the windows headers for in6_addr so\n * we need to provide our own definition for the kernel.\n */\nstruct in6_addr {\n        union {\n                uint8_t         __u6_addr8[16];\n                uint16_t        __u6_addr16[8]; \n                uint32_t        __u6_addr32[4];\n        } __u6_addr;                    /* 128-bit IP6 address */\n};\n\n#define\thtons(x) RtlUshortByteSwap(x)\n#define\tntohs(x) RtlUshortByteSwap(x)\n#define\thtonl(x) RtlUlongByteSwap(x)\n#define\tntohl(x) RtlUlongByteSwap(x)\n\n#define ENOSPC          28      /* No space left on device */\n#define\tEOPNOTSUPP\t45\t/* Operation not supported */\n#define\tEACCES\t\t13\t/* Permission denied */\n#define\tENOENT\t\t2\t/* No such file or directory */\n#define EINVAL          22      /* Invalid argument */\n#define\tEPROTONOSUPPORT\t43\t/* Protocol not supported */\n#define\tENOMEM\t\t12\t/* Cannot allocate memory */\n#define\tEEXIST\t\t17\t/* File exists */\n#define ESRCH\t\t3\n#define\tENOBUFS\t\t55\t/* No buffer space available */\n#define\tEBUSY\t\t16\t/* Module busy */\n\n\n#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)\n#define __packed \n#define __aligned(x);\n#define __user\n#define __init\n#define __exit\n#define __func__ __FUNCTION__\n#define inline __inline\n\nstruct sockaddr_in6 {\n\tint dummy;\n};\n\n//SPINLOCKS\n#define DEFINE_SPINLOCK(x)\t\tNDIS_SPIN_LOCK x\n#define mtx_init(m,a,b,c)\t\tNdisAllocateSpinLock(m)\n#define mtx_lock(_l)\t\t\tNdisAcquireSpinLock(_l)\n#define mtx_unlock(_l)\t\t\tNdisReleaseSpinLock(_l)\n#define\tmtx_destroy(m)\t\t\tNdisFreeSpinLock(m)\n#define mtx_assert(a, b)\n\n#define rw_rlock(_l)\t\t\tNdisAcquireSpinLock(_l)\n#define rw_runlock(_l)\t\t\tNdisReleaseSpinLock(_l)\n#define rw_assert(a, b)\n#define rw_wlock(_l)\t\t\tNdisAcquireSpinLock(_l)\n#define rw_wunlock(_l)\t\t\tNdisReleaseSpinLock(_l)\n#define rw_destroy(_l)\t\t\tNdisFreeSpinLock(_l)\n#define rw_init(_l, msg)\t\tNdisAllocateSpinLock(_l)\n#define rw_init_flags(_l, s, v)\t\tNdisAllocateSpinLock(_l)\n\n#define rwlock_t NDIS_SPIN_LOCK\n#define spinlock_t NDIS_SPIN_LOCK\n\n#define s6_addr   __u6_addr.__u6_addr8\n\n\nstruct icmphdr {\n\tu_char\ticmp_type;\t\t/* type of message, see below */\n\tu_char\ticmp_code;\t\t/* type sub code */\n\tu_short\ticmp_cksum;\t\t/* ones complement cksum of struct */\n};\n\n#define\tICMP_ECHO\t\t8\t\t/* echo service */\n\n#define IPOPT_OPTVAL            0               /* option ID */\n#define IPOPT_OLEN              1               /* option length */\n#define IPOPT_EOL               0               /* end of option list */\n#define IPOPT_NOP               1               /* no operation */\n#define IPOPT_LSRR              131             /* loose source route */\n#define IPOPT_SSRR              137             /* strict source route */\n#define IPOPT_RR                7               /* record packet route */\n#define IPOPT_TS                68              /* timestamp */\n\n#define\tIPPROTO_ICMP\t1\t\t/* control message protocol */\n#define\tIPPROTO_TCP\t\t6\t\t/* tcp */\n#define\tIPPROTO_UDP\t\t17\t\t/* user datagram protocol */\n#define\tIPPROTO_ICMPV6\t\t58\t\t/* ICMP6 */\n#define\tIPPROTO_SCTP\t\t132\t\t/* SCTP */\n#define\tIPPROTO_HOPOPTS\t\t0\t\t/* IP6 hop-by-hop options */\n#define\tIPPROTO_ROUTING\t\t43\t\t/* IP6 routing header */\n#define\tIPPROTO_FRAGMENT\t44\t\t/* IP6 fragmentation header */\n#define\tIPPROTO_DSTOPTS\t\t60\t\t/* IP6 destination option */\n#define\tIPPROTO_AH\t\t51\t\t/* IP6 Auth Header */\n#define\tIPPROTO_ESP\t\t50\t\t/* IP6 Encap Sec. Payload */\n#define\tIPPROTO_NONE\t\t59\t\t/* IP6 no next header */\n#define\tIPPROTO_PIM\t\t103\t\t/* Protocol Independent Mcast */\n\n#define IPPROTO_IPV6\t\t41\n#define\tIPPROTO_IPV4\t\t4\t\t/* IPv4 encapsulation */\n\n\n#define\tINADDR_ANY\t\t(uint32_t)0x00000000\n\n#define\tAF_INET\t\t2\t\t/* internetwork: UDP, TCP, etc. */\n#define\tAF_LINK\t\t18\t\t/* Link layer interface */\n\n#define\tIN_CLASSD(i)\t\t(((uint32_t)(i) & 0xf0000000) == 0xe0000000)\n#define\tIN_MULTICAST(i)\t\tIN_CLASSD(i)\n\n#define DROP 0\n#define PASS 1\n#define DUMMYNET 2\n#define INCOMING 0\n#define OUTGOING 1\n\nsize_t strlcpy(char *dst, const char *src, size_t siz);\nvoid do_gettimeofday(struct timeval *tv);\nint ffs(int bits);\nint time_uptime_w32();\n\n#endif /* _WINMISSING_H_ */\n"
  },
  {
    "path": "planetlab/Makefile.planetlab",
    "content": "# $Id: Makefile 11687 2012-08-12 20:51:25Z luigi $\n#\n# Top level makefile for building ipfw/dummynet (kernel and userspace).\n# You can run it manually or also under the Planetlab build.\n# Planetlab wants also the 'install' target.\n#\n# To build on system with non standard Kernel sources or userland files,\n# you should run this with\n#\n#\tmake KERNELPATH=/path/to/linux-2.x.y.z USRDIR=/path/to/usr\n#\n# We assume that $(USRDIR) contains include/ and lib/ used to build userland.\n#\n\ninclude Makefile.inc\n\nDATE ?= $(shell date +%Y%m%d)\nSNAPSHOT_NAME=$(DATE)-ipfw3.tgz\nBINDIST=$(DATE)-dummynet-linux.tgz\nWINDIST=$(DATE)-dummynet-windows.zip\n\n.PHONY: ipfw kipfw\n\n###########################################\n#  windows x86 and x64 specific variables #\n###########################################\n#  DRIVE must be the hard drive letter where DDK is installed\n#  DDKDIR must be the path to the DDK root directory, without drive letter\n#  TARGETOS (x64 only) must be one of the following:\n#  wnet   -> windows server 2003\n#  wlh    -> windows vista and windows server 2008\n#  win7   -> windows 7\n#  future version must be added here\nexport WIN64\nexport DDK\nexport DRIVE\nexport DDKDIR\nDRIVE ?= C:\nDDKDIR ?= /WinDDK/7600.16385.1\nDDK = $(DRIVE)$(DDKDIR)\n\nTARGETOS=win7\n\n_all: all\n\nclean distclean:\n\t-@(cd ipfw && $(MAKE) $(@) )\n\t-@rm -rf kipfw-mod binary64/[A-hj-z]*\n\nall: kipfw ipfw\n\t@# -- windows only\nifeq ($(OSARCH),Windows)\t# copy files\nifeq ($(WIN64),)\n\t-@ cp ipfw/ipfw.exe kipfw-mod/$(OBJDIR)/ipfw.sys binary/\n\t-@ cp kipfw/*.inf binary/\nelse\n\t-@ cp binary/* binary64/\n\t-@ cp ipfw/ipfw.exe kipfw-mod/objchk_win7_amd64/amd64/ipfw.sys binary64/\nendif\t# WIN64\nendif\t# Windows\n\nwin64:\n\t$(MAKE) WIN64=1\n\n# kipfw-src prepares the sources for the kernel part.\n# The windows files (passthru etc.) are modified version of the\n# examples found in the $(DDK)/src/network/ndis/passthru/driver/\n# They can be re-created using the 'ndis-glue' target\n# # We need a sed trick to remove newlines from the patchfile.\n\nndis-glue:\n\t-@mkdir -p kipfw-mod\n\tcp $(DDK)/src/network/ndis/passthru/driver/*.[ch] kipfw-mod\n\tcat kipfw/win-passthru.diff | sed \"s/$$(printf '\\r')//g\" | (cd kipfw-mod; patch )\n\nkipfw-src:\n\t-@rm -rf kipfw-mod\n\t-@mkdir -p kipfw-mod\n\t-@cp -Rp kipfw/* kipfw-mod\n\t-@cp `find sys -name \\*.c` kipfw-mod\n\t-@(cd kipfw-mod && $(MAKE) include_e)\nifeq ($(OSARCH),Windows)\n\tmake ndis-glue\nendif\n\nsnapshot:\n\t$(MAKE) distclean\n\t(cd ..; tar cvzhf /tmp/$(SNAPSHOT_NAME) --exclude .svn \\\n\t\t--exclude README.openwrt --exclude tags --exclude NOTES \\\n\t\t--exclude tcc-0.9.25-bsd \\\n\t\t--exclude original_passthru \\\n\t\t--exclude ipfw3.diff --exclude add_rules \\\n\t\t--exclude test --exclude test_ \\\n\t\tipfw3-2012 )\n\nbindist:\n\t$(MAKE) clean\n\t$(MAKE) all\n\ttar cvzf /tmp/$(BINDIST) ipfw/ipfw ipfw/ipfw.8 kipfw-mod/ipfw_mod.ko\n\nwindist:\n\t$(MAKE) clean\n\t-$(MAKE) all\n\t-rm /tmp/$(WINDIST)\n\tzip -r /tmp/$(WINDIST) binary -x \\*.svn\\*\n\n\nipfw:\n\t@(cd ipfw && $(MAKE) $(@) )\n\nkipfw: kipfw-src\nifeq ($(WIN64),)\t# linux or windows 32 bit\n\t@(cd kipfw-mod && $(MAKE) $(@) )\nelse\t#--- windows 64 bit, we use build.exe and nmake\n\trm -f kipfw-mod/Makefile\n\tmkdir kipfw-mod/tmpbuild\t\t# check mysetenv.sh\n\tbash kipfw/mysetenv.sh $(DRIVE) $(DDKDIR) $(TARGETOS)\nendif\n\nIPF3_REPO ?= svn+ssh://some.host/some/path/ipfw3-2012\n\nplanetlab_update:\n\t# clean and create a local working directory\n\trm -rf /tmp/pl-tmp\n\tmkdir -p /tmp/pl-tmp/pl\n\tmkdir -p /tmp/pl-tmp/ol2\n\t# get the trunk version of the PlanetLab repository\n\t# to specify the sshkey use the .ssh/config file\n\t(cd /tmp/pl-tmp/pl; \\\n\t\tsvn co svn+ssh://svn.planet-lab.org/svn/ipfw/trunk)\n\t# get an updated copy of the main ipfw repository\n\t(cd /tmp/pl-tmp/ol2; svn export $(IPFW3_REPO) )\n\t# copy the new version over the old one\n\t(cd /tmp/pl-tmp; cp -rP ol2/ipfw3/* pl/trunk)\n\t# files cleanup in the old version\n\t(cd /tmp/pl-tmp; diff -r ol2/ipfw3 pl/trunk | \\\n\t\tgrep -v \"svn\" | awk '{print $$3 $$4}' | \\\n\t\tsed 's/:/\\//' | xargs rm -rf)\n\t# local adjustments here\n\trm -rf /tmp/pl-tmp/pl/trunk/planetlab/check_planetlab_sync\n\t# commit to the remote repo\n\t@echo \"Please, revise the update with the commands:\"\n\t@echo \"(cd /tmp/pl-tmp/pl/trunk; svn diff)\"\n\t@echo \"(cd /tmp/pl-tmp/pl/trunk; svn status)\"\n\t@echo \"and commit with:\"\n\t@echo \"(cd /tmp/pl-tmp/pl/trunk; svn ci -m 'Update from the mail ipfw repo.')\"\n\nopenwrt_release:\n\t# create a temporary directory\n\t$(eval TMPDIR := $(shell mktemp -d -p /tmp/ ipfw3_openwrt_XXXXX))\n\t# create the source destination directory\n\t$(eval IPFWDIR := ipfw3-$(DATE))\n\t$(eval DSTDIR := $(TMPDIR)/$(IPFWDIR))\n\tmkdir $(DSTDIR)\n\t# copy the package, clean objects and svn info\n\tcp -r ./ipfw ./kipfw-mod glue.h Makefile ./configuration README $(DSTDIR)\n\t(cd $(DSTDIR); make -s distclean; find . -name .svn | xargs rm -rf)\n\t(cd $(TMPDIR); tar czf $(IPFWDIR).tar.gz $(IPFWDIR))\n\n\t# create the port files in /tmp/ipfw3-port\n\t$(eval PORTDIR := $(TMPDIR)/ipfw3)\n\tmkdir -p $(PORTDIR)/patches\n\t# generate the Makefile, PKG_VERSION and PKG_MD5SUM\n\tmd5sum $(DSTDIR).tar.gz | cut -d ' ' -f 1 > $(TMPDIR)/md5sum\n\tcat ./OPENWRT/Makefile | \\\n\t\tsed s/PKG_VERSION:=/PKG_VERSION:=$(DATE)/ | \\\n\t\tsed s/PKG_MD5SUM:=/PKG_MD5SUM:=`cat $(TMPDIR)/md5sum`/ \\\n\t\t> $(PORTDIR)/Makefile\n\n\t@echo \"\"\n\t@echo \"The openwrt port is in $(TMPDIR)/ipfw3-port\"\n\t@echo \"The source file should be copied to the public server:\"\n\t@echo \"scp $(DSTDIR).tar.gz marta@info.iet.unipi.it:~marta/public_html/dummynet\"\n\t@echo \"after this the temporary directory $(TMPDIR) can be removed.\"\n\ninstall:\n\ndiff:\n\t-@(diff -upr $(BSD_HEAD)/sbin/ipfw ipfw)\n\t-@(diff -upr $(BSD_HEAD)/sys sys)\n\n"
  },
  {
    "path": "planetlab/check_planetlab_sync",
    "content": "#!/bin/sh\n\n#\n# This script is used to check the sync of the local repo\n# with the remote planetlab repository\n\ntmpfile=/tmp/chech_planetlab_sync.tmp\n\n# check for local copy sync\nsvn diff > /tmp/chech_planetlab_sync.tmp\nif [ -s $tmpfile ] ; then\n\techo \"Local repo unsynced, can not continue\"\n\texit -1\n\trm $tmpfile\nfi\n\n# export remote copy\nsvn --force export http://svn.planet-lab.org/svn/ipfw/trunk ./ >> /dev/null\n\n# check diffs again, output to the user\nsvn diff \nsvn status | grep -v check_planetlab_sync\n"
  },
  {
    "path": "planetlab/ipfw",
    "content": "#!/bin/sh\n#\n# ipfw\tinit the emulation service\n#\n# chkconfig: 2345 09 91\n# description: ipfw init and shutdown\n#\n\n# Source function library.\n. /etc/init.d/functions\n\nIPFW=ipfw\nIPFW_BACKEND=/vsys/ipfw-be\nIPFW_MOD=ipfw_mod\n\nif [ ! -x /sbin/$IPFW ] || [ ! -x ${IPFW_BACKEND} ]; then\n    echo -n \"/sbin/$IPFW does not exist.\"; warning; echo\n    exit 0\nfi\n\n# Load the ipfw module, and initialize netconfig\nstart() {\n\t# load the module\n\tmodprobe $IPFW_MOD >& /dev/null\n\tlet ret=$?;\n        [ $ret -eq 0 ] && success || failure\n\n\t# init netconfig\n\techo \"super dbcleanup\" | ${IPFW_BACKEND} root >& /dev/null\n\techo \"super init\" | ${IPFW_BACKEND} root >& /dev/null\n\n\treturn $ret\n}\n\nstop() {\n\t# clean netconfig stuff\n\techo \"super dbcleanup\" | ${IPFW_BACKEND} root >& /dev/null\n\techo \"Unloading $IPFW_MOD module: \"\n\n\t# unload the ipfw module\n\trmmod ${IPFW_MOD}\n\tlet ret=$?;\n\t[ $ret -eq 0 ] && success || failure\n\n\treturn $ret\n}\n\n# echo the ipfw status\nstatus() {\n\t# check for module presence\n\tgrep '^ipfw_mod$' /proc/modules >& /dev/null || echo \"ipfw not loaded\" && return 0\n\n\t# Show active users\n\tUSERS=$(grep BLOCK /tmp/ff | wc -l)\n\techo \"ipfw is loaded and there are currently ${USERS} with active emulation.\"\n\treturn 0\n}\n\n# main\ncase \"$1\" in\n    start)\n\tstart\n\tRETVAL=$?\n\t;;\n    stop)\n\tstop\n\tRETVAL=$?\n\t;;\n    restart)\n\tstop\n\tstart\n\tRETVAL=$?\n\t;;\n    status)\n\tstatus\n\tRETVAL=$?\n\t;;\n    *)\n\techo $\"Usage: $0 {start|stop|restart|status}\"\n\texit 1\n\t;;\nesac\n\nexit $RETVAL\n"
  },
  {
    "path": "planetlab/ipfw.cron",
    "content": "# Runs every 5 minutes and clean ipfw expired rules\n# $Id: ipfw.cron 6069 2010-04-15 09:35:33Z marta $\n*/5 * * * * root     echo \"super killexpired\" | /vsys/ipfw-be root > /dev/null 2>&1\n"
  },
  {
    "path": "planetlab/ipfwroot.spec",
    "content": "#\n# Marta Carbone <marta.carbone@iet.unipi.it>\n# 2009 - Universita` di Pisa\n# License is BSD.\n\n# kernel_release, kernel_version and kernel_arch are expected to be set by the build to e.g.\n# kernel_release : 24.onelab  (24 is then the planetlab taglevel)\n# kernel_version : 2.6.27.57 | 2.6.32  (57 in the 27 case is the patch level)\n# kernel_arch :    i686 | x86_64\n\n# the 2012 release was pulled from http://info.iet.unipi.it/~marta/dummynet/ipfw3-20120610.tar.gz\n# seel also          http://sourceforge.net/p/dummynet/code\n# in 2013 Marta has moved to sourceforge at\n# git clone git://git.code.sf.net/p/dummynet/code your read-only code\n%define name ipfwroot\n%define version 3\n%define taglevel 1\n\n# when no planetlab kernel is being built, kernel_version is defined but empty\n%define _with_planetlab_kernel %{?kernel_version:1}%{!?kernel_version:0}\n# we need to make sure that this rpm gets upgraded when the kernel release changes\n%if %{_with_planetlab_kernel}\n# with the planetlab kernel\n%define pl_kernel_taglevel %( echo %{kernel_release} | cut -d. -f1 )\n%define ipfw_release %{kernel_version}.%{pl_kernel_taglevel}\n%else\n# with the stock kernel\n# this line below\n#%define ipfw_release %( rpm -q --qf \"%{version}\" kernel-headers )\n# causes recursive macro definition no matter how much you quote\n%define percent %\n%define braop \\{\n%define bracl \\}\n%define kernel_version %( rpm -q --qf %{percent}%{braop}version%{bracl} kernel-headers )\n%define kernel_release %( rpm -q --qf %{percent}%{braop}release%{bracl} kernel-headers )\n%define kernel_arch %( rpm -q --qf %{percent}%{braop}arch%{bracl} kernel-headers )\n%define ipfw_release %{kernel_version}.%{kernel_release}\n%endif\n\n%define release %{ipfw_release}.%{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}\n\n# guess which convention is used; k27 and before used dash, k32 uses dot\n%define kernelpath_dash /usr/src/kernels/%{kernel_version}-%{kernel_release}-%{kernel_arch}\n%define kernelpath_dot /usr/src/kernels/%{kernel_version}-%{kernel_release}.%{kernel_arch}\n%define kernelpath %( [ -d %{kernelpath_dot} ] && echo %{kernelpath_dot} || echo %{kernelpath_dash} )\n\n# the k32 kernel currently builds e.g. /lib/modules/2.6.32-0.onelab.2010.12.07-i686\n# the k27 and before does not have the -i686 part\n%define kernel_id_old %{kernel_version}-%{kernel_release}\n%define kernel_id_new %{kernel_version}-%{kernel_release}.%{kernel_arch}\n%define kernel_id %( [ -d %{kernelpath_dot} ] && echo %{kernel_id_new} || echo %{kernel_id_old} )\n\nSummary: ipfw and dummynet for Linux\nName: %{name}\nVersion: %{version}\nRelease: %{release}\nLicense: BSD\nGroup: System Environment/Kernel\nSource0: %{name}-%{version}.tar.bz2\nBuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot\nRequires: kernel = %{kernel_version}-%{kernel_release}\n# in fedora20 cronie does not provide vixie-cronie anymore, just cronie\nRequires: cronie\nRequires: vsys-scripts\nObsoletes: ipfw\n\nVendor: unipi\nPackager: PlanetLab <marta@onelab2.iet.unipi.it>\n# XXX ask \nDistribution: PlanetLab %{plrelease}\nURL: %{SCMURL}\n\n%description\nipfw is the Linux port of the FreeBSD ipfw and dummynet packages\n\n%prep\n%setup\n\n%build\n# clean the rpm build directory\nrm -rf $RPM_BUILD_ROOT\n\n%__make KERNELPATH=%kernelpath clean\n%__make KERNELPATH=%kernelpath IPFW_PLANETLAB=1\n\n%install\ninstall -D -m 755 kipfw-mod/ipfw_mod.ko $RPM_BUILD_ROOT/lib/modules/%{kernel_id}/net/netfilter/ipfw_mod.ko\ninstall -D -m 755 ipfw/ipfw $RPM_BUILD_ROOT/sbin/ipfw\ninstall -D -m 644 planetlab/ipfw.cron $RPM_BUILD_ROOT/%{_sysconfdir}/cron.d/ipfw.cron\ninstall -D -m 755 planetlab/ipfw $RPM_BUILD_ROOT/etc/rc.d/init.d/ipfw\n\n%clean\nrm -rf $RPM_BUILD_ROOT\n\n%post\n### this script is also triggered while the node image is being created at build-time\n# some parts of the script do not make sense in this context\n# this is why the build exports PL_BOOTCD=1 in such cases\ndepmod -a %{kernel_id}\n/sbin/chkconfig --add ipfw\n# start the service if not building\n[ -z \"$PL_BOOTCD\" ] && service ipfw start\n\n%postun\n# stop the service if not building\n[ -z \"$PL_BOOTCD\" ] && service ipfw stop\n\n# here there is a list of the final installation directories\n%files\n%defattr(-,root,root)\n%dir /lib/modules/%{kernel_id}\n/lib/modules/%{kernel_id}/net/netfilter/ipfw_mod.ko\n/sbin/ipfw\n%{_sysconfdir}/cron.d/ipfw.cron\n/etc/rc.d/init.d/ipfw\n\n%changelog\n* Mon Jul 09 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-20120610-2\n- cosmetic changes only in specfile\n\n* Fri Jun 15 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-20120610-1\n- integrated ipfw3 as of 20120610 from upstream\n\n* Mon Oct 24 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-23\n- for building against k32 on f8\n\n* Sun Oct 02 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-22\n- rpm version number has the kernel taglevel embedded\n\n* Fri Jun 10 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-21\n- build tweaks for gcc-4.6 on f15\n\n* Sun Jan 23 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-20\n- tweaks for compiling on k32/64 bits\n\n* Wed Dec 08 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-19\n- fix detection of kernel conventions\n\n* Tue Dec 07 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-18\n- guess conventions for either <=k27 or >=k32\n\n* Tue Jun 15 2010 Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-17\n- testing git only module-tag\n\n* Tue Jun 15 2010 Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-16\n- tagging ipfw to test module-tools on (pure) git\n\n* Wed May 12 2010 Talip Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-15\n- tagging for obsoletes\n\n* Tue Apr 27 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-13\n- Update to the ipfw3 version of the dummynet code.\n\n* Mon Apr 12 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-11\n- add ipfw initialization script to chkconfig\n\n* Wed Mar 03 2010 Talip Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-10\n- - Load module at installation - Marta\n\n* Mon Jan 11 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-9\n- consistent with vsys-scripts-0.95-13\n\n* Mon Jan 11 2010 Marta Carbone <marta.carbone@iet.unipi.it>\n- Integrated the ipfw rules cleanup into the backend\n\n* Sat Jan 09 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-8\n- builds on 2.6.22 & 2.6.27 - for 32 and 64 bits\n\n* Wed Jan 06 2010 Marta Carbone <marta.carbone@iet.unipi.it>\n- move to dummynet2, added support for table lookup\n- added the vsys-script dependencies and the ipfw initialization\n\n* Tue Dec 15 2009 Marta Carbone <marta.carbone@iet.unipi.it>\n- more work on the radix code, added sysctl read/write support\n\n* Sun Nov 29 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-7\n- added missing qsort.c - tag 0.9-6 was broken\n\n* Thu Nov 26 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-6\n- root: removed goto into the main ipfw switch, enabled slice_id matching\n- slice: completely move netconfig checks into the backend\n\n* Mon Nov 09 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-5\n- additional features on matching packets, including uid match\n\n* Mon Sep 07 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-4\n- on behalf of Marta Carbone, more options and features\n\n* Thu Jul 23 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-3\n- fixed memory usage issue\n\n* Wed Jul 15 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-2\n- patch for building on x86_64\n\n* Thu Jun 25 2009 Marta Carbone <marta.carbone@iet.unipi.it>\n- post installation removed for deployment, moved manpages to the slice package\n\n* Fri Apr 17 2009 Marta Carbone <marta.carbone@iet.unipi.it>\n- Initial release\n"
  },
  {
    "path": "planetlab/ipfwslice.spec",
    "content": "#\n# TODO:\n# restart crond\n# modprobe ipfw_mod.ko (depmod ?)\n#\n\n# Marta Carbone <marta.carbone@iet.unipi.it>\n# 2009 - Universita` di Pisa\n# License is BSD.\n\n# the 2012 release was pulled from http://info.iet.unipi.it/~marta/dummynet/ipfw3-20120610.tar.gz\n# seel also          http://sourceforge.net/p/dummynet/code\n# in 2013 Marta has moved to sourceforge at\n# git clone git://git.code.sf.net/p/dummynet/code your read-only code\n%define name ipfwslice\n%define version 3\n%define taglevel 1\n\n%define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}\n\nSummary: ipfw and dummynet for Linux\nName: %{name}\nVersion: %{version}\nRelease: %{release}\nLicense: BSD\nGroup: System Environment/Kernel\nSource0: %{name}-%{version}.tar.bz2\nBuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot\n\nVendor: unipi\nPackager: PlanetLab <marta@onelab2.iet.unipi.it>\nDistribution: PlanetLab %{plrelease}\nURL: %{SCMURL}\n\n%description\nthe frontend part of the ipfw planetlab package\n\n%prep\n%setup\n\n%build\nrm -rf $RPM_BUILD_ROOT\n\n%install\ninstall -D -m 755 planetlab/netconfig $RPM_BUILD_ROOT/sbin/netconfig\ninstall -D -m 755 planetlab/ipfw.8.gz $RPM_BUILD_ROOT/%{_mandir}/man8/ipfw.8.gz\n\n%clean\nrm -rf $RPM_BUILD_ROOT\n\n# here there is a list of the final installation directories\n%files\n%defattr(-,root,root)\n/sbin/netconfig\n%{_mandir}/man8/ipfw.8*\n\n%changelog\n* Mon Jul 09 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-20120610-2\n- cosmetic changes only in specfile\n\n* Fri Jun 15 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-20120610-1\n- integrated ipfw3 as of 20120610 from upstream\n\n* Mon Oct 24 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-23\n- for building against k32 on f8\n\n* Sun Oct 02 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-22\n- rpm version number has the kernel taglevel embedded\n\n* Fri Jun 10 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-21\n- build tweaks for gcc-4.6 on f15\n\n* Sun Jan 23 2011 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-20\n- tweaks for compiling on k32/64 bits\n\n* Wed Dec 08 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-19\n- fix detection of kernel conventions\n\n* Tue Dec 07 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-18\n- guess conventions for either <=k27 or >=k32\n\n* Tue Jun 15 2010 Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-17\n- testing git only module-tag\n\n* Tue Jun 15 2010 Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-16\n- tagging ipfw to test module-tools on (pure) git\n\n* Wed May 12 2010 Talip Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-15\n- tagging for obsoletes\n\n* Tue Apr 27 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-13\n- Update to the ipfw3 version of the dummynet code.\n\n* Mon Apr 12 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-11\n- add ipfw initialization script to chkconfig\n\n* Wed Mar 03 2010 Talip Baris Metin <Talip-Baris.Metin@sophia.inria.fr> - ipfw-0.9-10\n- - Load module at installation - Marta\n\n* Mon Jan 11 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-9\n- consistent with vsys-scripts-0.95-13\n\n* Sat Jan 09 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-8\n- builds on 2.6.22 & 2.6.27 - for 32 and 64 bits\n\n* Tue Dec 15 2009 Marta Carbone <marta.carbone@iet.unipi.it>\n- more work on the radix code, added sysctl read/write support\n\n* Sun Nov 29 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-7\n- added missing qsort.c - tag 0.9-6 was broken\n\n* Thu Nov 26 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-6\n- root: removed goto into the main ipfw switch, enabled slice_id matching\n- slice: completely move netconfig checks into the backend\n\n* Mon Nov 09 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-5\n- additional features on matching packets, including uid match\n\n* Mon Sep 07 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-4\n- on behalf of Marta Carbone, more options and features\n\n* Thu Jul 23 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-3\n- fixed memory usage issue\n\n* Wed Jul 15 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-2\n- patch for building on x86_64\n\n* Thu Jun 25 2009 Marta Carbone <marta.carbone@iet.unipi.it>\n- Initial release\n"
  },
  {
    "path": "planetlab/netconfig",
    "content": "#!/bin/sh\n#\n# Marta Carbone, Luigi Rizzo\n# Copyright (C) 2009 Universita` di Pisa\n# $Id: netconfig 4533 2009-12-16 14:39:23Z luigi $\n#\n# This script is the frontend to be used with the vsys system.\n# It simply passes information to the backend and gets back the reply\n\nPIPE_IN=/vsys/ipfw-be.in\nPIPE_OUT=/vsys/ipfw-be.out\n\nsudo sh -c \"echo $* >> ${PIPE_IN}\"\nsudo sh -c \"cat ${PIPE_OUT}\"\n"
  },
  {
    "path": "planetlab/planetlab-tags.mk",
    "content": "# $Id: planetlab-tags.mk 7450 2010-10-18 11:17:43Z marta $\n# These are good to build the ipfw modules from svn on kernels 2.6.22\n# and are used to fetch files from the onelab2 repository.\nlinux-2.6-SVNBRANCH\t:= 22\nlinux-2.6-SVNPATH\t:= http://svn.planet-lab.org/svn/linux-2.6/tags/linux-2.6-22-39-1\nipfwsrc-SVNPATH\t\t:= svn+ssh://luigi%40onelab2.iet.unipi.it/home/svn/ports-luigi/dummynet-branches/ipfw3\n"
  },
  {
    "path": "planetlab/planetlab.mk",
    "content": "# $Id: planetlab.mk 4533 2009-12-16 14:39:23Z luigi $\n# .mk file to build a module\nkernel-MODULES := linux-2.6\nkernel-SPEC := kernel-2.6.spec \nkernel-BUILD-FROM-SRPM := yes\nifeq \"$(HOSTARCH)\" \"i386\"\nkernel-RPMFLAGS:= --target i686\nelse\nkernel-RPMFLAGS:= --target $(HOSTARCH)\nendif\nALL += kernel\n\nipfwroot-MODULES := ipfwsrc\nipfwroot-SPEC := planetlab/ipfwroot.spec\nipfwroot-DEPEND-DEVEL-RPMS := kernel-devel\nipfwroot-SPECVARS = kernel_version=$(kernel.rpm-version) \\\n        kernel_release=$(kernel.rpm-release) \\\n        kernel_arch=$(kernel.rpm-arch)\nALL += ipfwroot \n\nipfwslice-MODULES := ipfwsrc\nipfwslice-SPEC := planetlab/ipfwslice.spec\nipfwslice-SPECVARS = kernel_version=$(kernel.rpm-version) \\\n        kernel_release=$(kernel.rpm-release) \\\n        kernel_arch=$(kernel.rpm-arch)\nALL += ipfwslice\n"
  },
  {
    "path": "planetlab/sample_hook",
    "content": "#!/bin/sh\n\n#\n# Marta Carbone <marta.carbone@iet.unipi.it>\n# 2009 - Universita` di Pisa\n#\n# This is a sample hook file in charge to collect\n# statistical information on netconfig usage. It dumps\n# on a log file slicename, port and the configuration string\n# used to configure a dummynet experiment.\n#\n# Each time a user configure a dummynet port, this file\n# will be executed.\n# The following variables will be passed as argument:\n# \n# ${SLICE} ${PORT} ${CONFIG_STRING} \n# ${SLICE} The slicename executing the netconfig command\n# ${PORT} The port to be configured\n# ${CONFIG_STRING} The configuration string\n#\n# Note that this script can get additional information\n# by executing the ipfw command, e.g.\n# ipfw list\t\t# list of installed rules\n# ipfw show\t\t# list of rules and statistical information\n# ipfw pipe show\t# list of pipes\n#\n# a complete list of ipfw commands is available at:\n# http://www.freebsd.org/cgi/man.cgi?query=ipfw&sektion=8\n\n# logfile\nLOG_FILE=/tmp/ipfw_hook.log\n\necho -e `date` >> ${LOG_FILE}\necho \"$*\" >> ${LOG_FILE}\n"
  },
  {
    "path": "sys/net/if.h",
    "content": "#include <linux/if.h>\n"
  },
  {
    "path": "sys/net/pfil.h",
    "content": "/*\t$FreeBSD: src/sys/net/pfil.h,v 1.16 2007/06/08 12:43:25 gallatin Exp $ */\n/*\t$NetBSD: pfil.h,v 1.22 2003/06/23 12:57:08 martin Exp $\t*/\n\n/*-\n * Copyright (c) 1996 Matthew R. Green\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#ifndef _NET_PFIL_H_\n#define _NET_PFIL_H_\n\n#include <sys/systm.h>\n#include <sys/queue.h>\n#include <sys/_lock.h>\n#include <sys/_mutex.h>\n#include <sys/lock.h>\n#include <sys/rmlock.h>\n\nstruct mbuf;\nstruct ifnet;\nstruct inpcb;\n\n/*\n * The packet filter hooks are designed for anything to call them to\n * possibly intercept the packet.\n */\nstruct packet_filter_hook {\n        TAILQ_ENTRY(packet_filter_hook) pfil_link;\n\tint\t(*pfil_func)(void *, struct mbuf **, struct ifnet *, int,\n\t\t    struct inpcb *);\n\tvoid\t*pfil_arg;\n};\n\n#define PFIL_IN\t\t0x00000001\n#define PFIL_OUT\t0x00000002\n#define PFIL_WAITOK\t0x00000004\n#define PFIL_ALL\t(PFIL_IN|PFIL_OUT)\n\ntypedef\tTAILQ_HEAD(pfil_list, packet_filter_hook) pfil_list_t;\n\n#define\tPFIL_TYPE_AF\t\t1\t/* key is AF_* type */\n#define\tPFIL_TYPE_IFNET\t\t2\t/* key is ifnet pointer */\n\nstruct pfil_head {\n\tpfil_list_t\tph_in;\n\tpfil_list_t\tph_out;\n\tint\t\tph_type;\n\tint\t\tph_nhooks;\n#if defined( __linux__ ) || defined( _WIN32 )\n\trwlock_t\tph_mtx;\n#else\n\tstruct rmlock\tph_lock;\n#endif\n\tunion {\n\t\tu_long\t\tphu_val;\n\t\tvoid\t\t*phu_ptr;\n\t} ph_un;\n#define\tph_af\t\tph_un.phu_val\n#define\tph_ifnet\tph_un.phu_ptr\n\tLIST_ENTRY(pfil_head) ph_list;\n};\n\nint\tpfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *,\n\t    int, struct inpcb *), void *, int, struct pfil_head *);\nint\tpfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *,\n\t    int, struct inpcb *), void *, int, struct pfil_head *);\nint\tpfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *,\n\t    int, struct inpcb *inp);\n\nint\tpfil_head_register(struct pfil_head *);\nint\tpfil_head_unregister(struct pfil_head *);\n\nstruct pfil_head *pfil_head_get(int, u_long);\n\n#define\tPFIL_HOOKED(p) ((p)->ph_nhooks > 0)\n#define\tPFIL_LOCK_INIT(p) \\\n    rm_init_flags(&(p)->ph_lock, \"PFil hook read/write mutex\", RM_RECURSE)\n#define\tPFIL_LOCK_DESTROY(p) rm_destroy(&(p)->ph_lock)\n#define PFIL_RLOCK(p, t) rm_rlock(&(p)->ph_lock, (t))\n#define PFIL_WLOCK(p) rm_wlock(&(p)->ph_lock)\n#define PFIL_RUNLOCK(p, t) rm_runlock(&(p)->ph_lock, (t))\n#define PFIL_WUNLOCK(p) rm_wunlock(&(p)->ph_lock)\n#define PFIL_LIST_LOCK() mtx_lock(&pfil_global_lock)\n#define PFIL_LIST_UNLOCK() mtx_unlock(&pfil_global_lock)\n\nstatic __inline struct packet_filter_hook *\npfil_hook_get(int dir, struct pfil_head *ph)\n{\n\n\tif (dir == PFIL_IN)\n\t\treturn (TAILQ_FIRST(&ph->ph_in));\n\telse if (dir == PFIL_OUT)\n\t\treturn (TAILQ_FIRST(&ph->ph_out));\n\telse\n\t\treturn (NULL);\n}\n\n#endif /* _NET_PFIL_H_ */\n"
  },
  {
    "path": "sys/net/radix.c",
    "content": "/*-\n * Copyright (c) 1988, 1989, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)radix.c\t8.5 (Berkeley) 5/19/95\n * $FreeBSD: head/sys/net/radix.c 200354 2009-12-10 10:34:30Z luigi $\n */\n\n/*\n * Routines to build and maintain radix trees for routing lookups.\n */\n#include <sys/param.h>\n#ifdef\t_KERNEL\n#include <sys/lock.h>\n#include <sys/mutex.h>\n#include <sys/rwlock.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/syslog.h>\n#include <net/radix.h>\n#include \"opt_mpath.h\"\n#ifdef RADIX_MPATH\n#include <net/radix_mpath.h>\n#endif\n#else /* !_KERNEL */\n#include <stdio.h>\n#include <strings.h>\n#include <stdlib.h>\n#define log(x, arg...)\tfprintf(stderr, ## arg)\n#define panic(x)\tfprintf(stderr, \"PANIC: %s\", x), exit(1)\n#define min(a, b) ((a) < (b) ? (a) : (b) )\n#include <net/radix.h>\n#endif /* !_KERNEL */\n\nstatic int\trn_walktree_from(struct radix_node_head *h, void *a, void *m,\n\t\t    walktree_f_t *f, void *w);\nstatic int rn_walktree(struct radix_node_head *, walktree_f_t *, void *);\nstatic struct radix_node\n\t *rn_insert(void *, struct radix_node_head *, int *,\n\t     struct radix_node [2]),\n\t *rn_newpair(void *, int, struct radix_node[2]),\n\t *rn_search(void *, struct radix_node *),\n\t *rn_search_m(void *, struct radix_node *, void *);\n\nstatic int\tmax_keylen;\nstatic struct radix_mask *rn_mkfreelist;\nstatic struct radix_node_head *mask_rnhead;\n/*\n * Work area -- the following point to 3 buffers of size max_keylen,\n * allocated in this order in a block of memory malloc'ed by rn_init.\n * rn_zeros, rn_ones are set in rn_init and used in readonly afterwards.\n * addmask_key is used in rn_addmask in rw mode and not thread-safe.\n */\nstatic char *rn_zeros, *rn_ones, *addmask_key;\n\n#define MKGet(m) {\t\t\t\t\t\t\\\n\tif (rn_mkfreelist) {\t\t\t\t\t\\\n\t\tm = rn_mkfreelist;\t\t\t\t\\\n\t\trn_mkfreelist = (m)->rm_mklist;\t\t\t\\\n\t} else\t\t\t\t\t\t\t\\\n\t\tR_Malloc(m, struct radix_mask *, sizeof (struct radix_mask)); }\n \n#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}\n\n#define rn_masktop (mask_rnhead->rnh_treetop)\n\nstatic int\trn_lexobetter(void *m_arg, void *n_arg);\nstatic struct radix_mask *\n\t\trn_new_radix_mask(struct radix_node *tt,\n\t\t    struct radix_mask *next);\nstatic int\trn_satisfies_leaf(char *trial, struct radix_node *leaf,\n\t\t    int skip);\n\n/*\n * The data structure for the keys is a radix tree with one way\n * branching removed.  The index rn_bit at an internal node n represents a bit\n * position to be tested.  The tree is arranged so that all descendants\n * of a node n have keys whose bits all agree up to position rn_bit - 1.\n * (We say the index of n is rn_bit.)\n *\n * There is at least one descendant which has a one bit at position rn_bit,\n * and at least one with a zero there.\n *\n * A route is determined by a pair of key and mask.  We require that the\n * bit-wise logical and of the key and mask to be the key.\n * We define the index of a route to associated with the mask to be\n * the first bit number in the mask where 0 occurs (with bit number 0\n * representing the highest order bit).\n *\n * We say a mask is normal if every bit is 0, past the index of the mask.\n * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit,\n * and m is a normal mask, then the route applies to every descendant of n.\n * If the index(m) < rn_bit, this implies the trailing last few bits of k\n * before bit b are all 0, (and hence consequently true of every descendant\n * of n), so the route applies to all descendants of the node as well.\n *\n * Similar logic shows that a non-normal mask m such that\n * index(m) <= index(n) could potentially apply to many children of n.\n * Thus, for each non-host route, we attach its mask to a list at an internal\n * node as high in the tree as we can go.\n *\n * The present version of the code makes use of normal routes in short-\n * circuiting an explict mask and compare operation when testing whether\n * a key satisfies a normal route, and also in remembering the unique leaf\n * that governs a subtree.\n */\n\n/*\n * Most of the functions in this code assume that the key/mask arguments\n * are sockaddr-like structures, where the first byte is an u_char\n * indicating the size of the entire structure.\n *\n * To make the assumption more explicit, we use the LEN() macro to access\n * this field. It is safe to pass an expression with side effects\n * to LEN() as the argument is evaluated only once.\n * We cast the result to int as this is the dominant usage.\n */\n#define LEN(x) ( (int) (*(const u_char *)(x)) )\n\n/*\n * XXX THIS NEEDS TO BE FIXED\n * In the code, pointers to keys and masks are passed as either\n * 'void *' (because callers use to pass pointers of various kinds), or\n * 'caddr_t' (which is fine for pointer arithmetics, but not very\n * clean when you dereference it to access data). Furthermore, caddr_t\n * is really 'char *', while the natural type to operate on keys and\n * masks would be 'u_char'. This mismatch require a lot of casts and\n * intermediate variables to adapt types that clutter the code.\n */\n\n/*\n * Search a node in the tree matching the key.\n */\nstatic struct radix_node *\nrn_search(v_arg, head)\n\tvoid *v_arg;\n\tstruct radix_node *head;\n{\n\tregister struct radix_node *x;\n\tregister caddr_t v;\n\n\tfor (x = head, v = v_arg; x->rn_bit >= 0;) {\n\t\tif (x->rn_bmask & v[x->rn_offset])\n\t\t\tx = x->rn_right;\n\t\telse\n\t\t\tx = x->rn_left;\n\t}\n\treturn (x);\n}\n\n/*\n * Same as above, but with an additional mask.\n * XXX note this function is used only once.\n */\nstatic struct radix_node *\nrn_search_m(v_arg, head, m_arg)\n\tstruct radix_node *head;\n\tvoid *v_arg, *m_arg;\n{\n\tregister struct radix_node *x;\n\tregister caddr_t v = v_arg, m = m_arg;\n\n\tfor (x = head; x->rn_bit >= 0;) {\n\t\tif ((x->rn_bmask & m[x->rn_offset]) &&\n\t\t    (x->rn_bmask & v[x->rn_offset]))\n\t\t\tx = x->rn_right;\n\t\telse\n\t\t\tx = x->rn_left;\n\t}\n\treturn x;\n}\n\nint\nrn_refines(m_arg, n_arg)\n\tvoid *m_arg, *n_arg;\n{\n\tregister caddr_t m = m_arg, n = n_arg;\n\tregister caddr_t lim, lim2 = lim = n + LEN(n);\n\tint longer = LEN(n++) - LEN(m++);\n\tint masks_are_equal = 1;\n\n\tif (longer > 0)\n\t\tlim -= longer;\n\twhile (n < lim) {\n\t\tif (*n & ~(*m))\n\t\t\treturn 0;\n\t\tif (*n++ != *m++)\n\t\t\tmasks_are_equal = 0;\n\t}\n\twhile (n < lim2)\n\t\tif (*n++)\n\t\t\treturn 0;\n\tif (masks_are_equal && (longer < 0))\n\t\tfor (lim2 = m - longer; m < lim2; )\n\t\t\tif (*m++)\n\t\t\t\treturn 1;\n\treturn (!masks_are_equal);\n}\n\nstruct radix_node *\nrn_lookup(v_arg, m_arg, head)\n\tvoid *v_arg, *m_arg;\n\tstruct radix_node_head *head;\n{\n\tregister struct radix_node *x;\n\tcaddr_t netmask = 0;\n\n\tif (m_arg) {\n\t\tx = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset);\n\t\tif (x == 0)\n\t\t\treturn (0);\n\t\tnetmask = x->rn_key;\n\t}\n\tx = rn_match(v_arg, head);\n\tif (x && netmask) {\n\t\twhile (x && x->rn_mask != netmask)\n\t\t\tx = x->rn_dupedkey;\n\t}\n\treturn x;\n}\n\nstatic int\nrn_satisfies_leaf(trial, leaf, skip)\n\tchar *trial;\n\tregister struct radix_node *leaf;\n\tint skip;\n{\n\tregister char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;\n\tchar *cplim;\n\tint length = min(LEN(cp), LEN(cp2));\n\n\tif (cp3 == NULL)\n\t\tcp3 = rn_ones;\n\telse\n\t\tlength = min(length, LEN(cp3));\n\tcplim = cp + length; cp3 += skip; cp2 += skip;\n\tfor (cp += skip; cp < cplim; cp++, cp2++, cp3++)\n\t\tif ((*cp ^ *cp2) & *cp3)\n\t\t\treturn 0;\n\treturn 1;\n}\n\nstruct radix_node *\nrn_match(v_arg, head)\n\tvoid *v_arg;\n\tstruct radix_node_head *head;\n{\n\tcaddr_t v = v_arg;\n\tregister struct radix_node *t = head->rnh_treetop, *x;\n\tregister caddr_t cp = v, cp2;\n\tcaddr_t cplim;\n\tstruct radix_node *saved_t, *top = t;\n\tint off = t->rn_offset, vlen = LEN(cp), matched_off;\n\tregister int test, b, rn_bit;\n\n\t/*\n\t * Open code rn_search(v, top) to avoid overhead of extra\n\t * subroutine call.\n\t */\n\tfor (; t->rn_bit >= 0; ) {\n\t\tif (t->rn_bmask & cp[t->rn_offset])\n\t\t\tt = t->rn_right;\n\t\telse\n\t\t\tt = t->rn_left;\n\t}\n\t/*\n\t * See if we match exactly as a host destination\n\t * or at least learn how many bits match, for normal mask finesse.\n\t *\n\t * It doesn't hurt us to limit how many bytes to check\n\t * to the length of the mask, since if it matches we had a genuine\n\t * match and the leaf we have is the most specific one anyway;\n\t * if it didn't match with a shorter length it would fail\n\t * with a long one.  This wins big for class B&C netmasks which\n\t * are probably the most common case...\n\t */\n\tif (t->rn_mask)\n\t\tvlen = *(u_char *)t->rn_mask;\n\tcp += off; cp2 = t->rn_key + off; cplim = v + vlen;\n\tfor (; cp < cplim; cp++, cp2++)\n\t\tif (*cp != *cp2)\n\t\t\tgoto on1;\n\t/*\n\t * This extra grot is in case we are explicitly asked\n\t * to look up the default.  Ugh!\n\t *\n\t * Never return the root node itself, it seems to cause a\n\t * lot of confusion.\n\t */\n\tif (t->rn_flags & RNF_ROOT)\n\t\tt = t->rn_dupedkey;\n\treturn t;\non1:\n\ttest = (*cp ^ *cp2) & 0xff; /* find first bit that differs */\n\tfor (b = 7; (test >>= 1) > 0;)\n\t\tb--;\n\tmatched_off = cp - v;\n\tb += matched_off << 3;\n\trn_bit = -1 - b;\n\t/*\n\t * If there is a host route in a duped-key chain, it will be first.\n\t */\n\tif ((saved_t = t)->rn_mask == 0)\n\t\tt = t->rn_dupedkey;\n\tfor (; t; t = t->rn_dupedkey)\n\t\t/*\n\t\t * Even if we don't match exactly as a host,\n\t\t * we may match if the leaf we wound up at is\n\t\t * a route to a net.\n\t\t */\n\t\tif (t->rn_flags & RNF_NORMAL) {\n\t\t\tif (rn_bit <= t->rn_bit)\n\t\t\t\treturn t;\n\t\t} else if (rn_satisfies_leaf(v, t, matched_off))\n\t\t\t\treturn t;\n\tt = saved_t;\n\t/* start searching up the tree */\n\tdo {\n\t\tregister struct radix_mask *m;\n\t\tt = t->rn_parent;\n\t\tm = t->rn_mklist;\n\t\t/*\n\t\t * If non-contiguous masks ever become important\n\t\t * we can restore the masking and open coding of\n\t\t * the search and satisfaction test and put the\n\t\t * calculation of \"off\" back before the \"do\".\n\t\t */\n\t\twhile (m) {\n\t\t\tif (m->rm_flags & RNF_NORMAL) {\n\t\t\t\tif (rn_bit <= m->rm_bit)\n\t\t\t\t\treturn (m->rm_leaf);\n\t\t\t} else {\n\t\t\t\toff = min(t->rn_offset, matched_off);\n\t\t\t\tx = rn_search_m(v, t, m->rm_mask);\n\t\t\t\twhile (x && x->rn_mask != m->rm_mask)\n\t\t\t\t\tx = x->rn_dupedkey;\n\t\t\t\tif (x && rn_satisfies_leaf(v, x, off))\n\t\t\t\t\treturn x;\n\t\t\t}\n\t\t\tm = m->rm_mklist;\n\t\t}\n\t} while (t != top);\n\treturn 0;\n}\n\n#ifdef RN_DEBUG\nint\trn_nodenum;\nstruct\tradix_node *rn_clist;\nint\trn_saveinfo;\nint\trn_debug =  1;\n#endif\n\n/*\n * Whenever we add a new leaf to the tree, we also add a parent node,\n * so we allocate them as an array of two elements: the first one must be\n * the leaf (see RNTORT() in route.c), the second one is the parent.\n * This routine initializes the relevant fields of the nodes, so that\n * the leaf is the left child of the parent node, and both nodes have\n * (almost) all all fields filled as appropriate.\n * (XXX some fields are left unset, see the '#if 0' section).\n * The function returns a pointer to the parent node.\n */\n\nstatic struct radix_node *\nrn_newpair(v, b, nodes)\n\tvoid *v;\n\tint b;\n\tstruct radix_node nodes[2];\n{\n\tregister struct radix_node *tt = nodes, *t = tt + 1;\n\tt->rn_bit = b;\n\tt->rn_bmask = 0x80 >> (b & 7);\n\tt->rn_left = tt;\n\tt->rn_offset = b >> 3;\n\n#if 0  /* XXX perhaps we should fill these fields as well. */\n\tt->rn_parent = t->rn_right = NULL;\n\n\ttt->rn_mask = NULL;\n\ttt->rn_dupedkey = NULL;\n\ttt->rn_bmask = 0;\n#endif\n\ttt->rn_bit = -1;\n\ttt->rn_key = (caddr_t)v;\n\ttt->rn_parent = t;\n\ttt->rn_flags = t->rn_flags = RNF_ACTIVE;\n\ttt->rn_mklist = t->rn_mklist = 0;\n#ifdef RN_DEBUG\n\ttt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;\n\ttt->rn_twin = t;\n\ttt->rn_ybro = rn_clist;\n\trn_clist = tt;\n#endif\n\treturn t;\n}\n\nstatic struct radix_node *\nrn_insert(v_arg, head, dupentry, nodes)\n\tvoid *v_arg;\n\tstruct radix_node_head *head;\n\tint *dupentry;\n\tstruct radix_node nodes[2];\n{\n\tcaddr_t v = v_arg;\n\tstruct radix_node *top = head->rnh_treetop;\n\tint head_off = top->rn_offset, vlen = LEN(v);\n\tregister struct radix_node *t = rn_search(v_arg, top);\n\tregister caddr_t cp = v + head_off;\n\tregister int b;\n\tstruct radix_node *tt;\n    \t/*\n\t * Find first bit at which v and t->rn_key differ\n\t */\n    {\n\tregister caddr_t cp2 = t->rn_key + head_off;\n\tregister int cmp_res;\n\tcaddr_t cplim = v + vlen;\n\n\twhile (cp < cplim)\n\t\tif (*cp2++ != *cp++)\n\t\t\tgoto on1;\n\t*dupentry = 1;\n\treturn t;\non1:\n\t*dupentry = 0;\n\tcmp_res = (cp[-1] ^ cp2[-1]) & 0xff;\n\tfor (b = (cp - v) << 3; cmp_res; b--)\n\t\tcmp_res >>= 1;\n    }\n    {\n\tregister struct radix_node *p, *x = top;\n\tcp = v;\n\tdo {\n\t\tp = x;\n\t\tif (cp[x->rn_offset] & x->rn_bmask)\n\t\t\tx = x->rn_right;\n\t\telse\n\t\t\tx = x->rn_left;\n\t} while (b > (unsigned) x->rn_bit);\n\t\t\t\t/* x->rn_bit < b && x->rn_bit >= 0 */\n#ifdef RN_DEBUG\n\tif (rn_debug)\n\t\tlog(LOG_DEBUG, \"rn_insert: Going In:\\n\"), traverse(p);\n#endif\n\tt = rn_newpair(v_arg, b, nodes); \n\ttt = t->rn_left;\n\tif ((cp[p->rn_offset] & p->rn_bmask) == 0)\n\t\tp->rn_left = t;\n\telse\n\t\tp->rn_right = t;\n\tx->rn_parent = t;\n\tt->rn_parent = p; /* frees x, p as temp vars below */\n\tif ((cp[t->rn_offset] & t->rn_bmask) == 0) {\n\t\tt->rn_right = x;\n\t} else {\n\t\tt->rn_right = tt;\n\t\tt->rn_left = x;\n\t}\n#ifdef RN_DEBUG\n\tif (rn_debug)\n\t\tlog(LOG_DEBUG, \"rn_insert: Coming Out:\\n\"), traverse(p);\n#endif\n    }\n\treturn (tt);\n}\n\nstruct radix_node *\nrn_addmask(n_arg, search, skip)\n\tint search, skip;\n\tvoid *n_arg;\n{\n\tcaddr_t netmask = (caddr_t)n_arg;\n\tregister struct radix_node *x;\n\tregister caddr_t cp, cplim;\n\tregister int b = 0, mlen, j;\n\tint maskduplicated, m0, isnormal;\n\tstruct radix_node *saved_x;\n\tstatic int last_zeroed = 0;\n\n\tif ((mlen = LEN(netmask)) > max_keylen)\n\t\tmlen = max_keylen;\n\tif (skip == 0)\n\t\tskip = 1;\n\tif (mlen <= skip)\n\t\treturn (mask_rnhead->rnh_nodes);\n\tif (skip > 1)\n\t\tbcopy(rn_ones + 1, addmask_key + 1, skip - 1);\n\tif ((m0 = mlen) > skip)\n\t\tbcopy(netmask + skip, addmask_key + skip, mlen - skip);\n\t/*\n\t * Trim trailing zeroes.\n\t */\n\tfor (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)\n\t\tcp--;\n\tmlen = cp - addmask_key;\n\tif (mlen <= skip) {\n\t\tif (m0 >= last_zeroed)\n\t\t\tlast_zeroed = mlen;\n\t\treturn (mask_rnhead->rnh_nodes);\n\t}\n\tif (m0 < last_zeroed)\n\t\tbzero(addmask_key + m0, last_zeroed - m0);\n\t*addmask_key = last_zeroed = mlen;\n\tx = rn_search(addmask_key, rn_masktop);\n\tif (bcmp(addmask_key, x->rn_key, mlen) != 0)\n\t\tx = 0;\n\tif (x || search)\n\t\treturn (x);\n\tR_Zalloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));\n\tif ((saved_x = x) == 0)\n\t\treturn (0);\n\tnetmask = cp = (caddr_t)(x + 2);\n\tbcopy(addmask_key, cp, mlen);\n\tx = rn_insert(cp, mask_rnhead, &maskduplicated, x);\n\tif (maskduplicated) {\n\t\tlog(LOG_ERR, \"rn_addmask: mask impossibly already in tree\");\n\t\tFree(saved_x);\n\t\treturn (x);\n\t}\n\t/*\n\t * Calculate index of mask, and check for normalcy.\n\t * First find the first byte with a 0 bit, then if there are\n\t * more bits left (remember we already trimmed the trailing 0's),\n\t * the pattern must be one of those in normal_chars[], or we have\n\t * a non-contiguous mask.\n\t */\n\tcplim = netmask + mlen;\n\tisnormal = 1;\n\tfor (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;)\n\t\tcp++;\n\tif (cp != cplim) {\n\t\tstatic char normal_chars[] = {\n\t\t\t0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};\n\n\t\tfor (j = 0x80; (j & *cp) != 0; j >>= 1)\n\t\t\tb++;\n\t\tif (*cp != normal_chars[b] || cp != (cplim - 1))\n\t\t\tisnormal = 0;\n\t}\n\tb += (cp - netmask) << 3;\n\tx->rn_bit = -1 - b;\n\tif (isnormal)\n\t\tx->rn_flags |= RNF_NORMAL;\n\treturn (x);\n}\n\nstatic int\t/* XXX: arbitrary ordering for non-contiguous masks */\nrn_lexobetter(m_arg, n_arg)\n\tvoid *m_arg, *n_arg;\n{\n\tregister u_char *mp = m_arg, *np = n_arg, *lim;\n\n\tif (LEN(mp) > LEN(np))\n\t\treturn 1;  /* not really, but need to check longer one first */\n\tif (LEN(mp) == LEN(np))\n\t\tfor (lim = mp + LEN(mp); mp < lim;)\n\t\t\tif (*mp++ > *np++)\n\t\t\t\treturn 1;\n\treturn 0;\n}\n\nstatic struct radix_mask *\nrn_new_radix_mask(tt, next)\n\tregister struct radix_node *tt;\n\tregister struct radix_mask *next;\n{\n\tregister struct radix_mask *m;\n\n\tMKGet(m);\n\tif (m == 0) {\n\t\tlog(LOG_ERR, \"Mask for route not entered\\n\");\n\t\treturn (0);\n\t}\n\tbzero(m, sizeof *m);\n\tm->rm_bit = tt->rn_bit;\n\tm->rm_flags = tt->rn_flags;\n\tif (tt->rn_flags & RNF_NORMAL)\n\t\tm->rm_leaf = tt;\n\telse\n\t\tm->rm_mask = tt->rn_mask;\n\tm->rm_mklist = next;\n\ttt->rn_mklist = m;\n\treturn m;\n}\n\nstruct radix_node *\nrn_addroute(v_arg, n_arg, head, treenodes)\n\tvoid *v_arg, *n_arg;\n\tstruct radix_node_head *head;\n\tstruct radix_node treenodes[2];\n{\n\tcaddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;\n\tregister struct radix_node *t, *x = 0, *tt;\n\tstruct radix_node *saved_tt, *top = head->rnh_treetop;\n\tshort b = 0, b_leaf = 0;\n\tint keyduplicated;\n\tcaddr_t mmask;\n\tstruct radix_mask *m, **mp;\n\n\t/*\n\t * In dealing with non-contiguous masks, there may be\n\t * many different routes which have the same mask.\n\t * We will find it useful to have a unique pointer to\n\t * the mask to speed avoiding duplicate references at\n\t * nodes and possibly save time in calculating indices.\n\t */\n\tif (netmask)  {\n\t\tif ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0)\n\t\t\treturn (0);\n\t\tb_leaf = x->rn_bit;\n\t\tb = -1 - x->rn_bit;\n\t\tnetmask = x->rn_key;\n\t}\n\t/*\n\t * Deal with duplicated keys: attach node to previous instance\n\t */\n\tsaved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);\n\tif (keyduplicated) {\n\t\tfor (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {\n#ifdef RADIX_MPATH\n\t\t\t/* permit multipath, if enabled for the family */\n\t\t\tif (rn_mpath_capable(head) && netmask == tt->rn_mask) {\n\t\t\t\t/*\n\t\t\t\t * go down to the end of multipaths, so that\n\t\t\t\t * new entry goes into the end of rn_dupedkey\n\t\t\t\t * chain.\n\t\t\t\t */\n\t\t\t\tdo {\n\t\t\t\t\tt = tt;\n\t\t\t\t\ttt = tt->rn_dupedkey;\n\t\t\t\t} while (tt && t->rn_mask == tt->rn_mask);\n\t\t\t\tbreak;\n\t\t\t}\n#endif\n\t\t\tif (tt->rn_mask == netmask)\n\t\t\t\treturn (0);\n\t\t\tif (netmask == 0 ||\n\t\t\t    (tt->rn_mask &&\n\t\t\t     ((b_leaf < tt->rn_bit) /* index(netmask) > node */\n\t\t\t      || rn_refines(netmask, tt->rn_mask)\n\t\t\t      || rn_lexobetter(netmask, tt->rn_mask))))\n\t\t\t\tbreak;\n\t\t}\n\t\t/*\n\t\t * If the mask is not duplicated, we wouldn't\n\t\t * find it among possible duplicate key entries\n\t\t * anyway, so the above test doesn't hurt.\n\t\t *\n\t\t * We sort the masks for a duplicated key the same way as\n\t\t * in a masklist -- most specific to least specific.\n\t\t * This may require the unfortunate nuisance of relocating\n\t\t * the head of the list.\n\t\t *\n\t\t * We also reverse, or doubly link the list through the\n\t\t * parent pointer.\n\t\t */\n\t\tif (tt == saved_tt) {\n\t\t\tstruct\tradix_node *xx = x;\n\t\t\t/* link in at head of list */\n\t\t\t(tt = treenodes)->rn_dupedkey = t;\n\t\t\ttt->rn_flags = t->rn_flags;\n\t\t\ttt->rn_parent = x = t->rn_parent;\n\t\t\tt->rn_parent = tt;\t \t\t/* parent */\n\t\t\tif (x->rn_left == t)\n\t\t\t\tx->rn_left = tt;\n\t\t\telse\n\t\t\t\tx->rn_right = tt;\n\t\t\tsaved_tt = tt; x = xx;\n\t\t} else {\n\t\t\t(tt = treenodes)->rn_dupedkey = t->rn_dupedkey;\n\t\t\tt->rn_dupedkey = tt;\n\t\t\ttt->rn_parent = t;\t\t\t/* parent */\n\t\t\tif (tt->rn_dupedkey)\t\t\t/* parent */\n\t\t\t\ttt->rn_dupedkey->rn_parent = tt; /* parent */\n\t\t}\n#ifdef RN_DEBUG\n\t\tt=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;\n\t\ttt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;\n#endif\n\t\ttt->rn_key = (caddr_t) v;\n\t\ttt->rn_bit = -1;\n\t\ttt->rn_flags = RNF_ACTIVE;\n\t}\n\t/*\n\t * Put mask in tree.\n\t */\n\tif (netmask) {\n\t\ttt->rn_mask = netmask;\n\t\ttt->rn_bit = x->rn_bit;\n\t\ttt->rn_flags |= x->rn_flags & RNF_NORMAL;\n\t}\n\tt = saved_tt->rn_parent;\n\tif (keyduplicated)\n\t\tgoto on2;\n\tb_leaf = -1 - t->rn_bit;\n\tif (t->rn_right == saved_tt)\n\t\tx = t->rn_left;\n\telse\n\t\tx = t->rn_right;\n\t/* Promote general routes from below */\n\tif (x->rn_bit < 0) {\n\t    for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)\n\t\tif (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {\n\t\t\t*mp = m = rn_new_radix_mask(x, 0);\n\t\t\tif (m)\n\t\t\t\tmp = &m->rm_mklist;\n\t\t}\n\t} else if (x->rn_mklist) {\n\t\t/*\n\t\t * Skip over masks whose index is > that of new node\n\t\t */\n\t\tfor (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)\n\t\t\tif (m->rm_bit >= b_leaf)\n\t\t\t\tbreak;\n\t\tt->rn_mklist = m; *mp = 0;\n\t}\non2:\n\t/* Add new route to highest possible ancestor's list */\n\tif ((netmask == 0) || (b > t->rn_bit ))\n\t\treturn tt; /* can't lift at all */\n\tb_leaf = tt->rn_bit;\n\tdo {\n\t\tx = t;\n\t\tt = t->rn_parent;\n\t} while (b <= t->rn_bit && x != top);\n\t/*\n\t * Search through routes associated with node to\n\t * insert new route according to index.\n\t * Need same criteria as when sorting dupedkeys to avoid\n\t * double loop on deletion.\n\t */\n\tfor (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) {\n\t\tif (m->rm_bit < b_leaf)\n\t\t\tcontinue;\n\t\tif (m->rm_bit > b_leaf)\n\t\t\tbreak;\n\t\tif (m->rm_flags & RNF_NORMAL) {\n\t\t\tmmask = m->rm_leaf->rn_mask;\n\t\t\tif (tt->rn_flags & RNF_NORMAL) {\n#if !defined(RADIX_MPATH)\n\t\t\t    log(LOG_ERR,\n\t\t\t        \"Non-unique normal route, mask not entered\\n\");\n#endif\n\t\t\t\treturn tt;\n\t\t\t}\n\t\t} else\n\t\t\tmmask = m->rm_mask;\n\t\tif (mmask == netmask) {\n\t\t\tm->rm_refs++;\n\t\t\ttt->rn_mklist = m;\n\t\t\treturn tt;\n\t\t}\n\t\tif (rn_refines(netmask, mmask)\n\t\t    || rn_lexobetter(netmask, mmask))\n\t\t\tbreak;\n\t}\n\t*mp = rn_new_radix_mask(tt, *mp);\n\treturn tt;\n}\n\nstruct radix_node *\nrn_delete(v_arg, netmask_arg, head)\n\tvoid *v_arg, *netmask_arg;\n\tstruct radix_node_head *head;\n{\n\tregister struct radix_node *t, *p, *x, *tt;\n\tstruct radix_mask *m, *saved_m, **mp;\n\tstruct radix_node *dupedkey, *saved_tt, *top;\n\tcaddr_t v, netmask;\n\tint b, head_off, vlen;\n\n\tv = v_arg;\n\tnetmask = netmask_arg;\n\tx = head->rnh_treetop;\n\ttt = rn_search(v, x);\n\thead_off = x->rn_offset;\n\tvlen =  LEN(v);\n\tsaved_tt = tt;\n\ttop = x;\n\tif (tt == 0 ||\n\t    bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))\n\t\treturn (0);\n\t/*\n\t * Delete our route from mask lists.\n\t */\n\tif (netmask) {\n\t\tif ((x = rn_addmask(netmask, 1, head_off)) == 0)\n\t\t\treturn (0);\n\t\tnetmask = x->rn_key;\n\t\twhile (tt->rn_mask != netmask)\n\t\t\tif ((tt = tt->rn_dupedkey) == 0)\n\t\t\t\treturn (0);\n\t}\n\tif (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)\n\t\tgoto on1;\n\tif (tt->rn_flags & RNF_NORMAL) {\n\t\tif (m->rm_leaf != tt || m->rm_refs > 0) {\n\t\t\tlog(LOG_ERR, \"rn_delete: inconsistent annotation\\n\");\n\t\t\treturn 0;  /* dangling ref could cause disaster */\n\t\t}\n\t} else {\n\t\tif (m->rm_mask != tt->rn_mask) {\n\t\t\tlog(LOG_ERR, \"rn_delete: inconsistent annotation\\n\");\n\t\t\tgoto on1;\n\t\t}\n\t\tif (--m->rm_refs >= 0)\n\t\t\tgoto on1;\n\t}\n\tb = -1 - tt->rn_bit;\n\tt = saved_tt->rn_parent;\n\tif (b > t->rn_bit)\n\t\tgoto on1; /* Wasn't lifted at all */\n\tdo {\n\t\tx = t;\n\t\tt = t->rn_parent;\n\t} while (b <= t->rn_bit && x != top);\n\tfor (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)\n\t\tif (m == saved_m) {\n\t\t\t*mp = m->rm_mklist;\n\t\t\tMKFree(m);\n\t\t\tbreak;\n\t\t}\n\tif (m == 0) {\n\t\tlog(LOG_ERR, \"rn_delete: couldn't find our annotation\\n\");\n\t\tif (tt->rn_flags & RNF_NORMAL)\n\t\t\treturn (0); /* Dangling ref to us */\n\t}\non1:\n\t/*\n\t * Eliminate us from tree\n\t */\n\tif (tt->rn_flags & RNF_ROOT)\n\t\treturn (0);\n#ifdef RN_DEBUG\n\t/* Get us out of the creation list */\n\tfor (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}\n\tif (t) t->rn_ybro = tt->rn_ybro;\n#endif\n\tt = tt->rn_parent;\n\tdupedkey = saved_tt->rn_dupedkey;\n\tif (dupedkey) {\n\t\t/*\n\t\t * Here, tt is the deletion target and\n\t\t * saved_tt is the head of the dupekey chain.\n\t\t */\n\t\tif (tt == saved_tt) {\n\t\t\t/* remove from head of chain */\n\t\t\tx = dupedkey; x->rn_parent = t;\n\t\t\tif (t->rn_left == tt)\n\t\t\t\tt->rn_left = x;\n\t\t\telse\n\t\t\t\tt->rn_right = x;\n\t\t} else {\n\t\t\t/* find node in front of tt on the chain */\n\t\t\tfor (x = p = saved_tt; p && p->rn_dupedkey != tt;)\n\t\t\t\tp = p->rn_dupedkey;\n\t\t\tif (p) {\n\t\t\t\tp->rn_dupedkey = tt->rn_dupedkey;\n\t\t\t\tif (tt->rn_dupedkey)\t\t/* parent */\n\t\t\t\t\ttt->rn_dupedkey->rn_parent = p;\n\t\t\t\t\t\t\t\t/* parent */\n\t\t\t} else log(LOG_ERR, \"rn_delete: couldn't find us\\n\");\n\t\t}\n\t\tt = tt + 1;\n\t\tif  (t->rn_flags & RNF_ACTIVE) {\n#ifndef RN_DEBUG\n\t\t\t*++x = *t;\n\t\t\tp = t->rn_parent;\n#else\n\t\t\tb = t->rn_info;\n\t\t\t*++x = *t;\n\t\t\tt->rn_info = b;\n\t\t\tp = t->rn_parent;\n#endif\n\t\t\tif (p->rn_left == t)\n\t\t\t\tp->rn_left = x;\n\t\t\telse\n\t\t\t\tp->rn_right = x;\n\t\t\tx->rn_left->rn_parent = x;\n\t\t\tx->rn_right->rn_parent = x;\n\t\t}\n\t\tgoto out;\n\t}\n\tif (t->rn_left == tt)\n\t\tx = t->rn_right;\n\telse\n\t\tx = t->rn_left;\n\tp = t->rn_parent;\n\tif (p->rn_right == t)\n\t\tp->rn_right = x;\n\telse\n\t\tp->rn_left = x;\n\tx->rn_parent = p;\n\t/*\n\t * Demote routes attached to us.\n\t */\n\tif (t->rn_mklist) {\n\t\tif (x->rn_bit >= 0) {\n\t\t\tfor (mp = &x->rn_mklist; (m = *mp);)\n\t\t\t\tmp = &m->rm_mklist;\n\t\t\t*mp = t->rn_mklist;\n\t\t} else {\n\t\t\t/* If there are any key,mask pairs in a sibling\n\t\t\t   duped-key chain, some subset will appear sorted\n\t\t\t   in the same order attached to our mklist */\n\t\t\tfor (m = t->rn_mklist; m && x; x = x->rn_dupedkey)\n\t\t\t\tif (m == x->rn_mklist) {\n\t\t\t\t\tstruct radix_mask *mm = m->rm_mklist;\n\t\t\t\t\tx->rn_mklist = 0;\n\t\t\t\t\tif (--(m->rm_refs) < 0)\n\t\t\t\t\t\tMKFree(m);\n\t\t\t\t\tm = mm;\n\t\t\t\t}\n\t\t\tif (m)\n\t\t\t\tlog(LOG_ERR,\n\t\t\t\t    \"rn_delete: Orphaned Mask %p at %p\\n\",\n\t\t\t\t    m, x);\n\t\t}\n\t}\n\t/*\n\t * We may be holding an active internal node in the tree.\n\t */\n\tx = tt + 1;\n\tif (t != x) {\n#ifndef RN_DEBUG\n\t\t*t = *x;\n#else\n\t\tb = t->rn_info;\n\t\t*t = *x;\n\t\tt->rn_info = b;\n#endif\n\t\tt->rn_left->rn_parent = t;\n\t\tt->rn_right->rn_parent = t;\n\t\tp = x->rn_parent;\n\t\tif (p->rn_left == x)\n\t\t\tp->rn_left = t;\n\t\telse\n\t\t\tp->rn_right = t;\n\t}\nout:\n\ttt->rn_flags &= ~RNF_ACTIVE;\n\ttt[1].rn_flags &= ~RNF_ACTIVE;\n\treturn (tt);\n}\n\n/*\n * This is the same as rn_walktree() except for the parameters and the\n * exit.\n */\nstatic int\nrn_walktree_from(h, a, m, f, w)\n\tstruct radix_node_head *h;\n\tvoid *a, *m;\n\twalktree_f_t *f;\n\tvoid *w;\n{\n\tint error;\n\tstruct radix_node *base, *next;\n\tu_char *xa = (u_char *)a;\n\tu_char *xm = (u_char *)m;\n\tregister struct radix_node *rn, *last = 0 /* shut up gcc */;\n\tint stopping = 0;\n\tint lastb;\n\n\t/*\n\t * rn_search_m is sort-of-open-coded here. We cannot use the\n\t * function because we need to keep track of the last node seen.\n\t */\n\t/* printf(\"about to search\\n\"); */\n\tfor (rn = h->rnh_treetop; rn->rn_bit >= 0; ) {\n\t\tlast = rn;\n\t\t/* printf(\"rn_bit %d, rn_bmask %x, xm[rn_offset] %x\\n\",\n\t\t       rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */\n\t\tif (!(rn->rn_bmask & xm[rn->rn_offset])) {\n\t\t\tbreak;\n\t\t}\n\t\tif (rn->rn_bmask & xa[rn->rn_offset]) {\n\t\t\trn = rn->rn_right;\n\t\t} else {\n\t\t\trn = rn->rn_left;\n\t\t}\n\t}\n\t/* printf(\"done searching\\n\"); */\n\n\t/*\n\t * Two cases: either we stepped off the end of our mask,\n\t * in which case last == rn, or we reached a leaf, in which\n\t * case we want to start from the last node we looked at.\n\t * Either way, last is the node we want to start from.\n\t */\n\trn = last;\n\tlastb = rn->rn_bit;\n\n\t/* printf(\"rn %p, lastb %d\\n\", rn, lastb);*/\n\n\t/*\n\t * This gets complicated because we may delete the node\n\t * while applying the function f to it, so we need to calculate\n\t * the successor node in advance.\n\t */\n\twhile (rn->rn_bit >= 0)\n\t\trn = rn->rn_left;\n\n\twhile (!stopping) {\n\t\t/* printf(\"node %p (%d)\\n\", rn, rn->rn_bit); */\n\t\tbase = rn;\n\t\t/* If at right child go back up, otherwise, go right */\n\t\twhile (rn->rn_parent->rn_right == rn\n\t\t       && !(rn->rn_flags & RNF_ROOT)) {\n\t\t\trn = rn->rn_parent;\n\n\t\t\t/* if went up beyond last, stop */\n\t\t\tif (rn->rn_bit <= lastb) {\n\t\t\t\tstopping = 1;\n\t\t\t\t/* printf(\"up too far\\n\"); */\n\t\t\t\t/*\n\t\t\t\t * XXX we should jump to the 'Process leaves'\n\t\t\t\t * part, because the values of 'rn' and 'next'\n\t\t\t\t * we compute will not be used. Not a big deal\n\t\t\t\t * because this loop will terminate, but it is\n\t\t\t\t * inefficient and hard to understand!\n\t\t\t\t */\n\t\t\t}\n\t\t}\n\t\t\n\t\t/* \n\t\t * At the top of the tree, no need to traverse the right\n\t\t * half, prevent the traversal of the entire tree in the\n\t\t * case of default route.\n\t\t */\n\t\tif (rn->rn_parent->rn_flags & RNF_ROOT)\n\t\t\tstopping = 1;\n\n\t\t/* Find the next *leaf* since next node might vanish, too */\n\t\tfor (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)\n\t\t\trn = rn->rn_left;\n\t\tnext = rn;\n\t\t/* Process leaves */\n\t\twhile ((rn = base) != 0) {\n\t\t\tbase = rn->rn_dupedkey;\n\t\t\t/* printf(\"leaf %p\\n\", rn); */\n\t\t\tif (!(rn->rn_flags & RNF_ROOT)\n\t\t\t    && (error = (*f)(rn, w)))\n\t\t\t\treturn (error);\n\t\t}\n\t\trn = next;\n\n\t\tif (rn->rn_flags & RNF_ROOT) {\n\t\t\t/* printf(\"root, stopping\"); */\n\t\t\tstopping = 1;\n\t\t}\n\n\t}\n\treturn 0;\n}\n\nstatic int\nrn_walktree(h, f, w)\n\tstruct radix_node_head *h;\n\twalktree_f_t *f;\n\tvoid *w;\n{\n\tint error;\n\tstruct radix_node *base, *next;\n\tregister struct radix_node *rn = h->rnh_treetop;\n\t/*\n\t * This gets complicated because we may delete the node\n\t * while applying the function f to it, so we need to calculate\n\t * the successor node in advance.\n\t */\n\n\t/* First time through node, go left */\n\twhile (rn->rn_bit >= 0)\n\t\trn = rn->rn_left;\n\tfor (;;) {\n\t\tbase = rn;\n\t\t/* If at right child go back up, otherwise, go right */\n\t\twhile (rn->rn_parent->rn_right == rn\n\t\t       && (rn->rn_flags & RNF_ROOT) == 0)\n\t\t\trn = rn->rn_parent;\n\t\t/* Find the next *leaf* since next node might vanish, too */\n\t\tfor (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)\n\t\t\trn = rn->rn_left;\n\t\tnext = rn;\n\t\t/* Process leaves */\n\t\twhile ((rn = base)) {\n\t\t\tbase = rn->rn_dupedkey;\n\t\t\tif (!(rn->rn_flags & RNF_ROOT)\n\t\t\t    && (error = (*f)(rn, w)))\n\t\t\t\treturn (error);\n\t\t}\n\t\trn = next;\n\t\tif (rn->rn_flags & RNF_ROOT)\n\t\t\treturn (0);\n\t}\n\t/* NOTREACHED */\n}\n\n/*\n * Allocate and initialize an empty tree. This has 3 nodes, which are\n * part of the radix_node_head (in the order <left,root,right>) and are\n * marked RNF_ROOT so they cannot be freed.\n * The leaves have all-zero and all-one keys, with significant\n * bits starting at 'off'.\n * Return 1 on success, 0 on error.\n */\nint\nrn_inithead(head, off)\n\tvoid **head;\n\tint off;\n{\n\tregister struct radix_node_head *rnh;\n\tregister struct radix_node *t, *tt, *ttt;\n\tif (*head)\n\t\treturn (1);\n\tR_Zalloc(rnh, struct radix_node_head *, sizeof (*rnh));\n\tif (rnh == 0)\n\t\treturn (0);\n#ifdef _KERNEL\n\tRADIX_NODE_HEAD_LOCK_INIT(rnh);\n#endif\n\t*head = rnh;\n\tt = rn_newpair(rn_zeros, off, rnh->rnh_nodes);\n\tttt = rnh->rnh_nodes + 2;\n\tt->rn_right = ttt;\n\tt->rn_parent = t;\n\ttt = t->rn_left;\t/* ... which in turn is rnh->rnh_nodes */\n\ttt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;\n\ttt->rn_bit = -1 - off;\n\t*ttt = *tt;\n\tttt->rn_key = rn_ones;\n\trnh->rnh_addaddr = rn_addroute;\n\trnh->rnh_deladdr = rn_delete;\n\trnh->rnh_matchaddr = rn_match;\n\trnh->rnh_lookup = rn_lookup;\n\trnh->rnh_walktree = rn_walktree;\n\trnh->rnh_walktree_from = rn_walktree_from;\n\trnh->rnh_treetop = t;\n\treturn (1);\n}\n\nint\nrn_detachhead(void **head)\n{\n\tstruct radix_node_head *rnh;\n\n\tKASSERT((head != NULL && *head != NULL),\n\t    (\"%s: head already freed\", __func__));\n\trnh = *head;\n\t\n\t/* Free <left,root,right> nodes. */\n\tFree(rnh);\n\n\t*head = NULL;\n\treturn (1);\n}\n\nvoid\nrn_init(int maxk)\n{\n\tchar *cp, *cplim;\n\n\tmax_keylen = maxk;\n\tif (max_keylen == 0) {\n\t\tlog(LOG_ERR,\n\t\t    \"rn_init: radix functions require max_keylen be set\\n\");\n\t\treturn;\n\t}\n\tR_Malloc(rn_zeros, char *, 3 * max_keylen);\n\tif (rn_zeros == NULL)\n\t\tpanic(\"rn_init\");\n\tbzero(rn_zeros, 3 * max_keylen);\n\trn_ones = cp = rn_zeros + max_keylen;\n\taddmask_key = cplim = rn_ones + max_keylen;\n\twhile (cp < cplim)\n\t\t*cp++ = -1;\n\tif (rn_inithead((void **)(void *)&mask_rnhead, 0) == 0)\n\t\tpanic(\"rn_init 2\");\n}\n"
  },
  {
    "path": "sys/net/radix.h",
    "content": "/*-\n * Copyright (c) 1988, 1989, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)radix.h\t8.2 (Berkeley) 10/31/94\n * $FreeBSD: head/sys/net/radix.h 185747 2008-12-07 21:15:43Z kmacy $\n */\n\n#ifndef _RADIX_H_\n#define\t_RADIX_H_\n\n#ifdef _KERNEL\n#include <sys/_lock.h>\n#include <sys/_mutex.h>\n#include <sys/_rwlock.h>\n#endif\n\n#ifdef MALLOC_DECLARE\nMALLOC_DECLARE(M_RTABLE);\n#endif\n\n/*\n * Radix search tree node layout.\n */\n\nstruct radix_node {\n\tstruct\tradix_mask *rn_mklist;\t/* list of masks contained in subtree */\n\tstruct\tradix_node *rn_parent;\t/* parent */\n\tshort\trn_bit;\t\t\t/* bit offset; -1-index(netmask) */\n\tchar\trn_bmask;\t\t/* node: mask for bit test*/\n\tu_char\trn_flags;\t\t/* enumerated next */\n#define RNF_NORMAL\t1\t\t/* leaf contains normal route */\n#define RNF_ROOT\t2\t\t/* leaf is root leaf for tree */\n#define RNF_ACTIVE\t4\t\t/* This node is alive (for rtfree) */\n\tunion {\n\t\tstruct {\t\t\t/* leaf only data: */\n\t\t\tcaddr_t\trn_Key;\t\t/* object of search */\n\t\t\tcaddr_t\trn_Mask;\t/* netmask, if present */\n\t\t\tstruct\tradix_node *rn_Dupedkey;\n\t\t} rn_leaf;\n\t\tstruct {\t\t\t/* node only data: */\n\t\t\tint\trn_Off;\t\t/* where to start compare */\n\t\t\tstruct\tradix_node *rn_L;/* progeny */\n\t\t\tstruct\tradix_node *rn_R;/* progeny */\n\t\t} rn_node;\n\t}\t\trn_u;\n#ifdef RN_DEBUG\n\tint rn_info;\n\tstruct radix_node *rn_twin;\n\tstruct radix_node *rn_ybro;\n#endif\n};\n\n#define\trn_dupedkey\trn_u.rn_leaf.rn_Dupedkey\n#define\trn_key\t\trn_u.rn_leaf.rn_Key\n#define\trn_mask\t\trn_u.rn_leaf.rn_Mask\n#define\trn_offset\trn_u.rn_node.rn_Off\n#define\trn_left\t\trn_u.rn_node.rn_L\n#define\trn_right\trn_u.rn_node.rn_R\n\n/*\n * Annotations to tree concerning potential routes applying to subtrees.\n */\n\nstruct radix_mask {\n\tshort\trm_bit;\t\t\t/* bit offset; -1-index(netmask) */\n\tchar\trm_unused;\t\t/* cf. rn_bmask */\n\tu_char\trm_flags;\t\t/* cf. rn_flags */\n\tstruct\tradix_mask *rm_mklist;\t/* more masks to try */\n\tunion\t{\n\t\tcaddr_t\trmu_mask;\t\t/* the mask */\n\t\tstruct\tradix_node *rmu_leaf;\t/* for normal routes */\n\t}\trm_rmu;\n\tint\trm_refs;\t\t/* # of references to this struct */\n};\n\n#define\trm_mask rm_rmu.rmu_mask\n#define\trm_leaf rm_rmu.rmu_leaf\t\t/* extra field would make 32 bytes */\n\ntypedef int walktree_f_t(struct radix_node *, void *);\n\nstruct radix_node_head {\n\tstruct\tradix_node *rnh_treetop;\n\tu_int\trnh_gen;\t\t/* generation counter */\n\tint\trnh_multipath;\t\t/* multipath capable ? */\n\tint\trnh_addrsize;\t\t/* permit, but not require fixed keys */\n\tint\trnh_pktsize;\t\t/* permit, but not require fixed keys */\n\tstruct\tradix_node *(*rnh_addaddr)\t/* add based on sockaddr */\n\t\t(void *v, void *mask,\n\t\t     struct radix_node_head *head, struct radix_node nodes[]);\n\tstruct\tradix_node *(*rnh_addpkt)\t/* add based on packet hdr */\n\t\t(void *v, void *mask,\n\t\t     struct radix_node_head *head, struct radix_node nodes[]);\n\tstruct\tradix_node *(*rnh_deladdr)\t/* remove based on sockaddr */\n\t\t(void *v, void *mask, struct radix_node_head *head);\n\tstruct\tradix_node *(*rnh_delpkt)\t/* remove based on packet hdr */\n\t\t(void *v, void *mask, struct radix_node_head *head);\n\tstruct\tradix_node *(*rnh_matchaddr)\t/* locate based on sockaddr */\n\t\t(void *v, struct radix_node_head *head);\n\tstruct\tradix_node *(*rnh_lookup)\t/* locate based on sockaddr */\n\t\t(void *v, void *mask, struct radix_node_head *head);\n\tstruct\tradix_node *(*rnh_matchpkt)\t/* locate based on packet hdr */\n\t\t(void *v, struct radix_node_head *head);\n\tint\t(*rnh_walktree)\t\t\t/* traverse tree */\n\t\t(struct radix_node_head *head, walktree_f_t *f, void *w);\n\tint\t(*rnh_walktree_from)\t\t/* traverse tree below a */\n\t\t(struct radix_node_head *head, void *a, void *m,\n\t\t     walktree_f_t *f, void *w);\n\tvoid\t(*rnh_close)\t/* do something when the last ref drops */\n\t\t(struct radix_node *rn, struct radix_node_head *head);\n\tstruct\tradix_node rnh_nodes[3];\t/* empty tree for common case */\n#ifdef _KERNEL\n#if defined( __linux__ ) || defined( _WIN32 )\n        spinlock_t rnh_lock;\n#else\n\tstruct\trwlock rnh_lock;\t\t/* locks entire radix tree */\n#endif /* !__linux__ */\n#endif\n};\n\n#ifndef _KERNEL\n#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))\n#define R_Zalloc(p, t, n) (p = (t) calloc(1,(unsigned int)(n)))\n#define Free(p) free((char *)p);\n#else\n#define R_Malloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_NOWAIT))\n#define R_Zalloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_NOWAIT | M_ZERO))\n#define Free(p) free((caddr_t)p, M_RTABLE);\n\n#define\tRADIX_NODE_HEAD_LOCK_INIT(rnh)\t\\\n    rw_init_flags(&(rnh)->rnh_lock, \"radix node head\", 0)\n#define\tRADIX_NODE_HEAD_LOCK(rnh)\trw_wlock(&(rnh)->rnh_lock)\n#define\tRADIX_NODE_HEAD_UNLOCK(rnh)\trw_wunlock(&(rnh)->rnh_lock)\n#define\tRADIX_NODE_HEAD_RLOCK(rnh)\trw_rlock(&(rnh)->rnh_lock)\n#define\tRADIX_NODE_HEAD_RUNLOCK(rnh)\trw_runlock(&(rnh)->rnh_lock)\n#define\tRADIX_NODE_HEAD_LOCK_TRY_UPGRADE(rnh)\trw_try_upgrade(&(rnh)->rnh_lock)\n\n\n#define\tRADIX_NODE_HEAD_DESTROY(rnh)\trw_destroy(&(rnh)->rnh_lock)\n#define\tRADIX_NODE_HEAD_LOCK_ASSERT(rnh) rw_assert(&(rnh)->rnh_lock, RA_LOCKED)\n#define\tRADIX_NODE_HEAD_WLOCK_ASSERT(rnh) rw_assert(&(rnh)->rnh_lock, RA_WLOCKED)\n#endif /* _KERNEL */\n\nvoid\t rn_init(int);\nint\t rn_inithead(void **, int);\nint\t rn_detachhead(void **);\nint\t rn_refines(void *, void *);\nstruct radix_node\n\t *rn_addmask(void *, int, int),\n\t *rn_addroute (void *, void *, struct radix_node_head *,\n\t\t\tstruct radix_node [2]),\n\t *rn_delete(void *, void *, struct radix_node_head *),\n\t *rn_lookup (void *v_arg, void *m_arg,\n\t\t        struct radix_node_head *head),\n\t *rn_match(void *, struct radix_node_head *);\n\n#endif /* _RADIX_H_ */\n"
  },
  {
    "path": "sys/netgraph/ng_ipfw.h",
    "content": "/*-\n * Copyright 2005, Gleb Smirnoff <glebius@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: src/sys/netgraph/ng_ipfw.h,v 1.2 2006/02/17 09:42:49 glebius Exp $\n */\n\n#ifndef _NG_IPFW_H\n#define _NG_IPFW_H\n#define NG_IPFW_NODE_TYPE    \"ipfw\"\n#define NGM_IPFW_COOKIE      1105988990\n#endif /* _NG_IPFW_H */\n"
  },
  {
    "path": "sys/netinet/in_cksum.c",
    "content": "/*-\n * Copyright (c) 1988, 1992, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)in_cksum.c\t8.1 (Berkeley) 6/10/93\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: src/sys/netinet/in_cksum.c,v 1.10 2007/10/07 20:44:22 silby Exp $\");\n\n#include <sys/param.h>\n#include <sys/mbuf.h>\n\n/*\n * Checksum routine for Internet Protocol family headers (Portable Version).\n *\n * This routine is very heavily used in the network\n * code and should be modified for each CPU to be as fast as possible.\n */\n\n#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)\n#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}\n\nint\nin_cksum(struct mbuf *m, int len)\n{\n\tregister u_short *w;\n\tregister int sum = 0;\n\tregister int mlen = 0;\n\tint byte_swapped = 0;\n\n\tunion {\n\t\tchar\tc[2];\n\t\tu_short\ts;\n\t} s_util;\n\tunion {\n\t\tu_short s[2];\n\t\tlong\tl;\n\t} l_util;\n\n\tfor (;m && len; m = m->m_next) {\n\t\tif (m->m_len == 0)\n\t\t\tcontinue;\n\t\tw = mtod(m, u_short *);\n\t\tif (mlen == -1) {\n\t\t\t/*\n\t\t\t * The first byte of this mbuf is the continuation\n\t\t\t * of a word spanning between this mbuf and the\n\t\t\t * last mbuf.\n\t\t\t *\n\t\t\t * s_util.c[0] is already saved when scanning previous\n\t\t\t * mbuf.\n\t\t\t */\n\t\t\ts_util.c[1] = *(char *)w;\n\t\t\tsum += s_util.s;\n\t\t\tw = (u_short *)((char *)w + 1);\n\t\t\tmlen = m->m_len - 1;\n\t\t\tlen--;\n\t\t} else\n\t\t\tmlen = m->m_len;\n\t\tif (len < mlen)\n\t\t\tmlen = len;\n\t\tlen -= mlen;\n\t\t/*\n\t\t * Force to even boundary.\n\t\t */\n\t\tif ((1 & (uintptr_t) w) && (mlen > 0)) {\n\t\t\tREDUCE;\n\t\t\tsum <<= 8;\n\t\t\ts_util.c[0] = *(u_char *)w;\n\t\t\tw = (u_short *)((char *)w + 1);\n\t\t\tmlen--;\n\t\t\tbyte_swapped = 1;\n\t\t}\n\t\t/*\n\t\t * Unroll the loop to make overhead from\n\t\t * branches &c small.\n\t\t */\n\t\twhile ((mlen -= 32) >= 0) {\n\t\t\tsum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];\n\t\t\tsum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];\n\t\t\tsum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];\n\t\t\tsum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];\n\t\t\tw += 16;\n\t\t}\n\t\tmlen += 32;\n\t\twhile ((mlen -= 8) >= 0) {\n\t\t\tsum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];\n\t\t\tw += 4;\n\t\t}\n\t\tmlen += 8;\n\t\tif (mlen == 0 && byte_swapped == 0)\n\t\t\tcontinue;\n\t\tREDUCE;\n\t\twhile ((mlen -= 2) >= 0) {\n\t\t\tsum += *w++;\n\t\t}\n\t\tif (byte_swapped) {\n\t\t\tREDUCE;\n\t\t\tsum <<= 8;\n\t\t\tbyte_swapped = 0;\n\t\t\tif (mlen == -1) {\n\t\t\t\ts_util.c[1] = *(char *)w;\n\t\t\t\tsum += s_util.s;\n\t\t\t\tmlen = 0;\n\t\t\t} else\n\t\t\t\tmlen = -1;\n\t\t} else if (mlen == -1)\n\t\t\ts_util.c[0] = *(char *)w;\n\t}\n\tif (len)\n\t\tprintf(\"cksum: out of data\\n\");\n\tif (mlen == -1) {\n\t\t/* The last mbuf has odd # of bytes. Follow the\n\t\t   standard (the odd byte may be shifted left by 8 bits\n\t\t   or not as determined by endian-ness of the machine) */\n\t\ts_util.c[1] = 0;\n\t\tsum += s_util.s;\n\t}\n\tREDUCE;\n\treturn (~sum & 0xffff);\n}\n"
  },
  {
    "path": "sys/netinet/ip.h",
    "content": "#ifndef _NETINET_IP_H_\n#define _NETINET_IP_H_\n\n#define LITTLE_ENDIAN   1234\n#define BIG_ENDIAN      4321\n#if defined(__BIG_ENDIAN)\n#define BYTE_ORDER      BIG_ENDIAN\n//#warning we are in bigendian\n#elif defined(__LITTLE_ENDIAN)\n//#warning we are in littleendian\n#define BYTE_ORDER      LITTLE_ENDIAN\n#else\n#error no platform\n#endif\n\n/* XXX endiannes doesn't belong here */\n// #define LITTLE_ENDIAN   1234\n// #define BIG_ENDIAN      4321\n// #define BYTE_ORDER      LITTLE_ENDIAN\n\n/*\n * Structure of an internet header, naked of options.\n */\nstruct ip {\n#if BYTE_ORDER == LITTLE_ENDIAN\n        u_char  ip_hl:4,                /* header length */\n                ip_v:4;                 /* version */\n#endif\n#if BYTE_ORDER == BIG_ENDIAN\n        u_char  ip_v:4,                 /* version */\n                ip_hl:4;                /* header length */\n#endif\n        u_char  ip_tos;                 /* type of service */\n        u_short ip_len;                 /* total length */\n        u_short ip_id;                  /* identification */\n        u_short ip_off;                 /* fragment offset field */\n#define IP_RF 0x8000                    /* reserved fragment flag */\n#define IP_DF 0x4000                    /* dont fragment flag */\n#define IP_MF 0x2000                    /* more fragments flag */\n#define IP_OFFMASK 0x1fff               /* mask for fragmenting bits */\n        u_char  ip_ttl;                 /* time to live */\n        u_char  ip_p;                   /* protocol */\n        u_short ip_sum;                 /* checksum */\n        struct  in_addr ip_src,ip_dst;  /* source and dest address */\n} __packed __aligned(4);\n\n#define\tIPTOS_LOWDELAY\t\t0x10\n\n#endif /* _NETINET_IP_H_ */\n"
  },
  {
    "path": "sys/netinet/ip6.h",
    "content": "#ifndef _NETINET_IP6_H_\n#define _NETINET_IP6_H_\n#define IN6_ARE_ADDR_EQUAL(a, b)                        \\\n(memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)\n\nstruct ip6_hdr {\n        union {\n                struct ip6_hdrctl {\n                        u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */  \n                        u_int16_t ip6_un1_plen; /* payload length */\n                        u_int8_t  ip6_un1_nxt;  /* next header */\n                        u_int8_t  ip6_un1_hlim; /* hop limit */\n                } ip6_un1;\n                u_int8_t ip6_un2_vfc;   /* 4 bits version, top 4 bits class */\n        } ip6_ctlun;\n        struct in6_addr ip6_src;        /* source address */\n        struct in6_addr ip6_dst;        /* destination address */\n};\n#define ip6_nxt         ip6_ctlun.ip6_un1.ip6_un1_nxt\n#define ip6_flow        ip6_ctlun.ip6_un1.ip6_un1_flow\n\n\nstruct icmp6_hdr {\n        u_int8_t        icmp6_type;     /* type field */\n        u_int8_t        icmp6_code;     /* code field */\n        u_int16_t       icmp6_cksum;    /* checksum field */\n        union {\n                u_int32_t       icmp6_un_data32[1]; /* type-specific field */\n                u_int16_t       icmp6_un_data16[2]; /* type-specific field */\n                u_int8_t        icmp6_un_data8[4];  /* type-specific field */\n        } icmp6_dataun;\n};\n\nstruct ip6_hbh {\n        u_int8_t ip6h_nxt;      /* next header */\n        u_int8_t ip6h_len;      /* length in units of 8 octets */\n        /* followed by options */\n}; \nstruct ip6_rthdr {\n        u_int8_t  ip6r_nxt;     /* next header */\n        u_int8_t  ip6r_len;     /* length in units of 8 octets */\n        u_int8_t  ip6r_type;    /* routing type */\n        u_int8_t  ip6r_segleft; /* segments left */\n        /* followed by routing type specific data */\n};\nstruct ip6_frag {\n        u_int8_t  ip6f_nxt;             /* next header */\n        u_int8_t  ip6f_reserved;        /* reserved field */\n        u_int16_t ip6f_offlg;           /* offset, reserved, and flag */\n        u_int32_t ip6f_ident;           /* identification */\n};\n#define IP6F_OFF_MASK           0xfff8  /* mask out offset from _offlg */\n#define IP6F_MORE_FRAG          0x0001  /* more-fragments flag */\nstruct  ip6_ext {\n        u_int8_t ip6e_nxt;\n        u_int8_t ip6e_len;\n};\n#endif /* _NETINET_IP6_H_ */\n"
  },
  {
    "path": "sys/netinet/ip_dummynet.h",
    "content": "/*-\n * Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa\n * Portions Copyright (c) 2000 Akamba Corp.\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h 203321 2010-01-31 21:39:25Z luigi $\n */\n\n#ifndef _IP_DUMMYNET_H\n#define _IP_DUMMYNET_H\n\n/*\n * Definition of the kernel-userland API for dummynet.\n *\n * Setsockopt() and getsockopt() pass a batch of objects, each\n * of them starting with a \"struct dn_id\" which should fully identify\n * the object and its relation with others in the sequence.\n * The first object in each request should have\n *\t type= DN_CMD_*, id = DN_API_VERSION.\n * For other objects, type and subtype specify the object, len indicates\n * the total length including the header, and 'id' identifies the specific\n * object.\n *\n * Most objects are numbered with an identifier in the range 1..65535.\n * DN_MAX_ID indicates the first value outside the range.\n */\n\n#define\tDN_API_VERSION\t12500000\n#define\tDN_MAX_ID\t0x10000\n\nstruct dn_id {\n\tuint16_t\tlen;\t/* total obj len including this header */\n\tuint8_t\t\ttype;\n\tuint8_t\t\tsubtype;\n\tuint32_t\tid;\t/* generic id */\n};\n\n/*\n * These values are in the type field of struct dn_id.\n * To preserve the ABI, never rearrange the list or delete\n * entries with the exception of DN_LAST\n */\nenum {\n\tDN_NONE = 0,\n\tDN_LINK = 1,\n\tDN_FS,\n\tDN_SCH,\n\tDN_SCH_I,\n\tDN_QUEUE,\n\tDN_DELAY_LINE,\n\tDN_PROFILE,\n\tDN_FLOW,\t\t/* struct dn_flow */\n\tDN_TEXT,\t\t/* opaque text is the object */\n\n\tDN_CMD_CONFIG = 0x80,\t/* objects follow */\n\tDN_CMD_DELETE,\t\t/* subtype + list of entries */\n\tDN_CMD_GET,\t\t/* subtype + list of entries */\n\tDN_CMD_FLUSH,\n\t/* for compatibility with FreeBSD 7.2/8 */\n\tDN_COMPAT_PIPE,\n\tDN_COMPAT_QUEUE,\n\tDN_GET_COMPAT,\n\n\t/* special commands for emulation of sysctl variables */\n\tDN_SYSCTL_GET,\n\tDN_SYSCTL_SET,\n\n\tDN_LAST,\n};\n\nenum { /* subtype for schedulers, flowset and the like */\n\tDN_SCHED_UNKNOWN = 0,\n\tDN_SCHED_FIFO = 1,\n\tDN_SCHED_WF2QP = 2,\n\t/* others are in individual modules */\n};\n\nenum {\t/* user flags */\n\tDN_HAVE_MASK\t= 0x0001,\t/* fs or sched has a mask */\n\tDN_NOERROR\t= 0x0002,\t/* do not report errors */\n\tDN_QHT_HASH\t= 0x0004,\t/* qht is a hash table */\n\tDN_QSIZE_BYTES\t= 0x0008,\t/* queue size is in bytes */\n\tDN_HAS_PROFILE\t= 0x0010,\t/* a link has a profile */\n\tDN_IS_RED\t= 0x0020,\n\tDN_IS_GENTLE_RED= 0x0040,\n\tDN_PIPE_CMD\t= 0x1000,\t/* pipe config... */\n};\n\n/*\n * link template.\n */\nstruct dn_link {\n\tstruct dn_id oid;\n\n\t/*\n\t * Userland sets bw and delay in bits/s and milliseconds.\n\t * The kernel converts this back and forth to bits/tick and ticks.\n\t * XXX what about burst ?\n\t */\n\tint32_t\t\tlink_nr;\n\tint\t\tbandwidth;\t/* bit/s or bits/tick.   */\n\tint\t\tdelay;\t\t/* ms and ticks */\n\tuint64_t\tburst;\t\t/* scaled. bits*Hz  XXX */\n};\n\n/*\n * A flowset, which is a template for flows. Contains parameters\n * from the command line: id, target scheduler, queue sizes, plr,\n * flow masks, buckets for the flow hash, and possibly scheduler-\n * specific parameters (weight, quantum and so on).\n */\nstruct dn_fs {\n\tstruct dn_id oid;\n\tuint32_t fs_nr;\t\t/* the flowset number */\n\tuint32_t flags;\t\t/* userland flags */\n\tint qsize;\t\t/* queue size in slots or bytes */\n\tint32_t plr;\t\t/* PLR, pkt loss rate (2^31-1 means 100%) */\n\tuint32_t buckets;\t/* buckets used for the queue hash table */\n\n\tstruct ipfw_flow_id flow_mask;\n\tuint32_t sched_nr;\t/* the scheduler we attach to */\n\t/* generic scheduler parameters. Leave them at -1 if unset.\n\t * Now we use 0: weight, 1: lmax, 2: priority\n\t */\n\tint par[4];\n\n\t/* RED/GRED parameters.\n\t * weight and probabilities are in the range 0..1 represented\n\t * in fixed point arithmetic with SCALE_RED decimal bits.\n\t */\n#define SCALE_RED\t16\n#define SCALE(x)\t( (x) << SCALE_RED )\n#define SCALE_VAL(x)\t( (x) >> SCALE_RED )\n#define SCALE_MUL(x,y)\t( ( (x) * (y) ) >> SCALE_RED )\n\tint w_q ;\t\t/* queue weight (scaled) */\n\tint max_th ;\t\t/* maximum threshold for queue (scaled) */\n\tint min_th ;\t\t/* minimum threshold for queue (scaled) */\n\tint max_p ;\t\t/* maximum value for p_b (scaled) */\n\n};\n\n/*\n * dn_flow collects flow_id and stats for queues and scheduler\n * instances, and is used to pass these info to userland.\n * oid.type/oid.subtype describe the object, oid.id is number\n * of the parent object.\n */\nstruct dn_flow {\n\tstruct dn_id\toid;\n\tstruct ipfw_flow_id fid;\n\tuint64_t\ttot_pkts; /* statistics counters  */\n\tuint64_t\ttot_bytes;\n\tuint32_t\tlength; /* Queue length, in packets */\n\tuint32_t\tlen_bytes; /* Queue length, in bytes */\n\tuint32_t\tdrops;\n};\n\n\n/*\n * Scheduler template, mostly indicating the name, number,\n * sched_mask and buckets.\n */\nstruct dn_sch {\n\tstruct dn_id\toid;\n\tuint32_t\tsched_nr; /* N, scheduler number */\n\tuint32_t\tbuckets; /* number of buckets for the instances */\n\tuint32_t\tflags;\t/* have_mask, ... */\n\n\tchar name[16];\t/* null terminated */\n\t/* mask to select the appropriate scheduler instance */\n\tstruct ipfw_flow_id sched_mask; /* M */\n};\n\n\n/* A delay profile is attached to a link.\n * Note that a profile, as any other object, cannot be longer than 2^16\n */\n#define\tED_MAX_SAMPLES_NO\t1024\nstruct dn_profile {\n\tstruct dn_id\toid;\n\t/* fields to simulate a delay profile */\n#define ED_MAX_NAME_LEN\t\t32\n\tchar\tname[ED_MAX_NAME_LEN];\n\tint\tlink_nr;\n\tint\tloss_level;\n\tint\tbandwidth;\t\t\t// XXX use link bandwidth?\n\tint\tsamples_no;\t\t\t/* actual len of samples[] */\n\tint\tsamples[0];\t\t\t/* may be shorter */\n};\n\n\n\n/*\n * Overall structure of dummynet\n\nIn dummynet, packets are selected with the firewall rules, and passed\nto two different objects: PIPE or QUEUE (bad name).\n\nA QUEUE defines a classifier, which groups packets into flows\naccording to a 'mask', puts them into independent queues (one\nper flow) with configurable size and queue management policy,\nand passes flows to a scheduler:\n\n                 (flow_mask|sched_mask)  sched_mask\n\t +---------+   weight Wx  +-------------+\n         |         |->-[flow]-->--|             |-+\n    -->--| QUEUE x |   ...        |             | |\n         |         |->-[flow]-->--| SCHEDuler N | |\n\t +---------+              |             | |\n\t     ...                  |             +--[LINK N]-->--\n\t +---------+   weight Wy  |             | +--[LINK N]-->--\n         |         |->-[flow]-->--|             | |\n    -->--| QUEUE y |   ...        |             | |\n         |         |->-[flow]-->--|             | |\n\t +---------+              +-------------+ |\n\t                            +-------------+\n\nMany QUEUE objects can connect to the same scheduler, each\nQUEUE object can have its own set of parameters.\n\nIn turn, the SCHEDuler 'forks' multiple instances according\nto a 'sched_mask', each instance manages its own set of queues\nand transmits on a private instance of a configurable LINK.\n\nA PIPE is a simplified version of the above, where there\nis no flow_mask, and each scheduler instance handles a single queue.\n\nThe following data structures (visible from userland) describe\nthe objects used by dummynet:\n\n + dn_link, contains the main configuration parameters related\n   to delay and bandwidth;\n + dn_profile describes a delay profile;\n + dn_flow describes the flow status (flow id, statistics)\n   \n + dn_sch describes a scheduler\n + dn_fs describes a flowset (msk, weight, queue parameters)\n\n *\n */\n\n#endif /* _IP_DUMMYNET_H */\n"
  },
  {
    "path": "sys/netinet/ip_fw.h",
    "content": "/*-\n * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: user/luigi/ipfw3-head/sys/netinet/ip_fw.h 202072 2010-01-11 10:12:35Z luigi $\n */\n\n#ifndef _IPFW2_H\n#define _IPFW2_H\n\n/*\n * The default rule number.  By the design of ip_fw, the default rule\n * is the last one, so its number can also serve as the highest number\n * allowed for a rule.  The ip_fw code relies on both meanings of this\n * constant. \n */\n#define\tIPFW_DEFAULT_RULE\t65535\n\n/*\n * The number of ipfw tables.  The maximum allowed table number is the\n * (IPFW_TABLES_MAX - 1).\n */\n#define\tIPFW_TABLES_MAX\t\t128\n\n/*\n * Most commands (queue, pipe, tag, untag, limit...) can have a 16-bit\n * argument between 1 and 65534. The value 0 is unused, the value\n * 65535 (IP_FW_TABLEARG) is used to represent 'tablearg', i.e. the\n * can be 1..65534, or 65535 to indicate the use of a 'tablearg'\n * result of the most recent table() lookup.\n * Note that 16bit is only a historical limit, resulting from\n * the use of a 16-bit fields for that value. In reality, we can have\n * 2^32 pipes, queues, tag values and so on, and use 0 as a tablearg.\n */\n#define\tIPFW_ARG_MIN\t\t1\n#define\tIPFW_ARG_MAX\t\t65534\n#define IP_FW_TABLEARG\t\t65535\t/* XXX should use 0 */\n\n /*\n * Number of entries in the call stack of the call/return commands.\n * Call stack currently is an uint16_t array with rule numbers.\n */\n#define\tIPFW_CALLSTACK_SIZE\t16\n\n/* IP_FW3 header/opcodes */\ntypedef struct _ip_fw3_opheader {\n\tuint16_t opcode;\t/* Operation opcode */\n\tuint16_t reserved[3];\t/* Align to 64-bit boundary */\n} ip_fw3_opheader;\n\n\n/* IPFW extented tables support XXX what namespace ? */\n#define\tIP_FW_TABLE_XADD\t86\t/* add entry */\n#define\tIP_FW_TABLE_XDEL\t87\t/* delete entry */\n#define\tIP_FW_TABLE_XGETSIZE\t88\t/* get table size */\n#define\tIP_FW_TABLE_XLIST\t89\t/* list table contents */\n\n/*\n * The kernel representation of ipfw rules is made of a list of\n * 'instructions' (for all practical purposes equivalent to BPF\n * instructions), which specify which fields of the packet\n * (or its metadata) should be analysed.\n *\n * Each instruction is stored in a structure which begins with\n * \"ipfw_insn\", and can contain extra fields depending on the\n * instruction type (listed below).\n * Note that the code is written so that individual instructions\n * have a size which is a multiple of 32 bits. This means that, if\n * such structures contain pointers or other 64-bit entities,\n * (there is just one instance now) they may end up unaligned on\n * 64-bit architectures, so the must be handled with care.\n *\n * \"enum ipfw_opcodes\" are the opcodes supported. We can have up\n * to 256 different opcodes. When adding new opcodes, they should\n * be appended to the end of the opcode list before O_LAST_OPCODE,\n * this will prevent the ABI from being broken, otherwise users\n * will have to recompile ipfw(8) when they update the kernel.\n */\n\nenum ipfw_opcodes {\t\t/* arguments (4 byte each)\t*/\n\tO_NOP,\n\n\tO_IP_SRC,\t\t/* u32 = IP\t\t\t*/\n\tO_IP_SRC_MASK,\t\t/* ip = IP/mask\t\t\t*/\n\tO_IP_SRC_ME,\t\t/* none\t\t\t\t*/\n\tO_IP_SRC_SET,\t\t/* u32=base, arg1=len, bitmap\t*/\n\n\tO_IP_DST,\t\t/* u32 = IP\t\t\t*/\n\tO_IP_DST_MASK,\t\t/* ip = IP/mask\t\t\t*/\n\tO_IP_DST_ME,\t\t/* none\t\t\t\t*/\n\tO_IP_DST_SET,\t\t/* u32=base, arg1=len, bitmap\t*/\n\n\tO_IP_SRCPORT,\t\t/* (n)port list:mask 4 byte ea\t*/\n\tO_IP_DSTPORT,\t\t/* (n)port list:mask 4 byte ea\t*/\n\tO_PROTO,\t\t/* arg1=protocol\t\t*/\n\n\tO_MACADDR2,\t\t/* 2 mac addr:mask\t\t*/\n\tO_MAC_TYPE,\t\t/* same as srcport\t\t*/\n\n\tO_LAYER2,\t\t/* none\t\t\t\t*/\n\tO_IN,\t\t\t/* none\t\t\t\t*/\n\tO_FRAG,\t\t\t/* none\t\t\t\t*/\n\n\tO_RECV,\t\t\t/* none\t\t\t\t*/\n\tO_XMIT,\t\t\t/* none\t\t\t\t*/\n\tO_VIA,\t\t\t/* none\t\t\t\t*/\n\n\tO_IPOPT,\t\t/* arg1 = 2*u8 bitmap\t\t*/\n\tO_IPLEN,\t\t/* arg1 = len\t\t\t*/\n\tO_IPID,\t\t\t/* arg1 = id\t\t\t*/\n\n\tO_IPTOS,\t\t/* arg1 = id\t\t\t*/\n\tO_IPPRECEDENCE,\t\t/* arg1 = precedence << 5\t*/\n\tO_IPTTL,\t\t/* arg1 = TTL\t\t\t*/\n\n\tO_IPVER,\t\t/* arg1 = version\t\t*/\n\tO_UID,\t\t\t/* u32 = id\t\t\t*/\n\tO_GID,\t\t\t/* u32 = id\t\t\t*/\n\tO_ESTAB,\t\t/* none (tcp established)\t*/\n\tO_TCPFLAGS,\t\t/* arg1 = 2*u8 bitmap\t\t*/\n\tO_TCPWIN,\t\t/* arg1 = desired win\t\t*/\n\tO_TCPSEQ,\t\t/* u32 = desired seq.\t\t*/\n\tO_TCPACK,\t\t/* u32 = desired seq.\t\t*/\n\tO_ICMPTYPE,\t\t/* u32 = icmp bitmap\t\t*/\n\tO_TCPOPTS,\t\t/* arg1 = 2*u8 bitmap\t\t*/\n\n\tO_VERREVPATH,\t\t/* none\t\t\t\t*/\n\tO_VERSRCREACH,\t\t/* none\t\t\t\t*/\n\n\tO_PROBE_STATE,\t\t/* none\t\t\t\t*/\n\tO_KEEP_STATE,\t\t/* none\t\t\t\t*/\n\tO_LIMIT,\t\t/* ipfw_insn_limit\t\t*/\n\tO_LIMIT_PARENT,\t\t/* dyn_type, not an opcode.\t*/\n\n\t/*\n\t * These are really 'actions'.\n\t */\n\n\tO_LOG,\t\t\t/* ipfw_insn_log\t\t*/\n\tO_PROB,\t\t\t/* u32 = match probability\t*/\n\n\tO_CHECK_STATE,\t\t/* none\t\t\t\t*/\n\tO_ACCEPT,\t\t/* none\t\t\t\t*/\n\tO_DENY,\t\t\t/* none \t\t\t*/\n\tO_REJECT,\t\t/* arg1=icmp arg (same as deny)\t*/\n\tO_COUNT,\t\t/* none\t\t\t\t*/\n\tO_SKIPTO,\t\t/* arg1=next rule number\t*/\n\tO_PIPE,\t\t\t/* arg1=pipe number\t\t*/\n\tO_QUEUE,\t\t/* arg1=queue number\t\t*/\n\tO_DIVERT,\t\t/* arg1=port number\t\t*/\n\tO_TEE,\t\t\t/* arg1=port number\t\t*/\n\tO_FORWARD_IP,\t\t/* fwd sockaddr\t\t\t*/\n\tO_FORWARD_MAC,\t\t/* fwd mac\t\t\t*/\n\tO_NAT,                  /* nope                         */\n\tO_REASS,                /* none                         */\n\t\n\t/*\n\t * More opcodes.\n\t */\n\tO_IPSEC,\t\t/* has ipsec history \t\t*/\n\tO_IP_SRC_LOOKUP,\t/* arg1=table number, u32=value\t*/\n\tO_IP_DST_LOOKUP,\t/* arg1=table number, u32=value\t*/\n\tO_ANTISPOOF,\t\t/* none\t\t\t\t*/\n\tO_JAIL,\t\t\t/* u32 = id\t\t\t*/\n\tO_ALTQ,\t\t\t/* u32 = altq classif. qid\t*/\n\tO_DIVERTED,\t\t/* arg1=bitmap (1:loop, 2:out)\t*/\n\tO_TCPDATALEN,\t\t/* arg1 = tcp data len\t\t*/\n\tO_IP6_SRC,\t\t/* address without mask\t\t*/\n\tO_IP6_SRC_ME,\t\t/* my addresses\t\t\t*/\n\tO_IP6_SRC_MASK,\t\t/* address with the mask\t*/\n\tO_IP6_DST,\n\tO_IP6_DST_ME,\n\tO_IP6_DST_MASK,\n\tO_FLOW6ID,\t\t/* for flow id tag in the ipv6 pkt */\n\tO_ICMP6TYPE,\t\t/* icmp6 packet type filtering\t*/\n\tO_EXT_HDR,\t\t/* filtering for ipv6 extension header */\n\tO_IP6,\n\n\t/*\n\t * actions for ng_ipfw\n\t */\n\tO_NETGRAPH,\t\t/* send to ng_ipfw\t\t*/\n\tO_NGTEE,\t\t/* copy to ng_ipfw\t\t*/\n\n\tO_IP4,\n\n\tO_UNREACH6,\t\t/* arg1=icmpv6 code arg (deny)  */\n\n\tO_TAG,   \t\t/* arg1=tag number */\n\tO_TAGGED,\t\t/* arg1=tag number */\n\n\tO_SETFIB,\t\t/* arg1=FIB number */\n\tO_FIB,\t\t\t/* arg1=FIB desired fib number */\n\n\tO_SOCKARG,\t\t/* socket argument */\n\n\tO_CALLRETURN,\t\t/* arg1=called rule number */\n\n\tO_FORWARD_IP6,\t\t/* fwd sockaddr_in6             */\n\n\tO_LAST_OPCODE\t\t/* not an opcode!\t\t*/\n};\n\n\n/*\n * The extension header are filtered only for presence using a bit\n * vector with a flag for each header.\n */\n#define EXT_FRAGMENT\t0x1\n#define EXT_HOPOPTS\t0x2\n#define EXT_ROUTING\t0x4\n#define EXT_AH\t\t0x8\n#define EXT_ESP\t\t0x10\n#define EXT_DSTOPTS\t0x20\n#define EXT_RTHDR0\t\t0x40\n#define EXT_RTHDR2\t\t0x80\n\n/*\n * Template for instructions.\n *\n * ipfw_insn is used for all instructions which require no operands,\n * a single 16-bit value (arg1), or a couple of 8-bit values.\n *\n * For other instructions which require different/larger arguments\n * we have derived structures, ipfw_insn_*.\n *\n * The size of the instruction (in 32-bit words) is in the low\n * 6 bits of \"len\". The 2 remaining bits are used to implement\n * NOT and OR on individual instructions. Given a type, you can\n * compute the length to be put in \"len\" using F_INSN_SIZE(t)\n *\n * F_NOT\tnegates the match result of the instruction.\n *\n * F_OR\t\tis used to build or blocks. By default, instructions\n *\t\tare evaluated as part of a logical AND. An \"or\" block\n *\t\t{ X or Y or Z } contains F_OR set in all but the last\n *\t\tinstruction of the block. A match will cause the code\n *\t\tto skip past the last instruction of the block.\n *\n * NOTA BENE: in a couple of places we assume that\n *\tsizeof(ipfw_insn) == sizeof(u_int32_t)\n * this needs to be fixed.\n *\n */\ntypedef struct\t_ipfw_insn {\t/* template for instructions */\n\tu_int8_t \topcode;\n\tu_int8_t\tlen;\t/* number of 32-bit words */\n#define\tF_NOT\t\t0x80\n#define\tF_OR\t\t0x40\n#define\tF_LEN_MASK\t0x3f\n#define\tF_LEN(cmd)\t((cmd)->len & F_LEN_MASK)\n\n\tu_int16_t\targ1;\n} ipfw_insn;\n\n/*\n * The F_INSN_SIZE(type) computes the size, in 4-byte words, of\n * a given type.\n */\n#define\tF_INSN_SIZE(t)\t((sizeof (t))/sizeof(u_int32_t))\n\n/*\n * This is used to store an array of 16-bit entries (ports etc.)\n */\ntypedef struct\t_ipfw_insn_u16 {\n\tipfw_insn o;\n\tu_int16_t ports[2];\t/* there may be more */\n} ipfw_insn_u16;\n\n/*\n * This is used to store an array of 32-bit entries\n * (uid, single IPv4 addresses etc.)\n */\ntypedef struct\t_ipfw_insn_u32 {\n\tipfw_insn o;\n\tu_int32_t d[1];\t/* one or more */\n} ipfw_insn_u32;\n\n/*\n * This is used to store IP addr-mask pairs.\n */\ntypedef struct\t_ipfw_insn_ip {\n\tipfw_insn o;\n\tstruct in_addr\taddr;\n\tstruct in_addr\tmask;\n} ipfw_insn_ip;\n\n/*\n * This is used to forward to a given address (ip).\n */\ntypedef struct  _ipfw_insn_sa {\n\tipfw_insn o;\n\tstruct sockaddr_in sa;\n} ipfw_insn_sa;\n\n/*\n* This is used to forward to a given address (ipv6).\n*/\ntypedef struct _ipfw_insn_sa6 {\n\tipfw_insn o;\n\tstruct sockaddr_in6 sa;\n} ipfw_insn_sa6;\n\n/*\n * This is used for MAC addr-mask pairs.\n */\ntypedef struct\t_ipfw_insn_mac {\n\tipfw_insn o;\n\tu_char addr[12];\t/* dst[6] + src[6] */\n\tu_char mask[12];\t/* dst[6] + src[6] */\n} ipfw_insn_mac;\n\n/*\n * This is used for interface match rules (recv xx, xmit xx).\n */\ntypedef struct\t_ipfw_insn_if {\n\tipfw_insn o;\n\tunion {\n\t\tstruct in_addr ip;\n\t\tint glob;\n\t} p;\n\tchar name[IFNAMSIZ];\n} ipfw_insn_if;\n\n/*\n * This is used for storing an altq queue id number.\n */\ntypedef struct _ipfw_insn_altq {\n\tipfw_insn\to;\n\tu_int32_t\tqid;\n} ipfw_insn_altq;\n\n/*\n * This is used for limit rules.\n */\ntypedef struct\t_ipfw_insn_limit {\n\tipfw_insn o;\n\tu_int8_t _pad;\n\tu_int8_t limit_mask;\t/* combination of DYN_* below\t*/\n#define\tDYN_SRC_ADDR\t0x1\n#define\tDYN_SRC_PORT\t0x2\n#define\tDYN_DST_ADDR\t0x4\n#define\tDYN_DST_PORT\t0x8\n\n\tu_int16_t conn_limit;\n} ipfw_insn_limit;\n\n/*\n * This is used for log instructions.\n */\ntypedef struct  _ipfw_insn_log {\n        ipfw_insn o;\n\tu_int32_t max_log;\t/* how many do we log -- 0 = all */\n\tu_int32_t log_left;\t/* how many left to log \t*/\n} ipfw_insn_log;\n\n/*\n * Data structures required by both ipfw(8) and ipfw(4) but not part of the\n * management API are protected by IPFW_INTERNAL.\n */\n#ifdef IPFW_INTERNAL\n/* Server pool support (LSNAT). */\nstruct cfg_spool {\n\tLIST_ENTRY(cfg_spool)   _next;          /* chain of spool instances */\n\tstruct in_addr          addr;\n\tu_short                 port;\n};\n#endif\n\n/* Redirect modes id. */\n#define REDIR_ADDR      0x01\n#define REDIR_PORT      0x02\n#define REDIR_PROTO     0x04\n\n#ifdef IPFW_INTERNAL\n/* Nat redirect configuration. */\nstruct cfg_redir {\n\tLIST_ENTRY(cfg_redir)   _next;          /* chain of redir instances */\n\tu_int16_t               mode;           /* type of redirect mode */\n\tstruct in_addr\t        laddr;          /* local ip address */\n\tstruct in_addr\t        paddr;          /* public ip address */\n\tstruct in_addr\t        raddr;          /* remote ip address */\n\tu_short                 lport;          /* local port */\n\tu_short                 pport;          /* public port */\n\tu_short                 rport;          /* remote port  */\n\tu_short                 pport_cnt;      /* number of public ports */\n\tu_short                 rport_cnt;      /* number of remote ports */\n\tint                     proto;          /* protocol: tcp/udp */\n\tstruct alias_link       **alink;\t\n\t/* num of entry in spool chain */\n\tu_int16_t               spool_cnt;      \n\t/* chain of spool instances */\n\tLIST_HEAD(spool_chain, cfg_spool) spool_chain;\n};\n#endif\n\n#define NAT_BUF_LEN     1024\n\n#ifdef IPFW_INTERNAL\n/* Nat configuration data struct. */\nstruct cfg_nat {\n\t/* chain of nat instances */\n\tLIST_ENTRY(cfg_nat)     _next;\n\tint                     id;                     /* nat id */\n\tstruct in_addr          ip;                     /* nat ip address */\n\tchar                    if_name[IF_NAMESIZE];   /* interface name */\n\tint                     mode;                   /* aliasing mode */\n\tstruct libalias\t        *lib;                   /* libalias instance */\n\t/* number of entry in spool chain */\n\tint                     redir_cnt;              \n\t/* chain of redir instances */\n\tLIST_HEAD(redir_chain, cfg_redir) redir_chain;  \n};\n#endif\n\n#define SOF_NAT         sizeof(struct cfg_nat)\n#define SOF_REDIR       sizeof(struct cfg_redir)\n#define SOF_SPOOL       sizeof(struct cfg_spool)\n\n/* Nat command. */\ntypedef struct\t_ipfw_insn_nat {\n \tipfw_insn\to;\n \tstruct cfg_nat *nat;\t\n} ipfw_insn_nat;\n\n/* Apply ipv6 mask on ipv6 addr */\n#define APPLY_MASK(addr,mask)                          \\\n    (addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \\\n    (addr)->__u6_addr.__u6_addr32[1] &= (mask)->__u6_addr.__u6_addr32[1]; \\\n    (addr)->__u6_addr.__u6_addr32[2] &= (mask)->__u6_addr.__u6_addr32[2]; \\\n    (addr)->__u6_addr.__u6_addr32[3] &= (mask)->__u6_addr.__u6_addr32[3];\n\n/* Structure for ipv6 */\ntypedef struct _ipfw_insn_ip6 {\n       ipfw_insn o;\n       struct in6_addr addr6;\n       struct in6_addr mask6;\n} ipfw_insn_ip6;\n\n/* Used to support icmp6 types */\ntypedef struct _ipfw_insn_icmp6 {\n       ipfw_insn o;\n       uint32_t d[7]; /* XXX This number si related to the netinet/icmp6.h\n                       *     define ICMP6_MAXTYPE\n                       *     as follows: n = ICMP6_MAXTYPE/32 + 1\n                        *     Actually is 203 \n                       */\n} ipfw_insn_icmp6;\n\n/*\n * Here we have the structure representing an ipfw rule.\n *\n * It starts with a general area (with link fields and counters)\n * followed by an array of one or more instructions, which the code\n * accesses as an array of 32-bit values.\n *\n * Given a rule pointer  r:\n *\n *  r->cmd\t\tis the start of the first instruction.\n *  ACTION_PTR(r)\tis the start of the first action (things to do\n *\t\t\tonce a rule matched).\n *\n * When assembling instruction, remember the following:\n *\n *  + if a rule has a \"keep-state\" (or \"limit\") option, then the\n *\tfirst instruction (at r->cmd) MUST BE an O_PROBE_STATE\n *  + if a rule has a \"log\" option, then the first action\n *\t(at ACTION_PTR(r)) MUST be O_LOG\n *  + if a rule has an \"altq\" option, it comes after \"log\"\n *  + if a rule has an O_TAG option, it comes after \"log\" and \"altq\"\n *\n * NOTE: we use a simple linked list of rules because we never need\n * \tto delete a rule without scanning the list. We do not use\n *\tqueue(3) macros for portability and readability.\n */\n\nstruct ip_fw {\n#ifdef _X64EMU\n\t\tint32_t pad1;\n#endif\n\tstruct ip_fw\t*x_next;\t/* linked list of rules\t\t*/\n#ifdef _X64EMU\n\t\tint32_t pad2;\n#endif\n\tstruct ip_fw\t*next_rule;\t/* ptr to next [skipto] rule\t*/\n\t/* 'next_rule' is used to pass up 'set_disable' status\t\t*/\n\n\tuint16_t\tact_ofs;\t/* offset of action in 32-bit units */\n\tuint16_t\tcmd_len;\t/* # of 32-bit words in cmd\t*/\n\tuint16_t\trulenum;\t/* rule number\t\t\t*/\n\tuint8_t\tset;\t\t/* rule set (0..31)\t\t*/\n#define\tRESVD_SET\t31\t/* set for default and persistent rules */\n\tuint8_t\t\t_pad;\t\t/* padding\t\t\t*/\n\tuint32_t\tid;\t\t/* rule id */\n\n\t/* These fields are present in all rules.\t\t\t*/\n\tuint64_t\tpcnt;\t\t/* Packet counter\t\t*/\n\tuint64_t\tbcnt;\t\t/* Byte counter\t\t\t*/\n\tuint32_t\ttimestamp;\t/* tv_sec of last match\t\t*/\n\n\tipfw_insn\tcmd[1];\t\t/* storage for commands\t\t*/\n};\n\n#define ACTION_PTR(rule)\t\t\t\t\\\n\t(ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) )\n\n#define RULESIZE(rule)  (sizeof(struct ip_fw) + \\\n\t((struct ip_fw *)(rule))->cmd_len * 4 - 4)\n\n#if 1 // should be moved to in.h\n/*\n * This structure is used as a flow mask and a flow id for various\n * parts of the code.\n * addr_type is used in userland and kernel to mark the address type.\n * fib is used in the kernel to record the fib in use.\n * _flags is used in the kernel to store tcp flags for dynamic rules.\n */\nstruct ipfw_flow_id {\n\tuint32_t\tdst_ip;\n\tuint32_t\tsrc_ip;\n\tuint16_t\tdst_port;\n\tuint16_t\tsrc_port;\n\tuint8_t\t\tfib;\n\tuint8_t\t\tproto;\n\tuint8_t\t\t_flags;\t/* protocol-specific flags */\n\tuint8_t\t\taddr_type; /* 4=ip4, 6=ip6, 1=ether ? */\n\tstruct in6_addr dst_ip6;\n\tstruct in6_addr src_ip6;\n\tuint32_t\tflow_id6;\n\tuint32_t\textra; /* queue/pipe or frag_id */\n};\n#endif\n\n#define IS_IP6_FLOW_ID(id)\t((id)->addr_type == 6)\n\n/*\n * Dynamic ipfw rule.\n */\ntypedef struct _ipfw_dyn_rule ipfw_dyn_rule;\n\nstruct _ipfw_dyn_rule {\n\tipfw_dyn_rule\t*next;\t\t/* linked list of rules.\t*/\n\tstruct ip_fw *rule;\t\t/* pointer to rule\t\t*/\n\t/* 'rule' is used to pass up the rule number (from the parent)\t*/\n\n\tipfw_dyn_rule *parent;\t\t/* pointer to parent rule\t*/\n\tu_int64_t\tpcnt;\t\t/* packet match counter\t\t*/\n\tu_int64_t\tbcnt;\t\t/* byte match counter\t\t*/\n\tstruct ipfw_flow_id id;\t\t/* (masked) flow id\t\t*/\n\tu_int32_t\texpire;\t\t/* expire time\t\t\t*/\n\tu_int32_t\tbucket;\t\t/* which bucket in hash table\t*/\n\tu_int32_t\tstate;\t\t/* state of this rule (typically a\n\t\t\t\t\t * combination of TCP flags)\n\t\t\t\t\t */\n\tu_int32_t\tack_fwd;\t/* most recent ACKs in forward\t*/\n\tu_int32_t\tack_rev;\t/* and reverse directions (used\t*/\n\t\t\t\t\t/* to generate keepalives)\t*/\n\tu_int16_t\tdyn_type;\t/* rule type\t\t\t*/\n\tu_int16_t\tcount;\t\t/* refcount\t\t\t*/\n};\n\n/*\n * Definitions for IP option names.\n */\n#define\tIP_FW_IPOPT_LSRR\t0x01\n#define\tIP_FW_IPOPT_SSRR\t0x02\n#define\tIP_FW_IPOPT_RR\t\t0x04\n#define\tIP_FW_IPOPT_TS\t\t0x08\n\n/*\n * Definitions for TCP option names.\n */\n#define\tIP_FW_TCPOPT_MSS\t0x01\n#define\tIP_FW_TCPOPT_WINDOW\t0x02\n#define\tIP_FW_TCPOPT_SACK\t0x04\n#define\tIP_FW_TCPOPT_TS\t\t0x08\n#define\tIP_FW_TCPOPT_CC\t\t0x10\n\n#define\tICMP_REJECT_RST\t\t0x100\t/* fake ICMP code (send a TCP RST) */\n#define\tICMP6_UNREACH_RST\t0x100\t/* fake ICMPv6 code (send a TCP RST) */\n\n/*\n * These are used for lookup tables.\n */\n\n#define\tIPFW_TABLE_CIDR\t\t1\t/* Table for holding IPv4/IPv6 prefixes */\n#define\tIPFW_TABLE_INTERFACE\t2\t/* Table for holding interface names */\n#define\tIPFW_TABLE_MAXTYPE\t2\t/* Maximum valid number */\n\ntypedef struct\t_ipfw_table_entry {\n\tin_addr_t\taddr;\t\t/* network address\t\t*/\n\tu_int32_t\tvalue;\t\t/* value\t\t\t*/\n\tu_int16_t\ttbl;\t\t/* table number\t\t\t*/\n\tu_int8_t\tmasklen;\t/* mask length\t\t\t*/\n} ipfw_table_entry;\n\ntypedef struct _ipfw_table_xentry {\n\tuint16_t\tlen;\t\t/* Total entry length\t\t*/\n\tuint8_t\t\ttype;\t\t/* entry type\t\t\t*/\n\tuint8_t\t\tmasklen;\t/* mask length\t\t\t*/\n\tuint16_t\ttbl;\t\t/* table number\t\t\t*/\n\tuint32_t\tvalue;\t\t/* value\t\t\t*/\n\tunion {\n\t\t/* Longest field needs to be aligned by 4-byte boundary */\n\t\tstruct\tin6_addr addr6;\t/* IPv6 address\t\t\t*/\n\t\tchar\tiface[IF_NAMESIZE];     /* interface name\t*/\n\t} k;\n} ipfw_table_xentry;\n\ntypedef struct\t_ipfw_table {\n\tu_int32_t\tsize;\t\t/* size of entries in bytes\t*/\n\tu_int32_t\tcnt;\t\t/* # of entries\t\t\t*/\n\tu_int16_t\ttbl;\t\t/* table number\t\t\t*/\n\tipfw_table_entry ent[0];\t/* entries\t\t\t*/\n} ipfw_table;\n\ntypedef struct _ipfw_xtable {\n\tip_fw3_opheader opheader;\t/* eXtended tables are controlled via IP_FW3 */\n\tuint32_t\tsize;\t\t/* size of entries in bytes\t*/\n\tuint32_t\tcnt;\t\t/* # of entries\t\t\t*/\n\tuint16_t\ttbl;\t\t/* table number\t\t\t*/\n\tuint8_t\t\ttype;\t\t/* table type\t\t\t*/\n\tipfw_table_xentry xent[0];\t/* entries\t\t\t*/\n} ipfw_xtable;\n\n#endif /* _IPFW2_H */\n"
  },
  {
    "path": "sys/netinet/ip_icmp.h",
    "content": "/*\n * additional define not present in linux\n * should go in glue.h\n */\n#ifndef _NETINET_IP_ICMP_H_\n#define _NETINET_IP_ICMP_H_\n\n#define ICMP_MAXTYPE            40      /* defined as 18 in compat.h */\n#define ICMP_ROUTERSOLICIT      10              /* router solicitation */\n#define ICMP_TSTAMP             13              /* timestamp request */\n#define ICMP_IREQ               15              /* information request */\n#define ICMP_MASKREQ            17              /* address mask request */\n#define         ICMP_UNREACH_HOST       1               /* bad host */\n\n#define ICMP_UNREACH            3               /* dest unreachable, codes: */\n\n#endif /* _NETINET_IP_ICMP_H_ */\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_heap.c",
    "content": "/*-\n * Copyright (c) 1998-2002,2010 Luigi Rizzo, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * Binary heap and hash tables, used in dummynet\n *\n * $Id: dn_heap.c 11480 2012-07-31 08:02:00Z luigi $\n */\n\n#include <sys/cdefs.h>\n#include <sys/param.h>\n#ifdef _KERNEL\n__FBSDID(\"$FreeBSD: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_heap.c 203279 2010-01-31 12:20:29Z luigi $\");\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/kernel.h>\n#include <netinet/ipfw/dn_heap.h>\n#ifndef log\n#define log(x, arg...)\n#endif\n\n#else /* !_KERNEL */\n\n#include <stdio.h>\n#include <dn_test.h>\n#include <strings.h>\n#include <stdlib.h>\n\n#include  \"dn_heap.h\"\n#define log(x, arg...)\tfprintf(stderr, ## arg)\n#define panic(x...)\tfprintf(stderr, ## x), exit(1)\n#define MALLOC_DEFINE(a, b, c)\nstatic void *my_malloc(int s) {\treturn malloc(s); }\nstatic void my_free(void *p) {\tfree(p); }\n#define malloc(s, t, w)\tmy_malloc(s)\n#define free(p, t)\tmy_free(p)\n#endif /* !_KERNEL */\n\nMALLOC_DEFINE(M_DN_HEAP, \"dummynet\", \"dummynet heap\");\n\n/*\n * Heap management functions.\n *\n * In the heap, first node is element 0. Children of i are 2i+1 and 2i+2.\n * Some macros help finding parent/children so we can optimize them.\n *\n * heap_init() is called to expand the heap when needed.\n * Increment size in blocks of 16 entries.\n * Returns 1 on error, 0 on success\n */\n#define HEAP_FATHER(x) ( ( (x) - 1 ) / 2 )\n#define HEAP_LEFT(x) ( (x)+(x) + 1 )\n#define\tHEAP_SWAP(a, b, buffer) { buffer = a ; a = b ; b = buffer ; }\n#define HEAP_INCREMENT\t15\n\nstatic int\nheap_resize(struct dn_heap *h, unsigned int new_size)\n{\n\tstruct dn_heap_entry *p;\n\n\tif (h->size >= new_size )\t/* have enough room */\n\t\treturn 0;\n#if 1  /* round to the next power of 2 */\n\tnew_size |= new_size >> 1;\n\tnew_size |= new_size >> 2;\n\tnew_size |= new_size >> 4;\n\tnew_size |= new_size >> 8;\n\tnew_size |= new_size >> 16;\n#else\n\tnew_size = (new_size + HEAP_INCREMENT ) & ~HEAP_INCREMENT;\n#endif\n\tp = malloc(new_size * sizeof(*p), M_DN_HEAP, M_NOWAIT);\n\tif (p == NULL) {\n\t\tprintf(\"--- %s, resize %d failed\\n\", __func__, new_size );\n\t\treturn 1; /* error */\n\t}\n\tif (h->size > 0) {\n\t\tbcopy(h->p, p, h->size * sizeof(*p) );\n\t\tfree(h->p, M_DN_HEAP);\n\t}\n\th->p = p;\n\th->size = new_size;\n\treturn 0;\n}\n\nint\nheap_init(struct dn_heap *h, int size, int ofs)\n{\n\tif (heap_resize(h, size))\n\t\treturn 1;\n\th->elements = 0;\n\th->ofs = ofs;\n\treturn 0;\n}\n\n/*\n * Insert element in heap. Normally, p != NULL, we insert p in\n * a new position and bubble up. If p == NULL, then the element is\n * already in place, and key is the position where to start the\n * bubble-up.\n * Returns 1 on failure (cannot allocate new heap entry)\n *\n * If ofs > 0 the position (index, int) of the element in the heap is\n * also stored in the element itself at the given offset in bytes.\n */\n#define SET_OFFSET(h, i) do {\t\t\t\t\t\\\n\tif (h->ofs > 0)\t\t\t\t\t\t\\\n\t    *((int32_t *)((char *)(h->p[i].object) + h->ofs)) = i;\t\\\n\t} while (0)\n/*\n * RESET_OFFSET is used for sanity checks. It sets ofs\n * to an invalid value.\n */\n#define RESET_OFFSET(h, i) do {\t\t\t\t\t\\\n\tif (h->ofs > 0)\t\t\t\t\t\t\\\n\t    *((int32_t *)((char *)(h->p[i].object) + h->ofs)) = -16;\t\\\n\t} while (0)\n\nint\nheap_insert(struct dn_heap *h, uint64_t key1, void *p)\n{\n\tint son = h->elements;\n\n\t//log(\"%s key %llu p %p\\n\", __FUNCTION__, key1, p);\n\tif (p == NULL) { /* data already there, set starting point */\n\t\tson = key1;\n\t} else { /* insert new element at the end, possibly resize */\n\t\tson = h->elements;\n\t\tif (son == h->size) /* need resize... */\n\t\t\t// XXX expand by 16 or so\n\t\t\tif (heap_resize(h, h->elements+16) )\n\t\t\t\treturn 1; /* failure... */\n\t\th->p[son].object = p;\n\t\th->p[son].key = key1;\n\t\th->elements++;\n\t}\n\t/* make sure that son >= father along the path */\n\twhile (son > 0) {\n\t\tint father = HEAP_FATHER(son);\n\t\tstruct dn_heap_entry tmp;\n\n\t\tif (DN_KEY_LT( h->p[father].key, h->p[son].key ) )\n\t\t\tbreak; /* found right position */\n\t\t/* son smaller than father, swap and repeat */\n\t\tHEAP_SWAP(h->p[son], h->p[father], tmp);\n\t\tSET_OFFSET(h, son);\n\t\tson = father;\n\t}\n\tSET_OFFSET(h, son);\n\treturn 0;\n}\n\n/*\n * remove top element from heap, or obj if obj != NULL\n */\nvoid\nheap_extract(struct dn_heap *h, void *obj)\n{\n\tint child, father, max = h->elements - 1;\n\n\tif (max < 0) {\n\t\tprintf(\"--- %s: empty heap 0x%p\\n\", __FUNCTION__, h);\n\t\treturn;\n\t}\n\tif (obj == NULL)\n\t\tfather = 0; /* default: move up smallest child */\n\telse { /* extract specific element, index is at offset */\n\t\tif (h->ofs <= 0)\n\t\t\tpanic(\"%s: extract from middle not set on %p\\n\",\n\t\t\t\t__FUNCTION__, h);\n\t\tfather = *((int *)((char *)obj + h->ofs));\n\t\tif (father < 0 || father >= h->elements) {\n\t\t\tpanic(\"%s: father %d out of bound 0..%d\\n\",\n\t\t\t\t__FUNCTION__, father, h->elements);\n\t\t}\n\t}\n\t/*\n\t * below, father is the index of the empty element, which\n\t * we replace at each step with the smallest child until we\n\t * reach the bottom level.\n\t */\n\t// XXX why removing RESET_OFFSET increases runtime by 10% ?\n\tRESET_OFFSET(h, father);\n\twhile ( (child = HEAP_LEFT(father)) <= max ) {\n\t\tif (child != max &&\n\t\t    DN_KEY_LT(h->p[child+1].key, h->p[child].key) )\n\t\t\tchild++; /* take right child, otherwise left */\n\t\th->p[father] = h->p[child];\n\t\tSET_OFFSET(h, father);\n\t\tfather = child;\n\t}\n\th->elements--;\n\tif (father != max) {\n\t\t/*\n\t\t * Fill hole with last entry and bubble up,\n\t\t * reusing the insert code\n\t\t */\n\t\th->p[father] = h->p[max];\n\t\theap_insert(h, father, NULL);\n\t}\n}\n\n#if 0\n/*\n * change object position and update references\n * XXX this one is never used!\n */\nstatic void\nheap_move(struct dn_heap *h, uint64_t new_key, void *object)\n{\n\tint temp, i, max = h->elements-1;\n\tstruct dn_heap_entry *p, buf;\n\n\tif (h->ofs <= 0)\n\t\tpanic(\"cannot move items on this heap\");\n\tp = h->p;\t/* shortcut */\n\n\ti = *((int *)((char *)object + h->ofs));\n\tif (DN_KEY_LT(new_key, p[i].key) ) { /* must move up */\n\t\tp[i].key = new_key;\n\t\tfor (; i>0 &&\n\t\t    DN_KEY_LT(new_key, p[(temp = HEAP_FATHER(i))].key);\n\t\t    i = temp ) { /* bubble up */\n\t\t\tHEAP_SWAP(p[i], p[temp], buf);\n\t\t\tSET_OFFSET(h, i);\n\t\t}\n\t} else {\t\t/* must move down */\n\t\tp[i].key = new_key;\n\t\twhile ( (temp = HEAP_LEFT(i)) <= max ) {\n\t\t\t/* found left child */\n\t\t\tif (temp != max &&\n\t\t\t    DN_KEY_LT(p[temp+1].key, p[temp].key))\n\t\t\t\ttemp++; /* select child with min key */\n\t\t\tif (DN_KEY_LT(>p[temp].key, new_key)) {\n\t\t\t\t/* go down */\n\t\t\t\tHEAP_SWAP(p[i], p[temp], buf);\n\t\t\t\tSET_OFFSET(h, i);\n\t\t\t} else\n\t\t\t\tbreak;\n\t\t\ti = temp;\n\t\t}\n\t}\n\tSET_OFFSET(h, i);\n}\n#endif /* heap_move, unused */\n\n/*\n * heapify() will reorganize data inside an array to maintain the\n * heap property. It is needed when we delete a bunch of entries.\n */\nstatic void\nheapify(struct dn_heap *h)\n{\n\tint i;\n\n\tfor (i = 0; i < h->elements; i++ )\n\t\theap_insert(h, i , NULL);\n}\n\nint\nheap_scan(struct dn_heap *h, int (*fn)(void *, uintptr_t),\n\tuintptr_t arg)\n{\n\tint i, ret, found;\n\n\tfor (i = found = 0 ; i < h->elements ;) {\n\t\tret = fn(h->p[i].object, arg);\n\t\tif (ret & HEAP_SCAN_DEL) {\n\t\t\th->elements-- ;\n\t\t\th->p[i] = h->p[h->elements] ;\n\t\t\tfound++ ;\n\t\t} else\n\t\t\ti++ ;\n\t\tif (ret & HEAP_SCAN_END)\n\t\t\tbreak;\n\t}\n\tif (found)\n\t\theapify(h);\n\treturn found;\n}\n\n/*\n * cleanup the heap and free data structure\n */\nvoid\nheap_free(struct dn_heap *h)\n{\n\tif (h->size >0 )\n\t\tfree(h->p, M_DN_HEAP);\n\tbzero(h, sizeof(*h) );\n}\n\n/*\n * hash table support.\n */\n\nstruct dn_ht {\n        int buckets;            /* how many buckets, really buckets - 1*/\n        int entries;            /* how many entries */\n        int ofs;\t        /* offset of link field */\n        uint32_t (*hash)(uintptr_t, int, void *arg);\n        int (*match)(void *_el, uintptr_t key, int, void *);\n        void *(*newh)(uintptr_t, int, void *);\n        void **ht;              /* bucket heads */\n};\n/*\n * Initialize, allocating bucket pointers inline.\n * Recycle previous record if possible.\n * If the 'newh' function is not supplied, we assume that the\n * key passed to ht_find is the same object to be stored in.\n */\nstruct dn_ht *\ndn_ht_init(struct dn_ht *ht, int buckets, int ofs,\n        uint32_t (*h)(uintptr_t, int, void *),\n        int (*match)(void *, uintptr_t, int, void *),\n\tvoid *(*newh)(uintptr_t, int, void *))\n{\n\tint l;\n\n\t/*\n\t * Notes about rounding bucket size to a power of two.\n\t * Given the original bucket size, we compute the nearest lower and\n\t * higher power of two, minus 1  (respectively b_min and b_max) because\n\t * this value will be used to do an AND with the index returned\n\t * by hash function.\n\t * To choice between these two values, the original bucket size is\n\t * compared with b_min. If the original size is greater than 4/3 b_min,\n\t * we round the bucket size to b_max, else to b_min.\n\t * This ratio try to round to the nearest power of two, advantaging\n\t * the greater size if the different between two power is relatively\n\t * big.\n\t * Rounding the bucket size to a power of two avoid the use of\n\t * module when calculating the correct bucket.\n\t * The ht->buckets variable store the bucket size - 1 to simply\n\t * do an AND between the index returned by hash function and ht->bucket\n\t * instead of a module.\n\t */\n\tint b_min; /* min buckets */\n\tint b_max; /* max buckets */\n\tint b_ori; /* original buckets */\n\n\tif (h == NULL || match == NULL) {\n\t\tprintf(\"--- missing hash or match function\");\n\t\treturn NULL;\n\t}\n\tif (buckets < 1 || buckets > 65536)\n\t\treturn NULL;\n\n\tb_ori = buckets;\n\t/* calculate next power of 2, - 1*/\n\tbuckets |= buckets >> 1;\n\tbuckets |= buckets >> 2;\n\tbuckets |= buckets >> 4;\n\tbuckets |= buckets >> 8;\n\tbuckets |= buckets >> 16;\n\n\tb_max = buckets; /* Next power */\n\tb_min = buckets >> 1; /* Previous power */\n\n\t/* Calculate the 'nearest' bucket size */\n\tif (b_min * 4000 / 3000 < b_ori)\n\t\tbuckets = b_max;\n\telse\n\t\tbuckets = b_min;\n\n\tif (ht) {\t/* see if we can reuse */\n\t\tif (buckets <= ht->buckets) {\n\t\t\tht->buckets = buckets;\n\t\t} else {\n\t\t\t/* free pointers if not allocated inline */\n\t\t\tif (ht->ht != (void *)(ht + 1))\n\t\t\t\tfree(ht->ht, M_DN_HEAP);\n\t\t\tfree(ht, M_DN_HEAP);\n\t\t\tht = NULL;\n\t\t}\n\t}\n\tif (ht == NULL) {\n\t\t/* Allocate buckets + 1 entries because buckets is use to\n\t\t * do the AND with the index returned by hash function\n\t\t */\n\t\tl = sizeof(*ht) + (buckets + 1) * sizeof(void **);\n\t\tht = malloc(l, M_DN_HEAP, M_NOWAIT | M_ZERO);\n\t}\n\tif (ht) {\n\t\tht->ht = (void **)(ht + 1);\n\t\tht->buckets = buckets;\n\t\tht->ofs = ofs;\n\t\tht->hash = h;\n\t\tht->match = match;\n\t\tht->newh = newh;\n\t}\n\treturn ht;\n}\n\n/* dummy callback for dn_ht_free to unlink all */\nstatic int\ndo_del(void *obj, void *arg)\n{\n\treturn DNHT_SCAN_DEL;\n}\n\nvoid\ndn_ht_free(struct dn_ht *ht, int flags)\n{\n\tif (ht == NULL)\n\t\treturn;\n\tif (flags & DNHT_REMOVE) {\n\t\t(void)dn_ht_scan(ht, do_del, NULL);\n\t} else {\n\t\tif (ht->ht && ht->ht != (void *)(ht + 1))\n\t\t\tfree(ht->ht, M_DN_HEAP);\n\t\tfree(ht, M_DN_HEAP);\n\t}\n}\n\nint\ndn_ht_entries(struct dn_ht *ht)\n{\n\treturn ht ? ht->entries : 0;\n}\n\n/*\n * Helper function to scan a bucket in the hash table, it\n * can only be called on a non-empty bucket for a valid table.\n *\n * In lookup and scan, consider ht->ht[i] as pointing to the tail\n * of the queue (head is NEXTP(tail). The 'empty' value is irrelevant.\n * While searching, start analysing p = head, end when p == tail.\n * Note that 'tail' is a cache of the _original_ ht->ht[i]\n * and is used to check for loop termination. If you remove\n * it, you must also adjust 'p' when deleting the 'tail' element.\n */\n#define NEXT(_h, _p) *((void **)((char *)(_p) + (_h)->ofs))\nstatic int\ndn_ht_scan_body(struct dn_ht *ht, int *bucket,\n\tint (*fn)(void *, void *), void *arg)\n{\n\tint ret, found = 0, i = *bucket;\n\tvoid *tail, *pp, *p, *nextp;\n\n\tpp = tail = ht->ht[i];\n\tdo {\n\t\tp = NEXT(ht, pp);\n\t\tnextp = NEXT(ht, p);\n\t\tret = fn(p, arg);\n\t\tif ((ret & DNHT_SCAN_DEL) == 0) {\n\t\t\tpp = p;\t /* prepare for next loop */\n\t\t} else {\n\t\t\tfound++;\n\t\t\tht->entries--;\n\t\t\t/* skip current element */\n\t\t\tif (pp != p)\n\t\t\t\t/* pp == p implies p == tail */\n\t\t\t\tNEXT(ht, pp) = nextp;\n\t\t\tif (p == tail)\n\t\t\t\tht->ht[i] = (pp != p) ? pp : NULL;\n\t\t}\n\t\tif (ret & DNHT_SCAN_END) {\n\t\t\t/* Update ht->ht[i] before returning */\n\t\t\tht->ht[i] = (ht->ht[i] == NULL) ? NULL : pp;\n\t\t\treturn found;\n\t\t}\n\t} while (p != tail);\n\n\t(*bucket)++;\n\treturn found;\n}\n\n/*\n * lookup and optionally create or delete element.\n * This is an optimized version of the scan so it is coded\n * inline.\n */\nvoid *\ndn_ht_find(struct dn_ht *ht, uintptr_t key, int flags, void *arg)\n{\n\tint i, found;\n\tvoid *tail, *pp, *p; /* pp is the prev element, pp is current */\n\n\tif (ht == NULL)\t/* easy on an empty hash */\n\t\treturn NULL;\n\ti = (ht->buckets == 1) ? 0 :\n\t\t(ht->hash(key, flags, arg) & ht->buckets);\n\n\tpp = tail = ht->ht[i];\n\tif (tail) { /* non empty, try a lookup */\n\t\tdo {\n\t\t\tp = NEXT(ht, pp);\n\t\t\tfound = (flags & DNHT_MATCH_PTR) ? key == (uintptr_t)p :\n\t\t\t\t\tht->match(p, key, flags, arg);\n\t\t\tif (!found)\n\t\t\t\tcontinue;\n\t\t\tif (flags & DNHT_REMOVE) {\n\t\t\t\tht->entries--;\n\t\t\t\tif (p != pp) \t/* skip current element */\n\t\t\t\t\tNEXT(ht, pp) = NEXT(ht, p);\n\t\t\t\tif (p == tail)\n\t\t\t\t\tht->ht[i] = (pp != p) ? pp : NULL;\n\t\t\t}\n\t\t\treturn p;\n\t\t} while ( (pp = p) != tail);\n\t}\n\t/* not found */\n\tif ((flags & DNHT_INSERT) == 0)\n\t\treturn NULL;\n\tp = ht->newh ? ht->newh(key, flags, arg) : (void *)key;\n\tif (p) {\n\t\tht->entries++;\n\t\tif (tail == NULL) {\n\t\t\tht->ht[i] = NEXT(ht, p) = p;\n\t\t} else {\n\t\t\tNEXT(ht, p) = NEXT(ht, tail);\n\t\t\tNEXT(ht, tail) = p;\n\t\t}\n\t}\n\n\treturn p;\n}\n\n/*\n * do a scan with the option to delete the object.\n * Similar to the lookup, but the match function is different,\n * and we extract 'next' before running the callback because\n * the element may be destroyed there.\n */\nint\ndn_ht_scan(struct dn_ht *ht, int (*fn)(void *, void *), void *arg)\n{\n\tint i, bucket, found = 0;\n\n\tif (ht == NULL || fn == NULL)\n\t\treturn 0;\n\tfor (i = 0; i <= ht->buckets; i++) {\n\t\tif (ht->ht[i] == NULL)\n\t\t\tcontinue; /* empty  bucket */\n\t\tbucket = i;\n\t\tfound += dn_ht_scan_body(ht, &bucket, fn, arg);\n\t\tif (bucket == i) /* early exit */\n\t\t\t\treturn found;\n\t}\n\treturn found;\n}\n\n/*\n * Similar to dn_ht_scan(), except that the scan is performed only\n * in the bucket 'bucket'. The function returns a correct bucket number if\n * the original is invalid.\n * If the callback returns DNHT_SCAN_END, the function move the ht->ht[i]\n * pointer to the last entry processed. Moreover, the bucket number passed\n * by caller is decremented, because usually the caller increment it.\n */\nint\ndn_ht_scan_bucket(struct dn_ht *ht, int *bucket, int (*fn)(void *, void *),\n\t\t void *arg)\n{\n\tif (ht == NULL || fn == NULL)\n\t\treturn 0;\n\tif (*bucket > ht->buckets || *bucket < 0)\n\t\t*bucket = 0;\n\tif (ht->ht[*bucket] == NULL) {\n\t\t(*bucket)++;\n\t\treturn 0;\n\t} else\n\t\treturn dn_ht_scan_body(ht, bucket, fn, arg);\n}\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_heap.h",
    "content": "/*-\n * Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * Binary heap and hash tables, header file\n *\n * $FreeBSD: head/sys/netinet/ipfw/dn_heap.h 204865 2010-03-08 11:27:08Z luigi $\n */\n\n#ifndef _IP_DN_HEAP_H\n#define _IP_DN_HEAP_H\n\n#define DN_KEY_LT(a,b)     ((int64_t)((a)-(b)) < 0)\n#define DN_KEY_LEQ(a,b)    ((int64_t)((a)-(b)) <= 0)\n\n/*\n * This module implements a binary heap supporting random extraction.\n *\n * A heap entry contains an uint64_t key and a pointer to object.\n * DN_KEY_LT(a,b) returns true if key 'a' is smaller than 'b'\n *\n * The heap is a struct dn_heap plus a dynamically allocated\n * array of dn_heap_entry entries. 'size' represents the size of\n * the array, 'elements' count entries in use. The topmost\n * element has the smallest key.\n * The heap supports ordered insert, and extract from the top.\n * To extract an object from the middle of the heap, we the object\n * must reserve an 'int32_t' to store the position of the object\n * in the heap itself, and the location of this field must be\n * passed as an argument to heap_init() -- use -1 if the feature\n * is not used.\n */\nstruct dn_heap_entry {\n\tuint64_t key;\t/* sorting key, smallest comes first */\n\tvoid *object;\t/* object pointer */\n};\n\nstruct dn_heap {\n\tint size;\t/* the size of the array */\n\tint elements;\t/* elements in use */\n\tint ofs;\t/* offset in the object of heap index */\n\tstruct dn_heap_entry *p;\t/* array of \"size\" entries */\n};\n\nenum {\n\tHEAP_SCAN_DEL = 1,\n\tHEAP_SCAN_END = 2,\n};\n\n/*\n * heap_init() reinitializes the heap setting the size and the offset\n *\tof the index for random extraction (use -1 if not used).\n *\tThe 'elements' counter is set to 0.\n *\n * SET_HEAP_OFS() indicates where, in the object, is stored the index\n *\tfor random extractions from the heap.\n *\n * heap_free() frees the memory associated to a heap.\n *\n * heap_insert() adds a key-pointer pair to the heap\n *\n * HEAP_TOP() returns a pointer to the top element of the heap,\n *\tbut makes no checks on its existance (XXX should we change ?)\n *\n * heap_extract() removes the entry at the top, returing the pointer.\n *\t(the key should have been read before).\n *\n * heap_scan() invokes a callback on each entry of the heap.\n *\tThe callback can return a combination of HEAP_SCAN_DEL and\n *\tHEAP_SCAN_END. HEAP_SCAN_DEL means the current element must\n *\tbe removed, and HEAP_SCAN_END means to terminate the scan.\n *\theap_scan() returns the number of elements removed.\n *\tBecause the order is not guaranteed, we should use heap_scan()\n *\tonly as a last resort mechanism.\n */\n#define HEAP_TOP(h)\t((h)->p)\n#define SET_HEAP_OFS(h, n)\tdo { (h)->ofs = n; } while (0)\nint     heap_init(struct dn_heap *h, int size, int ofs);\nint     heap_insert(struct dn_heap *h, uint64_t key1, void *p);\nvoid    heap_extract(struct dn_heap *h, void *obj);\nvoid heap_free(struct dn_heap *h);\nint heap_scan(struct dn_heap *, int (*)(void *, uintptr_t), uintptr_t);\n\n/*------------------------------------------------------\n * This module implements a generic hash table with support for\n * running callbacks on the entire table. To avoid allocating\n * memory during hash table operations, objects must reserve\n * space for a link field. XXX if the heap is moderately full,\n * an SLIST suffices, and we can tolerate the cost of a hash\n * computation on each removal.\n *\n * dn_ht_init() initializes the table, setting the number of\n *\tbuckets, the offset of the link field, the main callbacks.\n *\tCallbacks are:\n * \n *\thash(key, flags, arg) called to return a bucket index.\n *\tmatch(obj, key, flags, arg) called to determine if key\n *\t\tmatches the current 'obj' in the heap\n *\tnewh(key, flags, arg) optional, used to allocate a new\n *\t\tobject during insertions.\n *\n * dn_ht_free() frees the heap or unlink elements.\n *\tDNHT_REMOVE unlink elements, 0 frees the heap.\n *\tYou need two calls to do both.\n *\n * dn_ht_find() is the main lookup function, which can also be\n *\tused to insert or delete elements in the hash table.\n *\tThe final 'arg' is passed to all callbacks.\n *\n * dn_ht_scan() is used to invoke a callback on all entries of\n *\tthe heap, or possibly on just one bucket. The callback\n *\tis invoked with a pointer to the object, and must return\n *\tone of DNHT_SCAN_DEL or DNHT_SCAN_END to request the\n *\tremoval of the object from the heap and the end of the\n *\tscan, respectively.\n *\n * dn_ht_scan_bucket() is similar to dn_ht_scan(), except that it scans\n *\tonly the specific bucket of the table. The bucket is a in-out\n *\tparameter and return a valid bucket number if the original\n *\tis invalid.\n *\n * A combination of flags can be used to modify the operation\n * of the dn_ht_find(), and of the callbacks:\n *\n * DNHT_KEY_IS_OBJ\tmeans the key is the object pointer.\n *\tIt is usally of interest for the hash and match functions.\n *\n * DNHT_MATCH_PTR\tduring a lookup, match pointers instead\n *\tof calling match(). Normally used when removing specific\n *\tentries. Does not imply KEY_IS_OBJ as the latter _is_ used\n *\tby the match function.\n *\n * DNHT_INSERT\t\tinsert the element if not found.\n *\tCalls new() to allocates a new object unless\n *\tDNHT_KEY_IS_OBJ is set.\n *\n * DNHT_UNIQUE\t\tonly insert if object not found.\n *\tXXX should it imply DNHT_INSERT ?\n *\n * DNHT_REMOVE\t\tremove objects if we find them.\n */\nstruct dn_ht;\t/* should be opaque */\n\nstruct dn_ht *dn_ht_init(struct dn_ht *, int buckets, int ofs, \n        uint32_t (*hash)(uintptr_t, int, void *),\n        int (*match)(void *, uintptr_t, int, void *),\n        void *(*newh)(uintptr_t, int, void *));\nvoid dn_ht_free(struct dn_ht *, int flags);\n\nvoid *dn_ht_find(struct dn_ht *, uintptr_t, int, void *);\nint dn_ht_scan(struct dn_ht *, int (*)(void *, void *), void *);\nint dn_ht_scan_bucket(struct dn_ht *, int * , int (*)(void *, void *), void *);\nint dn_ht_entries(struct dn_ht *);\n\nenum {  /* flags values.\n\t * first two are returned by the scan callback to indicate\n\t * to delete the matching element or to end the scan\n\t */\n        DNHT_SCAN_DEL\t= 0x0001,\n        DNHT_SCAN_END\t= 0x0002,\n        DNHT_KEY_IS_OBJ\t= 0x0004,\t/* key is the obj pointer */\n        DNHT_MATCH_PTR\t= 0x0008,\t/* match by pointer, not match() */\n        DNHT_INSERT\t= 0x0010,\t/* insert if not found */\n        DNHT_UNIQUE\t= 0x0020,\t/* report error if already there */\n        DNHT_REMOVE\t= 0x0040,\t/* remove on find or dn_ht_free */\n}; \n\n#endif /* _IP_DN_HEAP_H */\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_sched.h",
    "content": "/*\n * Copyright (c) 2010 Riccardo Panicucci, Luigi Rizzo, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * The API to write a packet scheduling algorithm for dummynet.\n *\n * $FreeBSD: head/sys/netinet/ipfw/dn_sched.h 204591 2010-03-02 17:40:48Z luigi $\n */\n\n#ifndef _DN_SCHED_H\n#define _DN_SCHED_H\n\n#define\tDN_MULTIQUEUE\t0x01\n/*\n * Descriptor for a scheduling algorithm.\n * Contains all function pointers for a given scheduler\n * This is typically created when a module is loaded, and stored\n * in a global list of schedulers.\n */\nstruct dn_alg {\n\tuint32_t type;           /* the scheduler type */\n\tconst char *name;   /* scheduler name */\n\tuint32_t flags;\t/* DN_MULTIQUEUE if supports multiple queues */\n\n\t/*\n\t * The following define the size of 3 optional data structures\n\t * that may need to be allocated at runtime, and are appended\n\t * to each of the base data structures: scheduler, sched.inst,\n\t * and queue. We don't have a per-flowset structure.\n\t */\n\t/*    + parameters attached to the template, e.g.\n\t *\tdefault queue sizes, weights, quantum size, and so on;\n\t */\n\tsize_t schk_datalen;\n\n\t/*    + per-instance parameters, such as timestamps,\n\t *\tcontainers for queues, etc;\n\t */\n\tsize_t si_datalen;\n\n\tsize_t q_datalen;\t/* per-queue parameters (e.g. S,F) */\n\n\t/*\n\t * Methods implemented by the scheduler:\n\t * enqueue\tenqueue packet 'm' on scheduler 's', queue 'q'.\n\t *\tq is NULL for !MULTIQUEUE.\n\t *\tReturn 0 on success, 1 on drop (packet consumed anyways).\n\t *\tNote that q should be interpreted only as a hint\n\t *\ton the flow that the mbuf belongs to: while a\n\t *\tscheduler will normally enqueue m into q, it is ok\n\t *\tto leave q alone and put the mbuf elsewhere.\n\t *\tThis function is called in two cases:\n\t *\t - when a new packet arrives to the scheduler;\n\t *\t - when a scheduler is reconfigured. In this case the\n\t *\t   call is issued by the new_queue callback, with a \n\t *\t   non empty queue (q) and m pointing to the first\n\t *\t   mbuf in the queue. For this reason, the function\n\t *\t   should internally check for (m != q->mq.head)\n\t *\t   before calling dn_enqueue().\n\t *\n\t * dequeue\tCalled when scheduler instance 's' can\n\t *\tdequeue a packet. Return NULL if none are available.\n\t *\tXXX what about non work-conserving ?\n\t *\n\t * config\tcalled on 'sched X config ...', normally writes\n\t *\tin the area of size sch_arg\n\t *\n\t * destroy\tcalled on 'sched delete', frees everything\n\t *\tin sch_arg (other parts are handled by more specific\n\t *\tfunctions)\n\t *\n\t * new_sched    called when a new instance is created, e.g.\n\t *\tto create the local queue for !MULTIQUEUE, set V or\n\t *\tcopy parameters for WFQ, and so on.\n\t *\n\t * free_sched\tcalled when deleting an instance, cleans\n\t *\textra data in the per-instance area.\n\t *\n\t * new_fsk\tcalled when a flowset is linked to a scheduler,\n\t *\te.g. to validate parameters such as weights etc.\n\t * free_fsk\twhen a flowset is unlinked from a scheduler.\n\t *\t(probably unnecessary)\n\t *\n\t * new_queue\tcalled to set the per-queue parameters,\n\t *\te.g. S and F, adjust sum of weights in the parent, etc.\n\t *\n\t *\tThe new_queue callback is normally called from when\n\t *\tcreating a new queue. In some cases (such as a\n\t *\tscheduler change or reconfiguration) it can be called\n\t *\twith a non empty queue. In this case, the queue\n\t *\tIn case of non empty queue, the new_queue callback could\n\t *\tneed to call the enqueue function. In this case,\n\t *\tthe callback should eventually call enqueue() passing\n\t *\tas m the first element in the queue.\n\t *\n\t * free_queue\tactions related to a queue removal, e.g. undo\n\t *\tall the above. If the queue has data in it, also remove\n\t *\tfrom the scheduler. This can e.g. happen during a reconfigure.\n\t *\tIf safe == 1 remove the queue only if the scheduler no longer\n\t *\tneed it, otherwise delete it even if the scheduler is using\n\t *\tit. Usually, the flag safe is set when the drain routine is\n\t *\trunning to delete idle queues.\n\t */\n\tint (*enqueue)(struct dn_sch_inst *, struct dn_queue *,\n\t\tstruct mbuf *);\n\tstruct mbuf * (*dequeue)(struct dn_sch_inst *);\n\n\tint (*config)(struct dn_schk *);\n\tint (*destroy)(struct dn_schk*);\n\tint (*new_sched)(struct dn_sch_inst *);\n\tint (*free_sched)(struct dn_sch_inst *);\n\tint (*new_fsk)(struct dn_fsk *f);\n\tint (*free_fsk)(struct dn_fsk *f);\n\tint (*new_queue)(struct dn_queue *q);\n\tint (*free_queue)(struct dn_queue *q, int safe);\n\n\t/* run-time fields */\n\tint ref_count;      /* XXX number of instances in the system */\n\tSLIST_ENTRY(dn_alg) next; /* Next scheduler in the list */\n};\n\n/* MSVC does not support initializers so we need this ugly macro */\n#ifdef _WIN32\n#define _SI(fld)\n#else\n#define _SI(fld)\tfld\n#endif\n\n/*\n * Additionally, dummynet exports some functions and macros\n * to be used by schedulers:\n */\n\nvoid dn_free_pkts(struct mbuf *mnext);\nint dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop);\n/* bound a variable between min and max */\nint ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg);\n\n/*\n * Extract the head of a queue, update stats. Must be the very last\n * thing done on a dequeue as the queue itself may go away.\n */\nstatic __inline struct mbuf*\ndn_dequeue(struct dn_queue *q)\n{\n\tstruct mbuf *m = q->mq.head;\n\tif (m == NULL)\n\t\treturn NULL;\n\tq->mq.head = m->m_nextpkt;\n\n\t/* Update stats for the queue */\n\tq->ni.length--;\n\tq->ni.len_bytes -= m->m_pkthdr.len;\n\t/* When the queue becomes idle, update idle_time (used by RED)\n\t * and also update the count of idle queues (for garbage collection).\n\t */\n\tif (q->ni.length == 0) {\n\t\tdn_cfg.idle_queue++;\n\t\tq->q_time = dn_cfg.curr_time;\n\t}\n\tif (q->_si) {\n\t\tstruct dn_flow *ni = &(q->_si->ni);\n\t\t/* update stats for the scheduler instance, and keep track\n\t\t * of idle scheduler instances if needed\n\t\t */\n\t\tni->length--;\n\t\tni->len_bytes -= m->m_pkthdr.len;\n\t\tif (ni->length == 0)\n\t\t\tdn_cfg.idle_si++;\n\t}\n\treturn m;\n}\n\nint dn_sched_modevent(module_t mod, int cmd, void *arg);\n\n#define DECLARE_DNSCHED_MODULE(name, dnsched)\t\t\t\\\n\tstatic moduledata_t name##_mod = {\t\t\t\\\n\t\t#name, dn_sched_modevent, dnsched\t\t\\\n\t};\t\t\t\t\t\t\t\\\n\tDECLARE_MODULE(name, name##_mod, \t\t\t\\\n\t\tSI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); \t\\\n        MODULE_DEPEND(name, dummynet, 3, 3, 3);\n#endif /* _DN_SCHED_H */\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_sched_fifo.c",
    "content": "/*\n * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: dn_sched_fifo.c 11480 2012-07-31 08:02:00Z luigi $\n */\n\n#ifdef _KERNEL\n#include <sys/malloc.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/kernel.h>\n#include <sys/mbuf.h>\n#include <sys/module.h>\n#include <net/if.h>\t/* IFNAMSIZ */\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t\t/* ipfw_rule_ref */\n#include <netinet/ip_fw.h>\t/* flow_id */\n#include <netinet/ip_dummynet.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n#else\n#include <dn_test.h>\n#endif\n\n/*\n * This file implements a FIFO scheduler for a single queue.\n * The queue is allocated as part of the scheduler instance,\n * and there is a single flowset is in the template which stores\n * queue size and policy.\n * Enqueue and dequeue use the default library functions.\n */\nstatic int \nfifo_enqueue(struct dn_sch_inst *si, struct dn_queue *q, struct mbuf *m)\n{\n\t/* XXX if called with q != NULL and m=NULL, this is a\n\t * re-enqueue from an existing scheduler, which we should\n\t * handle.\n\t */\n\treturn dn_enqueue((struct dn_queue *)(si+1), m, 0);\n}\n\nstatic struct mbuf *\nfifo_dequeue(struct dn_sch_inst *si)\n{\n\treturn dn_dequeue((struct dn_queue *)(si + 1));\n}\n\nstatic int\nfifo_new_sched(struct dn_sch_inst *si)\n{\n\t/* This scheduler instance contains the queue */\n\tstruct dn_queue *q = (struct dn_queue *)(si + 1);\n\n        set_oid(&q->ni.oid, DN_QUEUE, sizeof(*q));\n\tq->_si = si;\n\tq->fs = si->sched->fs;\n\treturn 0;\n}\n\nstatic int\nfifo_free_sched(struct dn_sch_inst *si)\n{\n\tstruct dn_queue *q = (struct dn_queue *)(si + 1);\n\tdn_free_pkts(q->mq.head);\n\tbzero(q, sizeof(*q));\n\treturn 0;\n}\n\n/*\n * FIFO scheduler descriptor\n * contains the type of the scheduler, the name, the size of extra\n * data structures, and function pointers.\n */\nstatic struct dn_alg fifo_desc = {\n\t_SI( .type = )  DN_SCHED_FIFO,\n\t_SI( .name = )  \"FIFO\",\n\t_SI( .flags = ) 0,\n\n\t_SI( .schk_datalen = ) 0,\n\t_SI( .si_datalen = )  sizeof(struct dn_queue),\n\t_SI( .q_datalen = )  0,\n\n\t_SI( .enqueue = )  fifo_enqueue,\n\t_SI( .dequeue = )  fifo_dequeue,\n\t_SI( .config = )  NULL,\n\t_SI( .destroy = )  NULL,\n\t_SI( .new_sched = )  fifo_new_sched,\n\t_SI( .free_sched = )  fifo_free_sched,\n\t_SI( .new_fsk = )  NULL,\n\t_SI( .free_fsk = )  NULL,\n\t_SI( .new_queue = )  NULL,\n\t_SI( .free_queue = )  NULL,\n};\n\nDECLARE_DNSCHED_MODULE(dn_fifo, &fifo_desc);\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_sched_prio.c",
    "content": "/*\n * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: dn_sched_prio.c 11480 2012-07-31 08:02:00Z luigi $\n */\n#ifdef _KERNEL\n#include <sys/malloc.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/kernel.h>\n#include <sys/mbuf.h>\n#include <sys/module.h>\n#include <net/if.h>\t/* IFNAMSIZ */\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t\t/* ipfw_rule_ref */\n#include <netinet/ip_fw.h>\t/* flow_id */\n#include <netinet/ip_dummynet.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n#else\n#include <dn_test.h>\n#endif\n\n#define DN_SCHED_PRIO\t5 //XXX\n\n#if !defined(_KERNEL) || !defined(__linux__)\n#define test_bit(ix, pData)\t((*pData) & (1<<(ix)))\n#define __set_bit(ix, pData)\t(*pData) |= (1<<(ix))\n#define __clear_bit(ix, pData)\t(*pData) &= ~(1<<(ix))\n#endif\n\n#ifdef __MIPSEL__\n#define __clear_bit(ix, pData)\t(*pData) &= ~(1<<(ix))\n#endif\n\n/* Size of the array of queues pointers. */\n#define BITMAP_T\tunsigned long\n#define MAXPRIO\t\t(sizeof(BITMAP_T) * 8)\n\n/*\n * The scheduler instance contains an array of pointers to queues,\n * one for each priority, and a bitmap listing backlogged queues.\n */\nstruct prio_si {\n\tBITMAP_T bitmap;\t\t\t/* array bitmap */\n\tstruct dn_queue *q_array[MAXPRIO];\t/* Array of queues pointers */\n};\n\n/*\n * If a queue with the same priority is already backlogged, use\n * that one instead of the queue passed as argument.\n */\nstatic int \nprio_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)\n{\n\tstruct prio_si *si = (struct prio_si *)(_si + 1);\n\tint prio = q->fs->fs.par[0];\n\n\tif (test_bit(prio, &si->bitmap) == 0) {\n\t\t/* No queue with this priority, insert */\n\t\t__set_bit(prio, &si->bitmap);\n\t\tsi->q_array[prio] = q;\n\t} else { /* use the existing queue */\n\t\tq = si->q_array[prio];\n\t}\n\tif (dn_enqueue(q, m, 0))\n\t\treturn 1;\n\treturn 0;\n}\n\n/*\n * Packets are dequeued only from the highest priority queue.\n * The function ffs() return the lowest bit in the bitmap that rapresent\n * the array index (-1) which contains the pointer to the highest priority\n * queue.\n * After the dequeue, if this queue become empty, it is index is removed\n * from the bitmap.\n * Scheduler is idle if the bitmap is empty\n *\n * NOTE: highest priority is 0, lowest is sched->max_prio_q\n */\nstatic struct mbuf *\nprio_dequeue(struct dn_sch_inst *_si)\n{\n\tstruct prio_si *si = (struct prio_si *)(_si + 1);\n\tstruct mbuf *m;\n\tstruct dn_queue *q;\n\tint prio;\n\n\tif (si->bitmap == 0) /* scheduler idle */\n\t\treturn NULL;\n\n\tprio = ffs(si->bitmap) - 1;\n\n\t/* Take the highest priority queue in the scheduler */\n\tq = si->q_array[prio];\n\t// assert(q)\n\n\tm = dn_dequeue(q);\n\tif (q->mq.head == NULL) {\n\t\t/* Queue is now empty, remove from scheduler\n\t\t * and mark it\n\t\t */\n\t\tsi->q_array[prio] = NULL;\n\t\t__clear_bit(prio, &si->bitmap);\n\t}\n\treturn m;\n}\n\nstatic int\nprio_new_sched(struct dn_sch_inst *_si)\n{\n\tstruct prio_si *si = (struct prio_si *)(_si + 1);\n\n\tbzero(si->q_array, sizeof(si->q_array));\n\tsi->bitmap = 0;\n\n\treturn 0;\n}\n\nstatic int\nprio_new_fsk(struct dn_fsk *fs)\n{\n\t/* Check if the prioritiy is between 0 and MAXPRIO-1 */\n\tipdn_bound_var(&fs->fs.par[0], 0, 0, MAXPRIO - 1, \"PRIO priority\");\n\treturn 0;\n}\n\nstatic int\nprio_new_queue(struct dn_queue *q)\n{\n\tstruct prio_si *si = (struct prio_si *)(q->_si + 1);\n\tint prio = q->fs->fs.par[0];\n\tstruct dn_queue *oldq;\n\n\tq->ni.oid.subtype = DN_SCHED_PRIO;\n\n\tif (q->mq.head == NULL)\n\t\treturn 0;\n\n\t/* Queue already full, must insert in the scheduler or append\n\t * mbufs to existing queue. This partly duplicates prio_enqueue\n\t */\n\tif (test_bit(prio, &si->bitmap) == 0) {\n\t\t/* No queue with this priority, insert */\n\t\t__set_bit(prio, &si->bitmap);\n\t\tsi->q_array[prio] = q;\n\t} else if ( (oldq = si->q_array[prio]) != q) {\n\t\t/* must append to the existing queue.\n\t\t * can simply append q->mq.head to q2->...\n\t\t * and add the counters to those of q2\n\t\t */\n\t\toldq->mq.tail->m_nextpkt = q->mq.head;\n\t\toldq->mq.tail = q->mq.tail;\n\t\toldq->ni.length += q->ni.length;\n\t\tq->ni.length = 0;\n\t\toldq->ni.len_bytes += q->ni.len_bytes;\n\t\tq->ni.len_bytes = 0;\n\t\tq->mq.tail = q->mq.head = NULL;\n\t}\n\treturn 0;\n}\n\nstatic int\nprio_free_queue(struct dn_queue *q, int safe)\n{\n\tint prio = q->fs->fs.par[0];\n\tstruct prio_si *si = (struct prio_si *)(q->_si + 1);\n\n\tif (si->q_array[prio] == q) {\n\t\tsi->q_array[prio] = NULL;\n\t\t__clear_bit(prio, &si->bitmap);\n\t}\n\treturn 0;\n}\n\n\nstatic struct dn_alg prio_desc = {\n\t_SI( .type = ) DN_SCHED_PRIO,\n\t_SI( .name = ) \"PRIO\",\n\t_SI( .flags = ) DN_MULTIQUEUE,\n\n\t/* we need extra space in the si and the queue */\n\t_SI( .schk_datalen = ) 0,\n\t_SI( .si_datalen = ) sizeof(struct prio_si),\n\t_SI( .q_datalen = ) 0,\n\n\t_SI( .enqueue = ) prio_enqueue,\n\t_SI( .dequeue = ) prio_dequeue,\n\n\t_SI( .config = )  NULL,\n\t_SI( .destroy = )  NULL,\n\t_SI( .new_sched = ) prio_new_sched,\n\t_SI( .free_sched = ) NULL,\n\n\t_SI( .new_fsk = ) prio_new_fsk,\n\t_SI( .free_fsk = )  NULL,\n\n\t_SI( .new_queue = ) prio_new_queue,\n\t_SI( .free_queue = ) prio_free_queue,\n};\n\n\nDECLARE_DNSCHED_MODULE(dn_prio, &prio_desc);\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_sched_qfq.c",
    "content": "/*\n * Copyright (c) 2010 Fabio Checconi, Luigi Rizzo, Paolo Valente\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: dn_sched_qfq.c 11656 2012-08-07 08:39:06Z luigi $\n */\n\n#ifdef _KERNEL\n#include <sys/malloc.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/kernel.h>\n#include <sys/mbuf.h>\n#include <sys/module.h>\n#include <net/if.h>\t/* IFNAMSIZ */\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t\t/* ipfw_rule_ref */\n#include <netinet/ip_fw.h>\t/* flow_id */\n#include <netinet/ip_dummynet.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n#else\n#include <dn_test.h>\n#endif\n\n#ifdef QFQ_DEBUG\nstruct qfq_sched;\nstatic void dump_sched(struct qfq_sched *q, const char *msg);\n#define\tNO(x)\tx\n#else\n#define NO(x)\n#endif\n#define DN_SCHED_QFQ\t4 // XXX Where?\ntypedef\tunsigned long\tbitmap;\n\n/*\n * bitmaps ops are critical. Some linux versions have __fls\n * and the bitmap ops. Some machines have ffs\n */\n#if defined(_WIN32) || (defined(__MIPSEL__) && defined(LINUX_24))\nint fls(unsigned int n)\n{\n\tint i = 0;\n\tfor (i = 0; n > 0; n >>= 1, i++)\n\t\t;\n\treturn i;\n}\n#endif\n\n#if !defined(_KERNEL) || defined( __FreeBSD__ ) || defined(_WIN32) || (defined(__MIPSEL__) && defined(LINUX_24))\nstatic inline unsigned long __fls(unsigned long word)\n{\n\treturn fls(word) - 1;\n}\n#endif\n\n#if !defined(_KERNEL) || !defined(__linux__)\n#ifdef QFQ_DEBUG\nint test_bit(int ix, bitmap *p)\n{\n\tif (ix < 0 || ix > 31)\n\t\tD(\"bad index %d\", ix);\n\treturn *p & (1<<ix);\n}\nvoid __set_bit(int ix, bitmap *p)\n{\n\tif (ix < 0 || ix > 31)\n\t\tD(\"bad index %d\", ix);\n\t*p |= (1<<ix);\n}\nvoid __clear_bit(int ix, bitmap *p)\n{\n\tif (ix < 0 || ix > 31)\n\t\tD(\"bad index %d\", ix);\n\t*p &= ~(1<<ix);\n}\n#else /* !QFQ_DEBUG */\n/* XXX do we have fast version, or leave it to the compiler ? */\n#define test_bit(ix, pData)\t((*pData) & (1<<(ix)))\n#define __set_bit(ix, pData)\t(*pData) |= (1<<(ix))\n#define __clear_bit(ix, pData)\t(*pData) &= ~(1<<(ix))\n#endif /* !QFQ_DEBUG */\n#endif /* !__linux__ */\n\n#ifdef __MIPSEL__\n#define __clear_bit(ix, pData)\t(*pData) &= ~(1<<(ix))\n#endif\n\n/*-------------------------------------------*/\n/*\n\nVirtual time computations.\n\nS, F and V are all computed in fixed point arithmetic with\nFRAC_BITS decimal bits.\n\n   QFQ_MAX_INDEX is the maximum index allowed for a group. We need\n  \tone bit per index.\n   QFQ_MAX_WSHIFT is the maximum power of two supported as a weight.\n   The layout of the bits is as below:\n  \n                   [ MTU_SHIFT ][      FRAC_BITS    ]\n                   [ MAX_INDEX    ][ MIN_SLOT_SHIFT ]\n  \t\t\t\t ^.__grp->index = 0\n  \t\t\t\t *.__grp->slot_shift\n  \n   where MIN_SLOT_SHIFT is derived by difference from the others.\n\nThe max group index corresponds to Lmax/w_min, where\nLmax=1<<MTU_SHIFT, w_min = 1 .\nFrom this, and knowing how many groups (MAX_INDEX) we want,\nwe can derive the shift corresponding to each group.\n\nBecause we often need to compute\n\tF = S + len/w_i  and V = V + len/wsum\ninstead of storing w_i store the value\n\tinv_w = (1<<FRAC_BITS)/w_i\nso we can do F = S + len * inv_w * wsum.\nWe use W_TOT in the formulas so we can easily move between\nstatic and adaptive weight sum.\n\nThe per-scheduler-instance data contain all the data structures\nfor the scheduler: bitmaps and bucket lists.\n\n */\n/*\n * Maximum number of consecutive slots occupied by backlogged classes\n * inside a group. This is approx lmax/lmin + 5.\n * XXX check because it poses constraints on MAX_INDEX\n */\n#define QFQ_MAX_SLOTS\t32\n/*\n * Shifts used for class<->group mapping. Class weights are\n * in the range [1, QFQ_MAX_WEIGHT], we to map each class i to the\n * group with the smallest index that can support the L_i / r_i\n * configured for the class.\n *\n * grp->index is the index of the group; and grp->slot_shift\n * is the shift for the corresponding (scaled) sigma_i.\n *\n * When computing the group index, we do (len<<FP_SHIFT)/weight,\n * then compute an FLS (which is like a log2()), and if the result\n * is below the MAX_INDEX region we use 0 (which is the same as\n * using a larger len).\n */\n#define QFQ_MAX_INDEX\t\t19\n#define QFQ_MAX_WSHIFT\t\t16\t/* log2(max_weight) */\n\n#define\tQFQ_MAX_WEIGHT\t\t(1<<QFQ_MAX_WSHIFT)\n#define QFQ_MAX_WSUM\t\t(2*QFQ_MAX_WEIGHT)\n//#define IWSUM\t(q->i_wsum)\n#define IWSUM\t((1<<FRAC_BITS)/QFQ_MAX_WSUM)\n\n#define FRAC_BITS\t\t30\t/* fixed point arithmetic */\n#define ONE_FP\t\t\t(1UL << FRAC_BITS)\n\n#define QFQ_MTU_SHIFT\t\t11\t/* log2(max_len) */\n#define QFQ_MIN_SLOT_SHIFT\t(FRAC_BITS + QFQ_MTU_SHIFT - QFQ_MAX_INDEX)\n\n/*\n * Possible group states, also indexes for the bitmaps array in\n * struct qfq_queue. We rely on ER, IR, EB, IB being numbered 0..3\n */\nenum qfq_state { ER, IR, EB, IB, QFQ_MAX_STATE };\n\nstruct qfq_group;\n/*\n * additional queue info. Some of this info should come from\n * the flowset, we copy them here for faster processing.\n * This is an overlay of the struct dn_queue\n */\nstruct qfq_class {\n\tstruct dn_queue _q;\n\tuint64_t S, F;\t\t/* flow timestamps (exact) */\n\tstruct qfq_class *next; /* Link for the slot list. */\n\n\t/* group we belong to. In principle we would need the index,\n\t * which is log_2(lmax/weight), but we never reference it\n\t * directly, only the group.\n\t */\n\tstruct qfq_group *grp;\n\n\t/* these are copied from the flowset. */\n\tuint32_t\tinv_w;\t/* ONE_FP/weight */\n\tuint32_t \tlmax;\t/* Max packet size for this flow. */\n};\n\n/* Group descriptor, see the paper for details.\n * Basically this contains the bucket lists\n */\nstruct qfq_group {\n\tuint64_t S, F;\t\t\t/* group timestamps (approx). */\n\tunsigned int slot_shift;\t/* Slot shift. */\n\tunsigned int index;\t\t/* Group index. */\n\tunsigned int front;\t\t/* Index of the front slot. */\n\tbitmap full_slots;\t\t/* non-empty slots */\n\n\t/* Array of lists of active classes. */\n\tstruct qfq_class *slots[QFQ_MAX_SLOTS];\n};\n\n/* scheduler instance descriptor. */\nstruct qfq_sched {\n\tuint64_t\tV;\t\t/* Precise virtual time. */\n\tuint32_t\twsum;\t\t/* weight sum */\n\tNO(uint32_t\ti_wsum;\t\t/* ONE_FP/w_sum */\n\tuint32_t\t_queued;\t/* debugging */\n\tuint32_t\tloops;\t/* debugging */)\n\tbitmap bitmaps[QFQ_MAX_STATE];\t/* Group bitmaps. */\n\tstruct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */\n};\n\n/*---- support functions ----------------------------*/\n\n/* Generic comparison function, handling wraparound. */\nstatic inline int qfq_gt(uint64_t a, uint64_t b)\n{\n\treturn (int64_t)(a - b) > 0;\n}\n\n/* Round a precise timestamp to its slotted value. */\nstatic inline uint64_t qfq_round_down(uint64_t ts, unsigned int shift)\n{\n\treturn ts & ~((1ULL << shift) - 1);\n}\n\n/* return the pointer to the group with lowest index in the bitmap */\nstatic inline struct qfq_group *qfq_ffs(struct qfq_sched *q,\n\t\t\t\t\tunsigned long bitmap)\n{\n\tint index = ffs(bitmap) - 1; // zero-based\n\treturn &q->groups[index];\n}\n\n/*\n * Calculate a flow index, given its weight and maximum packet length.\n * index = log_2(maxlen/weight) but we need to apply the scaling.\n * This is used only once at flow creation.\n */\nstatic int qfq_calc_index(uint32_t inv_w, unsigned int maxlen)\n{\n\tuint64_t slot_size = (uint64_t)maxlen *inv_w;\n\tunsigned long size_map;\n\tint index = 0;\n\n\tsize_map = (unsigned long)(slot_size >> QFQ_MIN_SLOT_SHIFT);\n\tif (!size_map)\n\t\tgoto out;\n\n\tindex = __fls(size_map) + 1;\t// basically a log_2()\n\tindex -= !(slot_size - (1ULL << (index + QFQ_MIN_SLOT_SHIFT - 1)));\n\n\tif (index < 0)\n\t\tindex = 0;\n\nout:\n\tND(\"W = %d, L = %d, I = %d\\n\", ONE_FP/inv_w, maxlen, index);\n\treturn index;\n}\n/*---- end support functions ----*/\n\n/*-------- API calls --------------------------------*/\n/*\n * Validate and copy parameters from flowset.\n */\nstatic int\nqfq_new_queue(struct dn_queue *_q)\n{\n\tstruct qfq_sched *q = (struct qfq_sched *)(_q->_si + 1);\n\tstruct qfq_class *cl = (struct qfq_class *)_q;\n\tint i;\n\tuint32_t w;\t/* approximated weight */\n\n\t/* import parameters from the flowset. They should be correct\n\t * already.\n\t */\n\tw = _q->fs->fs.par[0];\n\tcl->lmax = _q->fs->fs.par[1];\n\tif (!w || w > QFQ_MAX_WEIGHT) {\n\t\tw = 1;\n\t\tD(\"rounding weight to 1\");\n\t}\n\tcl->inv_w = ONE_FP/w;\n\tw = ONE_FP/cl->inv_w;\t\n\tif (q->wsum + w > QFQ_MAX_WSUM)\n\t\treturn EINVAL;\n\n\ti = qfq_calc_index(cl->inv_w, cl->lmax);\n\tcl->grp = &q->groups[i];\n\tq->wsum += w;\n\t// XXX cl->S = q->V; ?\n\t// XXX compute q->i_wsum\n\treturn 0;\n}\n\n/* remove an empty queue */\nstatic int\nqfq_free_queue(struct dn_queue *_q, int safe)\n{\n\tstruct qfq_sched *q = (struct qfq_sched *)(_q->_si + 1);\n\tstruct qfq_class *cl = (struct qfq_class *)_q;\n\tif (cl->inv_w) {\n\t\tq->wsum -= ONE_FP/cl->inv_w;\n\t\tcl->inv_w = 0; /* reset weight to avoid run twice */\n\t}\n\treturn 0;\n}\n\n/* Calculate a mask to mimic what would be ffs_from(). */\nstatic inline unsigned long\nmask_from(unsigned long bitmap, int from)\n{\n\treturn bitmap & ~((1UL << from) - 1);\n}\n\n/*\n * The state computation relies on ER=0, IR=1, EB=2, IB=3\n * First compute eligibility comparing grp->S, q->V,\n * then check if someone is blocking us and possibly add EB\n */\nstatic inline unsigned int\nqfq_calc_state(struct qfq_sched *q, struct qfq_group *grp)\n{\n\t/* if S > V we are not eligible */\n\tunsigned int state = qfq_gt(grp->S, q->V);\n\tunsigned long mask = mask_from(q->bitmaps[ER], grp->index);\n\tstruct qfq_group *next;\n\n\tif (mask) {\n\t\tnext = qfq_ffs(q, mask);\n\t\tif (qfq_gt(grp->F, next->F))\n\t\t\tstate |= EB;\n\t}\n\n\treturn state;\n}\n\n/*\n * In principle\n *\tq->bitmaps[dst] |= q->bitmaps[src] & mask;\n *\tq->bitmaps[src] &= ~mask;\n * but we should make sure that src != dst\n */\nstatic inline void\nqfq_move_groups(struct qfq_sched *q, unsigned long mask, int src, int dst)\n{\n\tq->bitmaps[dst] |= q->bitmaps[src] & mask;\n\tq->bitmaps[src] &= ~mask;\n}\n\nstatic inline void\nqfq_unblock_groups(struct qfq_sched *q, int index, uint64_t old_finish)\n{\n\tunsigned long mask = mask_from(q->bitmaps[ER], index + 1);\n\tstruct qfq_group *next;\n\n\tif (mask) {\n\t\tnext = qfq_ffs(q, mask);\n\t\tif (!qfq_gt(next->F, old_finish))\n\t\t\treturn;\n\t}\n\n\tmask = (1UL << index) - 1;\n\tqfq_move_groups(q, mask, EB, ER);\n\tqfq_move_groups(q, mask, IB, IR);\n}\n\n/*\n * perhaps\n *\n\told_V ^= q->V;\n\told_V >>= QFQ_MIN_SLOT_SHIFT;\n\tif (old_V) {\n\t\t...\n\t}\n *\n */\nstatic inline void\nqfq_make_eligible(struct qfq_sched *q, uint64_t old_V)\n{\n\tunsigned long mask, vslot, old_vslot;\n\n\tvslot = q->V >> QFQ_MIN_SLOT_SHIFT;\n\told_vslot = old_V >> QFQ_MIN_SLOT_SHIFT;\n\n\tif (vslot != old_vslot) {\n\t\tmask = (2UL << (__fls(vslot ^ old_vslot))) - 1;\n\t\tqfq_move_groups(q, mask, IR, ER);\n\t\tqfq_move_groups(q, mask, IB, EB);\n\t}\n}\n\n/*\n * XXX we should make sure that slot becomes less than 32.\n * This is guaranteed by the input values.\n * roundedS is always cl->S rounded on grp->slot_shift bits.\n */\nstatic inline void\nqfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl, uint64_t roundedS)\n{\n\tuint64_t slot = (roundedS - grp->S) >> grp->slot_shift;\n\tunsigned int i = (grp->front + slot) % QFQ_MAX_SLOTS;\n\n\tcl->next = grp->slots[i];\n\tgrp->slots[i] = cl;\n\t__set_bit(slot, &grp->full_slots);\n}\n\n/*\n * remove the entry from the slot\n */\nstatic inline void\nqfq_front_slot_remove(struct qfq_group *grp)\n{\n\tstruct qfq_class **h = &grp->slots[grp->front];\n\n\t*h = (*h)->next;\n\tif (!*h)\n\t\t__clear_bit(0, &grp->full_slots);\n}\n\n/*\n * Returns the first full queue in a group. As a side effect,\n * adjust the bucket list so the first non-empty bucket is at\n * position 0 in full_slots.\n */\nstatic inline struct qfq_class *\nqfq_slot_scan(struct qfq_group *grp)\n{\n\tint i;\n\n\tND(\"grp %d full %x\", grp->index, grp->full_slots);\n\tif (!grp->full_slots)\n\t\treturn NULL;\n\n\ti = ffs(grp->full_slots) - 1; // zero-based\n\tif (i > 0) {\n\t\tgrp->front = (grp->front + i) % QFQ_MAX_SLOTS;\n\t\tgrp->full_slots >>= i;\n\t}\n\n\treturn grp->slots[grp->front];\n}\n\n/*\n * adjust the bucket list. When the start time of a group decreases,\n * we move the index down (modulo QFQ_MAX_SLOTS) so we don't need to\n * move the objects. The mask of occupied slots must be shifted\n * because we use ffs() to find the first non-empty slot.\n * This covers decreases in the group's start time, but what about\n * increases of the start time ?\n * Here too we should make sure that i is less than 32\n */\nstatic inline void\nqfq_slot_rotate(struct qfq_sched *q, struct qfq_group *grp, uint64_t roundedS)\n{\n\tunsigned int i = (grp->S - roundedS) >> grp->slot_shift;\n\n\tgrp->full_slots <<= i;\n\tgrp->front = (grp->front - i) % QFQ_MAX_SLOTS;\n}\n\n\nstatic inline void\nqfq_update_eligible(struct qfq_sched *q, uint64_t old_V)\n{\n\tbitmap ineligible;\n\n\tineligible = q->bitmaps[IR] | q->bitmaps[IB];\n\tif (ineligible) {\n\t\tif (!q->bitmaps[ER]) {\n\t\t\tstruct qfq_group *grp;\n\t\t\tgrp = qfq_ffs(q, ineligible);\n\t\t\tif (qfq_gt(grp->S, q->V))\n\t\t\t\tq->V = grp->S;\n\t\t}\n\t\tqfq_make_eligible(q, old_V);\n\t}\n}\n\n/*\n * Updates the class, returns true if also the group needs to be updated.\n */\nstatic inline int\nqfq_update_class(struct qfq_sched *q, struct qfq_group *grp,\n\t    struct qfq_class *cl)\n{\n\n\tcl->S = cl->F;\n\tif (cl->_q.mq.head == NULL)  {\n\t\tqfq_front_slot_remove(grp);\n\t} else {\n\t\tunsigned int len;\n\t\tuint64_t roundedS;\n\n\t\tlen = cl->_q.mq.head->m_pkthdr.len;\n\t\tcl->F = cl->S + (uint64_t)len * cl->inv_w;\n\t\troundedS = qfq_round_down(cl->S, grp->slot_shift);\n\t\tif (roundedS == grp->S)\n\t\t\treturn 0;\n\n\t\tqfq_front_slot_remove(grp);\n\t\tqfq_slot_insert(grp, cl, roundedS);\n\t}\n\treturn 1;\n}\n\nstatic struct mbuf *\nqfq_dequeue(struct dn_sch_inst *si)\n{\n\tstruct qfq_sched *q = (struct qfq_sched *)(si + 1);\n\tstruct qfq_group *grp;\n\tstruct qfq_class *cl;\n\tstruct mbuf *m;\n\tuint64_t old_V;\n\n\tNO(q->loops++;)\n\tif (!q->bitmaps[ER]) {\n\t\tNO(if (q->queued)\n\t\t\tdump_sched(q, \"start dequeue\");)\n\t\treturn NULL;\n\t}\n\n\tgrp = qfq_ffs(q, q->bitmaps[ER]);\n\n\tcl = grp->slots[grp->front];\n\t/* extract from the first bucket in the bucket list */\n\tm = dn_dequeue(&cl->_q);\n\n\tif (!m) {\n\t\tD(\"BUG/* non-workconserving leaf */\");\n\t\treturn NULL;\n\t}\n\tNO(q->queued--;)\n\told_V = q->V;\n\tq->V += (uint64_t)m->m_pkthdr.len * IWSUM;\n\tND(\"m is %p F 0x%llx V now 0x%llx\", m, cl->F, q->V);\n\n\tif (qfq_update_class(q, grp, cl)) {\n\t\tuint64_t old_F = grp->F;\n\t\tcl = qfq_slot_scan(grp);\n\t\tif (!cl) { /* group gone, remove from ER */\n\t\t\t__clear_bit(grp->index, &q->bitmaps[ER]);\n\t\t\t// grp->S = grp->F + 1; // XXX debugging only\n\t\t} else {\n\t\t\tuint64_t roundedS = qfq_round_down(cl->S, grp->slot_shift);\n\t\t\tunsigned int s;\n\n\t\t\tif (grp->S == roundedS)\n\t\t\t\tgoto skip_unblock;\n\t\t\tgrp->S = roundedS;\n\t\t\tgrp->F = roundedS + (2ULL << grp->slot_shift);\n\t\t\t/* remove from ER and put in the new set */\n\t\t\t__clear_bit(grp->index, &q->bitmaps[ER]);\n\t\t\ts = qfq_calc_state(q, grp);\n\t\t\t__set_bit(grp->index, &q->bitmaps[s]);\n\t\t}\n\t\t/* we need to unblock even if the group has gone away */\n\t\tqfq_unblock_groups(q, grp->index, old_F);\n\t}\n\nskip_unblock:\n\tqfq_update_eligible(q, old_V);\n\tNO(if (!q->bitmaps[ER] && q->queued)\n\t\tdump_sched(q, \"end dequeue\");)\n\n\treturn m;\n}\n\n/*\n * Assign a reasonable start time for a new flow k in group i.\n * Admissible values for \\hat(F) are multiples of \\sigma_i\n * no greater than V+\\sigma_i . Larger values mean that\n * we had a wraparound so we consider the timestamp to be stale.\n *\n * If F is not stale and F >= V then we set S = F.\n * Otherwise we should assign S = V, but this may violate\n * the ordering in ER. So, if we have groups in ER, set S to\n * the F_j of the first group j which would be blocking us.\n * We are guaranteed not to move S backward because\n * otherwise our group i would still be blocked.\n */\nstatic inline void\nqfq_update_start(struct qfq_sched *q, struct qfq_class *cl)\n{\n\tunsigned long mask;\n\tuint64_t limit, roundedF;\n\tint slot_shift = cl->grp->slot_shift;\n\n\troundedF = qfq_round_down(cl->F, slot_shift);\n\tlimit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift);\n\n\tif (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) {\n\t\t/* timestamp was stale */\n\t\tmask = mask_from(q->bitmaps[ER], cl->grp->index);\n\t\tif (mask) {\n\t\t\tstruct qfq_group *next = qfq_ffs(q, mask);\n\t\t\tif (qfq_gt(roundedF, next->F)) {\n\t\t\t\tcl->S = next->F;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tcl->S = q->V;\n\t} else { /* timestamp is not stale */\n\t\tcl->S = cl->F;\n\t}\n}\n\nstatic int\nqfq_enqueue(struct dn_sch_inst *si, struct dn_queue *_q, struct mbuf *m)\n{\n\tstruct qfq_sched *q = (struct qfq_sched *)(si + 1);\n\tstruct qfq_group *grp;\n\tstruct qfq_class *cl = (struct qfq_class *)_q;\n\tuint64_t roundedS;\n\tint s;\n\n\tNO(q->loops++;)\n\tDX(4, \"len %d flow %p inv_w 0x%x grp %d\", m->m_pkthdr.len,\n\t\t_q, cl->inv_w, cl->grp->index);\n\t/* XXX verify that the packet obeys the parameters */\n\tif (m != _q->mq.head) {\n\t\tif (dn_enqueue(_q, m, 0)) /* packet was dropped */\n\t\t\treturn 1;\n\t\tNO(q->queued++;)\n\t\tif (m != _q->mq.head)\n\t\t\treturn 0;\n\t}\n\t/* If reach this point, queue q was idle */\n\tgrp = cl->grp;\n\tqfq_update_start(q, cl); /* adjust start time */\n\t/* compute new finish time and rounded start. */\n\tcl->F = cl->S + (uint64_t)(m->m_pkthdr.len) * cl->inv_w;\n\troundedS = qfq_round_down(cl->S, grp->slot_shift);\n\n\t/*\n\t * insert cl in the correct bucket.\n\t * If cl->S >= grp->S we don't need to adjust the\n\t * bucket list and simply go to the insertion phase.\n\t * Otherwise grp->S is decreasing, we must make room\n\t * in the bucket list, and also recompute the group state.\n\t * Finally, if there were no flows in this group and nobody\n\t * was in ER make sure to adjust V.\n\t */\n\tif (grp->full_slots) {\n\t\tif (!qfq_gt(grp->S, cl->S))\n\t\t\tgoto skip_update;\n\t\t/* create a slot for this cl->S */\n\t\tqfq_slot_rotate(q, grp, roundedS);\n\t\t/* group was surely ineligible, remove */\n\t\t__clear_bit(grp->index, &q->bitmaps[IR]);\n\t\t__clear_bit(grp->index, &q->bitmaps[IB]);\n\t} else if (!q->bitmaps[ER] && qfq_gt(roundedS, q->V))\n\t\tq->V = roundedS;\n\n\tgrp->S = roundedS;\n\tgrp->F = roundedS + (2ULL << grp->slot_shift); // i.e. 2\\sigma_i\n\ts = qfq_calc_state(q, grp);\n\t__set_bit(grp->index, &q->bitmaps[s]);\n\tND(\"new state %d 0x%x\", s, q->bitmaps[s]);\n\tND(\"S %llx F %llx V %llx\", cl->S, cl->F, q->V);\nskip_update:\n\tqfq_slot_insert(grp, cl, roundedS);\n\n\treturn 0;\n}\n\n\n#if 0\nstatic inline void\nqfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp,\n\tstruct qfq_class *cl, struct qfq_class **pprev)\n{\n\tunsigned int i, offset;\n\tuint64_t roundedS;\n\n\troundedS = qfq_round_down(cl->S, grp->slot_shift);\n\toffset = (roundedS - grp->S) >> grp->slot_shift;\n\ti = (grp->front + offset) % QFQ_MAX_SLOTS;\n\n#ifdef notyet\n\tif (!pprev) {\n\t\tpprev = &grp->slots[i];\n\t\twhile (*pprev && *pprev != cl)\n\t\t\tpprev = &(*pprev)->next;\n\t}\n#endif\n\n\t*pprev = cl->next;\n\tif (!grp->slots[i])\n\t\t__clear_bit(offset, &grp->full_slots);\n}\n\n/*\n * called to forcibly destroy a queue.\n * If the queue is not in the front bucket, or if it has\n * other queues in the front bucket, we can simply remove\n * the queue with no other side effects.\n * Otherwise we must propagate the event up.\n * XXX description to be completed.\n */\nstatic void\nqfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl,\n\t\t\t\t struct qfq_class **pprev)\n{\n\tstruct qfq_group *grp = &q->groups[cl->index];\n\tunsigned long mask;\n\tuint64_t roundedS;\n\tint s;\n\n\tcl->F = cl->S;\t// not needed if the class goes away.\n\tqfq_slot_remove(q, grp, cl, pprev);\n\n\tif (!grp->full_slots) {\n\t\t/* nothing left in the group, remove from all sets.\n\t\t * Do ER last because if we were blocking other groups\n\t\t * we must unblock them.\n\t\t */\n\t\t__clear_bit(grp->index, &q->bitmaps[IR]);\n\t\t__clear_bit(grp->index, &q->bitmaps[EB]);\n\t\t__clear_bit(grp->index, &q->bitmaps[IB]);\n\n\t\tif (test_bit(grp->index, &q->bitmaps[ER]) &&\n\t\t    !(q->bitmaps[ER] & ~((1UL << grp->index) - 1))) {\n\t\t\tmask = q->bitmaps[ER] & ((1UL << grp->index) - 1);\n\t\t\tif (mask)\n\t\t\t\tmask = ~((1UL << __fls(mask)) - 1);\n\t\t\telse\n\t\t\t\tmask = ~0UL;\n\t\t\tqfq_move_groups(q, mask, EB, ER);\n\t\t\tqfq_move_groups(q, mask, IB, IR);\n\t\t}\n\t\t__clear_bit(grp->index, &q->bitmaps[ER]);\n\t} else if (!grp->slots[grp->front]) {\n\t\tcl = qfq_slot_scan(grp);\n\t\troundedS = qfq_round_down(cl->S, grp->slot_shift);\n\t\tif (grp->S != roundedS) {\n\t\t\t__clear_bit(grp->index, &q->bitmaps[ER]);\n\t\t\t__clear_bit(grp->index, &q->bitmaps[IR]);\n\t\t\t__clear_bit(grp->index, &q->bitmaps[EB]);\n\t\t\t__clear_bit(grp->index, &q->bitmaps[IB]);\n\t\t\tgrp->S = roundedS;\n\t\t\tgrp->F = roundedS + (2ULL << grp->slot_shift);\n\t\t\ts = qfq_calc_state(q, grp);\n\t\t\t__set_bit(grp->index, &q->bitmaps[s]);\n\t\t}\n\t}\n\tqfq_update_eligible(q, q->V);\n}\n#endif\n\nstatic int\nqfq_new_fsk(struct dn_fsk *f)\n{\n\tipdn_bound_var(&f->fs.par[0], 1, 1, QFQ_MAX_WEIGHT, \"qfq weight\");\n\tipdn_bound_var(&f->fs.par[1], 1500, 1, 2000, \"qfq maxlen\");\n\tND(\"weight %d len %d\\n\", f->fs.par[0], f->fs.par[1]);\n\treturn 0;\n}\n\n/*\n * initialize a new scheduler instance\n */\nstatic int\nqfq_new_sched(struct dn_sch_inst *si)\n{\n\tstruct qfq_sched *q = (struct qfq_sched *)(si + 1);\n\tstruct qfq_group *grp;\n\tint i;\n\n\tfor (i = 0; i <= QFQ_MAX_INDEX; i++) {\n\t\tgrp = &q->groups[i];\n\t\tgrp->index = i;\n\t\tgrp->slot_shift = QFQ_MTU_SHIFT + FRAC_BITS -\n\t\t\t\t\t(QFQ_MAX_INDEX - i);\n\t}\n\treturn 0;\n}\n\n/*\n * QFQ scheduler descriptor\n */\nstatic struct dn_alg qfq_desc = {\n\t_SI( .type = ) DN_SCHED_QFQ,\n\t_SI( .name = ) \"QFQ\",\n\t_SI( .flags = ) DN_MULTIQUEUE,\n\n\t_SI( .schk_datalen = ) 0,\n\t_SI( .si_datalen = ) sizeof(struct qfq_sched),\n\t_SI( .q_datalen = ) sizeof(struct qfq_class) - sizeof(struct dn_queue),\n\n\t_SI( .enqueue = ) qfq_enqueue,\n\t_SI( .dequeue = ) qfq_dequeue,\n\n\t_SI( .config = )  NULL,\n\t_SI( .destroy = )  NULL,\n\t_SI( .new_sched = ) qfq_new_sched,\n\t_SI( .free_sched = )  NULL,\n\t_SI( .new_fsk = ) qfq_new_fsk,\n\t_SI( .free_fsk = )  NULL,\n\t_SI( .new_queue = ) qfq_new_queue,\n\t_SI( .free_queue = ) qfq_free_queue,\n};\n\nDECLARE_DNSCHED_MODULE(dn_qfq, &qfq_desc);\n\n#ifdef QFQ_DEBUG\nstatic void\ndump_groups(struct qfq_sched *q, uint32_t mask)\n{\n\tint i, j;\n\n\tfor (i = 0; i < QFQ_MAX_INDEX + 1; i++) {\n\t\tstruct qfq_group *g = &q->groups[i];\n\n\t\tif (0 == (mask & (1<<i)))\n\t\t\tcontinue;\n\t\tfor (j = 0; j < QFQ_MAX_SLOTS; j++) {\n\t\t\tif (g->slots[j])\n\t\t\t\tD(\"    bucket %d %p\", j, g->slots[j]);\n\t\t}\n\t\tD(\"full_slots 0x%x\", g->full_slots);\n\t\tD(\"        %2d S 0x%20llx F 0x%llx %c\", i,\n\t\t\tg->S, g->F,\n\t\t\tmask & (1<<i) ? '1' : '0');\n\t}\n}\n\nstatic void\ndump_sched(struct qfq_sched *q, const char *msg)\n{\n\tD(\"--- in %s: ---\", msg);\n\tND(\"loops %d queued %d V 0x%llx\", q->loops, q->queued, q->V);\n\tD(\"    ER 0x%08x\", q->bitmaps[ER]);\n\tD(\"    EB 0x%08x\", q->bitmaps[EB]);\n\tD(\"    IR 0x%08x\", q->bitmaps[IR]);\n\tD(\"    IB 0x%08x\", q->bitmaps[IB]);\n\tdump_groups(q, 0xffffffff);\n};\n#endif /* QFQ_DEBUG */\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_sched_rr.c",
    "content": "/*\n * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: dn_sched_rr.c 11480 2012-07-31 08:02:00Z luigi $\n */\n\n#ifdef _KERNEL\n#include <sys/malloc.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/kernel.h>\n#include <sys/mbuf.h>\n#include <sys/module.h>\n#include <net/if.h>\t/* IFNAMSIZ */\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t\t/* ipfw_rule_ref */\n#include <netinet/ip_fw.h>\t/* flow_id */\n#include <netinet/ip_dummynet.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n#else\n#include <dn_test.h>\n#endif\n\n#define DN_SCHED_RR\t3 // XXX Where?\n\nstruct rr_queue {\n\tstruct dn_queue q;\t\t/* Standard queue */\n\tint status;\t\t\t/* 1: queue is in the list */\n\tint credit;\t\t\t/* Number of bytes to transmit */\n\tint quantum;\t\t\t/* quantum * C */\n\tstruct rr_queue *qnext;\t\t/* */\n};\n\n/* struct rr_schk contains global config parameters\n * and is right after dn_schk\n */\nstruct rr_schk {\n\tint min_q;\t\t/* Min quantum */\n\tint max_q;\t\t/* Max quantum */\n\tint q_bytes;\t\t/* Bytes per quantum */\n};\n\n/* per-instance round robin list, right after dn_sch_inst */\nstruct rr_si {\n\tstruct rr_queue *head, *tail;\t/* Pointer to current queue */\n};\n\n/* Append a queue to the rr list */\nstatic inline void\nrr_append(struct rr_queue *q, struct rr_si *si)\n{\n\tq->status = 1;\t\t/* mark as in-rr_list */\n\tq->credit = q->quantum;\t/* initialize credit */\n\n\t/* append to the tail */\n\tif (si->head == NULL)\n\t\tsi->head = q;\n\telse\n\t\tsi->tail->qnext = q;\n\tsi->tail = q;\t\t/* advance the tail pointer */\n\tq->qnext = si->head;\t/* make it circular */\n}\n\n/* Remove the head queue from circular list. */\nstatic inline void\nrr_remove_head(struct rr_si *si)\n{\n\tif (si->head == NULL)\n\t\treturn; /* empty queue */\n\tsi->head->status = 0;\n\n\tif (si->head == si->tail) {\n\t\tsi->head = si->tail = NULL;\n\t\treturn;\n\t}\n\n\tsi->head = si->head->qnext;\n\tsi->tail->qnext = si->head;\n}\n\n/* Remove a queue from circular list.\n * XXX see if ti can be merge with remove_queue()\n */\nstatic inline void\nremove_queue_q(struct rr_queue *q, struct rr_si *si)\n{\n\tstruct rr_queue *prev;\n\n\tif (q->status != 1)\n\t\treturn;\n\tif (q == si->head) {\n\t\trr_remove_head(si);\n\t\treturn;\n\t}\n\n\tfor (prev = si->head; prev; prev = prev->qnext) {\n\t\tif (prev->qnext != q)\n\t\t\tcontinue;\n\t\tprev->qnext = q->qnext;\n\t\tif (q == si->tail)\n\t\t\tsi->tail = prev;\n\t\tq->status = 0;\n\t\tbreak;\n\t}\n}\n\n\nstatic inline void\nnext_pointer(struct rr_si *si)\n{\n\tif (si->head == NULL)\n\t\treturn; /* empty queue */\n\n\tsi->head = si->head->qnext;\n\tsi->tail = si->tail->qnext;\n}\n\nstatic int\nrr_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)\n{\n\tstruct rr_si *si;\n\tstruct rr_queue *rrq;\n\n\tif (m != q->mq.head) {\n\t\tif (dn_enqueue(q, m, 0)) /* packet was dropped */\n\t\t\treturn 1;\n\t\tif (m != q->mq.head)\n\t\t\treturn 0;\n\t}\n\n\t/* If reach this point, queue q was idle */\n\tsi = (struct rr_si *)(_si + 1);\n\trrq = (struct rr_queue *)q;\n\n\tif (rrq->status == 1) /* Queue is already in the queue list */\n\t\treturn 0;\n\n\t/* Insert the queue in the queue list */\n\trr_append(rrq, si);\n\n\treturn 0;\n}\n\nstatic struct mbuf *\nrr_dequeue(struct dn_sch_inst *_si)\n{\n\t/* Access scheduler instance private data */\n\tstruct rr_si *si = (struct rr_si *)(_si + 1);\n\tstruct rr_queue *rrq;\n\tuint64_t len;\n\n\twhile ( (rrq = si->head) ) {\n\t\tstruct mbuf *m = rrq->q.mq.head;\n\t\tif ( m == NULL) {\n\t\t\t/* empty queue, remove from list */\n\t\t\trr_remove_head(si);\n\t\t\tcontinue;\n\t\t}\n\t\tlen = m->m_pkthdr.len;\n\n\t\tif (len > rrq->credit) {\n\t\t\t/* Packet too big */\n\t\t\trrq->credit += rrq->quantum;\n\t\t\t/* Try next queue */\n\t\t\tnext_pointer(si);\n\t\t} else {\n\t\t\trrq->credit -= len;\n\t\t\treturn dn_dequeue(&rrq->q);\n\t\t}\n\t}\n\n\t/* no packet to dequeue*/\n\treturn NULL;\n}\n\nstatic int\nrr_config(struct dn_schk *_schk)\n{\n\tstruct rr_schk *schk = (struct rr_schk *)(_schk + 1);\n\tND(\"called\");\n\n\t/* use reasonable quantums (64..2k bytes, default 1500) */\n\tschk->min_q = 64;\n\tschk->max_q = 2048;\n\tschk->q_bytes = 1500;\t/* quantum */\n\n\treturn 0;\n}\n\nstatic int\nrr_new_sched(struct dn_sch_inst *_si)\n{\n\tstruct rr_si *si = (struct rr_si *)(_si + 1);\n\n\tND(\"called\");\n\tsi->head = si->tail = NULL;\n\n\treturn 0;\n}\n\nstatic int\nrr_free_sched(struct dn_sch_inst *_si)\n{\n\tND(\"called\");\n\t/* Nothing to do? */\n\treturn 0;\n}\n\nstatic int\nrr_new_fsk(struct dn_fsk *fs)\n{\n\tstruct rr_schk *schk = (struct rr_schk *)(fs->sched + 1);\n\t/* par[0] is the weight, par[1] is the quantum step */\n\tipdn_bound_var(&fs->fs.par[0], 1,\n\t\t1, 65536, \"RR weight\");\n\tipdn_bound_var(&fs->fs.par[1], schk->q_bytes,\n\t\tschk->min_q, schk->max_q, \"RR quantum\");\n\treturn 0;\n}\n\nstatic int\nrr_new_queue(struct dn_queue *_q)\n{\n\tstruct rr_queue *q = (struct rr_queue *)_q;\n\n\t_q->ni.oid.subtype = DN_SCHED_RR;\n\n\tq->quantum = _q->fs->fs.par[0] * _q->fs->fs.par[1];\n\tND(\"called, q->quantum %d\", q->quantum);\n\tq->credit = q->quantum;\n\tq->status = 0;\n\n\tif (_q->mq.head != NULL) {\n\t\t/* Queue NOT empty, insert in the queue list */\n\t\trr_append(q, (struct rr_si *)(_q->_si + 1));\n\t}\n\treturn 0;\n}\n\nstatic int\nrr_free_queue(struct dn_queue *_q, int safe)\n{\n\tstruct rr_queue *q = (struct rr_queue *)_q;\n\n\tND(\"called\");\n\tif (safe) \t/* Delete only if status == 0 */\n\t\treturn q->status;\n\n\tif (q->status == 1) {\n\t\tstruct rr_si *si = (struct rr_si *)(_q->_si + 1);\n\t\tremove_queue_q(q, si);\n\t}\n\treturn 0;\n}\n\n/*\n * RR scheduler descriptor\n * contains the type of the scheduler, the name, the size of the\n * structures and function pointers.\n */\nstatic struct dn_alg rr_desc = {\n\t_SI( .type = ) DN_SCHED_RR,\n\t_SI( .name = ) \"RR\",\n\t_SI( .flags = ) DN_MULTIQUEUE,\n\n\t_SI( .schk_datalen = ) 0,\n\t_SI( .si_datalen = ) sizeof(struct rr_si),\n\t_SI( .q_datalen = ) sizeof(struct rr_queue) - sizeof(struct dn_queue),\n\n\t_SI( .enqueue = ) rr_enqueue,\n\t_SI( .dequeue = ) rr_dequeue,\n\n\t_SI( .config = ) rr_config,\n\t_SI( .destroy = ) NULL,\n\t_SI( .new_sched = ) rr_new_sched,\n\t_SI( .free_sched = ) rr_free_sched,\n\t_SI( .new_fsk = ) rr_new_fsk,\n\t_SI( .free_fsk = ) NULL,\n\t_SI( .new_queue = ) rr_new_queue,\n\t_SI( .free_queue = ) rr_free_queue,\n};\n\n\nDECLARE_DNSCHED_MODULE(dn_rr, &rr_desc);\n"
  },
  {
    "path": "sys/netinet/ipfw/dn_sched_wf2q.c",
    "content": "/*\n * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa\n * Copyright (c) 2000-2002 Luigi Rizzo, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: dn_sched_wf2q.c 11480 2012-07-31 08:02:00Z luigi $\n */\n\n#ifdef _KERNEL\n#include <sys/malloc.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/kernel.h>\n#include <sys/mbuf.h>\n#include <sys/module.h>\n#include <net/if.h>\t/* IFNAMSIZ */\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t\t/* ipfw_rule_ref */\n#include <netinet/ip_fw.h>\t/* flow_id */\n#include <netinet/ip_dummynet.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n#else\n#include <dn_test.h>\n#endif\n\n#ifndef MAX64\n#define MAX64(x,y)  (( (int64_t) ( (y)-(x) )) > 0 ) ? (y) : (x)\n#endif\n\n/*\n * timestamps are computed on 64 bit using fixed point arithmetic.\n * LMAX_BITS, WMAX_BITS are the max number of bits for the packet len\n * and sum of weights, respectively. FRAC_BITS is the number of\n * fractional bits. We want FRAC_BITS >> WMAX_BITS to avoid too large\n * errors when computing the inverse, FRAC_BITS < 32 so we can do 1/w\n * using an unsigned 32-bit division, and to avoid wraparounds we need\n * LMAX_BITS + WMAX_BITS + FRAC_BITS << 64\n * As an example\n * FRAC_BITS = 26, LMAX_BITS=14, WMAX_BITS = 19\n */\n#ifndef FRAC_BITS\n#define FRAC_BITS    28 /* shift for fixed point arithmetic */\n#define\tONE_FP\t(1UL << FRAC_BITS)\n#endif\n\n/*\n * Private information for the scheduler instance:\n * sch_heap (key is Finish time) returns the next queue to serve\n * ne_heap (key is Start time) stores not-eligible queues\n * idle_heap (key=start/finish time) stores idle flows. It must\n *\tsupport extract-from-middle.\n * A flow is only in 1 of the three heaps.\n * XXX todo: use a more efficient data structure, e.g. a tree sorted\n * by F with min_subtree(S) in each node\n */\nstruct wf2qp_si {\n    struct dn_heap sch_heap;\t/* top extract - key Finish  time */\n    struct dn_heap ne_heap;\t/* top extract - key Start   time */\n    struct dn_heap idle_heap;\t/* random extract - key Start=Finish time */\n    uint64_t V;\t\t\t/* virtual time */\n    uint32_t inv_wsum;\t\t/* inverse of sum of weights */\n    uint32_t wsum;\t\t/* sum of weights */\n};\n\nstruct wf2qp_queue {\n    struct dn_queue _q;\n    uint64_t S, F;\t\t/* start time, finish time */\n    uint32_t inv_w;\t\t/* ONE_FP / weight */\n    int32_t heap_pos;\t\t/* position (index) of struct in heap */\n};\n\n/*\n * This file implements a WF2Q+ scheduler as it has been in dummynet\n * since 2000.\n * The scheduler supports per-flow queues and has O(log N) complexity.\n *\n * WF2Q+ needs to drain entries from the idle heap so that we\n * can keep the sum of weights up to date. We can do it whenever\n * we get a chance, or periodically, or following some other\n * strategy. The function idle_check() drains at most N elements\n * from the idle heap.\n */\nstatic void\nidle_check(struct wf2qp_si *si, int n, int force)\n{\n    struct dn_heap *h = &si->idle_heap;\n    while (n-- > 0 && h->elements > 0 &&\n\t\t(force || DN_KEY_LT(HEAP_TOP(h)->key, si->V))) {\n\tstruct dn_queue *q = HEAP_TOP(h)->object;\n        struct wf2qp_queue *alg_fq = (struct wf2qp_queue *)q;\n\n        heap_extract(h, NULL);\n        /* XXX to let the flowset delete the queue we should\n\t * mark it as 'unused' by the scheduler.\n\t */\n        alg_fq->S = alg_fq->F + 1; /* Mark timestamp as invalid. */\n        si->wsum -= q->fs->fs.par[0];\t/* adjust sum of weights */\n\tif (si->wsum > 0)\n\t\tsi->inv_wsum = ONE_FP/si->wsum;\n    }\n}\n\nstatic int\nwf2qp_enqueue(struct dn_sch_inst *_si, struct dn_queue *q, struct mbuf *m)\n{\n    struct dn_fsk *fs = q->fs;\n    struct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);\n    struct wf2qp_queue *alg_fq;\n    uint64_t len = m->m_pkthdr.len;\n\n    if (m != q->mq.head) {\n\tif (dn_enqueue(q, m, 0)) /* packet was dropped */\n\t    return 1;\n\tif (m != q->mq.head)\t/* queue was already busy */\n\t    return 0;\n    }\n\n    /* If reach this point, queue q was idle */\n    alg_fq = (struct wf2qp_queue *)q;\n\n    if (DN_KEY_LT(alg_fq->F, alg_fq->S)) {\n        /* F<S means timestamps are invalid ->brand new queue. */\n        alg_fq->S = si->V;\t\t/* init start time */\n        si->wsum += fs->fs.par[0];\t/* add weight of new queue. */\n\tsi->inv_wsum = ONE_FP/si->wsum;\n    } else { /* if it was idle then it was in the idle heap */\n        heap_extract(&si->idle_heap, q);\n        alg_fq->S = MAX64(alg_fq->F, si->V);\t/* compute new S */\n    }\n    alg_fq->F = alg_fq->S + len * alg_fq->inv_w;\n\n    /* if nothing is backlogged, make sure this flow is eligible */\n    if (si->ne_heap.elements == 0 && si->sch_heap.elements == 0)\n        si->V = MAX64(alg_fq->S, si->V);\n\n    /*\n     * Look at eligibility. A flow is not eligibile if S>V (when\n     * this happens, it means that there is some other flow already\n     * scheduled for the same pipe, so the sch_heap cannot be\n     * empty). If the flow is not eligible we just store it in the\n     * ne_heap. Otherwise, we store in the sch_heap.\n     * Note that for all flows in sch_heap (SCH), S_i <= V,\n     * and for all flows in ne_heap (NEH), S_i > V.\n     * So when we need to compute max(V, min(S_i)) forall i in\n     * SCH+NEH, we only need to look into NEH.\n     */\n    if (DN_KEY_LT(si->V, alg_fq->S)) {\n        /* S>V means flow Not eligible. */\n        if (si->sch_heap.elements == 0)\n            D(\"++ ouch! not eligible but empty scheduler!\");\n        heap_insert(&si->ne_heap, alg_fq->S, q);\n    } else {\n        heap_insert(&si->sch_heap, alg_fq->F, q);\n    }\n    return 0;\n}\n\n/* XXX invariant: sch > 0 || V >= min(S in neh) */\nstatic struct mbuf *\nwf2qp_dequeue(struct dn_sch_inst *_si)\n{\n\t/* Access scheduler instance private data */\n\tstruct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);\n\tstruct mbuf *m;\n\tstruct dn_queue *q;\n\tstruct dn_heap *sch = &si->sch_heap;\n\tstruct dn_heap *neh = &si->ne_heap;\n\tstruct wf2qp_queue *alg_fq;\n\n\tif (sch->elements == 0 && neh->elements == 0) {\n\t\t/* we have nothing to do. We could kill the idle heap\n\t\t * altogether and reset V\n\t\t */\n\t\tidle_check(si, 0x7fffffff, 1);\n\t\tsi->V = 0;\n\t\tsi->wsum = 0;\t/* should be set already */\n\t\treturn NULL;\t/* quick return if nothing to do */\n\t}\n\tidle_check(si, 1, 0);\t/* drain something from the idle heap */\n\n\t/* make sure at least one element is eligible, bumping V\n\t * and moving entries that have become eligible.\n\t * We need to repeat the first part twice, before and\n\t * after extracting the candidate, or enqueue() will\n\t * find the data structure in a wrong state.\n\t */\n  m = NULL;\n  for(;;) {\n\t/*\n\t * Compute V = max(V, min(S_i)). Remember that all elements\n\t * in sch have by definition S_i <= V so if sch is not empty,\n\t * V is surely the max and we must not update it. Conversely,\n\t * if sch is empty we only need to look at neh.\n\t * We don't need to move the queues, as it will be done at the\n\t * next enqueue\n\t */\n\tif (sch->elements == 0 && neh->elements > 0) {\n\t\tsi->V = MAX64(si->V, HEAP_TOP(neh)->key);\n\t}\n\twhile (neh->elements > 0 &&\n\t\t    DN_KEY_LEQ(HEAP_TOP(neh)->key, si->V)) {\n\t\tq = HEAP_TOP(neh)->object;\n\t\talg_fq = (struct wf2qp_queue *)q;\n\t\theap_extract(neh, NULL);\n\t\theap_insert(sch, alg_fq->F, q);\n\t}\n\tif (m) /* pkt found in previous iteration */\n\t\tbreak;\n\t/* ok we have at least one eligible pkt */\n\tq = HEAP_TOP(sch)->object;\n\talg_fq = (struct wf2qp_queue *)q;\n\tm = dn_dequeue(q);\n\theap_extract(sch, NULL); /* Remove queue from heap. */\n\tsi->V += (uint64_t)(m->m_pkthdr.len) * si->inv_wsum;\n\talg_fq->S = alg_fq->F;  /* Update start time. */\n\tif (q->mq.head == 0) {\t/* not backlogged any more. */\n\t\theap_insert(&si->idle_heap, alg_fq->F, q);\n\t} else {\t\t\t/* Still backlogged. */\n\t\t/* Update F, store in neh or sch */\n\t\tuint64_t len = q->mq.head->m_pkthdr.len;\n\t\talg_fq->F += len * alg_fq->inv_w;\n\t\tif (DN_KEY_LEQ(alg_fq->S, si->V)) {\n\t\t\theap_insert(sch, alg_fq->F, q);\n\t\t} else {\n\t\t\theap_insert(neh, alg_fq->S, q);\n\t\t}\n\t}\n    }\n\treturn m;\n}\n\nstatic int\nwf2qp_new_sched(struct dn_sch_inst *_si)\n{\n\tstruct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);\n\tint ofs = offsetof(struct wf2qp_queue, heap_pos);\n\n\t/* all heaps support extract from middle */\n\tif (heap_init(&si->idle_heap, 16, ofs) ||\n\t    heap_init(&si->sch_heap, 16, ofs) ||\n\t    heap_init(&si->ne_heap, 16, ofs)) {\n\t\theap_free(&si->ne_heap);\n\t\theap_free(&si->sch_heap);\n\t\theap_free(&si->idle_heap);\n\t\treturn ENOMEM;\n\t}\n\treturn 0;\n}\n\nstatic int\nwf2qp_free_sched(struct dn_sch_inst *_si)\n{\n\tstruct wf2qp_si *si = (struct wf2qp_si *)(_si + 1);\n\n\theap_free(&si->sch_heap);\n\theap_free(&si->ne_heap);\n\theap_free(&si->idle_heap);\n\n\treturn 0;\n}\n\nstatic int\nwf2qp_new_fsk(struct dn_fsk *fs)\n{\n\tipdn_bound_var(&fs->fs.par[0], 1,\n\t\t1, 100, \"WF2Q+ weight\");\n\treturn 0;\n}\n\nstatic int\nwf2qp_new_queue(struct dn_queue *_q)\n{\n\tstruct wf2qp_queue *q = (struct wf2qp_queue *)_q;\n\n\t_q->ni.oid.subtype = DN_SCHED_WF2QP;\n\tq->F = 0;\t/* not strictly necessary */\n\tq->S = q->F + 1;    /* mark timestamp as invalid. */\n        q->inv_w = ONE_FP / _q->fs->fs.par[0];\n\tif (_q->mq.head != NULL) {\n\t\twf2qp_enqueue(_q->_si, _q, _q->mq.head);\n\t}\n\treturn 0;\n}\n\n/*\n * Called when the infrastructure removes a queue (e.g. flowset\n * is reconfigured). Nothing to do if we did not 'own' the queue,\n * otherwise remove it from the right heap and adjust the sum\n * of weights.\n */\nstatic int\nwf2qp_free_queue(struct dn_queue *q, int safe)\n{\n\tstruct wf2qp_queue *alg_fq = (struct wf2qp_queue *)q;\n\tstruct wf2qp_si *si = (struct wf2qp_si *)(q->_si + 1);\n\n\tif (alg_fq->S >= alg_fq->F + 1)\n\t\treturn 0;\t/* nothing to do, not in any heap */\n\n\t/* queue is in a scheduler heap */\n\tif (safe)\t/* do not delete in safe mode */\n\t\treturn 1;\n\n\tsi->wsum -= q->fs->fs.par[0];\n\tif (si->wsum > 0)\n\t\tsi->inv_wsum = ONE_FP/si->wsum;\n\n\t/* extract from the heap. XXX TODO we may need to adjust V\n\t * to make sure the invariants hold.\n\t */\n\tif (q->mq.head == NULL) {\n\t\theap_extract(&si->idle_heap, q);\n\t} else if (DN_KEY_LT(si->V, alg_fq->S)) {\n\t\theap_extract(&si->ne_heap, q);\n\t} else {\n\t\theap_extract(&si->sch_heap, q);\n\t}\n\treturn 0;\n}\n\n/*\n * WF2Q+ scheduler descriptor\n * contains the type of the scheduler, the name, the size of the\n * structures and function pointers.\n */\nstatic struct dn_alg wf2qp_desc = {\n\t_SI( .type = ) DN_SCHED_WF2QP,\n\t_SI( .name = ) \"WF2Q+\",\n\t_SI( .flags = ) DN_MULTIQUEUE,\n\n\t/* we need extra space in the si and the queue */\n\t_SI( .schk_datalen = ) 0,\n\t_SI( .si_datalen = ) sizeof(struct wf2qp_si),\n\t_SI( .q_datalen = ) sizeof(struct wf2qp_queue) -\n\t\t\t\tsizeof(struct dn_queue),\n\n\t_SI( .enqueue = ) wf2qp_enqueue,\n\t_SI( .dequeue = ) wf2qp_dequeue,\n\n\t_SI( .config = )  NULL,\n\t_SI( .destroy = )  NULL,\n\t_SI( .new_sched = ) wf2qp_new_sched,\n\t_SI( .free_sched = ) wf2qp_free_sched,\n\n\t_SI( .new_fsk = ) wf2qp_new_fsk,\n\t_SI( .free_fsk = )  NULL,\n\n\t_SI( .new_queue = ) wf2qp_new_queue,\n\t_SI( .free_queue = ) wf2qp_free_queue,\n};\n\n\nDECLARE_DNSCHED_MODULE(dn_wf2qp, &wf2qp_desc);\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_dn_glue.c",
    "content": "/*-\n * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * $Id: ip_dn_glue.c 12500 2013-12-11 23:07:58Z luigi $\n *\n * Binary compatibility support for /sbin/ipfw RELENG_7 and RELENG_8\n */\n\n#include \"opt_inet6.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/mbuf.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/module.h>\n#include <sys/priv.h>\n#include <sys/proc.h>\n#include <sys/rwlock.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/time.h>\n#include <sys/taskqueue.h>\n#include <net/if.h>\t/* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t/* ip_output(), IP_FORWARDING */\n#include <netinet/ip_fw.h>\n#include <netinet/ip_dummynet.h>\n\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n\n/* FREEBSD7.2 ip_dummynet.h r191715*/\n\nstruct dn_heap_entry7 {\n\tint64_t key;        /* sorting key. Topmost element is smallest one */\n\tvoid *object;      /* object pointer */\n};\n\nstruct dn_heap7 {\n\tint size;\n\tint elements;\n\tint offset; /* XXX if > 0 this is the offset of direct ptr to obj */\n\tstruct dn_heap_entry7 *p;   /* really an array of \"size\" entries */\n};\n\n/* Common to 7.2 and 8 */\nstruct dn_flow_set {\n\tSLIST_ENTRY(dn_flow_set)    next;   /* linked list in a hash slot */\n\n\tu_short fs_nr ;             /* flow_set number       */\n\tu_short flags_fs;\n#define DNOLD_HAVE_FLOW_MASK   0x0001\n#define DNOLD_IS_RED       0x0002\n#define DNOLD_IS_GENTLE_RED    0x0004\n#define DNOLD_QSIZE_IS_BYTES   0x0008  /* queue size is measured in bytes */\n#define DNOLD_NOERROR      0x0010  /* do not report ENOBUFS on drops  */\n#define DNOLD_HAS_PROFILE      0x0020  /* the pipe has a delay profile. */\n#define DNOLD_IS_PIPE      0x4000\n#define DNOLD_IS_QUEUE     0x8000\n\n\tstruct dn_pipe7 *pipe ;  /* pointer to parent pipe */\n\tu_short parent_nr ;     /* parent pipe#, 0 if local to a pipe */\n\n\tint weight ;        /* WFQ queue weight */\n\tint qsize ;         /* queue size in slots or bytes */\n\tint plr ;           /* pkt loss rate (2^31-1 means 100%) */\n\n\tstruct ipfw_flow_id flow_mask ;\n\n\t/* hash table of queues onto this flow_set */\n\tint rq_size ;       /* number of slots */\n\tint rq_elements ;       /* active elements */\n\tstruct dn_flow_queue7 **rq;  /* array of rq_size entries */\n\n\tu_int32_t last_expired ;    /* do not expire too frequently */\n\tint backlogged ;        /* #active queues for this flowset */\n\n        /* RED parameters */\n#define SCALE_RED               16\n#define SCALE(x)                ( (x) << SCALE_RED )\n#define SCALE_VAL(x)            ( (x) >> SCALE_RED )\n#define SCALE_MUL(x,y)          ( ( (x) * (y) ) >> SCALE_RED )\n\tint w_q ;           /* queue weight (scaled) */\n\tint max_th ;        /* maximum threshold for queue (scaled) */\n\tint min_th ;        /* minimum threshold for queue (scaled) */\n\tint max_p ;         /* maximum value for p_b (scaled) */\n\tu_int c_1 ;         /* max_p/(max_th-min_th) (scaled) */\n\tu_int c_2 ;         /* max_p*min_th/(max_th-min_th) (scaled) */\n\tu_int c_3 ;         /* for GRED, (1-max_p)/max_th (scaled) */\n\tu_int c_4 ;         /* for GRED, 1 - 2*max_p (scaled) */\n\tu_int * w_q_lookup ;    /* lookup table for computing (1-w_q)^t */\n\tu_int lookup_depth ;    /* depth of lookup table */\n\tint lookup_step ;       /* granularity inside the lookup table */\n\tint lookup_weight ;     /* equal to (1-w_q)^t / (1-w_q)^(t+1) */\n\tint avg_pkt_size ;      /* medium packet size */\n\tint max_pkt_size ;      /* max packet size */\n};\nSLIST_HEAD(dn_flow_set_head, dn_flow_set);\n\n#define DN_IS_PIPE\t\t0x4000\n#define DN_IS_QUEUE\t\t0x8000\nstruct dn_flow_queue7 {\n\tstruct dn_flow_queue7 *next ;\n\tstruct ipfw_flow_id id ;\n\n\tstruct mbuf *head, *tail ;  /* queue of packets */\n\tu_int len ;\n\tu_int len_bytes ;\n\n\tu_long numbytes;\n\n\tu_int64_t tot_pkts ;    /* statistics counters  */\n\tu_int64_t tot_bytes ;\n\tu_int32_t drops ;\n\n\tint hash_slot ;     /* debugging/diagnostic */\n\n\t/* RED parameters */\n\tint avg ;                   /* average queue length est. (scaled) */\n\tint count ;                 /* arrivals since last RED drop */\n\tint random ;                /* random value (scaled) */\n\tu_int32_t q_time;      /* start of queue idle time */\n\n\t/* WF2Q+ support */\n\tstruct dn_flow_set *fs ;    /* parent flow set */\n\tint heap_pos ;      /* position (index) of struct in heap */\n\tint64_t sched_time ;     /* current time when queue enters ready_heap */\n\n\tint64_t S,F ;        /* start time, finish time */\n};\n\nstruct dn_pipe7 {        /* a pipe */\n\tSLIST_ENTRY(dn_pipe7)    next;   /* linked list in a hash slot */\n\n\tint pipe_nr ;       /* number   */\n\tint bandwidth;      /* really, bytes/tick.  */\n\tint delay ;         /* really, ticks    */\n\n\tstruct  mbuf *head, *tail ; /* packets in delay line */\n\n\t/* WF2Q+ */\n\tstruct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/\n\tstruct dn_heap7 not_eligible_heap; /* top extract- key Start time */\n\tstruct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */\n\n\tint64_t V ;          /* virtual time */\n\tint sum;            /* sum of weights of all active sessions */\n\n\tint numbytes;\n\n\tint64_t sched_time ;     /* time pipe was scheduled in ready_heap */\n\n\t/*\n\t* When the tx clock come from an interface (if_name[0] != '\\0'), its name\n\t* is stored below, whereas the ifp is filled when the rule is configured.\n\t*/\n\tchar if_name[IFNAMSIZ];\n\tstruct ifnet *ifp ;\n\tint ready ; /* set if ifp != NULL and we got a signal from it */\n\n\tstruct dn_flow_set fs ; /* used with fixed-rate flows */\n};\nSLIST_HEAD(dn_pipe_head7, dn_pipe7);\n\n\n/* FREEBSD8 ip_dummynet.h r196045 */\nstruct dn_flow_queue8 {\n\tstruct dn_flow_queue8 *next ;\n\tstruct ipfw_flow_id id ;\n\n\tstruct mbuf *head, *tail ;  /* queue of packets */\n\tu_int len ;\n\tu_int len_bytes ;\n\n\tuint64_t numbytes ;     /* credit for transmission (dynamic queues) */\n\tint64_t extra_bits;     /* extra bits simulating unavailable channel */\n\n\tu_int64_t tot_pkts ;    /* statistics counters  */\n\tu_int64_t tot_bytes ;\n\tu_int32_t drops ;\n\n\tint hash_slot ;     /* debugging/diagnostic */\n\n\t/* RED parameters */\n\tint avg ;                   /* average queue length est. (scaled) */\n\tint count ;                 /* arrivals since last RED drop */\n\tint random ;                /* random value (scaled) */\n\tint64_t idle_time;       /* start of queue idle time */\n\n\t/* WF2Q+ support */\n\tstruct dn_flow_set *fs ;    /* parent flow set */\n\tint heap_pos ;      /* position (index) of struct in heap */\n\tint64_t sched_time ;     /* current time when queue enters ready_heap */\n\n\tint64_t S,F ;        /* start time, finish time */\n};\n\nstruct dn_pipe8 {        /* a pipe */\n\tSLIST_ENTRY(dn_pipe8)    next;   /* linked list in a hash slot */\n\n\tint pipe_nr ;       /* number   */\n\tint bandwidth;      /* really, bytes/tick.  */\n\tint delay ;         /* really, ticks    */\n\n\tstruct  mbuf *head, *tail ; /* packets in delay line */\n\n\t/* WF2Q+ */\n\tstruct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/\n\tstruct dn_heap7 not_eligible_heap; /* top extract- key Start time */\n\tstruct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */\n\n\tint64_t V ;          /* virtual time */\n\tint sum;            /* sum of weights of all active sessions */\n\n\t/* Same as in dn_flow_queue, numbytes can become large */\n\tint64_t numbytes;       /* bits I can transmit (more or less). */\n\tuint64_t burst;     /* burst size, scaled: bits * hz */\n\n\tint64_t sched_time ;     /* time pipe was scheduled in ready_heap */\n\tint64_t idle_time;       /* start of pipe idle time */\n\n\tchar if_name[IFNAMSIZ];\n\tstruct ifnet *ifp ;\n\tint ready ; /* set if ifp != NULL and we got a signal from it */\n\n\tstruct dn_flow_set fs ; /* used with fixed-rate flows */\n\n    /* fields to simulate a delay profile */\n#define ED_MAX_NAME_LEN     32\n\tchar name[ED_MAX_NAME_LEN];\n\tint loss_level;\n\tint samples_no;\n\tint *samples;\n};\n\n#define ED_MAX_SAMPLES_NO   1024\nstruct dn_pipe_max8 {\n\tstruct dn_pipe8 pipe;\n\tint samples[ED_MAX_SAMPLES_NO];\n};\nSLIST_HEAD(dn_pipe_head8, dn_pipe8);\n\n/*\n * Changes from 7.2 to 8:\n * dn_pipe:\n *      numbytes from int to int64_t\n *      add burst (int64_t)\n *      add idle_time (int64_t)\n *      add profile\n *      add struct dn_pipe_max\n *      add flag DN_HAS_PROFILE\n *\n * dn_flow_queue\n *      numbytes from u_long to int64_t\n *      add extra_bits (int64_t)\n *      q_time from u_int32_t to int64_t and name idle_time\n *\n * dn_flow_set unchanged\n *\n */\n\n/* NOTE:XXX copied from dummynet.c */\n#define O_NEXT(p, len) ((void *)((char *)p + len))\nstatic void\noid_fill(struct dn_id *oid, int len, int type, uintptr_t id)\n{\n\toid->len = len;\n\toid->type = type;\n\toid->subtype = 0;\n\toid->id = id;\n}\n/* make room in the buffer and move the pointer forward */\nstatic void *\no_next(struct dn_id **o, int len, int type)\n{\n\tstruct dn_id *ret = *o;\n\toid_fill(ret, len, type, 0);\n\t*o = O_NEXT(*o, len);\n\treturn ret;\n}\n\n\nstatic size_t pipesize7 = sizeof(struct dn_pipe7);\nstatic size_t pipesize8 = sizeof(struct dn_pipe8);\nstatic size_t pipesizemax8 = sizeof(struct dn_pipe_max8);\n\n/* Indicate 'ipfw' version\n * 1: from FreeBSD 7.2\n * 0: from FreeBSD 8\n * -1: unknown (for now is unused)\n *\n * It is update when a IP_DUMMYNET_DEL or IP_DUMMYNET_CONFIGURE request arrives\n * NOTE: if a IP_DUMMYNET_GET arrives and the 'ipfw' version is unknown,\n *       it is suppose to be the FreeBSD 8 version.\n */\nstatic int is7 = 0;\n\nstatic int\nconvertflags2new(int src)\n{\n\tint dst = 0;\n\n\tif (src & DNOLD_HAVE_FLOW_MASK)\n\t\tdst |= DN_HAVE_MASK;\n\tif (src & DNOLD_QSIZE_IS_BYTES)\n\t\tdst |= DN_QSIZE_BYTES;\n\tif (src & DNOLD_NOERROR)\n\t\tdst |= DN_NOERROR;\n\tif (src & DNOLD_IS_RED)\n\t\tdst |= DN_IS_RED;\n\tif (src & DNOLD_IS_GENTLE_RED)\n\t\tdst |= DN_IS_GENTLE_RED;\n\tif (src & DNOLD_HAS_PROFILE)\n\t\tdst |= DN_HAS_PROFILE;\n\n\treturn dst;\n}\n\nstatic int\nconvertflags2old(int src)\n{\n\tint dst = 0;\n\n\tif (src & DN_HAVE_MASK)\n\t\tdst |= DNOLD_HAVE_FLOW_MASK;\n\tif (src & DN_IS_RED)\n\t\tdst |= DNOLD_IS_RED;\n\tif (src & DN_IS_GENTLE_RED)\n\t\tdst |= DNOLD_IS_GENTLE_RED;\n\tif (src & DN_NOERROR)\n\t\tdst |= DNOLD_NOERROR;\n\tif (src & DN_HAS_PROFILE)\n\t\tdst |= DNOLD_HAS_PROFILE;\n\tif (src & DN_QSIZE_BYTES)\n\t\tdst |= DNOLD_QSIZE_IS_BYTES;\n\n\treturn dst;\n}\n\nstatic int\ndn_compat_del(void *v)\n{\n\tstruct dn_pipe7 *p = (struct dn_pipe7 *) v;\n\tstruct dn_pipe8 *p8 = (struct dn_pipe8 *) v;\n\tstruct {\n\t\tstruct dn_id oid;\n\t\tuintptr_t a[1];\t/* add more if we want a list */\n\t} cmd;\n\n\t/* XXX DN_API_VERSION ??? */\n\toid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION);\n\n\tif (is7) {\n\t\tif (p->pipe_nr == 0 && p->fs.fs_nr == 0)\n\t\t\treturn EINVAL;\n\t\tif (p->pipe_nr != 0 && p->fs.fs_nr != 0)\n\t\t\treturn EINVAL;\n\t} else {\n\t\tif (p8->pipe_nr == 0 && p8->fs.fs_nr == 0)\n\t\t\treturn EINVAL;\n\t\tif (p8->pipe_nr != 0 && p8->fs.fs_nr != 0)\n\t\t\treturn EINVAL;\n\t}\n\n\tif (p->pipe_nr != 0) { /* pipe x delete */\n\t\tcmd.a[0] = p->pipe_nr;\n\t\tcmd.oid.subtype = DN_LINK;\n\t} else { /* queue x delete */\n\t\tcmd.oid.subtype = DN_FS;\n\t\tcmd.a[0] = (is7) ? p->fs.fs_nr : p8->fs.fs_nr;\n\t}\n\n\treturn do_config(&cmd, cmd.oid.len);\n}\n\nstatic int\ndn_compat_config_queue(struct dn_fs *fs, void* v)\n{\n\tstruct dn_pipe7 *p7 = (struct dn_pipe7 *)v;\n\tstruct dn_pipe8 *p8 = (struct dn_pipe8 *)v;\n\tstruct dn_flow_set *f;\n\n\tif (is7)\n\t\tf = &p7->fs;\n\telse\n\t\tf = &p8->fs;\n\n\tfs->fs_nr = f->fs_nr;\n\tfs->sched_nr = f->parent_nr;\n\tfs->flow_mask = f->flow_mask;\n\tfs->buckets = f->rq_size;\n\tfs->qsize = f->qsize;\n\tfs->plr = f->plr;\n\tfs->par[0] = f->weight;\n\tfs->flags = convertflags2new(f->flags_fs);\n\tif (fs->flags & DN_IS_GENTLE_RED || fs->flags & DN_IS_RED) {\n\t\tfs->w_q = f->w_q;\n\t\tfs->max_th = f->max_th;\n\t\tfs->min_th = f->min_th;\n\t\tfs->max_p = f->max_p;\n\t}\n\n\treturn 0;\n}\n\nstatic int\ndn_compat_config_pipe(struct dn_sch *sch, struct dn_link *p, \n\t\t      struct dn_fs *fs, void* v)\n{\n\tstruct dn_pipe7 *p7 = (struct dn_pipe7 *)v;\n\tstruct dn_pipe8 *p8 = (struct dn_pipe8 *)v;\n\tint i = p7->pipe_nr;\n\n\tsch->sched_nr = i;\n\tsch->oid.subtype = 0;\n\tp->link_nr = i;\n\tfs->fs_nr = i + 2*DN_MAX_ID;\n\tfs->sched_nr = i + DN_MAX_ID;\n\n\t/* Common to 7 and 8 */\n\tp->bandwidth = p7->bandwidth;\n\tp->delay = p7->delay;\n\tif (!is7) {\n\t\t/* FreeBSD 8 has burst  */\n\t\tp->burst = p8->burst;\n\t}\n\n\t/* fill the fifo flowset */\n\tdn_compat_config_queue(fs, v);\n\tfs->fs_nr = i + 2*DN_MAX_ID;\n\tfs->sched_nr = i + DN_MAX_ID;\n\n\t/* Move scheduler related parameter from fs to sch */\n\tsch->buckets = fs->buckets; /*XXX*/\n\tfs->buckets = 0;\n\tif (fs->flags & DN_HAVE_MASK) {\n\t\tsch->flags |= DN_HAVE_MASK;\n\t\tfs->flags &= ~DN_HAVE_MASK;\n\t\tsch->sched_mask = fs->flow_mask;\n\t\tbzero(&fs->flow_mask, sizeof(struct ipfw_flow_id));\n\t}\n\n\treturn 0;\n}\n\nstatic int\ndn_compat_config_profile(struct dn_profile *pf, struct dn_link *p,\n\t\t\t void *v)\n{\n\tstruct dn_pipe8 *p8 = (struct dn_pipe8 *)v;\n\n\tp8->samples = &(((struct dn_pipe_max8 *)p8)->samples[0]);\n\t\n\tpf->link_nr = p->link_nr;\n\tpf->loss_level = p8->loss_level;\n// \tpf->bandwidth = p->bandwidth; //XXX bandwidth redundant?\n\tpf->samples_no = p8->samples_no;\n\tstrncpy(pf->name, p8->name,sizeof(pf->name));\n\tbcopy(p8->samples, pf->samples, sizeof(pf->samples));\n\n\treturn 0;\n}\n\n/*\n * If p->pipe_nr != 0 the command is 'pipe x config', so need to create\n * the three main struct, else only a flowset is created\n */\nstatic int\ndn_compat_configure(void *v)\n{\n\tstruct dn_id *buf = NULL, *base;\n\tstruct dn_sch *sch = NULL;\n\tstruct dn_link *p = NULL;\n\tstruct dn_fs *fs = NULL;\n\tstruct dn_profile *pf = NULL;\n\tint lmax;\n\tint error;\n\n\tstruct dn_pipe7 *p7 = (struct dn_pipe7 *)v;\n\tstruct dn_pipe8 *p8 = (struct dn_pipe8 *)v;\n\n\tint i; /* number of object to configure */\n\n\tlmax = sizeof(struct dn_id);\t/* command header */\n\tlmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +\n\t\tsizeof(struct dn_fs) + sizeof(struct dn_profile);\n\n\tbase = buf = malloc(lmax, M_DUMMYNET, M_WAITOK|M_ZERO);\n\to_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);\n\tbase->id = DN_API_VERSION;\n\n\t/* pipe_nr is the same in p7 and p8 */\n\ti = p7->pipe_nr;\n\tif (i != 0) { /* pipe config */\n\t\tsch = o_next(&buf, sizeof(*sch), DN_SCH);\n\t\tp = o_next(&buf, sizeof(*p), DN_LINK);\n\t\tfs = o_next(&buf, sizeof(*fs), DN_FS);\n\n\t\terror = dn_compat_config_pipe(sch, p, fs, v);\n\t\tif (error) {\n\t\t\tfree(buf, M_DUMMYNET);\n\t\t\treturn error;\n\t\t}\n\t\tif (!is7 && p8->samples_no > 0) {\n\t\t\t/* Add profiles*/\n\t\t\tpf = o_next(&buf, sizeof(*pf), DN_PROFILE);\n\t\t\terror = dn_compat_config_profile(pf, p, v);\n\t\t\tif (error) {\n\t\t\t\tfree(buf, M_DUMMYNET);\n\t\t\t\treturn error;\n\t\t\t}\n\t\t}\n\t} else { /* queue config */\n\t\tfs = o_next(&buf, sizeof(*fs), DN_FS);\n\t\terror = dn_compat_config_queue(fs, v);\n\t\tif (error) {\n\t\t\tfree(buf, M_DUMMYNET);\n\t\t\treturn error;\n\t\t}\n\t}\n\terror = do_config(base, (char *)buf - (char *)base);\n\n\tif (buf)\n\t\tfree(buf, M_DUMMYNET);\n\treturn error;\n}\n\nint\ndn_compat_calc_size(void)\n{\n\tint need = 0;\n\t/* XXX use FreeBSD 8 struct size */\n\t/* NOTE:\n\t * - half scheduler: \t\tschk_count/2\n\t * - all flowset:\t\tfsk_count\n\t * - all flowset queues:\tqueue_count\n\t * - all pipe queue:\t\tsi_count\n\t */\n\tneed += dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2;\n\tneed += dn_cfg.fsk_count * sizeof(struct dn_flow_set);\n\tneed += dn_cfg.si_count * sizeof(struct dn_flow_queue8);\n\tneed += dn_cfg.queue_count * sizeof(struct dn_flow_queue8);\n\n\treturn need;\n}\n\nint\ndn_c_copy_q (void *_ni, void *arg)\n{\n\tstruct copy_args *a = arg;\n\tstruct dn_flow_queue7 *fq7 = (struct dn_flow_queue7 *)*a->start;\n\tstruct dn_flow_queue8 *fq8 = (struct dn_flow_queue8 *)*a->start;\n\tstruct dn_flow *ni = (struct dn_flow *)_ni;\n\tint size = 0;\n\n\t/* XXX hash slot not set */\n\t/* No difference between 7.2/8 */\n\tfq7->len = ni->length;\n\tfq7->len_bytes = ni->len_bytes;\n\tfq7->id = ni->fid;\n\n\tif (is7) {\n\t\tsize = sizeof(struct dn_flow_queue7);\n\t\tfq7->tot_pkts = ni->tot_pkts;\n\t\tfq7->tot_bytes = ni->tot_bytes;\n\t\tfq7->drops = ni->drops;\n\t} else {\n\t\tsize = sizeof(struct dn_flow_queue8);\n\t\tfq8->tot_pkts = ni->tot_pkts;\n\t\tfq8->tot_bytes = ni->tot_bytes;\n\t\tfq8->drops = ni->drops;\n\t}\n\n\t*a->start += size;\n\treturn 0;\n}\n\nint\ndn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq)\n{\n\tstruct dn_link *l = &s->link;\n\tstruct dn_fsk *f = s->fs;\n\n\tstruct dn_pipe7 *pipe7 = (struct dn_pipe7 *)*a->start;\n\tstruct dn_pipe8 *pipe8 = (struct dn_pipe8 *)*a->start;\n\tstruct dn_flow_set *fs;\n\tint size = 0;\n\n\tif (is7) {\n\t\tfs = &pipe7->fs;\n\t\tsize = sizeof(struct dn_pipe7);\n\t} else {\n\t\tfs = &pipe8->fs;\n\t\tsize = sizeof(struct dn_pipe8);\n\t}\n\n\t/* These 4 field are the same in pipe7 and pipe8 */\n\tpipe7->next.sle_next = (struct dn_pipe7 *)DN_IS_PIPE;\n\tpipe7->bandwidth = l->bandwidth;\n\tpipe7->delay = l->delay * 1000 / hz;\n\tpipe7->pipe_nr = l->link_nr - DN_MAX_ID;\n\n\tif (!is7) {\n\t\tif (s->profile) {\n\t\t\tstruct dn_profile *pf = s->profile;\n\t\t\tstrncpy(pipe8->name, pf->name, sizeof(pf->name));\n\t\t\tpipe8->loss_level = pf->loss_level;\n\t\t\tpipe8->samples_no = pf->samples_no;\n\t\t}\n\t\tpipe8->burst = div64(l->burst , 8 * hz);\n\t}\n\n\tfs->flow_mask = s->sch.sched_mask;\n\tfs->rq_size = s->sch.buckets ? s->sch.buckets : 1;\n\n\tfs->parent_nr = l->link_nr - DN_MAX_ID;\n\tfs->qsize = f->fs.qsize;\n\tfs->plr = f->fs.plr;\n\tfs->w_q = f->fs.w_q;\n\tfs->max_th = f->max_th;\n\tfs->min_th = f->min_th;\n\tfs->max_p = f->fs.max_p;\n\tfs->rq_elements = nq;\n\n\tfs->flags_fs = convertflags2old(f->fs.flags);\n\n\t*a->start += size;\n\treturn 0;\n}\n\n\nint\ndn_compat_copy_pipe(struct copy_args *a, void *_o)\n{\n\tint have = a->end - *a->start;\n\tint need = 0;\n\tint pipe_size = sizeof(struct dn_pipe8);\n\tint queue_size = sizeof(struct dn_flow_queue8);\n\tint n_queue = 0; /* number of queues */\n\n\tstruct dn_schk *s = (struct dn_schk *)_o;\n\t/* calculate needed space:\n\t * - struct dn_pipe\n\t * - if there are instances, dn_queue * n_instances\n\t */\n\tn_queue = (s->sch.flags & DN_HAVE_MASK ? dn_ht_entries(s->siht) :\n\t\t\t\t\t\t(s->siht ? 1 : 0));\n\tneed = pipe_size + queue_size * n_queue;\n\tif (have < need) {\n\t\tD(\"have %d < need %d\", have, need);\n\t\treturn 1;\n\t}\n\t/* copy pipe */\n\tdn_c_copy_pipe(s, a, n_queue);\n\n\t/* copy queues */\n\tif (s->sch.flags & DN_HAVE_MASK)\n\t\tdn_ht_scan(s->siht, dn_c_copy_q, a);\n\telse if (s->siht)\n\t\tdn_c_copy_q(s->siht, a);\n\treturn 0;\n}\n\nint\ndn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq)\n{\n\tstruct dn_flow_set *fs = (struct dn_flow_set *)*a->start;\n\n\tfs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;\n\tfs->fs_nr = f->fs.fs_nr;\n\tfs->qsize = f->fs.qsize;\n\tfs->plr = f->fs.plr;\n\tfs->w_q = f->fs.w_q;\n\tfs->max_th = f->max_th;\n\tfs->min_th = f->min_th;\n\tfs->max_p = f->fs.max_p;\n\tfs->flow_mask = f->fs.flow_mask;\n\tfs->rq_elements = nq;\n\tfs->rq_size = (f->fs.buckets ? f->fs.buckets : 1);\n\tfs->parent_nr = f->fs.sched_nr;\n\tfs->weight = f->fs.par[0];\n\n\tfs->flags_fs = convertflags2old(f->fs.flags);\n\t*a->start += sizeof(struct dn_flow_set);\n\treturn 0;\n}\n\nint\ndn_compat_copy_queue(struct copy_args *a, void *_o)\n{\n\tint have = a->end - *a->start;\n\tint need = 0;\n\tint fs_size = sizeof(struct dn_flow_set);\n\tint queue_size = sizeof(struct dn_flow_queue8);\n\n\tstruct dn_fsk *fs = (struct dn_fsk *)_o;\n\tint n_queue = 0; /* number of queues */\n\n\tn_queue = (fs->fs.flags & DN_HAVE_MASK ? dn_ht_entries(fs->qht) :\n\t\t\t\t\t\t(fs->qht ? 1 : 0));\n\n\tneed = fs_size + queue_size * n_queue;\n\tif (have < need) {\n\t\tD(\"have < need\");\n\t\treturn 1;\n\t}\n\n\t/* copy flowset */\n\tdn_c_copy_fs(fs, a, n_queue);\n\n\t/* copy queues */\n\tif (fs->fs.flags & DN_HAVE_MASK)\n\t\tdn_ht_scan(fs->qht, dn_c_copy_q, a);\n\telse if (fs->qht)\n\t\tdn_c_copy_q(fs->qht, a);\n\n\treturn 0;\n}\n\nint\ncopy_data_helper_compat(void *_o, void *_arg)\n{\n\tstruct copy_args *a = _arg;\n\n\tif (a->type == DN_COMPAT_PIPE) {\n\t\tstruct dn_schk *s = _o;\n\t\tif (s->sch.oid.subtype != 1 || s->sch.sched_nr <= DN_MAX_ID) {\n\t\t\treturn 0;\t/* not old type */\n\t\t}\n\t\t/* copy pipe parameters, and if instance exists, copy\n\t\t * other parameters and eventually queues.\n\t\t */\n\t\tif(dn_compat_copy_pipe(a, _o))\n\t\t\treturn DNHT_SCAN_END;\n\t} else if (a->type == DN_COMPAT_QUEUE) {\n\t\tstruct dn_fsk *fs = _o;\n\t\tif (fs->fs.fs_nr >= DN_MAX_ID)\n\t\t\treturn 0;\n\t\tif (dn_compat_copy_queue(a, _o))\n\t\t\treturn DNHT_SCAN_END;\n\t}\n\treturn 0;\n}\n\n/* Main function to manage old requests */\nint\nip_dummynet_compat(struct sockopt *sopt)\n{\n\tint error=0;\n\tvoid *v = NULL;\n\tstruct dn_id oid;\n\n\t/* Lenght of data, used to found ipfw version... */\n\tint len = sopt->sopt_valsize;\n\n\t/* len can be 0 if command was dummynet_flush */\n\tif (len == pipesize7) {\n\t\tD(\"setting compatibility with FreeBSD 7.2\");\n\t\tis7 = 1;\n\t}\n\telse if (len == pipesize8 || len == pipesizemax8) {\n\t\tD(\"setting compatibility with FreeBSD 8\");\n\t\tis7 = 0;\n\t}\n\n\tswitch (sopt->sopt_name) {\n\tdefault:\n\t\tprintf(\"dummynet: -- unknown option %d\", sopt->sopt_name);\n\t\terror = EINVAL;\n\t\tbreak;\n\n\tcase IP_DUMMYNET_FLUSH:\n\t\toid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION);\n\t\tdo_config(&oid, oid.len);\n\t\tbreak;\n\n\tcase IP_DUMMYNET_DEL:\n\t\tv = malloc(len, M_TEMP, M_WAITOK);\n\t\terror = sooptcopyin(sopt, v, len, len);\n\t\tif (error)\n\t\t\tbreak;\n\t\terror = dn_compat_del(v);\n\t\tfree(v, M_TEMP);\n\t\tbreak;\n\n\tcase IP_DUMMYNET_CONFIGURE:\n\t\tv = malloc(len, M_TEMP, M_WAITOK);\n\t\terror = sooptcopyin(sopt, v, len, len);\n\t\tif (error)\n\t\t\tbreak;\n\t\terror = dn_compat_configure(v);\n\t\tfree(v, M_TEMP);\n\t\tbreak;\n\n\tcase IP_DUMMYNET_GET: {\n\t\tvoid *buf;\n\t\tint ret;\n\t\tint original_size = sopt->sopt_valsize;\n\t\tint size;\n\n\t\tret = dummynet_get(sopt, &buf);\n\t\tif (ret)\n\t\t\treturn 0;//XXX ?\n\t\tsize = sopt->sopt_valsize;\n\t\tsopt->sopt_valsize = original_size;\n\t\tD(\"size=%d, buf=%p\", size, buf);\n\t\tret = sooptcopyout(sopt, buf, size);\n\t\tif (ret)\n\t\t\tprintf(\"  %s ERROR sooptcopyout\\n\", __FUNCTION__);\n\t\tif (buf)\n\t\t\tfree(buf, M_DUMMYNET);\n\t    }\n\t}\n\n\treturn error;\n}\n\n\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_dn_io.c",
    "content": "/*-\n * Copyright (c) 2010 Luigi Rizzo, Riccardo Panicucci, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * Dummynet portions related to packet handling.\n */\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c 203321 2010-01-31 21:39:25Z luigi $\");\n\n#include \"opt_inet6.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/mbuf.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/module.h>\n#include <sys/priv.h>\n#include <sys/proc.h>\n#include <sys/rwlock.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <sys/sysctl.h>\n\n#include <net/if.h>\t/* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */\n#include <net/netisr.h>\n#include <net/vnet.h>\n\n#include <netinet/in.h>\n#include <netinet/ip.h>\t\t/* ip_len, ip_off */\n#include <netinet/ip_var.h>\t/* ip_output(), IP_FORWARDING */\n#include <netinet/ip_fw.h>\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ip_dummynet.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n\n#include <netinet/if_ether.h> /* various ether_* routines */\n\n#include <netinet/ip6.h>       /* for ip6_input, ip6_output prototypes */\n#include <netinet6/ip6_var.h>\n\n/*\n * We keep a private variable for the simulation time, but we could\n * probably use an existing one (\"softticks\" in sys/kern/kern_timeout.c)\n * instead of dn_cfg.curr_time\n */\n\nstruct dn_parms dn_cfg;\n//VNET_DEFINE(struct dn_parms, _base_dn_cfg);\n\nstatic long tick_last;\t\t/* Last tick duration (usec). */\nstatic long tick_delta;\t\t/* Last vs standard tick diff (usec). */\nstatic long tick_delta_sum;\t/* Accumulated tick difference (usec).*/\nstatic long tick_adjustment;\t/* Tick adjustments done. */\nstatic long tick_lost;\t\t/* Lost(coalesced) ticks number. */\n/* Adjusted vs non-adjusted curr_time difference (ticks). */\nstatic long tick_diff;\n\nstatic unsigned long\tio_pkt;\nstatic unsigned long\tio_pkt_fast;\nstatic unsigned long\tio_pkt_drop;\n\n/*\n * We use a heap to store entities for which we have pending timer events.\n * The heap is checked at every tick and all entities with expired events\n * are extracted.\n */\n  \nMALLOC_DEFINE(M_DUMMYNET, \"dummynet\", \"dummynet heap\");\n\nextern\tvoid (*bridge_dn_p)(struct mbuf *, struct ifnet *);\n\n#ifdef SYSCTL_NODE\n\nSYSBEGIN(f4)\n\nSYSCTL_DECL(_net_inet);\nSYSCTL_DECL(_net_inet_ip);\nSYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, \"Dummynet\");\n\n/* wrapper to pass dn_cfg fields to SYSCTL_* */\n//#define DC(x)\t(&(VNET_NAME(_base_dn_cfg).x))\n#define DC(x)\t(&(dn_cfg.x))\n/* parameters */\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, hash_size,\n    CTLFLAG_RW, DC(hash_size), 0, \"Default hash table size\");\nSYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_slot_limit,\n    CTLFLAG_RW, DC(slot_limit), 0,\n    \"Upper limit in slots for pipe queue.\");\nSYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, pipe_byte_limit,\n    CTLFLAG_RW, DC(byte_limit), 0,\n    \"Upper limit in bytes for pipe queue.\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, io_fast,\n    CTLFLAG_RW, DC(io_fast), 0, \"Enable fast dummynet io.\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug,\n    CTLFLAG_RW, DC(debug), 0, \"Dummynet debug level\");\n\n/* RED parameters */\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth,\n    CTLFLAG_RD, DC(red_lookup_depth), 0, \"Depth of RED lookup table\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_avg_pkt_size,\n    CTLFLAG_RD, DC(red_avg_pkt_size), 0, \"RED Medium packet size\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_max_pkt_size,\n    CTLFLAG_RD, DC(red_max_pkt_size), 0, \"RED Max packet size\");\n\n/* time adjustment */\nSYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta,\n    CTLFLAG_RD, &tick_delta, 0, \"Last vs standard tick difference (usec).\");\nSYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_delta_sum,\n    CTLFLAG_RD, &tick_delta_sum, 0, \"Accumulated tick difference (usec).\");\nSYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_adjustment,\n    CTLFLAG_RD, &tick_adjustment, 0, \"Tick adjustments done.\");\nSYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_diff,\n    CTLFLAG_RD, &tick_diff, 0,\n    \"Adjusted vs non-adjusted curr_time difference (ticks).\");\nSYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_lost,\n    CTLFLAG_RD, &tick_lost, 0,\n    \"Number of ticks coalesced by dummynet taskqueue.\");\n\n/* Drain parameters */\nSYSCTL_UINT(_net_inet_ip_dummynet, OID_AUTO, expire,\n    CTLFLAG_RW, DC(expire), 0, \"Expire empty queues/pipes\");\nSYSCTL_UINT(_net_inet_ip_dummynet, OID_AUTO, expire_cycle,\n    CTLFLAG_RD, DC(expire_cycle), 0, \"Expire cycle for queues/pipes\");\nSYSCTL_UINT(_net_inet_ip_dummynet, OID_AUTO, expire_object,\n    CTLFLAG_RW, DC(expire_object), 0, \"Min # of objects before start drain routine\");\nSYSCTL_UINT(_net_inet_ip_dummynet, OID_AUTO, object_idle_tick,\n    CTLFLAG_RD, DC(object_idle_tick), 0, \"Time (in ticks) to cosiderer an object as idle\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, drain_ratio,\n    CTLFLAG_RD, DC(drain_ratio), 0, \"% of dummynet_task() to dedicate to drain routine\");\n\n/* statistics */\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, schk_count,\n    CTLFLAG_RD, DC(schk_count), 0, \"Number of schedulers\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, si_count,\n    CTLFLAG_RD, DC(si_count), 0, \"Number of scheduler instances\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, fsk_count,\n    CTLFLAG_RD, DC(fsk_count), 0, \"Number of flowsets\");\nSYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, queue_count,\n    CTLFLAG_RD, DC(queue_count), 0, \"Number of queues\");\nSYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt,\n    CTLFLAG_RD, &io_pkt, 0,\n    \"Number of packets passed to dummynet.\");\nSYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_fast,\n    CTLFLAG_RD, &io_pkt_fast, 0,\n    \"Number of packets bypassed dummynet scheduler.\");\nSYSCTL_ULONG(_net_inet_ip_dummynet, OID_AUTO, io_pkt_drop,\n    CTLFLAG_RD, &io_pkt_drop, 0,\n    \"Number of packets dropped by dummynet.\");\n#undef DC\nSYSEND\n\n#endif\n\nstatic void\tdummynet_send(struct mbuf *);\n\n/*\n * Packets processed by dummynet have an mbuf tag associated with\n * them that carries their dummynet state.\n * Outside dummynet, only the 'rule' field is relevant, and it must\n * be at the beginning of the structure.\n */\nstruct dn_pkt_tag {\n\tstruct ipfw_rule_ref rule;\t/* matching rule\t*/\n\n\t/* second part, dummynet specific */\n\tint dn_dir;\t\t/* action when packet comes out.*/\n\t\t\t\t/* see ip_fw_private.h\t\t*/\n\tuint64_t output_time;\t/* when the pkt is due for delivery*/\n\tstruct ifnet *ifp;\t/* interface, for ip_output\t*/\n\tstruct _ip6dn_args ip6opt;\t/* XXX ipv6 options\t*/\n};\n\n/*\n * Return the mbuf tag holding the dummynet state (it should\n * be the first one on the list).\n */\nstatic struct dn_pkt_tag *\ndn_tag_get(struct mbuf *m)\n{\n\tstruct m_tag *mtag = m_tag_first(m);\n\tKASSERT(mtag != NULL &&\n\t    mtag->m_tag_cookie == MTAG_ABI_COMPAT &&\n\t    mtag->m_tag_id == PACKET_TAG_DUMMYNET,\n\t    (\"packet on dummynet queue w/o dummynet tag!\"));\n\treturn (struct dn_pkt_tag *)(mtag+1);\n}\n\nstatic inline void\nmq_append(struct mq *q, struct mbuf *m)\n{\n\tif (q->head == NULL)\n\t\tq->head = m;\n\telse\n\t\tq->tail->m_nextpkt = m;\n\tq->tail = m;\n\tm->m_nextpkt = NULL;\n}\n\n/*\n * Dispose a list of packet. Use a functions so if we need to do\n * more work, this is a central point to do it.\n */\nvoid dn_free_pkts(struct mbuf *mnext)\n{\n        struct mbuf *m;\n    \n        while ((m = mnext) != NULL) {\n                mnext = m->m_nextpkt;\n                FREE_PKT(m);\n        }\n}\n\nstatic int\nred_drops (struct dn_queue *q, int len)\n{\n\t/*\n\t * RED algorithm\n\t *\n\t * RED calculates the average queue size (avg) using a low-pass filter\n\t * with an exponential weighted (w_q) moving average:\n\t * \tavg  <-  (1-w_q) * avg + w_q * q_size\n\t * where q_size is the queue length (measured in bytes or * packets).\n\t *\n\t * If q_size == 0, we compute the idle time for the link, and set\n\t *\tavg = (1 - w_q)^(idle/s)\n\t * where s is the time needed for transmitting a medium-sized packet.\n\t *\n\t * Now, if avg < min_th the packet is enqueued.\n\t * If avg > max_th the packet is dropped. Otherwise, the packet is\n\t * dropped with probability P function of avg.\n\t */\n\n\tstruct dn_fsk *fs = q->fs;\n\tint64_t p_b = 0;\n\n\t/* Queue in bytes or packets? */\n\tuint32_t q_size = (fs->fs.flags & DN_QSIZE_BYTES) ?\n\t    q->ni.len_bytes : q->ni.length;\n\n\t/* Average queue size estimation. */\n\tif (q_size != 0) {\n\t\t/* Queue is not empty, avg <- avg + (q_size - avg) * w_q */\n\t\tint diff = SCALE(q_size) - q->avg;\n\t\tint64_t v = SCALE_MUL((int64_t)diff, (int64_t)fs->w_q);\n\n\t\tq->avg += (int)v;\n\t} else {\n\t\t/*\n\t\t * Queue is empty, find for how long the queue has been\n\t\t * empty and use a lookup table for computing\n\t\t * (1 - * w_q)^(idle_time/s) where s is the time to send a\n\t\t * (small) packet.\n\t\t * XXX check wraps...\n\t\t */\n\t\tif (q->avg) {\n\t\t\tu_int t = div64((dn_cfg.curr_time - q->q_time), fs->lookup_step);\n\n\t\t\tq->avg = (t < fs->lookup_depth) ?\n\t\t\t    SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;\n\t\t}\n\t}\n\n\t/* Should i drop? */\n\tif (q->avg < fs->min_th) {\n\t\tq->count = -1;\n\t\treturn (0);\t/* accept packet */\n\t}\n\tif (q->avg >= fs->max_th) {\t/* average queue >=  max threshold */\n\t\tif (fs->fs.flags & DN_IS_GENTLE_RED) {\n\t\t\t/*\n\t\t\t * According to Gentle-RED, if avg is greater than\n\t\t\t * max_th the packet is dropped with a probability\n\t\t\t *\t p_b = c_3 * avg - c_4\n\t\t\t * where c_3 = (1 - max_p) / max_th\n\t\t\t *       c_4 = 1 - 2 * max_p\n\t\t\t */\n\t\t\tp_b = SCALE_MUL((int64_t)fs->c_3, (int64_t)q->avg) -\n\t\t\t    fs->c_4;\n\t\t} else {\n\t\t\tq->count = -1;\n\t\t\treturn (1);\n\t\t}\n\t} else if (q->avg > fs->min_th) {\n\t\t/*\n\t\t * We compute p_b using the linear dropping function\n\t\t *\t p_b = c_1 * avg - c_2\n\t\t * where c_1 = max_p / (max_th - min_th)\n\t\t * \t c_2 = max_p * min_th / (max_th - min_th)\n\t\t */\n\t\tp_b = SCALE_MUL((int64_t)fs->c_1, (int64_t)q->avg) - fs->c_2;\n\t}\n\n\tif (fs->fs.flags & DN_QSIZE_BYTES)\n\t\tp_b = div64((p_b * len) , fs->max_pkt_size);\n\tif (++q->count == 0)\n\t\tq->random = random() & 0xffff;\n\telse {\n\t\t/*\n\t\t * q->count counts packets arrived since last drop, so a greater\n\t\t * value of q->count means a greater packet drop probability.\n\t\t */\n\t\tif (SCALE_MUL(p_b, SCALE((int64_t)q->count)) > q->random) {\n\t\t\tq->count = 0;\n\t\t\t/* After a drop we calculate a new random value. */\n\t\t\tq->random = random() & 0xffff;\n\t\t\treturn (1);\t/* drop */\n\t\t}\n\t}\n\t/* End of RED algorithm. */\n\n\treturn (0);\t/* accept */\n\n}\n\n/*\n * Enqueue a packet in q, subject to space and queue management policy\n * (whose parameters are in q->fs).\n * Update stats for the queue and the scheduler.\n * Return 0 on success, 1 on drop. The packet is consumed anyways.\n */\nint\ndn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)\n{   \n\tstruct dn_fs *f;\n\tstruct dn_flow *ni;\t/* stats for scheduler instance */\n\tuint64_t len;\n\n\tif (q->fs == NULL || q->_si == NULL) {\n\t\tprintf(\"%s fs %p si %p, dropping\\n\",\n\t\t\t__FUNCTION__, q->fs, q->_si);\n\t\tFREE_PKT(m);\n\t\treturn 1;\n\t}\n\tf = &(q->fs->fs);\n\tni = &q->_si->ni;\n\tlen = m->m_pkthdr.len;\n\t/* Update statistics, then check reasons to drop pkt. */\n\tq->ni.tot_bytes += len;\n\tq->ni.tot_pkts++;\n\tni->tot_bytes += len;\n\tni->tot_pkts++;\n\tif (drop)\n\t\tgoto drop;\n\tif (f->plr && random() < f->plr)\n\t\tgoto drop;\n\tif (f->flags & DN_IS_RED && red_drops(q, m->m_pkthdr.len))\n\t\tgoto drop;\n\tif (f->flags & DN_QSIZE_BYTES) {\n\t\tif (q->ni.len_bytes > f->qsize)\n\t\t\tgoto drop;\n\t} else if (q->ni.length >= f->qsize) {\n\t\tgoto drop;\n\t}\n\tmq_append(&q->mq, m);\n\tif (q->ni.length == 0) {\t/* queue was idle */\n\t\tdn_cfg.idle_queue--;\n\t\tif (ni->length == 0)\t/* scheduler was idle */\n\t\t\tdn_cfg.idle_si--;\n\t}\n\tq->ni.length++;\n\tq->ni.len_bytes += len;\n\tni->length++;\n\tni->len_bytes += len;\n\treturn 0;\n\ndrop:\n\tio_pkt_drop++;\n\tq->ni.drops++;\n\tni->drops++;\n\tFREE_PKT(m);\n\treturn 1;\n}\n\n/*\n * Fetch packets from the delay line which are due now. If there are\n * leftover packets, reinsert the delay line in the heap.\n * Runs under scheduler lock.\n */\nstatic void\ntransmit_event(struct mq *q, struct delay_line *dline, uint64_t now)\n{\n\tstruct mbuf *m;\n\tstruct dn_pkt_tag *pkt = NULL;\n\n\tdline->oid.subtype = 0; /* not in heap */\n\twhile ((m = dline->mq.head) != NULL) {\n\t\tpkt = dn_tag_get(m);\n\t\tif (!DN_KEY_LEQ(pkt->output_time, now))\n\t\t\tbreak;\n\t\tdline->mq.head = m->m_nextpkt;\n\t\tmq_append(q, m);\n\t}\n\tif (m != NULL) {\n\t\tdline->oid.subtype = 1; /* in heap */\n\t\theap_insert(&dn_cfg.evheap, pkt->output_time, dline);\n\t}\n}\n\n/*\n * Convert the additional MAC overheads/delays into an equivalent\n * number of bits for the given data rate. The samples are\n * in milliseconds so we need to divide by 1000.\n */\nstatic uint64_t\nextra_bits(struct mbuf *m, struct dn_schk *s)\n{\n\tint index;\n\tuint64_t bits;\n\tstruct dn_profile *pf = s->profile;\n\n\tif (!pf || pf->samples_no == 0)\n\t\treturn 0;\n\tindex  = random() % pf->samples_no;\n\tbits = div64((uint64_t)pf->samples[index] * s->link.bandwidth, 1000);\n\tif (index >= pf->loss_level) {\n\t\tstruct dn_pkt_tag *dt = dn_tag_get(m);\n\t\tif (dt)\n\t\t\tdt->dn_dir = DIR_DROP;\n\t}\n\treturn bits;\n}\n\n/*\n * Send traffic from a scheduler instance due by 'now'.\n * Return a pointer to the head of the queue.\n */\nstatic struct mbuf *\nserve_sched(struct mq *q, struct dn_sch_inst *si, uint64_t now)\n{\n\tstruct mq def_q;\n\tstruct dn_schk *s = si->sched;\n\tstruct mbuf *m = NULL;\n\tint delay_line_idle = (si->dline.mq.head == NULL);\n\tint done, bw;\n\n\tif (q == NULL) {\n\t\tq = &def_q;\n\t\tq->head = NULL;\n\t}\n\n\tbw = s->link.bandwidth;\n\tsi->kflags &= ~DN_ACTIVE;\n\n\tif (bw > 0)\n\t\tsi->credit += (now - si->sched_time) * bw;\n\telse\n\t\tsi->credit = 0;\n\tsi->sched_time = now;\n\tdone = 0;\n\twhile (si->credit >= 0 && (m = s->fp->dequeue(si)) != NULL) {\n\t\tuint64_t len_scaled;\n\n\t\t/*\n\t\t * Some schedulers might want wake up the scheduler later.\n\t\t * To suppor this the caller returns an mbuf with len < 0\n\t\t * this will result in a new wake up of the scheduler\n\t\t * instance between m->m_pkthdr.len ticks.\n\t\t */\n\t\tif (m->m_pkthdr.len < 0) {\n\t\t\tsi->kflags |= DN_ACTIVE;\n\t\t\theap_insert(&dn_cfg.evheap, now - m->m_pkthdr.len, si);\n\t\t\tif (delay_line_idle && done)\n\t\t\t\ttransmit_event(q, &si->dline, now);\n\t\t\treturn NULL;\n\t\t}\n\n \t\t/* a regular mbuf received */\n\t\tdone++;\n\t\tlen_scaled = (bw == 0) ? 0 : hz *\n\t\t\t(m->m_pkthdr.len * 8 + extra_bits(m, s));\n\t\tsi->credit -= len_scaled;\n\t\t/* Move packet in the delay line */\n\t\tdn_tag_get(m)->output_time = dn_cfg.curr_time + s->link.delay;\n\t\tmq_append(&si->dline.mq, m);\n\t}\n\n\t/*\n\t * If credit >= 0 the instance is idle, mark time.\n\t * Otherwise put back in the heap, and adjust the output\n\t * time of the last inserted packet, m, which was too early.\n\t */\n\tif (si->credit >= 0) {\n\t\tsi->idle_time = now;\n\t} else {\n\t\tuint64_t t;\n\t\tKASSERT (bw > 0, (\"bw=0 and credit<0 ?\"));\n\t\tt = div64(bw - 1 - si->credit, bw);\n\t\tif (m)\n\t\t\tdn_tag_get(m)->output_time += t;\n\t\tsi->kflags |= DN_ACTIVE;\n\t\theap_insert(&dn_cfg.evheap, now + t, si);\n\t}\n\tif (delay_line_idle && done)\n\t\ttransmit_event(q, &si->dline, now);\n\treturn q->head;\n}\n\n/*\n * Support function to read the TSC (or equivalent). We use this\n * high resolution timer to adapt the amount of work done for\n * expiring the clock.\n * Supports Linux and FreeBSD both i386 and amd64 platform\n * Supports OpenWRT mips architecture\n *\n * SMP no special works is needed in\n * - In linux 2.6 timers will always run in the same cpu that have added it.See\n * (http://book.opensourceproject.org.cn/kernel/kernel3rd/opensource/0596005652/understandlk-chp-6-sect-5.html)\n * - FreeBSD8 has a new callout_reset_on() with specify the cpu on which\n *   the timer must be run\n * - Windows runs dummynet_task() on cpu0.\n *\n * - Linux 2.4 doesn't assure to run a timer in the same cpu every time.\n */\n#ifdef HAVE_TSC\nuint64_t\nreadTSC (void)\n{\n\tuint64_t a=0;\n\n#ifdef __linux__\n\t/* Linux and openwrt have a macro to read the tsc for i386 and\n\t * amd64.\n\t * Openwrt have patched the kernel and allow use of tsc with mips\n\t * and other platforms\n\t * rdtscll() is a macro defined in include/asm-xxx/msr.h,\n\t * where xxx is the architecture (x86, mips).\n\t */\n\trdtscll(a);\n#elif defined(_WIN32)\n\t/* Microsoft recommends the use of KeQueryPerformanceCounter()\n\t * insteead of rdtsc().\n\t */\n\tKeQueryPerformanceCounter((PLARGE_INTEGER)&a);  //XXX not tested!\n#elif defined(__FreeBSD__)\n\t/* FreeBSD (i386/amd64) has macro rdtsc() defined in machine/cpufunc.h.\n\t * We could use the macro instead of explicity assembly XXX\n\t */\n\treturn rdtsc();\n#endif\n\treturn a;\n}\n#endif /* HAVE_TSC */\n\n/*\n * compute avg task period.\n * We could do something more complex, possibly.\n */\nstatic void\ndo_update_cycle(void)\n{\n#ifdef HAVE_TSC\n\tuint64_t tmp = readTSC();\n#if defined (LINUX_24) && defined(CONFIG_SMP)\n\t/* on LINUX24 and SMP, we have no guarantees on which cpu runs\n\t * the timer callbacks. If the difference between new and\n\t * old value is negative, we assume that the values come from\n\t * different cpus so we adjust 'new' accordingly.\n\t */\n\tif (tmp <= dn_cfg.cycle_task_new)\n\t\tdn_cfg.cycle_task_new = tmp - dn_cfg.cycle_task;\n#endif /* !(linux24 && SMP) */\n\tdn_cfg.cycle_task_old = dn_cfg.cycle_task_new;\n\tdn_cfg.cycle_task_new = tmp;\n\tdn_cfg.cycle_task = dn_cfg.cycle_task_new - dn_cfg.cycle_task_old;\n\n\t/* Update the average\n\t * avg = (2^N * avg + new - avg ) / 2^N * avg\n\t * N==4 seems to be a good compromise between clock clock change\n\t *      and 'spurious' cycle_task value\n\t */\n#define DN_N\t4\n\tdn_cfg.cycle_task_avg = (dn_cfg.cycle_task_avg << DN_N) +\n\t\t\t\tdn_cfg.cycle_task - dn_cfg.cycle_task_avg;\n\tdn_cfg.cycle_task_avg = dn_cfg.cycle_task_avg >> DN_N;\n#undef DN_N\n\n#endif /* HAVE_TSC */\n}\n\nstatic void\ndo_drain(void)\n{\n#ifdef HAVE_TSC\n\tuint64_t dt_max;\n#endif\n\tif (!dn_cfg.expire || ++dn_cfg.expire_cycle < dn_cfg.expire)\n\t\treturn;\n\t/* It's time to check if drain routines should be called */\n\tdn_cfg.expire_cycle = 0;\n\n\tdn_cfg.idle_queue_wait = 0;\n\tdn_cfg.idle_si_wait = 0;\n\t/* Do a drain cycle even if there isn't time to do it */\n#ifdef HAVE_TSC\n\tdt_max = dn_cfg.cycle_task_avg * dn_cfg.drain_ratio;\n#endif\n\tfor (;;) {\n\t\tint done = 0;\n\n\t\tif (dn_cfg.idle_queue > dn_cfg.expire_object &&\n\t\t    dn_cfg.idle_queue_wait < dn_cfg.idle_queue) {\n\t\t\tdn_drain_queue();\n\t\t\tdone = 1;\n\t\t}\n\t\tif (dn_cfg.idle_si > dn_cfg.expire_object &&\n\t\t    dn_cfg.idle_si_wait < dn_cfg.idle_si) {\n\t\t\tdn_drain_scheduler();\n\t\t\tdone = 1;\n\t\t}\n\t\t/* time to end ? */\n#ifndef HAVE_TSC\n\t\t/* If tsc does not exist, do only one drain cycle and exit */\n\t\tbreak;\n#else\n\t\t/* Exit when nothing was done or we have consumed all time */\n\t\tif ( (done == 0) || \n\t\t     ((readTSC() -  dn_cfg.cycle_task_new) * 100 > dt_max) )\n\t\t\tbreak;\n#endif\t/* HAVE_TSC */\n\t}\n}\n\n/*\n * The timer handler for dummynet. Time is computed in ticks, but\n * but the code is tolerant to the actual rate at which this is called.\n * Once complete, the function reschedules itself for the next tick.\n */\nvoid\ndummynet_task(void *context, int pending)\n{\n\tstruct timeval t;\n\tstruct mq q = { NULL, NULL }; /* queue to accumulate results */\n\n\tCURVNET_SET((struct vnet *)context);\n\n\tdo_update_cycle();      /* compute avg. tick duration */\n\n\tDN_BH_WLOCK();\n\n\t/* Update number of lost(coalesced) ticks. */\n\ttick_lost += pending - 1;\n\n\tgetmicrouptime(&t);\n\t/* Last tick duration (usec). */\n\ttick_last = (t.tv_sec - dn_cfg.prev_t.tv_sec) * 1000000 +\n\t(t.tv_usec - dn_cfg.prev_t.tv_usec);\n\t/* Last tick vs standard tick difference (usec). */\n\ttick_delta = (tick_last * hz - 1000000) / hz;\n\t/* Accumulated tick difference (usec). */\n\ttick_delta_sum += tick_delta;\n\n\tdn_cfg.prev_t = t;\n\n\t/*\n\t* Adjust curr_time if the accumulated tick difference is\n\t* greater than the 'standard' tick. Since curr_time should\n\t* be monotonically increasing, we do positive adjustments\n\t* as required, and throttle curr_time in case of negative\n\t* adjustment.\n\t*/\n\tdn_cfg.curr_time++;\n\tif (tick_delta_sum - tick >= 0) {\n\t\tint diff = tick_delta_sum / tick;\n\n\t\tdn_cfg.curr_time += diff;\n\t\ttick_diff += diff;\n\t\ttick_delta_sum %= tick;\n\t\ttick_adjustment++;\n\t} else if (tick_delta_sum + tick <= 0) {\n\t\tdn_cfg.curr_time--;\n\t\ttick_diff--;\n\t\ttick_delta_sum += tick;\n\t\ttick_adjustment++;\n\t}\n\n\t/* serve pending events, accumulate in q */\n\tfor (;;) {\n\t\tstruct dn_id *p;    /* generic parameter to handler */\n\n\t\tif (dn_cfg.evheap.elements == 0 ||\n\t\t    DN_KEY_LT(dn_cfg.curr_time, HEAP_TOP(&dn_cfg.evheap)->key))\n\t\t\tbreak;\n\t\tp = HEAP_TOP(&dn_cfg.evheap)->object;\n\t\theap_extract(&dn_cfg.evheap, NULL);\n\n\t\tif (p->type == DN_SCH_I) {\n\t\t\tserve_sched(&q, (struct dn_sch_inst *)p, dn_cfg.curr_time);\n\t\t} else { /* extracted a delay line */\n\t\t\ttransmit_event(&q, (struct delay_line *)p, dn_cfg.curr_time);\n\t\t}\n\t}\n\tdo_drain();\n\n\tDN_BH_WUNLOCK();\n\tdn_reschedule();\n\tif (q.head != NULL)\n\t\tdummynet_send(q.head);\n\tCURVNET_RESTORE();\n}\n\n/*\n * forward a chain of packets to the proper destination.\n * This runs outside the dummynet lock.\n */\nstatic void\ndummynet_send(struct mbuf *m)\n{\n\tstruct mbuf *n;\n\n\tfor (; m != NULL; m = n) {\n\t\tstruct ifnet *ifp = NULL;\t/* gcc 3.4.6 complains */\n        \tstruct m_tag *tag;\n\t\tint dst;\n\n\t\tn = m->m_nextpkt;\n\t\tm->m_nextpkt = NULL;\n\t\ttag = m_tag_first(m);\n\t\tif (tag == NULL) { /* should not happen */\n\t\t\tdst = DIR_DROP;\n\t\t} else {\n\t\t\tstruct dn_pkt_tag *pkt = dn_tag_get(m);\n\t\t\t/* extract the dummynet info, rename the tag\n\t\t\t * to carry reinject info.\n\t\t\t */\n\t\t\tdst = pkt->dn_dir;\n\t\t\tifp = pkt->ifp;\n\t\t\ttag->m_tag_cookie = MTAG_IPFW_RULE;\n\t\t\ttag->m_tag_id = 0;\n\t\t}\n\n\t\tswitch (dst) {\n\t\tcase DIR_OUT:\n\t\t\tSET_HOST_IPLEN(mtod(m, struct ip *));\n\t\t\tip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);\n\t\t\tbreak ;\n\n\t\tcase DIR_IN :\n\t\t\t/* put header in network format for ip_input() */\n\t\t\t//SET_NET_IPLEN(mtod(m, struct ip *));\n\t\t\tnetisr_dispatch(NETISR_IP, m);\n\t\t\tbreak;\n\n#ifdef INET6\n\t\tcase DIR_IN | PROTO_IPV6:\n\t\t\tnetisr_dispatch(NETISR_IPV6, m);\n\t\t\tbreak;\n\n\t\tcase DIR_OUT | PROTO_IPV6:\n\t\t\tSET_HOST_IPLEN(mtod(m, struct ip *));\n\t\t\tip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);\n\t\t\tbreak;\n#endif\n\n\t\tcase DIR_FWD | PROTO_IFB: /* DN_TO_IFB_FWD: */\n\t\t\tif (bridge_dn_p != NULL)\n\t\t\t\t((*bridge_dn_p)(m, ifp));\n\t\t\telse\n\t\t\t\tprintf(\"dummynet: if_bridge not loaded\\n\");\n\n\t\t\tbreak;\n\n\t\tcase DIR_IN | PROTO_LAYER2: /* DN_TO_ETH_DEMUX: */\n\t\t\t/*\n\t\t\t * The Ethernet code assumes the Ethernet header is\n\t\t\t * contiguous in the first mbuf header.\n\t\t\t * Insure this is true.\n\t\t\t */\n\t\t\tif (m->m_len < ETHER_HDR_LEN &&\n\t\t\t    (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {\n\t\t\t\tprintf(\"dummynet/ether: pullup failed, \"\n\t\t\t\t    \"dropping packet\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tether_demux(m->m_pkthdr.rcvif, m);\n\t\t\tbreak;\n\n\t\tcase DIR_OUT | PROTO_LAYER2: /* N_TO_ETH_OUT: */\n\t\t\tether_output_frame(ifp, m);\n\t\t\tbreak;\n\n\t\tcase DIR_DROP:\n\t\t\t/* drop the packet after some time */\n\t\t\tFREE_PKT(m);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tprintf(\"dummynet: bad switch %d!\\n\", dst);\n\t\t\tFREE_PKT(m);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nstatic inline int\ntag_mbuf(struct mbuf *m, int dir, struct ip_fw_args *fwa)\n{\n\tstruct dn_pkt_tag *dt;\n\tstruct m_tag *mtag;\n\n\tmtag = m_tag_get(PACKET_TAG_DUMMYNET,\n\t\t    sizeof(*dt), M_NOWAIT | M_ZERO);\n\tif (mtag == NULL)\n\t\treturn 1;\t\t/* Cannot allocate packet header. */\n\tm_tag_prepend(m, mtag);\t\t/* Attach to mbuf chain. */\n\tdt = (struct dn_pkt_tag *)(mtag + 1);\n\tdt->rule = fwa->rule;\n\tdt->rule.info &= IPFW_ONEPASS;\t/* only keep this info */\n\tdt->dn_dir = dir;\n\tdt->ifp = fwa->oif;\n\t/* dt->output tame is updated as we move through */\n\tdt->output_time = dn_cfg.curr_time;\n\treturn 0;\n}\n\n\n/*\n * dummynet hook for packets.\n * We use the argument to locate the flowset fs and the sched_set sch\n * associated to it. The we apply flow_mask and sched_mask to\n * determine the queue and scheduler instances.\n *\n * dir\t\twhere shall we send the packet after dummynet.\n * *m0\t\tthe mbuf with the packet\n * ifp\t\tthe 'ifp' parameter from the caller.\n *\t\tNULL in ip_input, destination interface in ip_output,\n */\nint\ndummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa)\n{\n\tstruct mbuf *m = *m0;\n\tstruct dn_fsk *fs = NULL;\n\tstruct dn_sch_inst *si;\n\tstruct dn_queue *q = NULL;\t/* default */\n\n\tint fs_id = (fwa->rule.info & IPFW_INFO_MASK) +\n\t\t((fwa->rule.info & IPFW_IS_PIPE) ? 2*DN_MAX_ID : 0);\n\tDN_BH_WLOCK();\n\tio_pkt++;\n\t/* we could actually tag outside the lock, but who cares... */\n\tif (tag_mbuf(m, dir, fwa))\n\t\tgoto dropit;\n\tif (dn_cfg.busy) {\n\t\t/* if the upper half is busy doing something expensive,\n\t\t * lets queue the packet and move forward\n\t\t */\n\t\tmq_append(&dn_cfg.pending, m);\n\t\tm = *m0 = NULL; /* consumed */\n\t\tgoto done; /* already active, nothing to do */\n\t}\n\t/* XXX locate_flowset could be optimised with a direct ref. */\n\tfs = dn_ht_find(dn_cfg.fshash, fs_id, 0, NULL);\n\tif (fs == NULL)\n\t\tgoto dropit;\t/* This queue/pipe does not exist! */\n\tif (fs->sched == NULL)\t/* should not happen */\n\t\tgoto dropit;\n\t/*\n\t * If the scheduler supports multiple queues, find the right one\n\t * (otherwise it will be ignored by enqueue).\n\t */\n\tif (fs->sched->fp->flags & DN_MULTIQUEUE) {\n\t\tq = ipdn_q_find(fs, &(fwa->f_id));\n\t\tif (q == NULL)\n\t\t\tgoto dropit;\n\t\t/* The scheduler instance lookup is done only for new queue.\n\t\t * The callback q_new() will create the scheduler instance\n\t\t * if needed.\n\t\t */\n\t\tsi = q->_si;\n\t} else\n\t\tsi = ipdn_si_find(fs->sched, &(fwa->f_id));\n\n\tif (si == NULL)\n\t\tgoto dropit;\n\tif (fs->sched->fp->enqueue(si, q, m)) {\n\t\t/* packet was dropped by enqueue() */\n\t\tm = *m0 = NULL;\n\t\tgoto dropit;\n\t}\n\n\tif (si->kflags & DN_ACTIVE) {\n\t\tm = *m0 = NULL; /* consumed */\n\t\tgoto done; /* already active, nothing to do */\n\t}\n\n\t/* compute the initial allowance */\n\tif (si->idle_time < dn_cfg.curr_time) {\n\t    /* Do this only on the first packet on an idle pipe */\n\t    struct dn_link *p = &fs->sched->link;\n\n\t    si->sched_time = dn_cfg.curr_time;\n\t    si->credit = dn_cfg.io_fast ? p->bandwidth : 0;\n\t    if (p->burst) {\n\t\tuint64_t burst = (dn_cfg.curr_time - si->idle_time) * p->bandwidth;\n\t\tif (burst > p->burst)\n\t\t\tburst = p->burst;\n\t\tsi->credit += burst;\n\t    }\n\t}\n\t/* pass through scheduler and delay line */\n\tm = serve_sched(NULL, si, dn_cfg.curr_time);\n\n\t/* optimization -- pass it back to ipfw for immediate send */\n\t/* XXX Don't call dummynet_send() if scheduler return the packet\n\t *     just enqueued. This avoid a lock order reversal.\n\t *     \n\t */\n\tif (/*dn_cfg.io_fast &&*/ m == *m0 && (dir & PROTO_LAYER2) == 0 ) {\n\t\t/* fast io, rename the tag * to carry reinject info. */\n\t\tstruct m_tag *tag = m_tag_first(m);\n\n\t\ttag->m_tag_cookie = MTAG_IPFW_RULE;\n\t\ttag->m_tag_id = 0;\n\t\tio_pkt_fast++;\n\t\tif (m->m_nextpkt != NULL) {\n\t\t\tprintf(\"dummynet: fast io: pkt chain detected!\\n\");\n\t\t\tm->m_nextpkt = NULL;\n\t\t}\n\t\tm = NULL;\n\t} else {\n\t\t*m0 = NULL;\n\t}\ndone:\n\tDN_BH_WUNLOCK();\n\tif (m)\n\t\tdummynet_send(m);\n\treturn 0;\n\ndropit:\n\tio_pkt_drop++;\n\tDN_BH_WUNLOCK();\n\tif (m)\n\t\tFREE_PKT(m);\n\t*m0 = NULL;\n\treturn (fs && (fs->fs.flags & DN_NOERROR)) ? 0 : ENOBUFS;\n}\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_dn_private.h",
    "content": "/*-\n * Copyright (c) 2010 Luigi Rizzo, Riccardo Panicucci, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * internal dummynet APIs.\n *\n * $FreeBSD: head/sys/netinet/ipfw/ip_dn_private.h 204591 2010-03-02 17:40:48Z luigi $\n */\n\n#ifndef _IP_DN_PRIVATE_H\n#define _IP_DN_PRIVATE_H\n\n/* debugging support\n * use ND() to remove debugging, D() to print a line,\n * DX(level, ...) to print above a certain level\n * If you redefine D() you are expected to redefine all.\n */\n#ifndef D\n#define ND(fmt, ...) do {} while (0)\n#define D1(fmt, ...) do {} while (0)\n#define D(fmt, ...) printf(\"%-10s \" fmt \"\\n\",      \\\n        __FUNCTION__, ## __VA_ARGS__)\n#define DX(lev, fmt, ...) do {              \\\n        if (dn_cfg.debug > lev) D(fmt, ## __VA_ARGS__); } while (0)\n#endif\n\nMALLOC_DECLARE(M_DUMMYNET);\n\n#ifndef __linux__\n#define div64(a, b)  ((int64_t)(a) / (int64_t)(b))\n#endif\n\n#define DN_LOCK_INIT() do {\t\t\t\t\\\n\tmtx_init(&dn_cfg.uh_mtx, \"dn_uh\", NULL, MTX_DEF);\t\\\n\tmtx_init(&dn_cfg.bh_mtx, \"dn_bh\", NULL, MTX_DEF);\t\\\n\t} while (0)\n#define DN_LOCK_DESTROY() do {\t\t\t\t\\\n\tmtx_destroy(&dn_cfg.uh_mtx);\t\t\t\\\n\tmtx_destroy(&dn_cfg.bh_mtx);\t\t\t\\\n\t} while (0)\n#if 0 /* not used yet */\n#define DN_UH_RLOCK()\t\tmtx_lock(&dn_cfg.uh_mtx)\n#define DN_UH_RUNLOCK()\t\tmtx_unlock(&dn_cfg.uh_mtx)\n#define DN_UH_WLOCK()\t\tmtx_lock(&dn_cfg.uh_mtx)\n#define DN_UH_WUNLOCK()\t\tmtx_unlock(&dn_cfg.uh_mtx)\n#define DN_UH_LOCK_ASSERT()\tmtx_assert(&dn_cfg.uh_mtx, MA_OWNED)\n#endif\n\n#define DN_BH_RLOCK()\t\tmtx_lock(&dn_cfg.uh_mtx)\n#define DN_BH_RUNLOCK()\t\tmtx_unlock(&dn_cfg.uh_mtx)\n#define DN_BH_WLOCK()\t\tmtx_lock(&dn_cfg.uh_mtx)\n#define DN_BH_WUNLOCK()\t\tmtx_unlock(&dn_cfg.uh_mtx)\n#define DN_BH_LOCK_ASSERT()\tmtx_assert(&dn_cfg.uh_mtx, MA_OWNED)\n\nSLIST_HEAD(dn_schk_head, dn_schk);\nSLIST_HEAD(dn_sch_inst_head, dn_sch_inst);\nSLIST_HEAD(dn_fsk_head, dn_fsk);\nSLIST_HEAD(dn_queue_head, dn_queue);\nSLIST_HEAD(dn_alg_head, dn_alg);\n\nstruct mq {\t/* a basic queue of packets*/\n        struct mbuf *head, *tail;\n};\n\nstatic inline void\nset_oid(struct dn_id *o, int type, int len)\n{\n        o->type = type;\n        o->len = len;\n        o->subtype = 0;\n};\n\nuint64_t readTSC (void);\n/*\n * see if tsc (ot other timer) is supported.\n * - FreeBSD has rdtsc macro for i386 and amd64\n * - Linux has rdtscll and/or rdtsc (also for openWRT patched kernel source)\n * - Windows has KeQueryPerformanceCounter() function that use tsc or other\n *   timer\n */\n#if defined(rdtscll) || defined(rdtsc) || defined(_WIN32)\n#define HAVE_TSC\n#endif\n/*\n * configuration and global data for a dummynet instance\n *\n * When a configuration is modified from userland, 'id' is incremented\n * so we can use the value to check for stale pointers.\n */\nstruct dn_parms {\n\tuint32_t\tid;\t\t/* configuration version */\n\n\t/* defaults (sysctl-accessible) */\n\tint\tred_lookup_depth;\n\tint\tred_avg_pkt_size;\n\tint\tred_max_pkt_size;\n\tint\thash_size;\n\tint\tmax_hash_size;\n\tlong\tbyte_limit;\t\t/* max queue sizes */\n\tlong\tslot_limit;\n\n\tint\tio_fast;\n\tint\tdebug;\n\n\t/* timekeeping */\n\tstruct timeval prev_t;\t\t/* last time dummynet_tick ran */\n\tstruct dn_heap\tevheap;\t\t/* scheduled events */\n\n\t/* counters of objects -- used for reporting space */\n\tint\tschk_count;\n\tint\tsi_count;\n\tint\tfsk_count;\n\tint\tqueue_count;\n\n\t/* ticks and other stuff */\n\tuint64_t\tcurr_time;\t/* in ticks */\n\n\t/*\n\t * Variables to manage the time spent in the drain routines.\n\t * max_drain is max the fraction of a tick (0..100) to be used\n\t * for draining.\n\t * We also need some variables to store the average number of\n\t * timecounter ticks between calls to the periodic task, etc.\n\t */\n\tint drain_ratio;\n\tuint64_t cycle_task_new;\t/* TSC when dummynet_task() starts */\n\tuint64_t cycle_task_old;\t/* TSC when prev. dummynet_task() starts */\n\tuint64_t cycle_task;\n\tuint64_t cycle_task_avg;\t/* Moving average of cicle_task */\n\n\t/* flowsets and schedulers are in hash tables, with 'hash_size'\n\t * buckets. fshash is looked up at every packet arrival\n\t * so better be generous if we expect many entries.\n\t */\n\tstruct dn_ht\t*fshash;\n\tstruct dn_ht\t*schedhash;\n\t/* list of flowsets without a scheduler -- use sch_chain */\n\tstruct dn_fsk_head\tfsu;\t/* list of unlinked flowsets */\n\tstruct dn_alg_head\tschedlist;\t/* list of algorithms */\n\n\t/* Counter of idle objects -- used by drain routine\n\t * We scan when idle_queue (or idle_si) > expire_object.\n\t * The drain routine is called every 'expire' cycles (the counter\n\t * used is expire_cycle).\n\t * We can disable the expire routine by setting expire to 0.\n\t * An object is kept alive for at least object_idle_tick after it\n\t * becomes idle. During the scan, we count the number of objects\n\t * that are idle but not ready in 'idle_si_wait' and 'idle_queue_wait'\n\t */\n\tint\tidle_queue;\n\tint\tidle_queue_wait;\t\t/* idle but not expired yet */\n\tint\tidle_si;\n\tint\tidle_si_wait;\t\t\t/* idle but not expired yet */\n\tuint32_t expire_object;\t\t\t/* threshold for expires */\n\tuint32_t expire;\t\t\t/* how often to expire */\n\tuint32_t expire_cycle;\n\tuint32_t object_idle_tick; \t\t/* lifetime of objs */\n\tuint32_t expire_object_examined;\t/* Burst of object examined */\n\n\t/* drain_fs and drain_sch point to the next bucket to scan when\n\t * draining.\n\t */\n\tuint32_t drain_fs;\n\tuint32_t drain_sch;\n\n\tint init_done;\n\n\t/* if the upper half is busy doing something long,\n\t * can set the busy flag and we will enqueue packets in\n\t * a queue for later processing.\n\t */\n\tint\tbusy;\n\tstruct\tmq\tpending;\n\n#ifdef _KERNEL\n\t/*\n\t * This file is normally used in the kernel, unless we do\n\t * some userland tests, in which case we do not need a mtx.\n\t * uh_mtx arbitrates between system calls and also\n\t * protects fshash, schedhash and fsunlinked.\n\t * These structures are readonly for the lower half.\n\t * bh_mtx protects all other structures which may be\n\t * modified upon packet arrivals\n\t */\n#if defined( __linux__ ) || defined( _WIN32 )\n\tspinlock_t uh_mtx;\n\tspinlock_t bh_mtx;\n#else\n\tstruct mtx uh_mtx;\n\tstruct mtx bh_mtx;\n#endif\n\n#endif /* _KERNEL */\n};\n\n/*\n * Delay line, contains all packets on output from a link.\n * Every scheduler instance has one.\n */\nstruct delay_line {\n\tstruct dn_id oid;\n\tstruct dn_sch_inst *si;\n\tstruct mq mq;\n};\n\n/*\n * The kernel side of a flowset. It is linked in a hash table\n * of flowsets, and in a list of children of their parent scheduler.\n * qht is either the queue or (if HAVE_MASK) a hash table queues.\n * Note that the mask to use is the (flow_mask|sched_mask), which\n * changes as we attach/detach schedulers. So we store it here.\n *\n * XXX If we want to add scheduler-specific parameters, we need to\n * put them in external storage because the scheduler may not be\n * available when the fsk is created.\n */\nstruct dn_fsk { /* kernel side of a flowset */\n\tstruct dn_fs fs;\n\tSLIST_ENTRY(dn_fsk) fsk_next;\t/* hash chain for fshash */\n\n\tstruct ipfw_flow_id fsk_mask;\n\n\t/* qht is a hash table of queues, or just a single queue\n\t * a bit in fs.flags tells us which one\n\t */\n\tstruct dn_ht\t*qht;\n\tstruct dn_schk *sched;\t\t/* Sched we are linked to */\n\tSLIST_ENTRY(dn_fsk) sch_chain;\t/* list of fsk attached to sched */\n\n\t/* bucket index used by drain routine to drain queues for this\n\t * flowset\n\t */\n\tint drain_bucket;\n\t/* Parameter realted to RED / GRED */\n\t/* original values are in dn_fs*/\n\tint w_q ;\t\t/* queue weight (scaled) */\n\tint max_th ;\t\t/* maximum threshold for queue (scaled) */\n\tint min_th ;\t\t/* minimum threshold for queue (scaled) */\n\tint max_p ;\t\t/* maximum value for p_b (scaled) */\n\n\tu_int c_1 ;\t\t/* max_p/(max_th-min_th) (scaled) */\n\tu_int c_2 ;\t\t/* max_p*min_th/(max_th-min_th) (scaled) */\n\tu_int c_3 ;\t\t/* for GRED, (1-max_p)/max_th (scaled) */\n\tu_int c_4 ;\t\t/* for GRED, 1 - 2*max_p (scaled) */\n\tu_int * w_q_lookup ;\t/* lookup table for computing (1-w_q)^t */\n\tu_int lookup_depth ;\t/* depth of lookup table */\n\tint lookup_step ;\t/* granularity inside the lookup table */\n\tint lookup_weight ;\t/* equal to (1-w_q)^t / (1-w_q)^(t+1) */\n\tint avg_pkt_size ;\t/* medium packet size */\n\tint max_pkt_size ;\t/* max packet size */\n};\n\n/*\n * A queue is created as a child of a flowset unless it belongs to\n * a !MULTIQUEUE scheduler. It is normally in a hash table in the\n * flowset. fs always points to the parent flowset.\n * si normally points to the sch_inst, unless the flowset has been\n * detached from the scheduler -- in this case si == NULL and we\n * should not enqueue.\n */\nstruct dn_queue {\n\tstruct dn_flow ni;\t/* oid, flow_id, stats */\n\tstruct mq mq;\t/* packets queue */\n\tstruct dn_sch_inst *_si;\t/* owner scheduler instance */\n\tSLIST_ENTRY(dn_queue) q_next; /* hash chain list for qht */\n\tstruct dn_fsk *fs;\t\t/* parent flowset. */\n\n\t/* RED parameters */\n\tint avg;\t\t/* average queue length est. (scaled) */\n\tint count;\t\t/* arrivals since last RED drop */\n\tint random;\t\t/* random value (scaled) */\n\tuint64_t q_time;\t/* start of queue idle time */\n\n};\n\n/*\n * The kernel side of a scheduler. Contains the userland config,\n * a link, pointer to extra config arguments from command line,\n * kernel flags, and a pointer to the scheduler methods.\n * It is stored in a hash table, and holds a list of all\n * flowsets and scheduler instances.\n * XXX sch must be at the beginning, see schk_hash().\n */\nstruct dn_schk {\n\tstruct dn_sch sch;\n\tstruct dn_alg *fp;\t/* Pointer to scheduler functions */\n\tstruct dn_link link;\t/* The link, embedded */\n\tstruct dn_profile *profile; /* delay profile, if any */\n\tstruct dn_id *cfg;\t/* extra config arguments */\n\n\tSLIST_ENTRY(dn_schk) schk_next;  /* hash chain for schedhash */\n\n\tstruct dn_fsk_head fsk_list;  /* all fsk linked to me */\n\tstruct dn_fsk *fs;\t/* Flowset for !MULTIQUEUE */\n\n\t/* bucket index used by the drain routine to drain the scheduler\n\t * instance for this flowset.\n\t */\n\tint drain_bucket;\n\n\t/* Hash table of all instances (through sch.sched_mask)\n\t * or single instance if no mask. Always valid.\n\t */\n\tstruct dn_ht\t*siht;\n};\n\n\n/*\n * Scheduler instance.\n * Contains variables and all queues relative to a this instance.\n * This struct is created a runtime.\n */\nstruct dn_sch_inst {\n\tstruct dn_flow\tni;\t/* oid, flowid and stats */\n\tSLIST_ENTRY(dn_sch_inst) si_next; /* hash chain for siht */\n\tstruct delay_line dline;\n\tstruct dn_schk *sched;\t/* the template */\n\tint\t\tkflags;\t/* DN_ACTIVE */\n\n\tint64_t\tcredit;\t\t/* bits I can transmit (more or less). */\n\tuint64_t sched_time;\t/* time link was scheduled in ready_heap */\n\tuint64_t idle_time;\t/* start of scheduler instance idle time */\n\n\t/* q_count is the number of queues that this instance is using.\n\t * The counter is incremented or decremented when\n\t * a reference from the queue is created or deleted.\n\t * It is used to make sure that a scheduler instance can be safely\n\t * deleted by the drain routine.\n\t */\n\tint q_count;\n\n};\n\n\n/* kernel-side flags. Linux has DN_DELETE in fcntl.h\n */\nenum {\n\t/* 1 and 2 are reserved for the SCAN flags */\n\tDN_DESTROY\t= 0x0004, /* destroy */\n\tDN_DELETE_FS\t= 0x0008, /* destroy flowset */\n\tDN_DETACH\t= 0x0010,\n\tDN_ACTIVE\t= 0x0020, /* object is in evheap */\n\tDN_F_DLINE\t= 0x0040, /* object is a delay line */\n\tDN_DEL_SAFE\t= 0x0080, /* delete a queue only if no longer needed\n\t\t\t\t   * by scheduler */\n\tDN_QHT_IS_Q\t= 0x0100, /* in flowset, qht is a single queue */\n};\n\nextern struct dn_parms dn_cfg;\n//VNET_DECLARE(struct dn_parms, _base_dn_cfg);\n//#define dn_cfg\tVNET(_base_dn_cfg)\n\nint dummynet_io(struct mbuf **, int , struct ip_fw_args *);\nvoid dummynet_task(void *context, int pending);\nvoid dn_reschedule(void);\n\nstruct dn_queue *ipdn_q_find(struct dn_fsk *, struct ipfw_flow_id *);\nstruct dn_sch_inst *ipdn_si_find(struct dn_schk *, struct ipfw_flow_id *);\n\n/*\n * copy_range is a template for requests for ranges of pipes/queues/scheds.\n * The number of ranges is variable and can be derived by o.len.\n * As a default, we use a small number of entries so that the struct\n * fits easily on the stack and is sufficient for most common requests.\n */\n#define DEFAULT_RANGES\t5\nstruct copy_range {\n        struct dn_id o;\n        uint32_t\tr[ 2 * DEFAULT_RANGES ];\n};\n\nstruct copy_args {\n\tchar **start;\n\tchar *end;\n\tint flags;\n\tint type;\n\tstruct copy_range *extra;\t/* extra filtering */\n};\n\nstruct sockopt;\nint ip_dummynet_compat(struct sockopt *sopt);\nint dummynet_get(struct sockopt *sopt, void **compat);\nint dn_c_copy_q (void *_ni, void *arg);\nint dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq);\nint dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq);\nint dn_compat_copy_queue(struct copy_args *a, void *_o);\nint dn_compat_copy_pipe(struct copy_args *a, void *_o);\nint copy_data_helper_compat(void *_o, void *_arg);\nint dn_compat_calc_size(void);\nint do_config(void *p, int l);\n\n/* function to drain idle object */\nvoid dn_drain_scheduler(void);\nvoid dn_drain_queue(void);\n\n#endif /* _IP_DN_PRIVATE_H */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_dummynet.c",
    "content": "/*-\n * Copyright (c) 1998-2002,2010 Luigi Rizzo, Universita` di Pisa\n * Portions Copyright (c) 2000 Akamba Corp.\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c 203340 2010-02-01 12:06:37Z luigi $\");\n\n/*\n * Configuration and internal object management for dummynet.\n */\n\n#include \"opt_inet6.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/mbuf.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/module.h>\n#include <sys/priv.h>\n#include <sys/proc.h>\n#include <sys/rwlock.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/time.h>\n#include <sys/taskqueue.h>\n#include <net/if.h>\t/* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t/* ip_output(), IP_FORWARDING */\n#include <netinet/ip_fw.h>\n#include <netinet/ip_dummynet.h>\n\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netinet/ipfw/dn_heap.h>\n#include <netinet/ipfw/ip_dn_private.h>\n#include <netinet/ipfw/dn_sched.h>\n\n/* which objects to copy */\n#define DN_C_LINK \t0x01\n#define DN_C_SCH\t0x02\n#define DN_C_FLOW\t0x04\n#define DN_C_FS\t\t0x08\n#define DN_C_QUEUE\t0x10\n\n/* we use this argument in case of a schk_new */\nstruct schk_new_arg {\n\tstruct dn_alg *fp;\n\tstruct dn_sch *sch;\n};\n\n/*---- callout hooks. ----*/\nstatic struct callout dn_timeout;\nstatic struct task\tdn_task;\nstatic struct taskqueue\t*dn_tq = NULL;\n\n/* dummynet and ipfw_tick can't be static in windows */\nvoid\ndummynet(void * arg)\n{\n\n\t(void)arg;\t/* UNUSED */\n\ttaskqueue_enqueue(dn_tq, &dn_task);\n}\n\nvoid\ndn_reschedule(void)\n{\n\tcallout_reset_on(&dn_timeout, 1, dummynet, NULL, 0);\n}\n/*----- end of callout hooks -----*/\n\n/* Return a scheduler descriptor given the type or name. */\nstatic struct dn_alg *\nfind_sched_type(int type, char *name)\n{\n\tstruct dn_alg *d;\n\n\tSLIST_FOREACH(d, &dn_cfg.schedlist, next) {\n\t\tif (d->type == type || (name && !strcasecmp(d->name, name)))\n\t\t\treturn d;\n\t}\n\treturn NULL; /* not found */\n}\n\nint\nipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg)\n{\n\tint oldv = *v;\n\tconst char *op = NULL;\n\tif (dflt < lo)\n\t\tdflt = lo;\n\tif (dflt > hi)\n\t\tdflt = hi;\n\tif (oldv < lo) {\n\t\t*v = dflt;\n\t\top = \"Bump\";\n\t} else if (oldv > hi) {\n\t\t*v = hi;\n\t\top = \"Clamp\";\n\t} else\n\t\treturn *v;\n\tif (op && msg)\n\t\tprintf(\"%s %s to %d (was %d)\\n\", op, msg, *v, oldv);\n\treturn *v;\n}\n\n/*---- flow_id mask, hash and compare functions ---*/\n/*\n * The flow_id includes the 5-tuple, the queue/pipe number\n * which we store in the extra area in host order,\n * and for ipv6 also the flow_id6.\n * XXX see if we want the tos byte (can store in 'flags')\n */\nstatic struct ipfw_flow_id *\nflow_id_mask(struct ipfw_flow_id *mask, struct ipfw_flow_id *id)\n{\n\tint is_v6 = IS_IP6_FLOW_ID(id);\n\n\tid->dst_port &= mask->dst_port;\n\tid->src_port &= mask->src_port;\n\tid->proto &= mask->proto;\n\tid->extra &= mask->extra;\n\tif (is_v6) {\n\t\tAPPLY_MASK(&id->dst_ip6, &mask->dst_ip6);\n\t\tAPPLY_MASK(&id->src_ip6, &mask->src_ip6);\n\t\tid->flow_id6 &= mask->flow_id6;\n\t} else {\n\t\tid->dst_ip &= mask->dst_ip;\n\t\tid->src_ip &= mask->src_ip;\n\t}\n\treturn id;\n}\n\n/* computes an OR of two masks, result in dst and also returned */\nstatic struct ipfw_flow_id *\nflow_id_or(struct ipfw_flow_id *src, struct ipfw_flow_id *dst)\n{\n\tint is_v6 = IS_IP6_FLOW_ID(dst);\n\n\tdst->dst_port |= src->dst_port;\n\tdst->src_port |= src->src_port;\n\tdst->proto |= src->proto;\n\tdst->extra |= src->extra;\n\tif (is_v6) {\n#define OR_MASK(_d, _s)                          \\\n    (_d)->__u6_addr.__u6_addr32[0] |= (_s)->__u6_addr.__u6_addr32[0]; \\\n    (_d)->__u6_addr.__u6_addr32[1] |= (_s)->__u6_addr.__u6_addr32[1]; \\\n    (_d)->__u6_addr.__u6_addr32[2] |= (_s)->__u6_addr.__u6_addr32[2]; \\\n    (_d)->__u6_addr.__u6_addr32[3] |= (_s)->__u6_addr.__u6_addr32[3];\n\t\tOR_MASK(&dst->dst_ip6, &src->dst_ip6);\n\t\tOR_MASK(&dst->src_ip6, &src->src_ip6);\n#undef OR_MASK\n\t\tdst->flow_id6 |= src->flow_id6;\n\t} else {\n\t\tdst->dst_ip |= src->dst_ip;\n\t\tdst->src_ip |= src->src_ip;\n\t}\n\treturn dst;\n}\n\nstatic int\nnonzero_mask(struct ipfw_flow_id *m)\n{\n\tif (m->dst_port || m->src_port || m->proto || m->extra)\n\t\treturn 1;\n\tif (IS_IP6_FLOW_ID(m)) {\n\t\treturn\n\t\t\tm->dst_ip6.__u6_addr.__u6_addr32[0] ||\n\t\t\tm->dst_ip6.__u6_addr.__u6_addr32[1] ||\n\t\t\tm->dst_ip6.__u6_addr.__u6_addr32[2] ||\n\t\t\tm->dst_ip6.__u6_addr.__u6_addr32[3] ||\n\t\t\tm->src_ip6.__u6_addr.__u6_addr32[0] ||\n\t\t\tm->src_ip6.__u6_addr.__u6_addr32[1] ||\n\t\t\tm->src_ip6.__u6_addr.__u6_addr32[2] ||\n\t\t\tm->src_ip6.__u6_addr.__u6_addr32[3] ||\n\t\t\tm->flow_id6;\n\t} else {\n\t\treturn m->dst_ip || m->src_ip;\n\t}\n}\n\n/* XXX we may want a better hash function */\nstatic uint32_t\nflow_id_hash(struct ipfw_flow_id *id)\n{\n    uint32_t i;\n\n    if (IS_IP6_FLOW_ID(id)) {\n\tuint32_t *d = (uint32_t *)&id->dst_ip6;\n\tuint32_t *s = (uint32_t *)&id->src_ip6;\n        i = (d[0]      ) ^ (d[1])       ^\n            (d[2]      ) ^ (d[3])       ^\n            (d[0] >> 15) ^ (d[1] >> 15) ^\n            (d[2] >> 15) ^ (d[3] >> 15) ^\n            (s[0] <<  1) ^ (s[1] <<  1) ^\n            (s[2] <<  1) ^ (s[3] <<  1) ^\n            (s[0] << 16) ^ (s[1] << 16) ^\n            (s[2] << 16) ^ (s[3] << 16) ^\n            (id->dst_port << 1) ^ (id->src_port) ^\n\t    (id->extra) ^\n            (id->proto ) ^ (id->flow_id6);\n    } else {\n        i = (id->dst_ip)        ^ (id->dst_ip >> 15) ^\n            (id->src_ip << 1)   ^ (id->src_ip >> 16) ^\n\t    (id->extra) ^\n            (id->dst_port << 1) ^ (id->src_port)     ^ (id->proto);\n    }\n    return i;\n}\n\n/* Like bcmp, returns 0 if ids match, 1 otherwise. */\nstatic int\nflow_id_cmp(struct ipfw_flow_id *id1, struct ipfw_flow_id *id2)\n{\n\tint is_v6 = IS_IP6_FLOW_ID(id1);\n\n\tif (!is_v6) {\n\t    if (IS_IP6_FLOW_ID(id2))\n\t\treturn 1; /* different address families */\n\n\t    return (id1->dst_ip == id2->dst_ip &&\n\t\t    id1->src_ip == id2->src_ip &&\n\t\t    id1->dst_port == id2->dst_port &&\n\t\t    id1->src_port == id2->src_port &&\n\t\t    id1->proto == id2->proto &&\n\t\t    id1->extra == id2->extra) ? 0 : 1;\n\t}\n\t/* the ipv6 case */\n\treturn (\n\t    !bcmp(&id1->dst_ip6,&id2->dst_ip6, sizeof(id1->dst_ip6)) &&\n\t    !bcmp(&id1->src_ip6,&id2->src_ip6, sizeof(id1->src_ip6)) &&\n\t    id1->dst_port == id2->dst_port &&\n\t    id1->src_port == id2->src_port &&\n\t    id1->proto == id2->proto &&\n\t    id1->extra == id2->extra &&\n\t    id1->flow_id6 == id2->flow_id6) ? 0 : 1;\n}\n/*--------- end of flow-id mask, hash and compare ---------*/\n\n/*--- support functions for the qht hashtable ----\n * Entries are hashed by flow-id\n */\nstatic uint32_t\nq_hash(uintptr_t key, int flags, void *arg)\n{\n\t/* compute the hash slot from the flow id */\n\tstruct ipfw_flow_id *id = (flags & DNHT_KEY_IS_OBJ) ?\n\t\t&((struct dn_queue *)key)->ni.fid :\n\t\t(struct ipfw_flow_id *)key;\n\n\treturn flow_id_hash(id);\n}\n\nstatic int\nq_match(void *obj, uintptr_t key, int flags, void *arg)\n{\n\tstruct dn_queue *o = (struct dn_queue *)obj;\n\tstruct ipfw_flow_id *id2;\n\n\tif (flags & DNHT_KEY_IS_OBJ) {\n\t\t/* compare pointers */\n\t\tid2 = &((struct dn_queue *)key)->ni.fid;\n\t} else {\n\t\tid2 = (struct ipfw_flow_id *)key;\n\t}\n\treturn (0 == flow_id_cmp(&o->ni.fid,  id2));\n}\n\n/*\n * create a new queue instance for the given 'key'.\n */\nstatic void *\nq_new(uintptr_t key, int flags, void *arg)\n{   \n\tstruct dn_queue *q, *template = arg;\n\tstruct dn_fsk *fs = template->fs;\n\tint size = sizeof(*q) + fs->sched->fp->q_datalen;\n\n\tq = malloc(size, M_DUMMYNET, M_NOWAIT | M_ZERO);\n\tif (q == NULL) {\n\t\tD(\"no memory for new queue\");\n\t\treturn NULL;\n\t}\n\n\tset_oid(&q->ni.oid, DN_QUEUE, size);\n\tif (fs->fs.flags & DN_QHT_HASH)\n\t\tq->ni.fid = *(struct ipfw_flow_id *)key;\n\tq->fs = fs;\n\tq->_si = ipdn_si_find(q->fs->sched, &(template->ni.fid));\n\tif (q->_si == NULL) {\n\t\tD(\"no memory for new si\");\n\t\tfree (q, M_DUMMYNET);\n\t\treturn NULL;\n\t}\n\n\tq->_si->q_count++;\n\n\tif (fs->sched->fp->new_queue)\n\t\tfs->sched->fp->new_queue(q);\n\tdn_cfg.queue_count++;\n\tdn_cfg.idle_queue++;\n\treturn q;\n}\n\n/*\n * Notify schedulers that a queue is going away.\n * If (flags & DN_DESTROY), also free the packets.\n * The version for callbacks is called q_delete_cb().\n * Returns 1 if the queue is NOT deleted (usually when \n * the drain routine try to delete a queue that a scheduler\n * instance needs), 0 otherwise.\n * NOTE: flag DN_DEL_SAFE means that the queue should be\n *       deleted only if the scheduler no longer needs it\n */\nstatic int\ndn_delete_queue(struct dn_queue *q, int flags)\n{\n\tstruct dn_fsk *fs = q->fs;\n\n\t// D(\"fs %p si %p\\n\", fs, q->_si);\n\t/* notify the parent scheduler that the queue is going away */\n\tif (fs && fs->sched->fp->free_queue)\n\t\tif (fs->sched->fp->free_queue(q, flags & DN_DEL_SAFE) == 1)\n\t\t\treturn 1; \t/* queue NOT deleted */\n\tq->_si->q_count--;\n\tq->_si = NULL;\n\tif (flags & DN_DESTROY) {\n\t\tif (q->mq.head)\n\t\t\tdn_free_pkts(q->mq.head);\n\t\telse\n\t\t\tdn_cfg.idle_queue--;\n\t\tbzero(q, sizeof(*q));\t// safety\n\t\tfree(q, M_DUMMYNET);\n\t\tdn_cfg.queue_count--;\n\t}\n\treturn 0;\n}\n\nstatic int\nq_delete_cb(void *q, void *arg)\n{\n\tint flags = (int)(uintptr_t)arg;\n\tdn_delete_queue(q, flags);\n\treturn (flags & DN_DESTROY) ? DNHT_SCAN_DEL : 0;\n}\n\n/*\n * calls dn_delete_queue/q_delete_cb on all queues,\n * which notifies the parent scheduler and possibly drains packets.\n * flags & DN_DESTROY: drains queues and destroy qht;\n */\nstatic void\nqht_delete(struct dn_fsk *fs, int flags)\n{\n\tND(\"fs %d start flags %d qht %p\",\n\t\tfs->fs.fs_nr, flags, fs->qht);\n\tif (!fs->qht)\n\t\treturn;\n\tif (fs->fs.flags & DN_QHT_HASH) {\n\t\tdn_ht_scan(fs->qht, q_delete_cb, (void *)(uintptr_t)flags);\n\t\tif (flags & DN_DESTROY) {\n\t\t\tdn_ht_free(fs->qht, 0);\n\t\t\tfs->qht = NULL;\n\t\t}\n\t} else {\n\t\tdn_delete_queue((struct dn_queue *)(fs->qht), flags);\n\t\tif (flags & DN_DESTROY)\n\t\t\tfs->qht = NULL;\n\t}\n}\n\n/*\n * Find and possibly create the queue for a MULTIQUEUE scheduler.\n * We never call it for !MULTIQUEUE (the queue is in the sch_inst).\n */\nstruct dn_queue *\nipdn_q_find(struct dn_fsk *fs, struct ipfw_flow_id *id)\n{\n\tstruct dn_queue template;\n\n\ttemplate.fs = fs;\n\n\tif (fs->fs.flags & DN_QHT_HASH) {\n\t\tstruct ipfw_flow_id masked_id;\n\t\tif (fs->qht == NULL) {\n\t\t\tfs->qht = dn_ht_init(NULL, fs->fs.buckets,\n\t\t\t\toffsetof(struct dn_queue, q_next),\n\t\t\t\tq_hash, q_match, q_new);\n\t\t\tif (fs->qht == NULL)\n\t\t\t\treturn NULL;\n\t\t}\n\t\tmasked_id = *id;\n\t\tflow_id_mask(&fs->fsk_mask, &masked_id);\n\t\treturn dn_ht_find(fs->qht, (uintptr_t)&masked_id,\n\t\t\tDNHT_INSERT, &template);\n\t} else {\n\t\tif (fs->qht == NULL)\n\t\t\tfs->qht = q_new(0, 0, &template);\n\t\treturn (struct dn_queue *)fs->qht;\n\t}\n}\n/*--- end of queue hash table ---*/\n\n/*--- support functions for the sch_inst hashtable ----\n *\n * These are hashed by flow-id\n */\nstatic uint32_t\nsi_hash(uintptr_t key, int flags, void *arg)\n{\n\t/* compute the hash slot from the flow id */\n\tstruct ipfw_flow_id *id = (flags & DNHT_KEY_IS_OBJ) ?\n\t\t&((struct dn_sch_inst *)key)->ni.fid :\n\t\t(struct ipfw_flow_id *)key;\n\n\treturn flow_id_hash(id);\n}\n\nstatic int\nsi_match(void *obj, uintptr_t key, int flags, void *arg)\n{\n\tstruct dn_sch_inst *o = obj;\n\tstruct ipfw_flow_id *id2;\n\n\tid2 = (flags & DNHT_KEY_IS_OBJ) ?\n\t\t&((struct dn_sch_inst *)key)->ni.fid :\n\t\t(struct ipfw_flow_id *)key;\n\treturn flow_id_cmp(&o->ni.fid,  id2) == 0;\n}\n\nstatic int si_reset_credit(void *_si, void *arg); // XXX si_new use this\n\n/*\n * create a new instance for the given 'key'\n * Allocate memory for instance, delay line and scheduler private data.\n */\nstatic void *\nsi_new(uintptr_t key, int flags, void *arg)\n{\n\tstruct dn_schk *s = arg;\n\tstruct dn_sch_inst *si;\n\tint l = sizeof(*si) + s->fp->si_datalen;\n\n\tsi = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);\n\tif (si == NULL)\n\t\tgoto error;\n\n\t/* Set length only for the part passed up to userland. */\n\tset_oid(&si->ni.oid, DN_SCH_I, sizeof(struct dn_flow));\n\tset_oid(&(si->dline.oid), DN_DELAY_LINE,\n\t\tsizeof(struct delay_line));\n\t/* mark si and dline as outside the event queue */\n\tsi->ni.oid.id = si->dline.oid.id = -1;\n\n\tsi->sched = s;\n\tsi->dline.si = si;\n\n\tif (s->fp->new_sched && s->fp->new_sched(si)) {\n\t\tD(\"new_sched error\");\n\t\tgoto error;\n\t}\n\tif (s->sch.flags & DN_HAVE_MASK)\n\t\tsi->ni.fid = *(struct ipfw_flow_id *)key;\n\n\tsi_reset_credit(si, NULL);\n\tdn_cfg.si_count++;\n\tdn_cfg.idle_si++;\n\treturn si;\n\nerror:\n\tif (si) {\n\t\tbzero(si, sizeof(*si)); // safety\n\t\tfree(si, M_DUMMYNET);\n\t}\n        return NULL;\n}\n\n/*\n * Callback from siht to delete all scheduler instances. Remove\n * si and delay line from the system heap, destroy all queues.\n * We assume that all flowset have been notified and do not\n * point to us anymore.\n */\nstatic int\nsi_destroy(void *_si, void *arg)\n{\n\tstruct dn_sch_inst *si = _si;\n\tstruct dn_schk *s = si->sched;\n\tstruct delay_line *dl = &si->dline;\n\n\tif (dl->oid.subtype) /* remove delay line from event heap */\n\t\theap_extract(&dn_cfg.evheap, dl);\n\tif (si->ni.length == 0)\n\t\tdn_cfg.idle_si--;\n\tdn_free_pkts(dl->mq.head);\t/* drain delay line */\n\tif (si->kflags & DN_ACTIVE) /* remove si from event heap */\n\t\theap_extract(&dn_cfg.evheap, si);\n\tif (s->fp->free_sched)\n\t\ts->fp->free_sched(si);\n\tbzero(si, sizeof(*si));\t/* safety */\n\tfree(si, M_DUMMYNET);\n\tdn_cfg.si_count--;\n\treturn DNHT_SCAN_DEL;\n}\n\n/*\n * Find the scheduler instance for this packet. If we need to apply\n * a mask, do on a local copy of the flow_id to preserve the original.\n * Assume siht is always initialized if we have a mask.\n */\nstruct dn_sch_inst *\nipdn_si_find(struct dn_schk *s, struct ipfw_flow_id *id)\n{\n\n\tif (s->sch.flags & DN_HAVE_MASK) {\n\t\tstruct ipfw_flow_id id_t = *id;\n\t\tflow_id_mask(&s->sch.sched_mask, &id_t);\n\t\treturn dn_ht_find(s->siht, (uintptr_t)&id_t,\n\t\t\tDNHT_INSERT, s);\n\t}\n\tif (!s->siht)\n\t\ts->siht = si_new(0, 0, s);\n\treturn (struct dn_sch_inst *)s->siht;\n}\n\n/* callback to flush credit for the scheduler instance */\nstatic int\nsi_reset_credit(void *_si, void *arg)\n{\n\tstruct dn_sch_inst *si = _si;\n\tstruct dn_link *p = &si->sched->link;\n\n\tsi->idle_time = dn_cfg.curr_time;\n\tsi->credit = p->burst + (dn_cfg.io_fast ?  p->bandwidth : 0);\n\treturn 0;\n}\n\nstatic void\nschk_reset_credit(struct dn_schk *s)\n{\n\tif (s->sch.flags & DN_HAVE_MASK)\n\t\tdn_ht_scan(s->siht, si_reset_credit, NULL);\n\telse if (s->siht)\n\t\tsi_reset_credit(s->siht, NULL);\n}\n/*---- end of sch_inst hashtable ---------------------*/\n\n/*-------------------------------------------------------\n * flowset hash (fshash) support. Entries are hashed by fs_nr.\n * New allocations are put in the fsunlinked list, from which\n * they are removed when they point to a specific scheduler.\n */\nstatic uint32_t\nfsk_hash(uintptr_t key, int flags, void *arg)\n{\n\tuint32_t i = !(flags & DNHT_KEY_IS_OBJ) ? key :\n\t\t((struct dn_fsk *)key)->fs.fs_nr;\n\n\treturn ( (i>>8)^(i>>4)^i );\n}\n\nstatic int\nfsk_match(void *obj, uintptr_t key, int flags, void *arg)\n{\n\tstruct dn_fsk *fs = obj;\n\tint i = !(flags & DNHT_KEY_IS_OBJ) ? key :\n\t\t((struct dn_fsk *)key)->fs.fs_nr;\n\n\treturn (fs->fs.fs_nr == i);\n}\n\nstatic void *\nfsk_new(uintptr_t key, int flags, void *arg)\n{\n\tstruct dn_fsk *fs;\n\n\tfs = malloc(sizeof(*fs), M_DUMMYNET, M_NOWAIT | M_ZERO);\n\tif (fs) {\n\t\tset_oid(&fs->fs.oid, DN_FS, sizeof(fs->fs));\n\t\tdn_cfg.fsk_count++;\n\t\tfs->drain_bucket = 0;\n\t\tSLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);\n\t}\n\treturn fs;\n}\n\n/*\n * detach flowset from its current scheduler. Flags as follows:\n * DN_DETACH removes from the fsk_list\n * DN_DESTROY deletes individual queues\n * DN_DELETE_FS destroys the flowset (otherwise goes in unlinked).\n */\nstatic void\nfsk_detach(struct dn_fsk *fs, int flags)\n{\n\tif (flags & DN_DELETE_FS)\n\t\tflags |= DN_DESTROY;\n\tND(\"fs %d from sched %d flags %s %s %s\",\n\t\tfs->fs.fs_nr, fs->fs.sched_nr,\n\t\t(flags & DN_DELETE_FS) ? \"DEL_FS\":\"\",\n\t\t(flags & DN_DESTROY) ? \"DEL\":\"\",\n\t\t(flags & DN_DETACH) ? \"DET\":\"\");\n\tif (flags & DN_DETACH) { /* detach from the list */\n\t\tstruct dn_fsk_head *h;\n\t\th = fs->sched ? &fs->sched->fsk_list : &dn_cfg.fsu;\n\t\tSLIST_REMOVE(h, fs, dn_fsk, sch_chain);\n\t}\n\t/* Free the RED parameters, they will be recomputed on\n\t * subsequent attach if needed.\n\t */\n\tif (fs->w_q_lookup)\n\t\tfree(fs->w_q_lookup, M_DUMMYNET);\n\tfs->w_q_lookup = NULL;\n\tqht_delete(fs, flags);\n\tif (fs->sched && fs->sched->fp->free_fsk)\n\t\tfs->sched->fp->free_fsk(fs);\n\tfs->sched = NULL;\n\tif (flags & DN_DELETE_FS) {\n\t\tbzero(fs, sizeof(*fs));\t/* safety */\n\t\tfree(fs, M_DUMMYNET);\n\t\tdn_cfg.fsk_count--;\n\t} else {\n\t\tSLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain);\n\t}\n}\n\n/*\n * Detach or destroy all flowsets in a list.\n * flags specifies what to do:\n * DN_DESTROY:\tflush all queues\n * DN_DELETE_FS:\tDN_DESTROY + destroy flowset\n *\tDN_DELETE_FS implies DN_DESTROY\n */\nstatic void\nfsk_detach_list(struct dn_fsk_head *h, int flags)\n{\n\tstruct dn_fsk *fs;\n\tint n = 0; /* only for stats */\n\n\tND(\"head %p flags %x\", h, flags);\n\twhile ((fs = SLIST_FIRST(h))) {\n\t\tSLIST_REMOVE_HEAD(h, sch_chain);\n\t\tn++;\n\t\tfsk_detach(fs, flags);\n\t}\n\tND(\"done %d flowsets\", n);\n}\n\n/*\n * called on 'queue X delete' -- removes the flowset from fshash,\n * deletes all queues for the flowset, and removes the flowset.\n */\nstatic int\ndelete_fs(int i, int locked)\n{\n\tstruct dn_fsk *fs;\n\tint err = 0;\n\n\tif (!locked)\n\t\tDN_BH_WLOCK();\n\tfs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL);\n\tif (dn_ht_entries(dn_cfg.fshash) == 0) {\n\t\tdn_ht_free(dn_cfg.fshash, 0);\n\t\tdn_cfg.fshash = NULL;\n\t}\n\tND(\"fs %d found %p\", i, fs);\n\tif (fs) {\n\t\tfsk_detach(fs, DN_DETACH | DN_DELETE_FS);\n\t\terr = 0;\n\t} else\n\t\terr = EINVAL;\n\tif (!locked)\n\t\tDN_BH_WUNLOCK();\n\treturn err;\n}\n\n/*----- end of flowset hashtable support -------------*/\n\n/*------------------------------------------------------------\n * Scheduler hash. When searching by index we pass sched_nr,\n * otherwise we pass struct dn_sch * which is the first field in\n * struct dn_schk so we can cast between the two. We use this trick\n * because in the create phase (but it should be fixed).\n */\nstatic uint32_t\nschk_hash(uintptr_t key, int flags, void *_arg)\n{\n\tuint32_t i = !(flags & DNHT_KEY_IS_OBJ) ? key :\n\t\t((struct dn_schk *)key)->sch.sched_nr;\n\treturn ( (i>>8)^(i>>4)^i );\n}\n\nstatic int\nschk_match(void *obj, uintptr_t key, int flags, void *_arg)\n{\n\tstruct dn_schk *s = (struct dn_schk *)obj;\n\tint i = !(flags & DNHT_KEY_IS_OBJ) ? key :\n\t\t((struct dn_schk *)key)->sch.sched_nr;\n\treturn (s->sch.sched_nr == i);\n}\n\n/*\n * Create the entry and intialize with the sched hash if needed.\n * Leave s->fp unset so we can tell whether a dn_ht_find() returns\n * a new object or a previously existing one.\n */\nstatic void *\nschk_new(uintptr_t key, int flags, void *arg)\n{\n\tstruct schk_new_arg *a = arg;\n\tstruct dn_schk *s;\n\tint l = sizeof(*s) +a->fp->schk_datalen;\n\n\ts = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO);\n\tif (s == NULL)\n\t\treturn NULL;\n\tset_oid(&s->link.oid, DN_LINK, sizeof(s->link));\n\ts->sch = *a->sch; // copy initial values\n\ts->link.link_nr = s->sch.sched_nr;\n\tSLIST_INIT(&s->fsk_list);\n\t/* initialize the hash table or create the single instance */\n\ts->fp = a->fp;\t/* si_new needs this */\n\ts->drain_bucket = 0;\n\tif (s->sch.flags & DN_HAVE_MASK) {\n\t\ts->siht = dn_ht_init(NULL, s->sch.buckets,\n\t\t\toffsetof(struct dn_sch_inst, si_next),\n\t\t\tsi_hash, si_match, si_new);\n\t\tif (s->siht == NULL) {\n\t\t\tfree(s, M_DUMMYNET);\n\t\t\treturn NULL;\n\t\t}\n\t}\n\ts->fp = NULL;\t/* mark as a new scheduler */\n\tdn_cfg.schk_count++;\n\treturn s;\n}\n\n/*\n * Callback for sched delete. Notify all attached flowsets to\n * detach from the scheduler, destroy the internal flowset, and\n * all instances. The scheduler goes away too.\n * arg is 0 (only detach flowsets and destroy instances)\n * DN_DESTROY (detach & delete queues, delete schk)\n * or DN_DELETE_FS (delete queues and flowsets, delete schk)\n */\nstatic int\nschk_delete_cb(void *obj, void *arg)\n{\n\tstruct dn_schk *s = obj;\n#if 0\n\tint a = (int)arg;\n\tND(\"sched %d arg %s%s\",\n\t\ts->sch.sched_nr,\n\t\ta&DN_DESTROY ? \"DEL \":\"\",\n\t\ta&DN_DELETE_FS ? \"DEL_FS\":\"\");\n#endif\n\tfsk_detach_list(&s->fsk_list, arg ? DN_DESTROY : 0);\n\t/* no more flowset pointing to us now */\n\tif (s->sch.flags & DN_HAVE_MASK) {\n\t\tdn_ht_scan(s->siht, si_destroy, NULL);\n\t\tdn_ht_free(s->siht, 0);\n\t}\n\telse if (s->siht)\n\t\tsi_destroy(s->siht, NULL);\n\tif (s->profile) {\n\t\tfree(s->profile, M_DUMMYNET);\n\t\ts->profile = NULL;\n\t}\n\ts->siht = NULL;\n\tif (s->fp->destroy)\n\t\ts->fp->destroy(s);\n\tbzero(s, sizeof(*s));\t// safety\n\tfree(obj, M_DUMMYNET);\n\tdn_cfg.schk_count--;\n\treturn DNHT_SCAN_DEL;\n}\n\n/*\n * called on a 'sched X delete' command. Deletes a single scheduler.\n * This is done by removing from the schedhash, unlinking all\n * flowsets and deleting their traffic.\n */\nstatic int\ndelete_schk(int i)\n{\n\tstruct dn_schk *s;\n\n\ts = dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL);\n\tif (dn_ht_entries(dn_cfg.schedhash) == 0) {\n\t\tdn_ht_free(dn_cfg.schedhash, 0);\n\t\tdn_cfg.schedhash = NULL;\n\t}\n\tND(\"%d %p\", i, s);\n\tif (!s)\n\t\treturn EINVAL;\n\tdelete_fs(i + DN_MAX_ID, 1); /* first delete internal fs */\n\t/* then detach flowsets, delete traffic */\n\tschk_delete_cb(s, (void*)(uintptr_t)DN_DESTROY);\n\treturn 0;\n}\n/*--- end of schk hashtable support ---*/\n\nstatic int\ncopy_obj(char **start, char *end, void *_o, const char *msg, int i)\n{\n\tstruct dn_id *o = _o;\n\tint have = end - *start;\n\n\tif (have < o->len || o->len == 0 || o->type == 0) {\n\t\tD(\"(WARN) type %d %s %d have %d need %d\",\n\t\t\to->type, msg, i, have, o->len);\n\t\treturn 1;\n\t}\n\tND(\"type %d %s %d len %d\", o->type, msg, i, o->len);\n\tbcopy(_o, *start, o->len);\n\tif (o->type == DN_LINK) {\n\t\t/* Adjust burst parameter for link */\n\t\tstruct dn_link *l = (struct dn_link *)*start;\n\t\tl->burst =  div64(l->burst, 8 * hz);\n\t} else if (o->type == DN_SCH) {\n\t\t/* Set id->id to the number of instances */\n\t\tstruct dn_schk *s = _o;\n\t\tstruct dn_id *id = (struct dn_id *)(*start);\n\t\tid->id = (s->sch.flags & DN_HAVE_MASK) ?\n\t\t\tdn_ht_entries(s->siht) : (s->siht ? 1 : 0);\n\t}\n\t*start += o->len;\n\treturn 0;\n}\n\n/* Specific function to copy a queue.\n * Copies only the user-visible part of a queue (which is in\n * a struct dn_flow), and sets len accordingly.\n */\nstatic int\ncopy_obj_q(char **start, char *end, void *_o, const char *msg, int i)\n{\n\tstruct dn_id *o = _o;\n\tint have = end - *start;\n\tint len = sizeof(struct dn_flow); /* see above comment */\n\n\tif (have < len || o->len == 0 || o->type != DN_QUEUE) {\n\t\tD(\"ERROR type %d %s %d have %d need %d\",\n\t\t\to->type, msg, i, have, len);\n\t\treturn 1;\n\t}\n\tND(\"type %d %s %d len %d\", o->type, msg, i, len);\n\tbcopy(_o, *start, len);\n\t((struct dn_id*)(*start))->len = len;\n\t*start += len;\n\treturn 0;\n}\n\nstatic int\ncopy_q_cb(void *obj, void *arg)\n{\n\tstruct dn_queue *q = obj;\n\tstruct copy_args *a = arg;\n\tstruct dn_flow *ni = (struct dn_flow *)(*a->start);\n        if (copy_obj_q(a->start, a->end, &q->ni, \"queue\", -1))\n                return DNHT_SCAN_END;\n        ni->oid.type = DN_FLOW; /* override the DN_QUEUE */\n        ni->oid.id = si_hash((uintptr_t)&ni->fid, 0, NULL);\n        return 0;\n}\n\nstatic int\ncopy_q(struct copy_args *a, struct dn_fsk *fs, int flags)\n{\n\tif (!fs->qht)\n\t\treturn 0;\n\tif (fs->fs.flags & DN_QHT_HASH)\n\t\tdn_ht_scan(fs->qht, copy_q_cb, a);\n\telse\n\t\tcopy_q_cb(fs->qht, a);\n\treturn 0;\n}\n\n/*\n * This routine only copies the initial part of a profile ? XXX\n * XXX marta: I think this routine is called to print a summary\n * of the pipe configuration and does not need to show the \n * profile samples list.\n */\nstatic int\ncopy_profile(struct copy_args *a, struct dn_profile *p)\n{\n\tint have = a->end - *a->start;\n\t/* XXX here we check for max length */\n\tint profile_len = sizeof(struct dn_profile);\n\n\tif (p == NULL)\n\t\treturn 0;\n\tif (have < profile_len) {\n\t\tD(\"error have %d need %d\", have, profile_len);\n\t\treturn 1;\n\t}\n\tbcopy(p, *a->start, profile_len);\n\t((struct dn_id *)(*a->start))->len = profile_len;\n\t*a->start += profile_len;\n\treturn 0;\n}\n\nstatic int\ncopy_flowset(struct copy_args *a, struct dn_fsk *fs, int flags)\n{\n\tstruct dn_fs *ufs = (struct dn_fs *)(*a->start);\n\tif (!fs)\n\t\treturn 0;\n\tND(\"flowset %d\", fs->fs.fs_nr);\n\tif (copy_obj(a->start, a->end, &fs->fs, \"flowset\", fs->fs.fs_nr))\n\t\treturn DNHT_SCAN_END;\n\tufs->oid.id = (fs->fs.flags & DN_QHT_HASH) ?\n\t\tdn_ht_entries(fs->qht) : (fs->qht ? 1 : 0);\n\tif (flags) {\t/* copy queues */\n\t\tcopy_q(a, fs, 0);\n\t}\n\treturn 0;\n}\n\nstatic int\ncopy_si_cb(void *obj, void *arg)\n{\n\tstruct dn_sch_inst *si = obj;\n\tstruct copy_args *a = arg;\n\tstruct dn_flow *ni = (struct dn_flow *)(*a->start);\n\tif (copy_obj(a->start, a->end, &si->ni, \"inst\",\n\t\t\tsi->sched->sch.sched_nr))\n\t\treturn DNHT_SCAN_END;\n\tni->oid.type = DN_FLOW; /* override the DN_SCH_I */\n\tni->oid.id = si_hash((uintptr_t)si, DNHT_KEY_IS_OBJ, NULL);\n\treturn 0;\n}\n\nstatic int\ncopy_si(struct copy_args *a, struct dn_schk *s, int flags)\n{\n\tif (s->sch.flags & DN_HAVE_MASK)\n\t\tdn_ht_scan(s->siht, copy_si_cb, a);\n\telse if (s->siht)\n\t\tcopy_si_cb(s->siht, a);\n\treturn 0;\n}\n\n/*\n * compute a list of children of a scheduler and copy up\n */\nstatic int\ncopy_fsk_list(struct copy_args *a, struct dn_schk *s, int flags)\n{\n\tstruct dn_fsk *fs;\n\tstruct dn_id *o;\n\tuint32_t *p;\n\n\tint n = 0, space = sizeof(*o);\n\tSLIST_FOREACH(fs, &s->fsk_list, sch_chain) {\n\t\tif (fs->fs.fs_nr < DN_MAX_ID)\n\t\t\tn++;\n\t}\n\tspace += n * sizeof(uint32_t);\n\tDX(3, \"sched %d has %d flowsets\", s->sch.sched_nr, n);\n\tif (a->end - *(a->start) < space)\n\t\treturn DNHT_SCAN_END;\n\to = (struct dn_id *)(*(a->start));\n\to->len = space;\n\t*a->start += o->len;\n\to->type = DN_TEXT;\n\tp = (uint32_t *)(o+1);\n\tSLIST_FOREACH(fs, &s->fsk_list, sch_chain)\n\t\tif (fs->fs.fs_nr < DN_MAX_ID)\n\t\t\t*p++ = fs->fs.fs_nr;\n\treturn 0;\n}\n\nstatic int\ncopy_data_helper(void *_o, void *_arg)\n{\n\tstruct copy_args *a = _arg;\n\tuint32_t *r = a->extra->r; /* start of first range */\n\tuint32_t *lim;\t/* first invalid pointer */\n\tint n;\n\n\tlim = (uint32_t *)((char *)(a->extra) + a->extra->o.len);\n\n\tif (a->type == DN_LINK || a->type == DN_SCH) {\n\t\t/* pipe|sched show, we receive a dn_schk */\n\t\tstruct dn_schk *s = _o;\n\n\t\tn = s->sch.sched_nr;\n\t\tif (a->type == DN_SCH && n >= DN_MAX_ID)\n\t\t\treturn 0;\t/* not a scheduler */\n\t\tif (a->type == DN_LINK && n <= DN_MAX_ID)\n\t\t    return 0;\t/* not a pipe */\n\n\t\t/* see if the object is within one of our ranges */\n\t\tfor (;r < lim; r += 2) {\n\t\t\tif (n < r[0] || n > r[1])\n\t\t\t\tcontinue;\n\t\t\t/* Found a valid entry, copy and we are done */\n\t\t\tif (a->flags & DN_C_LINK) {\n\t\t\t\tif (copy_obj(a->start, a->end,\n\t\t\t\t    &s->link, \"link\", n))\n\t\t\t\t\treturn DNHT_SCAN_END;\n\t\t\t\tif (copy_profile(a, s->profile))\n\t\t\t\t\treturn DNHT_SCAN_END;\n\t\t\t\tif (copy_flowset(a, s->fs, 0))\n\t\t\t\t\treturn DNHT_SCAN_END;\n\t\t\t}\n\t\t\tif (a->flags & DN_C_SCH) {\n\t\t\t\tif (copy_obj(a->start, a->end,\n\t\t\t\t    &s->sch, \"sched\", n))\n\t\t\t\t\treturn DNHT_SCAN_END;\n\t\t\t\t/* list all attached flowsets */\n\t\t\t\tif (copy_fsk_list(a, s, 0))\n\t\t\t\t\treturn DNHT_SCAN_END;\n\t\t\t}\n\t\t\tif (a->flags & DN_C_FLOW)\n\t\t\t\tcopy_si(a, s, 0);\n\t\t\tbreak;\n\t\t}\n\t} else if (a->type == DN_FS) {\n\t\t/* queue show, skip internal flowsets */\n\t\tstruct dn_fsk *fs = _o;\n\n\t\tn = fs->fs.fs_nr;\n\t\tif (n >= DN_MAX_ID)\n\t\t\treturn 0;\n\t\t/* see if the object is within one of our ranges */\n\t\tfor (;r < lim; r += 2) {\n\t\t\tif (n < r[0] || n > r[1])\n\t\t\t\tcontinue;\n\t\t\tif (copy_flowset(a, fs, 0))\n\t\t\t\treturn DNHT_SCAN_END;\n\t\t\tcopy_q(a, fs, 0);\n\t\t\tbreak; /* we are done */\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic inline struct dn_schk *\nlocate_scheduler(int i)\n{\n\treturn dn_ht_find(dn_cfg.schedhash, i, 0, NULL);\n}\n\n/*\n * red parameters are in fixed point arithmetic.\n */\nstatic int\nconfig_red(struct dn_fsk *fs)\n{\n\tint64_t s, idle, weight, w0;\n\tint t, i;\n\n\tfs->w_q = fs->fs.w_q;\n\tfs->max_p = fs->fs.max_p;\n\tND(\"called\");\n\t/* Doing stuff that was in userland */\n\ti = fs->sched->link.bandwidth;\n\ts = (i <= 0) ? 0 :\n\t\thz * dn_cfg.red_avg_pkt_size * 8 * SCALE(1) / i;\n\n\tidle = div64((s * 3) , fs->w_q); /* s, fs->w_q scaled; idle not scaled */\n\tfs->lookup_step = div64(idle , dn_cfg.red_lookup_depth);\n\t/* fs->lookup_step not scaled, */\n\tif (!fs->lookup_step)\n\t\tfs->lookup_step = 1;\n\tw0 = weight = SCALE(1) - fs->w_q; //fs->w_q scaled\n\n\tfor (t = fs->lookup_step; t > 1; --t)\n\t\tweight = SCALE_MUL(weight, w0);\n\tfs->lookup_weight = (int)(weight); // scaled\n\n\t/* Now doing stuff that was in kerneland */\n\tfs->min_th = SCALE(fs->fs.min_th);\n\tfs->max_th = SCALE(fs->fs.max_th);\n\n\tfs->c_1 = fs->max_p / (fs->fs.max_th - fs->fs.min_th);\n\tfs->c_2 = SCALE_MUL(fs->c_1, SCALE(fs->fs.min_th));\n\n\tif (fs->fs.flags & DN_IS_GENTLE_RED) {\n\t\tfs->c_3 = (SCALE(1) - fs->max_p) / fs->fs.max_th;\n\t\tfs->c_4 = SCALE(1) - 2 * fs->max_p;\n\t}\n\n\t/* If the lookup table already exist, free and create it again. */\n\tif (fs->w_q_lookup) {\n\t\tfree(fs->w_q_lookup, M_DUMMYNET);\n\t\tfs->w_q_lookup = NULL;\n\t}\n\tif (dn_cfg.red_lookup_depth == 0) {\n\t\tprintf(\"\\ndummynet: net.inet.ip.dummynet.red_lookup_depth\"\n\t\t    \"must be > 0\\n\");\n\t\tfs->fs.flags &= ~DN_IS_RED;\n\t\tfs->fs.flags &= ~DN_IS_GENTLE_RED;\n\t\treturn (EINVAL);\n\t}\n\tfs->lookup_depth = dn_cfg.red_lookup_depth;\n\tfs->w_q_lookup = (u_int *)malloc(fs->lookup_depth * sizeof(int),\n\t    M_DUMMYNET, M_NOWAIT);\n\tif (fs->w_q_lookup == NULL) {\n\t\tprintf(\"dummynet: sorry, cannot allocate red lookup table\\n\");\n\t\tfs->fs.flags &= ~DN_IS_RED;\n\t\tfs->fs.flags &= ~DN_IS_GENTLE_RED;\n\t\treturn(ENOSPC);\n\t}\n\n\t/* Fill the lookup table with (1 - w_q)^x */\n\tfs->w_q_lookup[0] = SCALE(1) - fs->w_q;\n\n\tfor (i = 1; i < fs->lookup_depth; i++)\n\t\tfs->w_q_lookup[i] =\n\t\t    SCALE_MUL(fs->w_q_lookup[i - 1], fs->lookup_weight);\n\n\tif (dn_cfg.red_avg_pkt_size < 1)\n\t\tdn_cfg.red_avg_pkt_size = 512;\n\tfs->avg_pkt_size = dn_cfg.red_avg_pkt_size;\n\tif (dn_cfg.red_max_pkt_size < 1)\n\t\tdn_cfg.red_max_pkt_size = 1500;\n\tfs->max_pkt_size = dn_cfg.red_max_pkt_size;\n\tND(\"exit\");\n\treturn 0;\n}\n\n/* Scan all flowset attached to this scheduler and update red */\nstatic void\nupdate_red(struct dn_schk *s)\n{\n\tstruct dn_fsk *fs;\n\tSLIST_FOREACH(fs, &s->fsk_list, sch_chain) {\n\t\tif (fs && (fs->fs.flags & DN_IS_RED))\n\t\t\tconfig_red(fs);\n\t}\n}\n\n/* attach flowset to scheduler s, possibly requeue */\nstatic void\nfsk_attach(struct dn_fsk *fs, struct dn_schk *s)\n{\n\tND(\"remove fs %d from fsunlinked, link to sched %d\",\n\t\tfs->fs.fs_nr, s->sch.sched_nr);\n\tSLIST_REMOVE(&dn_cfg.fsu, fs, dn_fsk, sch_chain);\n\tfs->sched = s;\n\tSLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain);\n\tif (s->fp->new_fsk)\n\t\ts->fp->new_fsk(fs);\n\t/* XXX compute fsk_mask */\n\tfs->fsk_mask = fs->fs.flow_mask;\n\tif (fs->sched->sch.flags & DN_HAVE_MASK)\n\t\tflow_id_or(&fs->sched->sch.sched_mask, &fs->fsk_mask);\n\tif (fs->qht) {\n\t\t/*\n\t\t * we must drain qht according to the old\n\t\t * type, and reinsert according to the new one.\n\t\t * The requeue is complex -- in general we need to\n\t\t * reclassify every single packet.\n\t\t * For the time being, let's hope qht is never set\n\t\t * when we reach this point.\n\t\t */\n\t\tD(\"XXX TODO requeue from fs %d to sch %d\",\n\t\t\tfs->fs.fs_nr, s->sch.sched_nr);\n\t\tfs->qht = NULL;\n\t}\n\t/* set the new type for qht */\n\tif (nonzero_mask(&fs->fsk_mask))\n\t\tfs->fs.flags |= DN_QHT_HASH;\n\telse\n\t\tfs->fs.flags &= ~DN_QHT_HASH;\n\n\t/* XXX config_red() can fail... */\n\tif (fs->fs.flags & DN_IS_RED)\n\t\tconfig_red(fs);\n}\n\n/* update all flowsets which may refer to this scheduler */\nstatic void\nupdate_fs(struct dn_schk *s)\n{\n\tstruct dn_fsk *fs, *tmp;\n\n\tSLIST_FOREACH_SAFE(fs, &dn_cfg.fsu, sch_chain, tmp) {\n\t\tif (s->sch.sched_nr != fs->fs.sched_nr) {\n\t\t\tD(\"fs %d for sch %d not %d still unlinked\",\n\t\t\t\tfs->fs.fs_nr, fs->fs.sched_nr,\n\t\t\t\ts->sch.sched_nr);\n\t\t\tcontinue;\n\t\t}\n\t\tfsk_attach(fs, s);\n\t}\n}\n\n/*\n * Configuration -- to preserve backward compatibility we use\n * the following scheme (N is 65536)\n *\tNUMBER\t\tSCHED\tLINK\tFLOWSET\n *\t   1 ..  N-1\t(1)WFQ\t(2)WFQ\t(3)queue\n *\t N+1 .. 2N-1\t(4)FIFO (5)FIFO\t(6)FIFO for sched 1..N-1\n *\t2N+1 .. 3N-1\t--\t--\t(7)FIFO for sched N+1..2N-1\n *\n * \"pipe i config\" configures #1, #2 and #3\n * \"sched i config\" configures #1 and possibly #6\n * \"queue i config\" configures #3\n * #1 is configured with 'pipe i config' or 'sched i config'\n * #2 is configured with 'pipe i config', and created if not\n *\texisting with 'sched i config'\n * #3 is configured with 'queue i config'\n * #4 is automatically configured after #1, can only be FIFO\n * #5 is automatically configured after #2\n * #6 is automatically created when #1 is !MULTIQUEUE,\n *\tand can be updated.\n * #7 is automatically configured after #2\n */\n\n/*\n * configure a link (and its FIFO instance)\n */\nstatic int\nconfig_link(struct dn_link *p, struct dn_id *arg)\n{\n\tint i;\n\n\tif (p->oid.len != sizeof(*p)) {\n\t\tD(\"invalid pipe len %d\", p->oid.len);\n\t\treturn EINVAL;\n\t}\n\ti = p->link_nr;\n\tif (i <= 0 || i >= DN_MAX_ID)\n\t\treturn EINVAL;\n\t/*\n\t * The config program passes parameters as follows:\n\t * bw = bits/second (0 means no limits),\n\t * delay = ms, must be translated into ticks.\n\t * qsize = slots/bytes\n\t * burst ???\n\t */\n\tp->delay = (p->delay * hz) / 1000;\n\t/* Scale burst size: bytes -> bits * hz */\n\tp->burst *= 8 * hz;\n\n\tDN_BH_WLOCK();\n\t/* do it twice, base link and FIFO link */\n\tfor (; i < 2*DN_MAX_ID; i += DN_MAX_ID) {\n\t    struct dn_schk *s = locate_scheduler(i);\n\t    if (s == NULL) {\n\t\tDN_BH_WUNLOCK();\n\t\tD(\"sched %d not found\", i);\n\t\treturn EINVAL;\n\t    }\n\t    /* remove profile if exists */\n\t    if (s->profile) {\n\t\tfree(s->profile, M_DUMMYNET);\n\t\ts->profile = NULL;\n\t    }\n\t    /* copy all parameters */\n\t    s->link.oid = p->oid;\n\t    s->link.link_nr = i;\n\t    s->link.delay = p->delay;\n\t    if (s->link.bandwidth != p->bandwidth) {\n\t\t/* XXX bandwidth changes, need to update red params */\n\t    s->link.bandwidth = p->bandwidth;\n\t\tupdate_red(s);\n\t    }\n\t    s->link.burst = p->burst;\n\t    schk_reset_credit(s);\n\t}\n\tdn_cfg.id++;\n\tDN_BH_WUNLOCK();\n\treturn 0;\n}\n\n/*\n * configure a flowset. Can be called from inside with locked=1,\n */\nstatic struct dn_fsk *\nconfig_fs(struct dn_fs *nfs, struct dn_id *arg, int locked)\n{\n\tint i;\n\tstruct dn_fsk *fs;\n\n\tif (nfs->oid.len != sizeof(*nfs)) {\n\t\tD(\"invalid flowset len %d\", nfs->oid.len);\n\t\treturn NULL;\n\t}\n\ti = nfs->fs_nr;\n\tif (i <= 0 || i >= 3*DN_MAX_ID)\n\t\treturn NULL;\n\tND(\"flowset %d\", i);\n\t/* XXX other sanity checks */\n        if (nfs->flags & DN_QSIZE_BYTES) {\n\t\tipdn_bound_var(&nfs->qsize, 16384,\n\t\t    1500, dn_cfg.byte_limit, NULL); // \"queue byte size\");\n        } else {\n\t\tipdn_bound_var(&nfs->qsize, 50,\n\t\t    1, dn_cfg.slot_limit, NULL); // \"queue slot size\");\n        }\n\tif (nfs->flags & DN_HAVE_MASK) {\n\t\t/* make sure we have some buckets */\n\t\tipdn_bound_var((int *)&nfs->buckets, dn_cfg.hash_size,\n\t\t\t1, dn_cfg.max_hash_size, \"flowset buckets\");\n\t} else {\n\t\tnfs->buckets = 1;\t/* we only need 1 */\n\t}\n\tif (!locked)\n\t\tDN_BH_WLOCK();\n\tif (dn_cfg.fshash == NULL)\n\t\tdn_cfg.fshash = dn_ht_init(NULL, dn_cfg.hash_size,\n\t\t\t\t\toffsetof(struct dn_fsk, fsk_next),\n\t\t\t\t\tfsk_hash, fsk_match, fsk_new);\n\tdo { /* exit with break when done */\n\t    struct dn_schk *s;\n\t    int flags = nfs->sched_nr ? DNHT_INSERT : 0;\n\t    int j;\n\t    int oldc = dn_cfg.fsk_count;\n\t    fs = dn_ht_find(dn_cfg.fshash, i, flags, NULL);\n\t    if (fs == NULL) {\n\t\tD(\"missing sched for flowset %d\", i);\n\t        break;\n\t    }\n\t    /* grab some defaults from the existing one */\n\t    if (nfs->sched_nr == 0) /* reuse */\n\t\tnfs->sched_nr = fs->fs.sched_nr;\n\t    for (j = 0; j < sizeof(nfs->par)/sizeof(nfs->par[0]); j++) {\n\t\tif (nfs->par[j] == -1) /* reuse */\n\t\t    nfs->par[j] = fs->fs.par[j];\n\t    }\n\t    if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0) {\n\t\tND(\"flowset %d unchanged\", i);\n\t\tbreak; /* no change, nothing to do */\n\t    }\n\t    if (oldc != dn_cfg.fsk_count)\t/* new item */\n\t\tdn_cfg.id++;\n\t    s = locate_scheduler(nfs->sched_nr);\n\t    /* detach from old scheduler if needed, preserving\n\t     * queues if we need to reattach. Then update the\n\t     * configuration, and possibly attach to the new sched.\n\t     */\n\t    DX(2, \"fs %d changed sched %d@%p to %d@%p\",\n\t\tfs->fs.fs_nr,\n\t\tfs->fs.sched_nr, fs->sched, nfs->sched_nr, s);\n\t    if (fs->sched) {\n\t\tint flags = s ? DN_DETACH : (DN_DETACH | DN_DESTROY);\n\t\tflags |= DN_DESTROY; /* XXX temporary */\n\t\tfsk_detach(fs, flags);\n\t    }\n\t    fs->fs = *nfs; /* copy configuration */\n\t    if (s != NULL)\n\t\tfsk_attach(fs, s);\n\t} while (0);\n\tif (!locked)\n\t\tDN_BH_WUNLOCK();\n\treturn fs;\n}\n\n/*\n * config/reconfig a scheduler and its FIFO variant.\n * For !MULTIQUEUE schedulers, also set up the flowset.\n *\n * On reconfigurations (detected because s->fp is set),\n * detach existing flowsets preserving traffic, preserve link,\n * and delete the old scheduler creating a new one.\n */\nstatic int\nconfig_sched(struct dn_sch *_nsch, struct dn_id *arg)\n{\n\tstruct dn_schk *s;\n\tstruct schk_new_arg a; /* argument for schk_new */\n\tint i;\n\tstruct dn_link p;\t/* copy of oldlink */\n\tstruct dn_profile *pf = NULL;\t/* copy of old link profile */\n\t/* Used to preserv mask parameter */\n\tstruct ipfw_flow_id new_mask;\n\tint new_buckets = 0;\n\tint new_flags = 0;\n\tint pipe_cmd;\n\tint err = ENOMEM;\n\n\ta.sch = _nsch;\n\tif (a.sch->oid.len != sizeof(*a.sch)) {\n\t\tD(\"bad sched len %d\", a.sch->oid.len);\n\t\treturn EINVAL;\n\t}\n\ti = a.sch->sched_nr;\n\tif (i <= 0 || i >= DN_MAX_ID)\n\t\treturn EINVAL;\n\t/* make sure we have some buckets */\n\tif (a.sch->flags & DN_HAVE_MASK)\n\t\tipdn_bound_var((int *)&a.sch->buckets, dn_cfg.hash_size,\n\t\t\t1, dn_cfg.max_hash_size, \"sched buckets\");\n\t/* XXX other sanity checks */\n\tbzero(&p, sizeof(p));\n\n\tpipe_cmd = a.sch->flags & DN_PIPE_CMD;\n\ta.sch->flags &= ~DN_PIPE_CMD; //XXX do it even if is not set?\n\tif (pipe_cmd) {\n\t\t/* Copy mask parameter */\n\t\tnew_mask = a.sch->sched_mask;\n\t\tnew_buckets = a.sch->buckets;\n\t\tnew_flags = a.sch->flags;\n\t}\n\tDN_BH_WLOCK();\n\tif (dn_cfg.schedhash == NULL)\n\t\tdn_cfg.schedhash = dn_ht_init(NULL, dn_cfg.hash_size,\n\t\t\t\t\toffsetof(struct dn_schk, schk_next),\n\t\t\t\t\tschk_hash, schk_match, schk_new);\nagain: /* run twice, for wfq and fifo */\n\t/*\n\t * lookup the type. If not supplied, use the previous one\n\t * or default to WF2Q+. Otherwise, return an error.\n\t */\n\tdn_cfg.id++;\n\ta.fp = find_sched_type(a.sch->oid.subtype, a.sch->name);\n\tif (a.fp != NULL) {\n\t\t/* found. Lookup or create entry */\n\t\ts = dn_ht_find(dn_cfg.schedhash, i, DNHT_INSERT, &a);\n\t} else if (a.sch->oid.subtype == 0 && !a.sch->name[0]) {\n\t\t/* No type. search existing s* or retry with WF2Q+ */\n\t\ts = dn_ht_find(dn_cfg.schedhash, i, 0, &a);\n\t\tif (s != NULL) {\n\t\t\ta.fp = s->fp;\n\t\t\t/* Scheduler exists, skip to FIFO scheduler \n\t\t\t * if command was pipe config...\n\t\t\t */\n\t\t\tif (pipe_cmd)\n\t\t\t\tgoto next;\n\t\t} else {\n\t\t\t/* New scheduler, create a wf2q+ with no mask\n\t\t\t * if command was pipe config...\n\t\t\t */\n\t\t\tif (pipe_cmd) {\n\t\t\t\t/* clear mask parameter */\n\t\t\t\tbzero(&a.sch->sched_mask, sizeof(new_mask));\n\t\t\t\ta.sch->buckets = 0;\n\t\t\t\ta.sch->flags &= ~DN_HAVE_MASK;\n\t\t\t}\n\t\t\ta.sch->oid.subtype = DN_SCHED_WF2QP;\n\t\t\tgoto again;\n\t\t}\n\t} else {\n\t\tD(\"invalid scheduler type %d %s\",\n\t\t\ta.sch->oid.subtype, a.sch->name);\n\t\terr = EINVAL;\n\t\tgoto error;\n\t}\n\t/* normalize name and subtype */\n\ta.sch->oid.subtype = a.fp->type;\n\tbzero(a.sch->name, sizeof(a.sch->name));\n\tstrlcpy(a.sch->name, a.fp->name, sizeof(a.sch->name));\n\tif (s == NULL) {\n\t\tD(\"cannot allocate scheduler %d\", i);\n\t\tgoto error;\n\t}\n\t/* restore existing link if any */\n\tif (p.link_nr) {\n\t\ts->link = p;\n\t\tif (!pf || pf->link_nr != p.link_nr) { /* no saved value */\n\t\t\ts->profile = NULL; /* XXX maybe not needed */\n\t\t} else {\n\t\t\tsize_t pf_size = sizeof(struct dn_profile) +\n\t\t\t\ts->profile->samples_no * sizeof(int);\n\n\t\t\ts->profile = malloc(pf_size,\n\t\t\t\t\t     M_DUMMYNET, M_NOWAIT | M_ZERO);\n\t\t\tif (s->profile == NULL) {\n\t\t\t\tD(\"cannot allocate profile\");\n\t\t\t\tgoto error; //XXX\n\t\t\t}\n\t\t\tbcopy(pf, s->profile, pf_size);\n\t\t}\n\t}\n\tp.link_nr = 0;\n\tif (s->fp == NULL) {\n\t\tDX(2, \"sched %d new type %s\", i, a.fp->name);\n\t} else if (s->fp != a.fp ||\n\t\t\tbcmp(a.sch, &s->sch, sizeof(*a.sch)) ) {\n\t\t/* already existing. */\n\t\tDX(2, \"sched %d type changed from %s to %s\",\n\t\t\ti, s->fp->name, a.fp->name);\n\t\tDX(4, \"   type/sub %d/%d -> %d/%d\",\n\t\t\ts->sch.oid.type, s->sch.oid.subtype, \n\t\t\ta.sch->oid.type, a.sch->oid.subtype);\n\t\tif (s->link.link_nr == 0)\n\t\t\tD(\"XXX WARNING link 0 for sched %d\", i);\n\t\tp = s->link;\t/* preserve link */\n\t\tif (s->profile) {/* preserve profile */\n\t\t\tif (!pf)\n\t\t\t\tpf = malloc(sizeof(*pf),\n\t\t\t\t    M_DUMMYNET, M_NOWAIT | M_ZERO);\n\t\t\tif (pf)\t/* XXX should issue a warning otherwise */\n\t\t\t\tbcopy(s->profile, pf, sizeof(*pf));\n\t\t}\n\t\t/* remove from the hash */\n\t\tdn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL);\n\t\t/* Detach flowsets, preserve queues. */\n\t\t// schk_delete_cb(s, NULL);\n\t\t// XXX temporarily, kill queues\n\t\tschk_delete_cb(s, (void *)DN_DESTROY);\n\t\tgoto again;\n\t} else {\n\t\tDX(4, \"sched %d unchanged type %s\", i, a.fp->name);\n\t}\n\t/* complete initialization */\n\ts->sch = *a.sch;\n\ts->fp = a.fp;\n\ts->cfg = arg;\n\t// XXX schk_reset_credit(s);\n\t/* create the internal flowset if needed,\n\t * trying to reuse existing ones if available\n\t */\n\tif (!(s->fp->flags & DN_MULTIQUEUE) && !s->fs) {\n\t        s->fs = dn_ht_find(dn_cfg.fshash, i, 0, NULL);\n\t\tif (!s->fs) {\n\t\t\tstruct dn_fs fs;\n\t\t\tbzero(&fs, sizeof(fs));\n\t\t\tset_oid(&fs.oid, DN_FS, sizeof(fs));\n\t\t\tfs.fs_nr = i + DN_MAX_ID;\n\t\t\tfs.sched_nr = i;\n\t\t\ts->fs = config_fs(&fs, NULL, 1 /* locked */);\n\t\t}\n\t\tif (!s->fs) {\n\t\t\tschk_delete_cb(s, (void *)DN_DESTROY);\n\t\t\tD(\"error creating internal fs for %d\", i);\n\t\t\tgoto error;\n\t\t}\n\t}\n\t/* call init function after the flowset is created */\n\tif (s->fp->config)\n\t\ts->fp->config(s);\n\tupdate_fs(s);\nnext:\n\tif (i < DN_MAX_ID) { /* now configure the FIFO instance */\n\t\ti += DN_MAX_ID;\n\t\tif (pipe_cmd) {\n\t\t\t/* Restore mask parameter for FIFO */\n\t\t\ta.sch->sched_mask = new_mask;\n\t\t\ta.sch->buckets = new_buckets;\n\t\t\ta.sch->flags = new_flags;\n\t\t} else {\n\t\t\t/* sched config shouldn't modify the FIFO scheduler */\n\t\t\tif (dn_ht_find(dn_cfg.schedhash, i, 0, &a) != NULL) {\n\t\t\t\t/* FIFO already exist, don't touch it */\n\t\t\t\terr = 0; /* and this is not an error */\n\t\t\t\tgoto error;\n\t\t\t}\n\t\t}\n\t\ta.sch->sched_nr = i;\n\t\ta.sch->oid.subtype = DN_SCHED_FIFO;\n\t\tbzero(a.sch->name, sizeof(a.sch->name));\n\t\tgoto again;\n\t}\n\terr = 0;\nerror:\n\tDN_BH_WUNLOCK();\n\tif (pf)\n\t\tfree(pf, M_DUMMYNET);\n\treturn err;\n}\n\n/*\n * attach a profile to a link\n */\nstatic int\nconfig_profile(struct dn_profile *pf, struct dn_id *arg)\n{\n\tstruct dn_schk *s;\n\tint i, olen, err = 0;\n\n\tif (pf->oid.len < sizeof(*pf)) {\n\t\tD(\"short profile len %d\", pf->oid.len);\n\t\treturn EINVAL;\n\t}\n\ti = pf->link_nr;\n\tif (i <= 0 || i >= DN_MAX_ID)\n\t\treturn EINVAL;\n\t/* XXX other sanity checks */\n\tDN_BH_WLOCK();\n\tfor (; i < 2*DN_MAX_ID; i += DN_MAX_ID) {\n\t\ts = locate_scheduler(i);\n\n\t\tif (s == NULL) {\n\t\t\terr = EINVAL;\n\t\t\tbreak;\n\t\t}\n\t\tdn_cfg.id++;\n\t\t/*\n\t\t * If we had a profile and the new one does not fit,\n\t\t * or it is deleted, then we need to free memory.\n\t\t */\n\t\tif (s->profile && (pf->samples_no == 0 ||\n\t\t    s->profile->oid.len < pf->oid.len)) {\n\t\t\tfree(s->profile, M_DUMMYNET);\n\t\t\ts->profile = NULL;\n\t\t}\n\t\tif (pf->samples_no == 0)\n\t\t\tcontinue;\n\t\t/*\n\t\t * new profile, possibly allocate memory\n\t\t * and copy data.\n\t\t */\n\t\tif (s->profile == NULL)\n\t\t\ts->profile = malloc(pf->oid.len,\n\t\t\t\t    M_DUMMYNET, M_NOWAIT | M_ZERO);\n\t\tif (s->profile == NULL) {\n\t\t\tD(\"no memory for profile %d\", i);\n\t\t\terr = ENOMEM;\n\t\t\tbreak;\n\t\t}\n\t\t/* preserve larger length XXX double check */\n\t\tolen = s->profile->oid.len;\n\t\tif (olen < pf->oid.len)\n\t\t\tolen = pf->oid.len;\n\t\tbcopy(pf, s->profile, pf->oid.len);\n\t\ts->profile->oid.len = olen;\n\t}\n\tDN_BH_WUNLOCK();\n\treturn err;\n}\n\n/*\n * Delete all objects:\n */\nstatic void\ndummynet_flush(void)\n{\n\n\t/* delete all schedulers and related links/queues/flowsets */\n\tdn_ht_scan(dn_cfg.schedhash, schk_delete_cb,\n\t\t(void *)(uintptr_t)DN_DELETE_FS);\n\t/* delete all remaining (unlinked) flowsets */\n\tDX(4, \"still %d unlinked fs\", dn_cfg.fsk_count);\n\tdn_ht_free(dn_cfg.fshash, DNHT_REMOVE);\n\tfsk_detach_list(&dn_cfg.fsu, DN_DELETE_FS);\n\n\tdn_ht_free(dn_cfg.schedhash, DNHT_REMOVE);\n\t/* Reinitialize system heap... */\n\theap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id));\n}\n\n/*\n * Main handler for configuration. We are guaranteed to be called\n * with an oid which is at least a dn_id.\n * - the first object is the command (config, delete, flush, ...)\n * - config_link must be issued after the corresponding config_sched\n * - parameters (DN_TXT) for an object must preceed the object\n *   processed on a config_sched.\n */\nint\ndo_config(void *p, int l)\n{\n\tstruct dn_id *next, *o;\n\tint err = 0, err2 = 0;\n\tstruct dn_id *arg = NULL;\n\tuintptr_t *a;\n\n\to = p;\n\tif (o->id != DN_API_VERSION) {\n\t\tD(\"invalid api version got %d need %d\",\n\t\t\to->id, DN_API_VERSION);\n\t\treturn EINVAL;\n\t}\n\tfor (; l >= sizeof(*o); o = next) {\n\t\tstruct dn_id *prev = arg;\n\t\tif (o->len < sizeof(*o) || l < o->len) {\n\t\t\tD(\"bad len o->len %d len %d\", o->len, l);\n\t\t\terr = EINVAL;\n\t\t\tbreak;\n\t\t}\n\t\tl -= o->len;\n\t\tnext = (struct dn_id *)((char *)o + o->len);\n\t\terr = 0;\n\t\tswitch (o->type) {\n\t\tdefault:\n\t\t\tD(\"cmd %d not implemented\", o->type);\n\t\t\tbreak;\n\n#ifdef EMULATE_SYSCTL\n\t\t/* sysctl emulation.\n\t\t * if we recognize the command, jump to the correct\n\t\t * handler and return\n\t\t */\n\t\tcase DN_SYSCTL_SET:\n\t\t\terr = kesysctl_emu_set(p, l);\n\t\t\treturn err;\n#endif\n\n\t\tcase DN_CMD_CONFIG: /* simply a header */\n\t\t\tbreak;\n\n\t\tcase DN_CMD_DELETE:\n\t\t\t/* the argument is in the first uintptr_t after o */\n\t\t\ta = (uintptr_t *)(o+1);\n\t\t\tif (o->len < sizeof(*o) + sizeof(*a)) {\n\t\t\t\terr = EINVAL;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tswitch (o->subtype) {\n\t\t\tcase DN_LINK:\n\t\t\t\t/* delete base and derived schedulers */\n\t\t\t\tDN_BH_WLOCK();\n\t\t\t\terr = delete_schk(*a);\n\t\t\t\terr2 = delete_schk(*a + DN_MAX_ID);\n\t\t\t\tDN_BH_WUNLOCK();\n\t\t\t\tif (!err)\n\t\t\t\t\terr = err2;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tD(\"invalid delete type %d\",\n\t\t\t\t\to->subtype);\n\t\t\t\terr = EINVAL;\n\t\t\t\tbreak;\n\n\t\t\tcase DN_FS:\n\t\t\t\terr = (*a <1 || *a >= DN_MAX_ID) ?\n\t\t\t\t\tEINVAL : delete_fs(*a, 0) ;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase DN_CMD_FLUSH:\n\t\t\tDN_BH_WLOCK();\n\t\t\tdummynet_flush();\n\t\t\tDN_BH_WUNLOCK();\n\t\t\tbreak;\n\t\tcase DN_TEXT:\t/* store argument the next block */\n\t\t\tprev = NULL;\n\t\t\targ = o;\n\t\t\tbreak;\n\t\tcase DN_LINK:\n\t\t\terr = config_link((struct dn_link *)o, arg);\n\t\t\tbreak;\n\t\tcase DN_PROFILE:\n\t\t\terr = config_profile((struct dn_profile *)o, arg);\n\t\t\tbreak;\n\t\tcase DN_SCH:\n\t\t\terr = config_sched((struct dn_sch *)o, arg);\n\t\t\tbreak;\n\t\tcase DN_FS:\n\t\t\terr = (NULL==config_fs((struct dn_fs *)o, arg, 0));\n\t\t\tbreak;\n\t\t}\n\t\tif (prev)\n\t\t\targ = NULL;\n\t\tif (err != 0)\n\t\t\tbreak;\n\t}\n\treturn err;\n}\n\nstatic int\ncompute_space(struct dn_id *cmd, struct copy_args *a)\n{\n\tint x = 0, need = 0;\n\tint profile_size = sizeof(struct dn_profile);\n\n\t/* NOTE about compute space:\n\t * NP \t= dn_cfg.schk_count\n\t * NSI \t= dn_cfg.si_count\n\t * NF \t= dn_cfg.fsk_count\n\t * NQ \t= dn_cfg.queue_count\n\t * - ipfw pipe show\n\t *   (NP/2)*(dn_link + dn_sch + dn_id + dn_fs) only half scheduler\n\t *                             link, scheduler template, flowset\n\t *                             integrated in scheduler and header\n\t *                             for flowset list\n\t *   (NSI)*(dn_flow) all scheduler instance (includes\n\t *                              the queue instance)\n\t * - ipfw sched show\n\t *   (NP/2)*(dn_link + dn_sch + dn_id + dn_fs) only half scheduler\n\t *                             link, scheduler template, flowset\n\t *                             integrated in scheduler and header\n\t *                             for flowset list\n\t *   (NSI * dn_flow) all scheduler instances\n\t *   (NF * sizeof(uint_32)) space for flowset list linked to scheduler\n\t *   (NQ * dn_queue) all queue [XXXfor now not listed]\n\t * - ipfw queue show\n\t *   (NF * dn_fs) all flowset\n\t *   (NQ * dn_queue) all queues\n\t */\n\tswitch (cmd->subtype) {\n\tdefault:\n\t\treturn -1;\n\t/* XXX where do LINK and SCH differ ? */\n\t/* 'ipfw sched show' could list all queues associated to\n\t * a scheduler. This feature for now is disabled\n\t */\n\tcase DN_LINK:\t/* pipe show */\n\t\tx = DN_C_LINK | DN_C_SCH | DN_C_FLOW;\n\t\tneed += dn_cfg.schk_count *\n\t\t\t(sizeof(struct dn_fs) + profile_size) / 2;\n\t\tneed += dn_cfg.fsk_count * sizeof(uint32_t);\n\t\tbreak;\n\tcase DN_SCH:\t/* sched show */\n\t\tneed += dn_cfg.schk_count *\n\t\t\t(sizeof(struct dn_fs) + profile_size) / 2;\n\t\tneed += dn_cfg.fsk_count * sizeof(uint32_t);\n\t\tx = DN_C_SCH | DN_C_LINK | DN_C_FLOW;\n\t\tbreak;\n\tcase DN_FS:\t/* queue show */\n\t\tx = DN_C_FS | DN_C_QUEUE;\n\t\tbreak;\n\tcase DN_GET_COMPAT:\t/* compatibility mode */\n\t\tneed =  dn_compat_calc_size(); \n\t\tbreak;\n\t}\n\ta->flags = x;\n\tif (x & DN_C_SCH) {\n\t\tneed += dn_cfg.schk_count * sizeof(struct dn_sch) / 2;\n\t\t/* NOT also, each fs might be attached to a sched */\n\t\tneed += dn_cfg.schk_count * sizeof(struct dn_id) / 2;\n\t}\n\tif (x & DN_C_FS)\n\t\tneed += dn_cfg.fsk_count * sizeof(struct dn_fs);\n\tif (x & DN_C_LINK) {\n\t\tneed += dn_cfg.schk_count * sizeof(struct dn_link) / 2;\n\t}\n\t/*\n\t * When exporting a queue to userland, only pass up the\n\t * struct dn_flow, which is the only visible part.\n\t */\n\n\tif (x & DN_C_QUEUE)\n\t\tneed += dn_cfg.queue_count * sizeof(struct dn_flow);\n\tif (x & DN_C_FLOW)\n\t\tneed += dn_cfg.si_count * (sizeof(struct dn_flow));\n\treturn need;\n}\n\n/*\n * If compat != NULL dummynet_get is called in compatibility mode.\n * *compat will be the pointer to the buffer to pass to ipfw\n */\nint\ndummynet_get(struct sockopt *sopt, void **compat)\n{\n\tint have, i, need, error;\n\tchar *start = NULL, *buf;\n\tsize_t sopt_valsize;\n\tstruct dn_id *cmd;\n\tstruct copy_args a;\n\tstruct copy_range r;\n\tint l = sizeof(struct dn_id);\n\n\tbzero(&a, sizeof(a));\n\tbzero(&r, sizeof(r));\n\n\t/* save and restore original sopt_valsize around copyin */\n\tsopt_valsize = sopt->sopt_valsize;\n\n\tcmd = &r.o;\n\n\tif (!compat) {\n\t\t/* copy at least an oid, and possibly a full object */\n\t\terror = sooptcopyin(sopt, cmd, sizeof(r), sizeof(*cmd));\n\t\tsopt->sopt_valsize = sopt_valsize;\n\t\tif (error)\n\t\t\tgoto done;\n\t\tl = cmd->len;\n#ifdef EMULATE_SYSCTL\n\t\t/* sysctl emulation. */\n\t\tif (cmd->type == DN_SYSCTL_GET)\n\t\t\treturn kesysctl_emu_get(sopt);\n#endif\n\t\tif (l > sizeof(r)) {\n\t\t\t/* request larger than default, allocate buffer */\n\t\t\tcmd = malloc(l,  M_DUMMYNET, M_WAITOK);\n\t\t\terror = sooptcopyin(sopt, cmd, l, l);\n\t\t\tsopt->sopt_valsize = sopt_valsize;\n\t\t\tif (error)\n\t\t\t\tgoto done;\n\t\t}\n\t} else { /* compatibility */\n\t\terror = 0;\n\t\tcmd->type = DN_CMD_GET;\n\t\tcmd->len = sizeof(struct dn_id);\n\t\tcmd->subtype = DN_GET_COMPAT;\n\t\t// cmd->id = sopt_valsize;\n\t\tD(\"compatibility mode\");\n\t}\n\ta.extra = (struct copy_range *)cmd;\n\tif (cmd->len == sizeof(*cmd)) { /* no range, create a default */\n\t\tuint32_t *rp = (uint32_t *)(cmd + 1);\n\t\tcmd->len += 2* sizeof(uint32_t);\n\t\trp[0] = 1;\n\t\trp[1] = DN_MAX_ID - 1;\n\t\tif (cmd->subtype == DN_LINK) {\n\t\t\trp[0] += DN_MAX_ID;\n\t\t\trp[1] += DN_MAX_ID;\n\t\t}\n\t}\n\t/* Count space (under lock) and allocate (outside lock).\n\t * Exit with lock held if we manage to get enough buffer.\n\t * Try a few times then give up.\n\t */\n\tfor (have = 0, i = 0; i < 10; i++) {\n\t\tDN_BH_WLOCK();\n\t\tneed = compute_space(cmd, &a);\n\n\t\t/* if there is a range, ignore value from compute_space() */\n\t\tif (l > sizeof(*cmd))\n\t\t\tneed = sopt_valsize - sizeof(*cmd);\n\n\t\tif (need < 0) {\n\t\t\tDN_BH_WUNLOCK();\n\t\t\terror = EINVAL;\n\t\t\tgoto done;\n\t\t}\n\t\tneed += sizeof(*cmd);\n\t\tcmd->id = need;\n\t\tif (have >= need)\n\t\t\tbreak;\n\n\t\tDN_BH_WUNLOCK();\n\t\tif (start)\n\t\t\tfree(start, M_DUMMYNET);\n\t\tstart = NULL;\n\t\tif (need > sopt_valsize)\n\t\t\tbreak;\n\n\t\thave = need;\n\t\tstart = malloc(have, M_DUMMYNET, M_WAITOK | M_ZERO);\n\t}\n\n\tif (start == NULL) {\n\t\tif (compat) {\n\t\t\t*compat = NULL;\n\t\t\terror =  1; // XXX\n\t\t} else {\n\t\t\terror = sooptcopyout(sopt, cmd, sizeof(*cmd));\n\t\t}\n\t\tgoto done;\n\t}\n\tND(\"have %d:%d sched %d, %d:%d links %d, %d:%d flowsets %d, \"\n\t\t\"%d:%d si %d, %d:%d queues %d\",\n\t\tdn_cfg.schk_count, sizeof(struct dn_sch), DN_SCH,\n\t\tdn_cfg.schk_count, sizeof(struct dn_link), DN_LINK,\n\t\tdn_cfg.fsk_count, sizeof(struct dn_fs), DN_FS,\n\t\tdn_cfg.si_count, sizeof(struct dn_flow), DN_SCH_I,\n\t\tdn_cfg.queue_count, sizeof(struct dn_queue), DN_QUEUE);\n\tsopt->sopt_valsize = sopt_valsize;\n\ta.type = cmd->subtype;\n\n\tif (compat == NULL) {\n\t\tbcopy(cmd, start, sizeof(*cmd));\n\t\t((struct dn_id*)(start))->len = sizeof(struct dn_id);\n\t\tbuf = start + sizeof(*cmd);\n\t} else\n\t\tbuf = start;\n\ta.start = &buf;\n\ta.end = start + have;\n\t/* start copying other objects */\n\tif (compat) {\n\t\ta.type = DN_COMPAT_PIPE;\n\t\tdn_ht_scan(dn_cfg.schedhash, copy_data_helper_compat, &a);\n\t\ta.type = DN_COMPAT_QUEUE;\n\t\tdn_ht_scan(dn_cfg.fshash, copy_data_helper_compat, &a);\n\t} else if (a.type == DN_FS) {\n\t\tdn_ht_scan(dn_cfg.fshash, copy_data_helper, &a);\n\t} else {\n\t\tdn_ht_scan(dn_cfg.schedhash, copy_data_helper, &a);\n\t}\n\tDN_BH_WUNLOCK();\n\n\tif (compat) {\n\t\t*compat = start;\n\t\tsopt->sopt_valsize = buf - start;\n\t\t/* free() is done by ip_dummynet_compat() */\n\t\tstart = NULL; //XXX hack\n\t} else {\n\t\terror = sooptcopyout(sopt, start, buf - start);\n\t}\ndone:\n\tif (cmd && cmd != &r.o)\n\t\tfree(cmd, M_DUMMYNET);\n\tif (start)\n\t\tfree(start, M_DUMMYNET);\n\treturn error;\n}\n\n/*\n * Functions to drain idle objects -- see dummynet_task() for some notes\n */\n/* Callback called on scheduler instance to delete it if idle */\nstatic int\ndrain_scheduler_cb(void *_si, void *_arg)\n{\n\tstruct dn_sch_inst *si = _si;\n\tint *arg = _arg;\n\tint empty;\n\n\tif ( (*arg++) > dn_cfg.expire_object_examined)\n\t\treturn DNHT_SCAN_END;\n\n\tif ((si->kflags & DN_ACTIVE) || si->dline.mq.head != NULL)\n\t\treturn 0;\n\n\t/*\n\t * if the scheduler is multiqueue, q_count also reflects empty\n\t * queues that point to si, so we need to check si->q_count to\n\t * tell whether we can remove the instance.\n\t */\n\tif (si->ni.length == 0) {\n\t\t/* si was marked as idle:\n\t\t * remove it or increment idle_si_wait counter\n\t\t */\n\t\tempty = (si->sched->fp->flags & DN_MULTIQUEUE) ? \n\t\t\t\t(si->q_count == 0) : 1;\n\t\tif (empty && \n\t\t\t(si->idle_time < dn_cfg.curr_time - dn_cfg.object_idle_tick))\n\t\t\t\treturn si_destroy(si, NULL);\n\t\telse\n\t\t\tdn_cfg.idle_si_wait++;\n\t}\n\treturn 0;\n}\n\n/* Callback called on scheduler to check if it has instances */\nstatic int\ndrain_scheduler_sch_cb(void *_s, void *_arg)\n{\n\tstruct dn_schk *s = _s;\n\tint *arg = _arg;\n\n\tif (s->sch.flags & DN_HAVE_MASK) {\n\t\tdn_ht_scan_bucket(s->siht, &s->drain_bucket,\n\t\t\t\tdrain_scheduler_cb, _arg);\n\t} else {\n\t\tif (s->siht) {\n\t\t\tif (drain_scheduler_cb(s->siht, _arg) == DNHT_SCAN_DEL)\n\t\t\t\ts->siht = NULL;\n\t\t}\n\t}\n\treturn ( (*arg++) > dn_cfg.expire_object_examined) ? DNHT_SCAN_END : 0;\n}\n\n/* Called every tick, try to delete a 'bucket' of scheduler */\nvoid\ndn_drain_scheduler(void)\n{\n\tint arg = 0;\n\n\tdn_ht_scan_bucket(dn_cfg.schedhash, (int *)&dn_cfg.drain_sch,\n\t\t\t   drain_scheduler_sch_cb, &arg);\n}\n\n/* Callback called on queue to delete if it is idle */\nstatic int\ndrain_queue_cb(void *_q, void *_arg)\n{\n\tstruct dn_queue *q = _q;\n\tint *arg = _arg;\n\n\tif ( (*arg++) > dn_cfg.expire_object_examined)\n\t\treturn DNHT_SCAN_END;\n\n\tif (q->ni.length == 0) {\n\t\tif (q->q_time < dn_cfg.curr_time - dn_cfg.object_idle_tick) {\n\t\t\tif (dn_delete_queue(q, DN_DESTROY | DN_DEL_SAFE) == 0)\n\t\t\t\treturn DNHT_SCAN_DEL; /* queue is deleted */\n\t\t} else\n\t\t\tdn_cfg.idle_queue_wait++;\n\t}\n\n\treturn 0; /* queue isn't deleted */\n}\n\n/* Callback called on flowset used to check if it has queues */\nstatic int\ndrain_queue_fs_cb(void *_fs, void *_arg)\n{\n\tstruct dn_fsk *fs = _fs;\n\tint *arg = _arg;\n\n\tif (fs->fs.flags & DN_QHT_HASH) {\n\t\t/* Flowset has a hash table for queues */\n\t\tdn_ht_scan_bucket(fs->qht, &fs->drain_bucket,\n\t\t\t\tdrain_queue_cb, _arg);\n\t} else {\n\t\t/* No hash table for this flowset, null the pointer \n\t\t * if the queue is deleted\n\t\t */\n\t\tif (fs->qht) {\n\t\t\tif (drain_queue_cb(fs->qht, _arg) == DNHT_SCAN_DEL)\n\t\t\t\tfs->qht = NULL;\n\t\t}\n\t}\n\treturn ( (*arg++) > dn_cfg.expire_object_examined) ? DNHT_SCAN_END : 0;\n}\n\n/* Called every tick, try to delete a 'bucket' of queue */\nvoid\ndn_drain_queue(void)\n{\n\tint arg = 0;\n\n\t/* scan a bucket of flowset */\n\tdn_ht_scan_bucket(dn_cfg.fshash, (int *)&dn_cfg.drain_fs,\n                               drain_queue_fs_cb, &arg);\n}\n\n/*\n * Handler for the various dummynet socket options\n */\nstatic int\nip_dn_ctl(struct sockopt *sopt)\n{\n\tvoid *p = NULL;\n\tint error, l;\n\n\terror = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET);\n\tif (error)\n\t\treturn (error);\n\n\t/* Disallow sets in really-really secure mode. */\n\tif (sopt->sopt_dir == SOPT_SET) {\n\t\terror =  securelevel_ge(sopt->sopt_td->td_ucred, 3);\n\t\tif (error)\n\t\t\treturn (error);\n\t}\n\n\tswitch (sopt->sopt_name) {\n\tdefault :\n\t\tD(\"dummynet: unknown option %d\", sopt->sopt_name);\n\t\terror = EINVAL;\n\t\tbreak;\n\n\tcase IP_DUMMYNET_FLUSH:\n\tcase IP_DUMMYNET_CONFIGURE:\n\tcase IP_DUMMYNET_DEL:\t/* remove a pipe or queue */\n\tcase IP_DUMMYNET_GET:\n\t\tD(\"dummynet: compat option %d\", sopt->sopt_name);\n\t\terror = ip_dummynet_compat(sopt);\n\t\tbreak;\n\n\tcase IP_DUMMYNET3 :\n\t\tif (sopt->sopt_dir == SOPT_GET) {\n\t\t\terror = dummynet_get(sopt, NULL);\n\t\t\tbreak;\n\t\t}\n\t\tl = sopt->sopt_valsize;\n\t\tif (l < sizeof(struct dn_id) || l > 12000) {\n\t\t\tD(\"argument len %d invalid\", l);\n\t\t\tbreak;\n\t\t}\n\t\tp = malloc(l, M_TEMP, M_WAITOK); // XXX can it fail ?\n\t\terror = sooptcopyin(sopt, p, l, l);\n\t\tif (error)\n\t\t\tbreak ;\n\t\terror = do_config(p, l);\n\t\tbreak;\n\t}\n\n\tif (p != NULL)\n\t\tfree(p, M_TEMP);\n\n\treturn error ;\n}\n\n\nstatic void\nip_dn_init(void)\n{\n\tif (dn_cfg.init_done)\n\t\treturn;\n\tprintf(\"DUMMYNET %p with IPv6 initialized (100409)\\n\", curvnet);\n\tdn_cfg.init_done = 1;\n\t/* Set defaults here. MSVC does not accept initializers,\n\t * and this is also useful for vimages\n\t */\n\t/* queue limits */\n\tdn_cfg.slot_limit = 100; /* Foot shooting limit for queues. */\n\tdn_cfg.byte_limit = 1024 * 1024;\n\tdn_cfg.expire = 1;\n\n\t/* RED parameters */\n\tdn_cfg.red_lookup_depth = 256;\t/* default lookup table depth */\n\tdn_cfg.red_avg_pkt_size = 512;\t/* default medium packet size */\n\tdn_cfg.red_max_pkt_size = 1500;\t/* default max packet size */\n\n\t/* hash tables */\n\tdn_cfg.max_hash_size = 1024;\t/* max in the hash tables */\n\n\tif (dn_cfg.hash_size == 0) /* XXX or <= 0 ? */\n\t\tdn_cfg.hash_size = 64;\t\t/* default hash size */\n\n\t/* hash tables for schedulers and flowsets are created\n\t * when the first scheduler/flowset is inserted.\n\t * This is done to allow to use the right hash_size value.\n\t * When the last object is deleted, the table is destroyed,\n\t * so a new hash_size value can be used.\n\t * XXX rehash is not supported for now\n\t */\n\tdn_cfg.schedhash = NULL;\n\tdn_cfg.fshash = NULL;\n\t/* bucket index to drain object */\n\tdn_cfg.drain_fs = 0;\n\tdn_cfg.drain_sch = 0;\n\n\tif (dn_cfg.expire_object == 0)\n\t\tdn_cfg.expire_object = 50;\n\tif (dn_cfg.object_idle_tick == 0)\n\t\tdn_cfg.object_idle_tick = 1000;\n\tif (dn_cfg.expire_object_examined == 0)\n\t\tdn_cfg.expire_object_examined = 10;\n\tif (dn_cfg.drain_ratio == 0)\n\t\tdn_cfg.drain_ratio = 1;\n\n\t// XXX what if we don't have a tsc ?\n#ifdef HAVE_TSC\n\tdn_cfg.cycle_task_new = dn_cfg.cycle_task_old = readTSC();\n#endif\n\theap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id));\n\tSLIST_INIT(&dn_cfg.fsu);\n\tSLIST_INIT(&dn_cfg.schedlist);\n\n\tDN_LOCK_INIT();\n\n\tTASK_INIT(&dn_task, 0, dummynet_task, curvnet);\n\tdn_tq = taskqueue_create_fast(\"dummynet\", M_NOWAIT,\n\t    taskqueue_thread_enqueue, &dn_tq);\n\ttaskqueue_start_threads(&dn_tq, 1, PI_NET, \"dummynet\");\n\n\tcallout_init(&dn_timeout, CALLOUT_MPSAFE);\n\tcallout_reset_on(&dn_timeout, 1, dummynet, NULL, 0);\n\n\t/* Initialize curr_time adjustment mechanics. */\n\tgetmicrouptime(&dn_cfg.prev_t);\n}\n\n#ifdef KLD_MODULE\nstatic void\nip_dn_destroy(int last)\n{\n\tcallout_drain(&dn_timeout);\n\n\tDN_BH_WLOCK();\n\tif (last) {\n\t\tND(\"removing last instance\\n\");\n\t\tip_dn_ctl_ptr = NULL;\n\t\tip_dn_io_ptr = NULL;\n\t}\n\n\tdummynet_flush();\n\tDN_BH_WUNLOCK();\n\ttaskqueue_drain(dn_tq, &dn_task);\n\ttaskqueue_free(dn_tq);\n\n\tdn_ht_free(dn_cfg.schedhash, 0);\n\tdn_ht_free(dn_cfg.fshash, 0);\n\theap_free(&dn_cfg.evheap);\n\n\tDN_LOCK_DESTROY();\n}\n#endif /* KLD_MODULE */\n\nstatic int\ndummynet_modevent(module_t mod, int type, void *data)\n{\n\n\tif (type == MOD_LOAD) {\n\t\tif (ip_dn_io_ptr) {\n\t\t\tprintf(\"DUMMYNET already loaded\\n\");\n\t\t\treturn EEXIST ;\n\t\t}\n\t\tip_dn_init();\n\t\tip_dn_ctl_ptr = ip_dn_ctl;\n\t\tip_dn_io_ptr = dummynet_io;\n\t\treturn 0;\n\t} else if (type == MOD_UNLOAD) {\n#if !defined(KLD_MODULE)\n\t\tprintf(\"dummynet statically compiled, cannot unload\\n\");\n\t\treturn EINVAL ;\n#else\n\t\tip_dn_destroy(1 /* last */);\n\t\treturn 0;\n#endif\n\t} else\n\t\treturn EOPNOTSUPP;\n}\n\n/* modevent helpers for the modules */\nstatic int\nload_dn_sched(struct dn_alg *d)\n{\n\tstruct dn_alg *s;\n\n\tif (d == NULL)\n\t\treturn 1; /* error */\n\tip_dn_init();\t/* just in case, we need the lock */\n\n\t/* Check that mandatory funcs exists */\n\tif (d->enqueue == NULL || d->dequeue == NULL) {\n\t\tD(\"missing enqueue or dequeue for %s\", d->name);\n\t\treturn 1;\n\t}\n\n\t/* Search if scheduler already exists */\n\tDN_BH_WLOCK();\n\tSLIST_FOREACH(s, &dn_cfg.schedlist, next) {\n\t\tif (strcmp(s->name, d->name) == 0) {\n\t\t\tD(\"%s already loaded\", d->name);\n\t\t\tbreak; /* scheduler already exists */\n\t\t}\n\t}\n\tif (s == NULL)\n\t\tSLIST_INSERT_HEAD(&dn_cfg.schedlist, d, next);\n\tDN_BH_WUNLOCK();\n\tD(\"dn_sched %s %sloaded\", d->name, s ? \"not \":\"\");\n\treturn s ? 1 : 0;\n}\n\nstatic int\nunload_dn_sched(struct dn_alg *s)\n{\n\tstruct dn_alg *tmp, *r;\n\tint err = EINVAL;\n\n\tND(\"called for %s\", s->name);\n\n\tDN_BH_WLOCK();\n\tSLIST_FOREACH_SAFE(r, &dn_cfg.schedlist, next, tmp) {\n\t\tif (strcmp(s->name, r->name) != 0)\n\t\t\tcontinue;\n\t\tND(\"ref_count = %d\", r->ref_count);\n\t\terr = (r->ref_count != 0) ? EBUSY : 0;\n\t\tif (err == 0)\n\t\t\tSLIST_REMOVE(&dn_cfg.schedlist, r, dn_alg, next);\n\t\tbreak;\n\t}\n\tDN_BH_WUNLOCK();\n\tD(\"dn_sched %s %sunloaded\", s->name, err ? \"not \":\"\");\n\treturn err;\n}\n\nint\ndn_sched_modevent(module_t mod, int cmd, void *arg)\n{\n\tstruct dn_alg *sch = arg;\n\n\tif (cmd == MOD_LOAD)\n\t\treturn load_dn_sched(sch);\n\telse if (cmd == MOD_UNLOAD)\n\t\treturn unload_dn_sched(sch);\n\telse\n\t\treturn EINVAL;\n}\n\nstatic moduledata_t dummynet_mod = {\n\t\"dummynet\", dummynet_modevent, NULL\n};\n\n#define\tDN_SI_SUB\tSI_SUB_PROTO_IFATTACHDOMAIN\n#define\tDN_MODEV_ORD\t(SI_ORDER_ANY - 128) /* after ipfw */\nDECLARE_MODULE(dummynet, dummynet_mod, DN_SI_SUB, DN_MODEV_ORD);\nMODULE_DEPEND(dummynet, ipfw, 2, 2, 2);\nMODULE_VERSION(dummynet, 3);\n\n/*\n * Starting up. Done in order after dummynet_modevent() has been called.\n * VNET_SYSINIT is also called for each existing vnet and each new vnet.\n */\n//VNET_SYSINIT(vnet_dn_init, DN_SI_SUB, DN_MODEV_ORD+2, ip_dn_init, NULL);\n\n/*\n * Shutdown handlers up shop. These are done in REVERSE ORDER, but still\n * after dummynet_modevent() has been called. Not called on reboot.\n * VNET_SYSUNINIT is also called for each exiting vnet as it exits.\n * or when the module is unloaded.\n */\n//VNET_SYSUNINIT(vnet_dn_uninit, DN_SI_SUB, DN_MODEV_ORD+2, ip_dn_destroy, NULL);\n\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw2.c",
    "content": "/*-\n * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: head/sys/netinet/ipfw/ip_fw2.c 200601 2009-12-16 10:48:40Z luigi $\");\n\n/*\n * The FreeBSD IP packet firewall, main file\n */\n\n#include \"opt_ipfw.h\"\n#include \"opt_ipdivert.h\"\n#include \"opt_inet.h\"\n#ifndef INET\n#error \"IPFIREWALL requires INET\"\n#endif /* INET */\n#include \"opt_inet6.h\"\n#include \"opt_ipsec.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/condvar.h>\n#include <sys/eventhandler.h>\n#include <sys/malloc.h>\n#include <sys/mbuf.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/jail.h>\n#include <sys/module.h>\n#include <sys/priv.h>\n#include <sys/proc.h>\n#include <sys/rwlock.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/sysctl.h>\n#include <sys/syslog.h>\n#include <sys/ucred.h>\n#include <net/ethernet.h> /* for ETHERTYPE_IP */\n#include <net/if.h>\n#include <net/route.h>\n#include <net/pf_mtag.h>\n#include <net/vnet.h>\n\n#include <netinet/in.h>\n#include <netinet/in_var.h>\n#include <netinet/in_pcb.h>\n#include <netinet/ip.h>\n#include <netinet/ip_var.h>\n#include <netinet/ip_icmp.h>\n#include <netinet/ip_fw.h>\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netinet/ip_carp.h>\n#include <netinet/pim.h>\n#include <netinet/tcp_var.h>\n#include <netinet/udp.h>\n#include <netinet/udp_var.h>\n#include <netinet/sctp.h>\n\n#include <netinet/ip6.h>\n#include <netinet/icmp6.h>\n#ifdef INET6\n#include <netinet6/in6_pcb.h>\n#include <netinet6/scope6_var.h>\n#include <netinet6/ip6_var.h>\n#endif\n\n#include <machine/in_cksum.h>\t/* XXX for in_cksum */\n\n#ifdef MAC\n#include <security/mac/mac_framework.h>\n#endif\n\n/*\n * static variables followed by global ones.\n * All ipfw global variables are here.\n */\n\n/* ipfw_vnet_ready controls when we are open for business */\nstatic VNET_DEFINE(int, ipfw_vnet_ready) = 0;\n#define\tV_ipfw_vnet_ready\tVNET(ipfw_vnet_ready)\n\nstatic VNET_DEFINE(int, fw_deny_unknown_exthdrs);\n#define\tV_fw_deny_unknown_exthdrs\tVNET(fw_deny_unknown_exthdrs)\n\n#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT\nstatic int default_to_accept = 1;\n#else\nstatic int default_to_accept;\n#endif\n\nVNET_DEFINE(int, autoinc_step);\n\n/*\n * Each rule belongs to one of 32 different sets (0..31).\n * The variable set_disable contains one bit per set.\n * If the bit is set, all rules in the corresponding set\n * are disabled. Set RESVD_SET(31) is reserved for the default rule\n * and rules that are not deleted by the flush command,\n * and CANNOT be disabled.\n * Rules in set RESVD_SET can only be deleted individually.\n */\nVNET_DEFINE(u_int32_t, set_disable);\n#define\tV_set_disable\t\t\tVNET(set_disable)\n\nVNET_DEFINE(int, fw_verbose);\n/* counter for ipfw_log(NULL...) */\nVNET_DEFINE(u_int64_t, norule_counter);\nVNET_DEFINE(int, verbose_limit);\n\n/* layer3_chain contains the list of rules for layer 3 */\nVNET_DEFINE(struct ip_fw_chain, layer3_chain);\n\nipfw_nat_t *ipfw_nat_ptr = NULL;\nstruct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);\nipfw_nat_cfg_t *ipfw_nat_cfg_ptr;\nipfw_nat_cfg_t *ipfw_nat_del_ptr;\nipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;\nipfw_nat_cfg_t *ipfw_nat_get_log_ptr;\n\n#ifdef SYSCTL_NODE\nuint32_t dummy_def = IPFW_DEFAULT_RULE;\nuint32_t dummy_tables_max = IPFW_TABLES_MAX;\n\nSYSBEGIN(f3)\n\nSYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, \"Firewall\");\nSYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, one_pass,\n    CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0,\n    \"Only do a single pass through ipfw when using dummynet(4)\");\nSYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step,\n    CTLFLAG_RW, &VNET_NAME(autoinc_step), 0,\n    \"Rule number auto-increment step\");\nSYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose,\n    CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_verbose), 0,\n    \"Log matches to ipfw rules\");\nSYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit,\n    CTLFLAG_RW, &VNET_NAME(verbose_limit), 0,\n    \"Set upper limit of matches of ipfw rules logged\");\nSYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,\n    &dummy_def, 0,\n    \"The default/max possible rule number.\");\nSYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,\n    &dummy_tables_max, 0,\n    \"The maximum number of tables.\");\nSYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,\n    &default_to_accept, 0,\n    \"Make the default rule accept all packets.\");\nTUNABLE_INT(\"net.inet.ip.fw.default_to_accept\", &default_to_accept);\nSYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,\n    CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,\n    \"Number of static rules\");\n\n#ifdef INET6\nSYSCTL_DECL(_net_inet6_ip6);\nSYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, \"Firewall\");\nSYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,\n    CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0,\n    \"Deny packets with unknown IPv6 Extension Headers\");\n#endif /* INET6 */\n\nSYSEND\n\n#endif /* SYSCTL_NODE */\n\n\n/*\n * Some macros used in the various matching options.\n * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T\n * Other macros just cast void * into the appropriate type\n */\n#define\tL3HDR(T, ip)\t((T *)((u_int32_t *)(ip) + (ip)->ip_hl))\n#define\tTCP(p)\t\t((struct tcphdr *)(p))\n#define\tSCTP(p)\t\t((struct sctphdr *)(p))\n#define\tUDP(p)\t\t((struct udphdr *)(p))\n#define\tICMP(p)\t\t((struct icmphdr *)(p))\n#define\tICMP6(p)\t((struct icmp6_hdr *)(p))\n\nstatic __inline int\nicmptype_match(struct icmphdr *icmp, ipfw_insn_u32 *cmd)\n{\n\tint type = icmp->icmp_type;\n\n\treturn (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<<type)) );\n}\n\n#define TT\t( (1 << ICMP_ECHO) | (1 << ICMP_ROUTERSOLICIT) | \\\n    (1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) )\n\nstatic int\nis_icmp_query(struct icmphdr *icmp)\n{\n\tint type = icmp->icmp_type;\n\n\treturn (type <= ICMP_MAXTYPE && (TT & (1<<type)) );\n}\n#undef TT\n\n/*\n * The following checks use two arrays of 8 or 16 bits to store the\n * bits that we want set or clear, respectively. They are in the\n * low and high half of cmd->arg1 or cmd->d[0].\n *\n * We scan options and store the bits we find set. We succeed if\n *\n *\t(want_set & ~bits) == 0 && (want_clear & ~bits) == want_clear\n *\n * The code is sometimes optimized not to store additional variables.\n */\n\nstatic int\nflags_match(ipfw_insn *cmd, u_int8_t bits)\n{\n\tu_char want_clear;\n\tbits = ~bits;\n\n\tif ( ((cmd->arg1 & 0xff) & bits) != 0)\n\t\treturn 0; /* some bits we want set were clear */\n\twant_clear = (cmd->arg1 >> 8) & 0xff;\n\tif ( (want_clear & bits) != want_clear)\n\t\treturn 0; /* some bits we want clear were set */\n\treturn 1;\n}\n\nstatic int\nipopts_match(struct ip *ip, ipfw_insn *cmd)\n{\n\tint optlen, bits = 0;\n\tu_char *cp = (u_char *)(ip + 1);\n\tint x = (ip->ip_hl << 2) - sizeof (struct ip);\n\n\tfor (; x > 0; x -= optlen, cp += optlen) {\n\t\tint opt = cp[IPOPT_OPTVAL];\n\n\t\tif (opt == IPOPT_EOL)\n\t\t\tbreak;\n\t\tif (opt == IPOPT_NOP)\n\t\t\toptlen = 1;\n\t\telse {\n\t\t\toptlen = cp[IPOPT_OLEN];\n\t\t\tif (optlen <= 0 || optlen > x)\n\t\t\t\treturn 0; /* invalid or truncated */\n\t\t}\n\t\tswitch (opt) {\n\n\t\tdefault:\n\t\t\tbreak;\n\n\t\tcase IPOPT_LSRR:\n\t\t\tbits |= IP_FW_IPOPT_LSRR;\n\t\t\tbreak;\n\n\t\tcase IPOPT_SSRR:\n\t\t\tbits |= IP_FW_IPOPT_SSRR;\n\t\t\tbreak;\n\n\t\tcase IPOPT_RR:\n\t\t\tbits |= IP_FW_IPOPT_RR;\n\t\t\tbreak;\n\n\t\tcase IPOPT_TS:\n\t\t\tbits |= IP_FW_IPOPT_TS;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn (flags_match(cmd, bits));\n}\n\nstatic int\ntcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)\n{\n\tint optlen, bits = 0;\n\tu_char *cp = (u_char *)(tcp + 1);\n\tint x = (tcp->th_off << 2) - sizeof(struct tcphdr);\n\n\tfor (; x > 0; x -= optlen, cp += optlen) {\n\t\tint opt = cp[0];\n\t\tif (opt == TCPOPT_EOL)\n\t\t\tbreak;\n\t\tif (opt == TCPOPT_NOP)\n\t\t\toptlen = 1;\n\t\telse {\n\t\t\toptlen = cp[1];\n\t\t\tif (optlen <= 0)\n\t\t\t\tbreak;\n\t\t}\n\n\t\tswitch (opt) {\n\n\t\tdefault:\n\t\t\tbreak;\n\n\t\tcase TCPOPT_MAXSEG:\n\t\t\tbits |= IP_FW_TCPOPT_MSS;\n\t\t\tbreak;\n\n\t\tcase TCPOPT_WINDOW:\n\t\t\tbits |= IP_FW_TCPOPT_WINDOW;\n\t\t\tbreak;\n\n\t\tcase TCPOPT_SACK_PERMITTED:\n\t\tcase TCPOPT_SACK:\n\t\t\tbits |= IP_FW_TCPOPT_SACK;\n\t\t\tbreak;\n\n\t\tcase TCPOPT_TIMESTAMP:\n\t\t\tbits |= IP_FW_TCPOPT_TS;\n\t\t\tbreak;\n\n\t\t}\n\t}\n\treturn (flags_match(cmd, bits));\n}\n\nstatic int\niface_match(struct ifnet *ifp, ipfw_insn_if *cmd)\n{\n\tif (ifp == NULL)\t/* no iface with this packet, match fails */\n\t\treturn 0;\n\t/* Check by name or by IP address */\n\tif (cmd->name[0] != '\\0') { /* match by name */\n\t\t/* Check name */\n\t\tif (cmd->p.glob) {\n\t\t\tif (fnmatch(cmd->name, ifp->if_xname, 0) == 0)\n\t\t\t\treturn(1);\n\t\t} else {\n\t\t\tif (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)\n\t\t\t\treturn(1);\n\t\t}\n\t} else {\n#ifdef __FreeBSD__\t/* and OSX too ? */\n\t\tstruct ifaddr *ia;\n\n\t\tif_addr_rlock(ifp);\n\t\tTAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) {\n\t\t\tif (ia->ifa_addr->sa_family != AF_INET)\n\t\t\t\tcontinue;\n\t\t\tif (cmd->p.ip.s_addr == ((struct sockaddr_in *)\n\t\t\t    (ia->ifa_addr))->sin_addr.s_addr) {\n\t\t\t\tif_addr_runlock(ifp);\n\t\t\t\treturn(1);\t/* match */\n\t\t\t}\n\t\t}\n\t\tif_addr_runlock(ifp);\n#endif /* __FreeBSD__ */\n\t}\n\treturn(0);\t/* no match, fail ... */\n}\n\n/*\n * The verify_path function checks if a route to the src exists and\n * if it is reachable via ifp (when provided).\n * \n * The 'verrevpath' option checks that the interface that an IP packet\n * arrives on is the same interface that traffic destined for the\n * packet's source address would be routed out of.\n * The 'versrcreach' option just checks that the source address is\n * reachable via any route (except default) in the routing table.\n * These two are a measure to block forged packets. This is also\n * commonly known as \"anti-spoofing\" or Unicast Reverse Path\n * Forwarding (Unicast RFP) in Cisco-ese. The name of the knobs\n * is purposely reminiscent of the Cisco IOS command,\n *\n *   ip verify unicast reverse-path\n *   ip verify unicast source reachable-via any\n *\n * which implements the same functionality. But note that the syntax\n * is misleading, and the check may be performed on all IP packets\n * whether unicast, multicast, or broadcast.\n */\nstatic int\nverify_path(struct in_addr src, struct ifnet *ifp, u_int fib)\n{\n#ifndef __FreeBSD__\n\treturn 0;\n#else\n\tstruct route ro;\n\tstruct sockaddr_in *dst;\n\n\tbzero(&ro, sizeof(ro));\n\n\tdst = (struct sockaddr_in *)&(ro.ro_dst);\n\tdst->sin_family = AF_INET;\n\tdst->sin_len = sizeof(*dst);\n\tdst->sin_addr = src;\n\tin_rtalloc_ign(&ro, 0, fib);\n\n\tif (ro.ro_rt == NULL)\n\t\treturn 0;\n\n\t/*\n\t * If ifp is provided, check for equality with rtentry.\n\t * We should use rt->rt_ifa->ifa_ifp, instead of rt->rt_ifp,\n\t * in order to pass packets injected back by if_simloop():\n\t * if useloopback == 1 routing entry (via lo0) for our own address\n\t * may exist, so we need to handle routing assymetry.\n\t */\n\tif (ifp != NULL && ro.ro_rt->rt_ifa->ifa_ifp != ifp) {\n\t\tRTFREE(ro.ro_rt);\n\t\treturn 0;\n\t}\n\n\t/* if no ifp provided, check if rtentry is not default route */\n\tif (ifp == NULL &&\n\t     satosin(rt_key(ro.ro_rt))->sin_addr.s_addr == INADDR_ANY) {\n\t\tRTFREE(ro.ro_rt);\n\t\treturn 0;\n\t}\n\n\t/* or if this is a blackhole/reject route */\n\tif (ifp == NULL && ro.ro_rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {\n\t\tRTFREE(ro.ro_rt);\n\t\treturn 0;\n\t}\n\n\t/* found valid route */\n\tRTFREE(ro.ro_rt);\n\treturn 1;\n#endif /* __FreeBSD__ */\n}\n\n#ifdef INET6\n/*\n * ipv6 specific rules here...\n */\nstatic __inline int\nicmp6type_match (int type, ipfw_insn_u32 *cmd)\n{\n\treturn (type <= ICMP6_MAXTYPE && (cmd->d[type/32] & (1<<(type%32)) ) );\n}\n\nstatic int\nflow6id_match( int curr_flow, ipfw_insn_u32 *cmd )\n{\n\tint i;\n\tfor (i=0; i <= cmd->o.arg1; ++i )\n\t\tif (curr_flow == cmd->d[i] )\n\t\t\treturn 1;\n\treturn 0;\n}\n\n/* support for IP6_*_ME opcodes */\nstatic int\nsearch_ip6_addr_net (struct in6_addr * ip6_addr)\n{\n\tstruct ifnet *mdc;\n\tstruct ifaddr *mdc2;\n\tstruct in6_ifaddr *fdm;\n\tstruct in6_addr copia;\n\n\tTAILQ_FOREACH(mdc, &V_ifnet, if_link) {\n\t\tif_addr_rlock(mdc);\n\t\tTAILQ_FOREACH(mdc2, &mdc->if_addrhead, ifa_link) {\n\t\t\tif (mdc2->ifa_addr->sa_family == AF_INET6) {\n\t\t\t\tfdm = (struct in6_ifaddr *)mdc2;\n\t\t\t\tcopia = fdm->ia_addr.sin6_addr;\n\t\t\t\t/* need for leaving scope_id in the sock_addr */\n\t\t\t\tin6_clearscope(&copia);\n\t\t\t\tif (IN6_ARE_ADDR_EQUAL(ip6_addr, &copia)) {\n\t\t\t\t\tif_addr_runlock(mdc);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif_addr_runlock(mdc);\n\t}\n\treturn 0;\n}\n\nstatic int\nverify_path6(struct in6_addr *src, struct ifnet *ifp)\n{\n\tstruct route_in6 ro;\n\tstruct sockaddr_in6 *dst;\n\n\tbzero(&ro, sizeof(ro));\n\n\tdst = (struct sockaddr_in6 * )&(ro.ro_dst);\n\tdst->sin6_family = AF_INET6;\n\tdst->sin6_len = sizeof(*dst);\n\tdst->sin6_addr = *src;\n\t/* XXX MRT 0 for ipv6 at this time */\n\trtalloc_ign((struct route *)&ro, 0);\n\n\tif (ro.ro_rt == NULL)\n\t\treturn 0;\n\n\t/* \n\t * if ifp is provided, check for equality with rtentry\n\t * We should use rt->rt_ifa->ifa_ifp, instead of rt->rt_ifp,\n\t * to support the case of sending packets to an address of our own.\n\t * (where the former interface is the first argument of if_simloop()\n\t *  (=ifp), the latter is lo0)\n\t */\n\tif (ifp != NULL && ro.ro_rt->rt_ifa->ifa_ifp != ifp) {\n\t\tRTFREE(ro.ro_rt);\n\t\treturn 0;\n\t}\n\n\t/* if no ifp provided, check if rtentry is not default route */\n\tif (ifp == NULL &&\n\t    IN6_IS_ADDR_UNSPECIFIED(&satosin6(rt_key(ro.ro_rt))->sin6_addr)) {\n\t\tRTFREE(ro.ro_rt);\n\t\treturn 0;\n\t}\n\n\t/* or if this is a blackhole/reject route */\n\tif (ifp == NULL && ro.ro_rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {\n\t\tRTFREE(ro.ro_rt);\n\t\treturn 0;\n\t}\n\n\t/* found valid route */\n\tRTFREE(ro.ro_rt);\n\treturn 1;\n\n}\n\nstatic int\nis_icmp6_query(int icmp6_type)\n{\n\tif ((icmp6_type <= ICMP6_MAXTYPE) &&\n\t    (icmp6_type == ICMP6_ECHO_REQUEST ||\n\t    icmp6_type == ICMP6_MEMBERSHIP_QUERY ||\n\t    icmp6_type == ICMP6_WRUREQUEST ||\n\t    icmp6_type == ICMP6_FQDN_QUERY ||\n\t    icmp6_type == ICMP6_NI_QUERY))\n\t\treturn (1);\n\n\treturn (0);\n}\n\nstatic void\nsend_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)\n{\n\tstruct mbuf *m;\n\n\tm = args->m;\n\tif (code == ICMP6_UNREACH_RST && args->f_id.proto == IPPROTO_TCP) {\n\t\tstruct tcphdr *tcp;\n\t\ttcp = (struct tcphdr *)((char *)ip6 + hlen);\n\n\t\tif ((tcp->th_flags & TH_RST) == 0) {\n\t\t\tstruct mbuf *m0;\n\t\t\tm0 = ipfw_send_pkt(args->m, &(args->f_id),\n\t\t\t    ntohl(tcp->th_seq), ntohl(tcp->th_ack),\n\t\t\t    tcp->th_flags | TH_RST);\n\t\t\tif (m0 != NULL)\n\t\t\t\tip6_output(m0, NULL, NULL, 0, NULL, NULL,\n\t\t\t\t    NULL);\n\t\t}\n\t\tFREE_PKT(m);\n\t} else if (code != ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */\n#if 0\n\t\t/*\n\t\t * Unlike above, the mbufs need to line up with the ip6 hdr,\n\t\t * as the contents are read. We need to m_adj() the\n\t\t * needed amount.\n\t\t * The mbuf will however be thrown away so we can adjust it.\n\t\t * Remember we did an m_pullup on it already so we\n\t\t * can make some assumptions about contiguousness.\n\t\t */\n\t\tif (args->L3offset)\n\t\t\tm_adj(m, args->L3offset);\n#endif\n\t\ticmp6_error(m, ICMP6_DST_UNREACH, code, 0);\n\t} else\n\t\tFREE_PKT(m);\n\n\targs->m = NULL;\n}\n\n#endif /* INET6 */\n\n\n/*\n * sends a reject message, consuming the mbuf passed as an argument.\n */\nstatic void\nsend_reject(struct ip_fw_args *args, int code, int iplen, struct ip *ip)\n{\n\n#if 0\n\t/* XXX When ip is not guaranteed to be at mtod() we will\n\t * need to account for this */\n\t * The mbuf will however be thrown away so we can adjust it.\n\t * Remember we did an m_pullup on it already so we\n\t * can make some assumptions about contiguousness.\n\t */\n\tif (args->L3offset)\n\t\tm_adj(m, args->L3offset);\n#endif\n\tif (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */\n\t\t/* We need the IP header in host order for icmp_error(). */\n\t\tSET_HOST_IPLEN(ip);\n\t\ticmp_error(args->m, ICMP_UNREACH, code, 0L, 0);\n\t} else if (args->f_id.proto == IPPROTO_TCP) {\n\t\tstruct tcphdr *const tcp =\n\t\t    L3HDR(struct tcphdr, mtod(args->m, struct ip *));\n\t\tif ( (tcp->th_flags & TH_RST) == 0) {\n\t\t\tstruct mbuf *m;\n\t\t\tm = ipfw_send_pkt(args->m, &(args->f_id),\n\t\t\t\tntohl(tcp->th_seq), ntohl(tcp->th_ack),\n\t\t\t\ttcp->th_flags | TH_RST);\n\t\t\tif (m != NULL)\n\t\t\t\tip_output(m, NULL, NULL, 0, NULL, NULL);\n\t\t}\n\t\tFREE_PKT(args->m);\n\t} else\n\t\tFREE_PKT(args->m);\n\targs->m = NULL;\n}\n\n/*\n * Support for uid/gid/jail lookup. These tests are expensive\n * (because we may need to look into the list of active sockets)\n * so we cache the results. ugid_lookupp is 0 if we have not\n * yet done a lookup, 1 if we succeeded, and -1 if we tried\n * and failed. The function always returns the match value.\n * We could actually spare the variable and use *uc, setting\n * it to '(void *)check_uidgid if we have no info, NULL if\n * we tried and failed, or any other value if successful.\n */\nstatic int\ncheck_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,\n    struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,\n    u_int16_t src_port, int *ugid_lookupp,\n    struct ucred **uc, struct inpcb *inp)\n{\n#ifndef __FreeBSD__\n\treturn cred_check(insn, proto, oif,\n\t    dst_ip, dst_port, src_ip, src_port,\n\t    (struct bsd_ucred *)uc, ugid_lookupp, ((struct mbuf *)inp)->m_skb);\n#else  /* FreeBSD */\n\tstruct inpcbinfo *pi;\n\tint wildcard;\n\tstruct inpcb *pcb;\n\tint match;\n\n\t/*\n\t * Check to see if the UDP or TCP stack supplied us with\n\t * the PCB. If so, rather then holding a lock and looking\n\t * up the PCB, we can use the one that was supplied.\n\t */\n\tif (inp && *ugid_lookupp == 0) {\n\t\tINP_LOCK_ASSERT(inp);\n\t\tif (inp->inp_socket != NULL) {\n\t\t\t*uc = crhold(inp->inp_cred);\n\t\t\t*ugid_lookupp = 1;\n\t\t} else\n\t\t\t*ugid_lookupp = -1;\n\t}\n\t/*\n\t * If we have already been here and the packet has no\n\t * PCB entry associated with it, then we can safely\n\t * assume that this is a no match.\n\t */\n\tif (*ugid_lookupp == -1)\n\t\treturn (0);\n\tif (proto == IPPROTO_TCP) {\n\t\twildcard = 0;\n\t\tpi = &V_tcbinfo;\n\t} else if (proto == IPPROTO_UDP) {\n\t\twildcard = INPLOOKUP_WILDCARD;\n\t\tpi = &V_udbinfo;\n\t} else\n\t\treturn 0;\n\tmatch = 0;\n\tif (*ugid_lookupp == 0) {\n\t\tINP_INFO_RLOCK(pi);\n\t\tpcb =  (oif) ?\n\t\t\tin_pcblookup_hash(pi,\n\t\t\t\tdst_ip, htons(dst_port),\n\t\t\t\tsrc_ip, htons(src_port),\n\t\t\t\twildcard, oif) :\n\t\t\tin_pcblookup_hash(pi,\n\t\t\t\tsrc_ip, htons(src_port),\n\t\t\t\tdst_ip, htons(dst_port),\n\t\t\t\twildcard, NULL);\n\t\tif (pcb != NULL) {\n\t\t\t*uc = crhold(pcb->inp_cred);\n\t\t\t*ugid_lookupp = 1;\n\t\t}\n\t\tINP_INFO_RUNLOCK(pi);\n\t\tif (*ugid_lookupp == 0) {\n\t\t\t/*\n\t\t\t * We tried and failed, set the variable to -1\n\t\t\t * so we will not try again on this packet.\n\t\t\t */\n\t\t\t*ugid_lookupp = -1;\n\t\t\treturn (0);\n\t\t}\n\t} \n\tif (insn->o.opcode == O_UID)\n\t\tmatch = ((*uc)->cr_uid == (uid_t)insn->d[0]);\n\telse if (insn->o.opcode == O_GID)\n\t\tmatch = groupmember((gid_t)insn->d[0], *uc);\n\telse if (insn->o.opcode == O_JAIL)\n\t\tmatch = ((*uc)->cr_prison->pr_id == (int)insn->d[0]);\n\treturn match;\n#endif /* __FreeBSD__ */\n}\n\n/*\n * Helper function to set args with info on the rule after the matching\n * one. slot is precise, whereas we guess rule_id as they are\n * assigned sequentially.\n */\nstatic inline void\nset_match(struct ip_fw_args *args, int slot,\n\tstruct ip_fw_chain *chain)\n{\n\targs->rule.chain_id = chain->id;\n\targs->rule.slot = slot + 1; /* we use 0 as a marker */\n\targs->rule.rule_id = 1 + chain->map[slot]->id;\n\targs->rule.rulenum = chain->map[slot]->rulenum;\n}\n\n/*\n * The main check routine for the firewall.\n *\n * All arguments are in args so we can modify them and return them\n * back to the caller.\n *\n * Parameters:\n *\n *\targs->m\t(in/out) The packet; we set to NULL when/if we nuke it.\n *\t\tStarts with the IP header.\n *\targs->eh (in)\tMac header if present, NULL for layer3 packet.\n *\targs->L3offset\tNumber of bytes bypassed if we came from L2.\n *\t\t\te.g. often sizeof(eh)  ** NOTYET **\n *\targs->oif\tOutgoing interface, NULL if packet is incoming.\n *\t\tThe incoming interface is in the mbuf. (in)\n *\targs->divert_rule (in/out)\n *\t\tSkip up to the first rule past this rule number;\n *\t\tupon return, non-zero port number for divert or tee.\n *\n *\targs->rule\tPointer to the last matching rule (in/out)\n *\targs->next_hop\tSocket we are forwarding to (out).\n *\targs->f_id\tAddresses grabbed from the packet (out)\n * \targs->rule.info\ta cookie depending on rule action\n *\n * Return value:\n *\n *\tIP_FW_PASS\tthe packet must be accepted\n *\tIP_FW_DENY\tthe packet must be dropped\n *\tIP_FW_DIVERT\tdivert packet, port in m_tag\n *\tIP_FW_TEE\ttee packet, port in m_tag\n *\tIP_FW_DUMMYNET\tto dummynet, pipe in args->cookie\n *\tIP_FW_NETGRAPH\tinto netgraph, cookie args->cookie\n *\t\targs->rule contains the matching rule,\n *\t\targs->rule.info has additional information.\n *\n */\nint\nipfw_chk(struct ip_fw_args *args)\n{\n\n\t/*\n\t * Local variables holding state while processing a packet:\n\t *\n\t * IMPORTANT NOTE: to speed up the processing of rules, there\n\t * are some assumption on the values of the variables, which\n\t * are documented here. Should you change them, please check\n\t * the implementation of the various instructions to make sure\n\t * that they still work.\n\t *\n\t * args->eh\tThe MAC header. It is non-null for a layer2\n\t *\tpacket, it is NULL for a layer-3 packet.\n\t * **notyet**\n\t * args->L3offset Offset in the packet to the L3 (IP or equiv.) header.\n\t *\n\t * m | args->m\tPointer to the mbuf, as received from the caller.\n\t *\tIt may change if ipfw_chk() does an m_pullup, or if it\n\t *\tconsumes the packet because it calls send_reject().\n\t *\tXXX This has to change, so that ipfw_chk() never modifies\n\t *\tor consumes the buffer.\n\t * ip\tis the beginning of the ip(4 or 6) header.\n\t *\tCalculated by adding the L3offset to the start of data.\n\t *\t(Until we start using L3offset, the packet is\n\t *\tsupposed to start with the ip header).\n\t */\n\tstruct mbuf *m = args->m;\n\tstruct ip *ip = mtod(m, struct ip *);\n\n\t/*\n\t * For rules which contain uid/gid or jail constraints, cache\n\t * a copy of the users credentials after the pcb lookup has been\n\t * executed. This will speed up the processing of rules with\n\t * these types of constraints, as well as decrease contention\n\t * on pcb related locks.\n\t */\n#ifndef __FreeBSD__\n\tstruct bsd_ucred ucred_cache;\n#else\n\tstruct ucred *ucred_cache = NULL;\n#endif\n\tint ucred_lookup = 0;\n\n\t/*\n\t * oif | args->oif\tIf NULL, ipfw_chk has been called on the\n\t *\tinbound path (ether_input, ip_input).\n\t *\tIf non-NULL, ipfw_chk has been called on the outbound path\n\t *\t(ether_output, ip_output).\n\t */\n\tstruct ifnet *oif = args->oif;\n\n\tint f_pos = 0;\t\t/* index of current rule in the array */\n\tint retval = 0;\n\n\t/*\n\t * hlen\tThe length of the IP header.\n\t */\n\tu_int hlen = 0;\t\t/* hlen >0 means we have an IP pkt */\n\n\t/*\n\t * offset\tThe offset of a fragment. offset != 0 means that\n\t *\twe have a fragment at this offset of an IPv4 packet.\n\t *\toffset == 0 means that (if this is an IPv4 packet)\n\t *\tthis is the first or only fragment.\n\t *\tFor IPv6 offset == 0 means there is no Fragment Header. \n\t *\tIf offset != 0 for IPv6 always use correct mask to\n\t *\tget the correct offset because we add IP6F_MORE_FRAG\n\t *\tto be able to dectect the first fragment which would\n\t *\totherwise have offset = 0.\n\t */\n\tu_short offset = 0;\n\n\t/*\n\t * Local copies of addresses. They are only valid if we have\n\t * an IP packet.\n\t *\n\t * proto\tThe protocol. Set to 0 for non-ip packets,\n\t *\tor to the protocol read from the packet otherwise.\n\t *\tproto != 0 means that we have an IPv4 packet.\n\t *\n\t * src_port, dst_port\tport numbers, in HOST format. Only\n\t *\tvalid for TCP and UDP packets.\n\t *\n\t * src_ip, dst_ip\tip addresses, in NETWORK format.\n\t *\tOnly valid for IPv4 packets.\n\t */\n\tuint8_t proto;\n\tuint16_t src_port = 0, dst_port = 0;\t/* NOTE: host format\t*/\n\tstruct in_addr src_ip, dst_ip;\t\t/* NOTE: network format\t*/\n\tuint16_t iplen=0;\n\tint pktlen;\n\tuint16_t\tetype = 0;\t/* Host order stored ether type */\n\n\t/*\n\t * dyn_dir = MATCH_UNKNOWN when rules unchecked,\n\t * \tMATCH_NONE when checked and not matched (q = NULL),\n\t *\tMATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL)\n\t */\n\tint dyn_dir = MATCH_UNKNOWN;\n\tipfw_dyn_rule *q = NULL;\n\tstruct ip_fw_chain *chain = &V_layer3_chain;\n\n\t/*\n\t * We store in ulp a pointer to the upper layer protocol header.\n\t * In the ipv4 case this is easy to determine from the header,\n\t * but for ipv6 we might have some additional headers in the middle.\n\t * ulp is NULL if not found.\n\t */\n\tvoid *ulp = NULL;\t\t/* upper layer protocol pointer. */\n\n\t/* XXX ipv6 variables */\n\tint is_ipv6 = 0;\n\tuint8_t\ticmp6_type = 0;\n\tuint16_t ext_hd = 0;\t/* bits vector for extension header filtering */\n\t/* end of ipv6 variables */\n\n\tint is_ipv4 = 0;\n\n\tint done = 0;\t\t/* flag to exit the outer loop */\n\n\tif (m->m_flags & M_SKIP_FIREWALL || (! V_ipfw_vnet_ready))\n\t\treturn (IP_FW_PASS);\t/* accept */\n\n\tdst_ip.s_addr = 0;\t\t/* make sure it is initialized */\n\tsrc_ip.s_addr = 0;\t\t/* make sure it is initialized */\n\tpktlen = m->m_pkthdr.len;\n\targs->f_id.fib = M_GETFIB(m); /* note mbuf not altered) */\n\tproto = args->f_id.proto = 0;\t/* mark f_id invalid */\n\t\t/* XXX 0 is a valid proto: IP/IPv6 Hop-by-Hop Option */\n\n/*\n * PULLUP_TO(len, p, T) makes sure that len + sizeof(T) is contiguous,\n * then it sets p to point at the offset \"len\" in the mbuf. WARNING: the\n * pointer might become stale after other pullups (but we never use it\n * this way).\n */\n#define PULLUP_TO(_len, p, T)\t\t\t\t\t\\\ndo {\t\t\t\t\t\t\t\t\\\n\tint x = (_len) + sizeof(T);\t\t\t\t\\\n\tif ((m)->m_len < x) {\t\t\t\t\t\\\n\t\targs->m = m = m_pullup(m, x);\t\t\t\\\n\t\tif (m == NULL)\t\t\t\t\t\\\n\t\t\tgoto pullup_failed;\t\t\t\\\n\t}\t\t\t\t\t\t\t\\\n\tp = (mtod(m, char *) + (_len));\t\t\t\t\\\n} while (0)\n\n\t/*\n\t * if we have an ether header,\n\t */\n\tif (args->eh)\n\t\tetype = ntohs(args->eh->ether_type);\n\n\t/* Identify IP packets and fill up variables. */\n\tif (pktlen >= sizeof(struct ip6_hdr) &&\n\t    (args->eh == NULL || etype == ETHERTYPE_IPV6) && ip->ip_v == 6) {\n\t\tstruct ip6_hdr *ip6 = (struct ip6_hdr *)ip;\n\t\tis_ipv6 = 1;\n\t\targs->f_id.addr_type = 6;\n\t\thlen = sizeof(struct ip6_hdr);\n\t\tproto = ip6->ip6_nxt;\n\n\t\t/* Search extension headers to find upper layer protocols */\n\t\twhile (ulp == NULL) {\n\t\t\tswitch (proto) {\n\t\t\tcase IPPROTO_ICMPV6:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct icmp6_hdr);\n\t\t\t\ticmp6_type = ICMP6(ulp)->icmp6_type;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_TCP:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct tcphdr);\n\t\t\t\tdst_port = TCP(ulp)->th_dport;\n\t\t\t\tsrc_port = TCP(ulp)->th_sport;\n\t\t\t\t/* save flags for dynamic rules */\n\t\t\t\targs->f_id._flags = TCP(ulp)->th_flags;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_SCTP:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct sctphdr);\n\t\t\t\tsrc_port = SCTP(ulp)->src_port;\n\t\t\t\tdst_port = SCTP(ulp)->dest_port;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_UDP:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct udphdr);\n\t\t\t\tdst_port = UDP(ulp)->uh_dport;\n\t\t\t\tsrc_port = UDP(ulp)->uh_sport;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_HOPOPTS:\t/* RFC 2460 */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_hbh);\n\t\t\t\text_hd |= EXT_HOPOPTS;\n\t\t\t\thlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;\n\t\t\t\tproto = ((struct ip6_hbh *)ulp)->ip6h_nxt;\n\t\t\t\tulp = NULL;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_ROUTING:\t/* RFC 2460 */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_rthdr);\n\t\t\t\tswitch (((struct ip6_rthdr *)ulp)->ip6r_type) {\n\t\t\t\tcase 0:\n\t\t\t\t\text_hd |= EXT_RTHDR0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\text_hd |= EXT_RTHDR2;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tprintf(\"IPFW2: IPV6 - Unknown Routing \"\n\t\t\t\t\t    \"Header type(%d)\\n\",\n\t\t\t\t\t    ((struct ip6_rthdr *)ulp)->ip6r_type);\n\t\t\t\t\tif (V_fw_deny_unknown_exthdrs)\n\t\t\t\t\t    return (IP_FW_DENY);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\text_hd |= EXT_ROUTING;\n\t\t\t\thlen += (((struct ip6_rthdr *)ulp)->ip6r_len + 1) << 3;\n\t\t\t\tproto = ((struct ip6_rthdr *)ulp)->ip6r_nxt;\n\t\t\t\tulp = NULL;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_FRAGMENT:\t/* RFC 2460 */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_frag);\n\t\t\t\text_hd |= EXT_FRAGMENT;\n\t\t\t\thlen += sizeof (struct ip6_frag);\n\t\t\t\tproto = ((struct ip6_frag *)ulp)->ip6f_nxt;\n\t\t\t\toffset = ((struct ip6_frag *)ulp)->ip6f_offlg &\n\t\t\t\t\tIP6F_OFF_MASK;\n\t\t\t\t/* Add IP6F_MORE_FRAG for offset of first\n\t\t\t\t * fragment to be != 0. */\n\t\t\t\toffset |= ((struct ip6_frag *)ulp)->ip6f_offlg &\n\t\t\t\t\tIP6F_MORE_FRAG;\n\t\t\t\tif (offset == 0) {\n\t\t\t\t\tprintf(\"IPFW2: IPV6 - Invalid Fragment \"\n\t\t\t\t\t    \"Header\\n\");\n\t\t\t\t\tif (V_fw_deny_unknown_exthdrs)\n\t\t\t\t\t    return (IP_FW_DENY);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\targs->f_id.extra =\n\t\t\t\t    ntohl(((struct ip6_frag *)ulp)->ip6f_ident);\n\t\t\t\tulp = NULL;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_DSTOPTS:\t/* RFC 2460 */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_hbh);\n\t\t\t\text_hd |= EXT_DSTOPTS;\n\t\t\t\thlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;\n\t\t\t\tproto = ((struct ip6_hbh *)ulp)->ip6h_nxt;\n\t\t\t\tulp = NULL;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_AH:\t/* RFC 2402 */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_ext);\n\t\t\t\text_hd |= EXT_AH;\n\t\t\t\thlen += (((struct ip6_ext *)ulp)->ip6e_len + 2) << 2;\n\t\t\t\tproto = ((struct ip6_ext *)ulp)->ip6e_nxt;\n\t\t\t\tulp = NULL;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_ESP:\t/* RFC 2406 */\n\t\t\t\tPULLUP_TO(hlen, ulp, uint32_t);\t/* SPI, Seq# */\n\t\t\t\t/* Anything past Seq# is variable length and\n\t\t\t\t * data past this ext. header is encrypted. */\n\t\t\t\text_hd |= EXT_ESP;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_NONE:\t/* RFC 2460 */\n\t\t\t\t/*\n\t\t\t\t * Packet ends here, and IPv6 header has\n\t\t\t\t * already been pulled up. If ip6e_len!=0\n\t\t\t\t * then octets must be ignored.\n\t\t\t\t */\n\t\t\t\tulp = ip; /* non-NULL to get out of loop. */\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_OSPFIGP:\n\t\t\t\t/* XXX OSPF header check? */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_ext);\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_PIM:\n\t\t\t\t/* XXX PIM header check? */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct pim);\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_CARP:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct carp_header);\n\t\t\t\tif (((struct carp_header *)ulp)->carp_version !=\n\t\t\t\t    CARP_VERSION) \n\t\t\t\t\treturn (IP_FW_DENY);\n\t\t\t\tif (((struct carp_header *)ulp)->carp_type !=\n\t\t\t\t    CARP_ADVERTISEMENT) \n\t\t\t\t\treturn (IP_FW_DENY);\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_IPV6:\t/* RFC 2893 */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_hdr);\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_IPV4:\t/* RFC 2893 */\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tprintf(\"IPFW2: IPV6 - Unknown Extension \"\n\t\t\t\t    \"Header(%d), ext_hd=%x\\n\", proto, ext_hd);\n\t\t\t\tif (V_fw_deny_unknown_exthdrs)\n\t\t\t\t    return (IP_FW_DENY);\n\t\t\t\tPULLUP_TO(hlen, ulp, struct ip6_ext);\n\t\t\t\tbreak;\n\t\t\t} /*switch */\n\t\t}\n\t\tip = mtod(m, struct ip *);\n\t\tip6 = (struct ip6_hdr *)ip;\n\t\targs->f_id.src_ip6 = ip6->ip6_src;\n\t\targs->f_id.dst_ip6 = ip6->ip6_dst;\n\t\targs->f_id.src_ip = 0;\n\t\targs->f_id.dst_ip = 0;\n\t\targs->f_id.flow_id6 = ntohl(ip6->ip6_flow);\n\t} else if (pktlen >= sizeof(struct ip) &&\n\t    (args->eh == NULL || etype == ETHERTYPE_IP) && ip->ip_v == 4) {\n\t    \tis_ipv4 = 1;\n\t\thlen = ip->ip_hl << 2;\n\t\targs->f_id.addr_type = 4;\n\n\t\t/*\n\t\t * Collect parameters into local variables for faster matching.\n\t\t */\n\t\tproto = ip->ip_p;\n\t\tsrc_ip = ip->ip_src;\n\t\tdst_ip = ip->ip_dst;\n\t\toffset = ntohs(ip->ip_off) & IP_OFFMASK;\n\t\tiplen = ntohs(ip->ip_len);\n\t\tpktlen = iplen < pktlen ? iplen : pktlen;\n\n\t\tif (offset == 0) {\n\t\t\tswitch (proto) {\n\t\t\tcase IPPROTO_TCP:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct tcphdr);\n\t\t\t\tdst_port = TCP(ulp)->th_dport;\n\t\t\t\tsrc_port = TCP(ulp)->th_sport;\n\t\t\t\t/* save flags for dynamic rules */\n\t\t\t\targs->f_id._flags = TCP(ulp)->th_flags;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_UDP:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct udphdr);\n\t\t\t\tdst_port = UDP(ulp)->uh_dport;\n\t\t\t\tsrc_port = UDP(ulp)->uh_sport;\n\t\t\t\tbreak;\n\n\t\t\tcase IPPROTO_ICMP:\n\t\t\t\tPULLUP_TO(hlen, ulp, struct icmphdr);\n\t\t\t\t//args->f_id.flags = ICMP(ulp)->icmp_type;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tip = mtod(m, struct ip *);\n\t\targs->f_id.src_ip = ntohl(src_ip.s_addr);\n\t\targs->f_id.dst_ip = ntohl(dst_ip.s_addr);\n\t}\n#undef PULLUP_TO\n\tif (proto) { /* we may have port numbers, store them */\n\t\targs->f_id.proto = proto;\n\t\targs->f_id.src_port = src_port = ntohs(src_port);\n\t\targs->f_id.dst_port = dst_port = ntohs(dst_port);\n\t}\n\n\tIPFW_RLOCK(chain);\n\tif (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */\n\t\tIPFW_RUNLOCK(chain);\n\t\treturn (IP_FW_PASS);\t/* accept */\n\t}\n\tif (args->rule.slot) {\n\t\t/*\n\t\t * Packet has already been tagged as a result of a previous\n\t\t * match on rule args->rule aka args->rule_id (PIPE, QUEUE,\n\t\t * REASS, NETGRAPH, DIVERT/TEE...)\n\t\t * Validate the slot and continue from the next one\n\t\t * if still present, otherwise do a lookup.\n\t\t */\n\t\tf_pos = (args->rule.chain_id == chain->id) ?\n\t\t    args->rule.slot :\n\t\t    ipfw_find_rule(chain, args->rule.rulenum,\n\t\t\targs->rule.rule_id);\n\t} else {\n\t\tf_pos = 0;\n\t}\n\n\t/*\n\t * Now scan the rules, and parse microinstructions for each rule.\n\t * We have two nested loops and an inner switch. Sometimes we\n\t * need to break out of one or both loops, or re-enter one of\n\t * the loops with updated variables. Loop variables are:\n\t *\n\t *\tf_pos (outer loop) points to the current rule.\n\t *\t\tOn output it points to the matching rule.\n\t *\tdone (outer loop) is used as a flag to break the loop.\n\t *\tl (inner loop)\tresidual length of current rule.\n\t *\t\tcmd points to the current microinstruction.\n\t *\n\t * We break the inner loop by setting l=0 and possibly\n\t * cmdlen=0 if we don't want to advance cmd.\n\t * We break the outer loop by setting done=1\n\t * We can restart the inner loop by setting l>0 and f_pos, f, cmd\n\t * as needed.\n\t */\n\tfor (; f_pos < chain->n_rules; f_pos++) {\n\t\tipfw_insn *cmd;\n\t\tuint32_t tablearg = 0;\n\t\tint l, cmdlen, skip_or; /* skip rest of OR block */\n\t\tstruct ip_fw *f;\n\n\t\tf = chain->map[f_pos];\n\t\tif (V_set_disable & (1 << f->set) )\n\t\t\tcontinue;\n\n\t\tskip_or = 0;\n\t\tfor (l = f->cmd_len, cmd = f->cmd ; l > 0 ;\n\t\t    l -= cmdlen, cmd += cmdlen) {\n\t\t\tint match;\n\n\t\t\t/*\n\t\t\t * check_body is a jump target used when we find a\n\t\t\t * CHECK_STATE, and need to jump to the body of\n\t\t\t * the target rule.\n\t\t\t */\n\n/* check_body: */\n\t\t\tcmdlen = F_LEN(cmd);\n\t\t\t/*\n\t\t\t * An OR block (insn_1 || .. || insn_n) has the\n\t\t\t * F_OR bit set in all but the last instruction.\n\t\t\t * The first match will set \"skip_or\", and cause\n\t\t\t * the following instructions to be skipped until\n\t\t\t * past the one with the F_OR bit clear.\n\t\t\t */\n\t\t\tif (skip_or) {\t\t/* skip this instruction */\n\t\t\t\tif ((cmd->len & F_OR) == 0)\n\t\t\t\t\tskip_or = 0;\t/* next one is good */\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmatch = 0; /* set to 1 if we succeed */\n\n\t\t\tswitch (cmd->opcode) {\n\t\t\t/*\n\t\t\t * The first set of opcodes compares the packet's\n\t\t\t * fields with some pattern, setting 'match' if a\n\t\t\t * match is found. At the end of the loop there is\n\t\t\t * logic to deal with F_NOT and F_OR flags associated\n\t\t\t * with the opcode.\n\t\t\t */\n\t\t\tcase O_NOP:\n\t\t\t\tmatch = 1;\n\t\t\t\tbreak;\n\n\t\t\tcase O_FORWARD_MAC:\n\t\t\t\tprintf(\"ipfw: opcode %d unimplemented\\n\",\n\t\t\t\t    cmd->opcode);\n\t\t\t\tbreak;\n\n\t\t\tcase O_GID:\n\t\t\tcase O_UID:\n\t\t\tcase O_JAIL:\n\t\t\t\t/*\n\t\t\t\t * We only check offset == 0 && proto != 0,\n\t\t\t\t * as this ensures that we have a\n\t\t\t\t * packet with the ports info.\n\t\t\t\t */\n\t\t\t\tif (offset!=0)\n\t\t\t\t\tbreak;\n\t\t\t\tif (is_ipv6) /* XXX to be fixed later */\n\t\t\t\t\tbreak;\n\t\t\t\tif (proto == IPPROTO_TCP ||\n\t\t\t\t    proto == IPPROTO_UDP)\n\t\t\t\t\tmatch = check_uidgid(\n\t\t\t\t\t\t    (ipfw_insn_u32 *)cmd,\n\t\t\t\t\t\t    proto, oif,\n\t\t\t\t\t\t    dst_ip, dst_port,\n\t\t\t\t\t\t    src_ip, src_port, &ucred_lookup,\n#ifdef __FreeBSD__\n\t\t\t\t\t\t    &ucred_cache, args->inp);\n#else\n\t\t\t\t\t\t    (void *)&ucred_cache,\n\t\t\t\t\t\t    (struct inpcb *)args->m);\n#endif\n\t\t\t\tbreak;\n\n\t\t\tcase O_RECV:\n\t\t\t\tmatch = iface_match(m->m_pkthdr.rcvif,\n\t\t\t\t    (ipfw_insn_if *)cmd);\n\t\t\t\tbreak;\n\n\t\t\tcase O_XMIT:\n\t\t\t\tmatch = iface_match(oif, (ipfw_insn_if *)cmd);\n\t\t\t\tbreak;\n\n\t\t\tcase O_VIA:\n\t\t\t\tmatch = iface_match(oif ? oif :\n\t\t\t\t    m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd);\n\t\t\t\tbreak;\n\n\t\t\tcase O_MACADDR2:\n\t\t\t\tif (args->eh != NULL) {\t/* have MAC header */\n\t\t\t\t\tu_int32_t *want = (u_int32_t *)\n\t\t\t\t\t\t((ipfw_insn_mac *)cmd)->addr;\n\t\t\t\t\tu_int32_t *mask = (u_int32_t *)\n\t\t\t\t\t\t((ipfw_insn_mac *)cmd)->mask;\n\t\t\t\t\tu_int32_t *hdr = (u_int32_t *)args->eh;\n\n\t\t\t\t\tmatch =\n\t\t\t\t\t    ( want[0] == (hdr[0] & mask[0]) &&\n\t\t\t\t\t      want[1] == (hdr[1] & mask[1]) &&\n\t\t\t\t\t      want[2] == (hdr[2] & mask[2]) );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_MAC_TYPE:\n\t\t\t\tif (args->eh != NULL) {\n\t\t\t\t\tu_int16_t *p =\n\t\t\t\t\t    ((ipfw_insn_u16 *)cmd)->ports;\n\t\t\t\t\tint i;\n\n\t\t\t\t\tfor (i = cmdlen - 1; !match && i>0;\n\t\t\t\t\t    i--, p += 2)\n\t\t\t\t\t\tmatch = (etype >= p[0] &&\n\t\t\t\t\t\t    etype <= p[1]);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_FRAG:\n\t\t\t\tmatch = (offset != 0);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IN:\t/* \"out\" is \"not in\" */\n\t\t\t\tmatch = (oif == NULL);\n\t\t\t\tbreak;\n\n\t\t\tcase O_LAYER2:\n\t\t\t\tmatch = (args->eh != NULL);\n\t\t\t\tbreak;\n\n\t\t\tcase O_DIVERTED:\n\t\t\t    {\n\t\t\t\t/* For diverted packets, args->rule.info\n\t\t\t\t * contains the divert port (in host format)\n\t\t\t\t * reason and direction.\n\t\t\t\t */\n\t\t\t\tuint32_t i = args->rule.info;\n\t\t\t\tmatch = (i&IPFW_IS_MASK) == IPFW_IS_DIVERT &&\n\t\t\t\t    cmd->arg1 & ((i & IPFW_INFO_IN) ? 1 : 2);\n\t\t\t    }\n\t\t\t\tbreak;\n\n\t\t\tcase O_PROTO:\n\t\t\t\t/*\n\t\t\t\t * We do not allow an arg of 0 so the\n\t\t\t\t * check of \"proto\" only suffices.\n\t\t\t\t */\n\t\t\t\tmatch = (proto == cmd->arg1);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP_SRC:\n\t\t\t\tmatch = is_ipv4 &&\n\t\t\t\t    (((ipfw_insn_ip *)cmd)->addr.s_addr ==\n\t\t\t\t    src_ip.s_addr);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP_SRC_LOOKUP:\n\t\t\tcase O_IP_DST_LOOKUP:\n\t\t\t\tif (is_ipv4) {\n\t\t\t\t    uint32_t key =\n\t\t\t\t\t(cmd->opcode == O_IP_DST_LOOKUP) ?\n\t\t\t\t\t    dst_ip.s_addr : src_ip.s_addr;\n\t\t\t\t    uint32_t v = 0;\n\n\t\t\t\t    if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {\n\t\t\t\t\t/* generic lookup. The key must be\n\t\t\t\t\t * in 32bit big-endian format.\n\t\t\t\t\t */\n\t\t\t\t\tv = ((ipfw_insn_u32 *)cmd)->d[1];\n\t\t\t\t\tif (v == 0)\n\t\t\t\t\t    key = dst_ip.s_addr;\n\t\t\t\t\telse if (v == 1)\n\t\t\t\t\t    key = src_ip.s_addr;\n\t\t\t\t\telse if (v == 6) /* dscp */\n\t\t\t\t\t    key = (ip->ip_tos >> 2) & 0x3f;\n\t\t\t\t\telse if (offset != 0)\n\t\t\t\t\t    break;\n\t\t\t\t\telse if (proto != IPPROTO_TCP &&\n\t\t\t\t\t\tproto != IPPROTO_UDP)\n\t\t\t\t\t    break;\n\t\t\t\t\telse if (v == 2)\n\t\t\t\t\t    key = htonl(dst_port);\n\t\t\t\t\telse if (v == 3)\n\t\t\t\t\t    key = htonl(src_port);\n\t\t\t\t\telse if (v == 4 || v == 5) {\n\t\t\t\t\t    check_uidgid(\n\t\t\t\t\t\t(ipfw_insn_u32 *)cmd,\n\t\t\t\t\t\tproto, oif,\n\t\t\t\t\t\tdst_ip, dst_port,\n\t\t\t\t\t\tsrc_ip, src_port, &ucred_lookup,\n#ifdef __FreeBSD__\n\t\t\t\t\t\t&ucred_cache, args->inp);\n\t\t\t\t\t    if (v == 4 /* O_UID */)\n\t\t\t\t\t\tkey = ucred_cache->cr_uid;\n\t\t\t\t\t    else if (v == 5 /* O_JAIL */)\n\t\t\t\t\t\tkey = ucred_cache->cr_prison->pr_id;\n#else /* !__FreeBSD__ */\n\t\t\t\t\t\t(void *)&ucred_cache,\n\t\t\t\t\t\t(struct inpcb *)args->m);\n\t\t\t\t\t    if (v ==4 /* O_UID */)\n\t\t\t\t\t\tkey = ucred_cache.uid;\n\t\t\t\t\t    else if (v == 5 /* O_JAIL */)\n\t\t\t\t\t\tkey = ucred_cache.xid;\n#endif /* !__FreeBSD__ */\n\t\t\t\t\t    key = htonl(key);\n\t\t\t\t\t} else\n\t\t\t\t\t    break;\n\t\t\t\t    }\n\t\t\t\t    match = ipfw_lookup_table(chain,\n\t\t\t\t\tcmd->arg1, key, &v);\n\t\t\t\t    if (!match)\n\t\t\t\t\tbreak;\n\t\t\t\t    if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))\n\t\t\t\t\tmatch =\n\t\t\t\t\t    ((ipfw_insn_u32 *)cmd)->d[0] == v;\n\t\t\t\t    else\n\t\t\t\t\ttablearg = v;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP_SRC_MASK:\n\t\t\tcase O_IP_DST_MASK:\n\t\t\t\tif (is_ipv4) {\n\t\t\t\t    uint32_t a =\n\t\t\t\t\t(cmd->opcode == O_IP_DST_MASK) ?\n\t\t\t\t\t    dst_ip.s_addr : src_ip.s_addr;\n\t\t\t\t    uint32_t *p = ((ipfw_insn_u32 *)cmd)->d;\n\t\t\t\t    int i = cmdlen-1;\n\n\t\t\t\t    for (; !match && i>0; i-= 2, p+= 2)\n\t\t\t\t\tmatch = (p[0] == (a & p[1]));\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP_SRC_ME:\n\t\t\t\tif (is_ipv4) {\n\t\t\t\t\tstruct ifnet *tif;\n\n\t\t\t\t\tINADDR_TO_IFP(src_ip, tif);\n\t\t\t\t\tmatch = (tif != NULL);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n#ifdef INET6\n\t\t\t\t/* FALLTHROUGH */\n\t\t\tcase O_IP6_SRC_ME:\n\t\t\t\tmatch= is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6);\n#endif\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP_DST_SET:\n\t\t\tcase O_IP_SRC_SET:\n\t\t\t\tif (is_ipv4) {\n\t\t\t\t\tu_int32_t *d = (u_int32_t *)(cmd+1);\n\t\t\t\t\tu_int32_t addr =\n\t\t\t\t\t    cmd->opcode == O_IP_DST_SET ?\n\t\t\t\t\t\targs->f_id.dst_ip :\n\t\t\t\t\t\targs->f_id.src_ip;\n\n\t\t\t\t\t    if (addr < d[0])\n\t\t\t\t\t\t    break;\n\t\t\t\t\t    addr -= d[0]; /* subtract base */\n\t\t\t\t\t    match = (addr < cmd->arg1) &&\n\t\t\t\t\t\t( d[ 1 + (addr>>5)] &\n\t\t\t\t\t\t  (1<<(addr & 0x1f)) );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP_DST:\n\t\t\t\tmatch = is_ipv4 &&\n\t\t\t\t    (((ipfw_insn_ip *)cmd)->addr.s_addr ==\n\t\t\t\t    dst_ip.s_addr);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP_DST_ME:\n\t\t\t\tif (is_ipv4) {\n\t\t\t\t\tstruct ifnet *tif;\n\n\t\t\t\t\tINADDR_TO_IFP(dst_ip, tif);\n\t\t\t\t\tmatch = (tif != NULL);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n#ifdef INET6\n\t\t\t\t/* FALLTHROUGH */\n\t\t\tcase O_IP6_DST_ME:\n\t\t\t\tmatch= is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6);\n#endif\n\t\t\t\tbreak;\n\n\n\t\t\tcase O_IP_SRCPORT:\n\t\t\tcase O_IP_DSTPORT:\n\t\t\t\t/*\n\t\t\t\t * offset == 0 && proto != 0 is enough\n\t\t\t\t * to guarantee that we have a\n\t\t\t\t * packet with port info.\n\t\t\t\t */\n\t\t\t\tif ((proto==IPPROTO_UDP || proto==IPPROTO_TCP)\n\t\t\t\t    && offset == 0) {\n\t\t\t\t\tu_int16_t x =\n\t\t\t\t\t    (cmd->opcode == O_IP_SRCPORT) ?\n\t\t\t\t\t\tsrc_port : dst_port ;\n\t\t\t\t\tu_int16_t *p =\n\t\t\t\t\t    ((ipfw_insn_u16 *)cmd)->ports;\n\t\t\t\t\tint i;\n\n\t\t\t\t\tfor (i = cmdlen - 1; !match && i>0;\n\t\t\t\t\t    i--, p += 2)\n\t\t\t\t\t\tmatch = (x>=p[0] && x<=p[1]);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_ICMPTYPE:\n\t\t\t\tmatch = (offset == 0 && proto==IPPROTO_ICMP &&\n\t\t\t\t    icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) );\n\t\t\t\tbreak;\n\n#ifdef INET6\n\t\t\tcase O_ICMP6TYPE:\n\t\t\t\tmatch = is_ipv6 && offset == 0 &&\n\t\t\t\t    proto==IPPROTO_ICMPV6 &&\n\t\t\t\t    icmp6type_match(\n\t\t\t\t\tICMP6(ulp)->icmp6_type,\n\t\t\t\t\t(ipfw_insn_u32 *)cmd);\n\t\t\t\tbreak;\n#endif /* INET6 */\n\n\t\t\tcase O_IPOPT:\n\t\t\t\tmatch = (is_ipv4 &&\n\t\t\t\t    ipopts_match(ip, cmd) );\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPVER:\n\t\t\t\tmatch = (is_ipv4 &&\n\t\t\t\t    cmd->arg1 == ip->ip_v);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPID:\n\t\t\tcase O_IPLEN:\n\t\t\tcase O_IPTTL:\n\t\t\t\tif (is_ipv4) {\t/* only for IP packets */\n\t\t\t\t    uint16_t x;\n\t\t\t\t    uint16_t *p;\n\t\t\t\t    int i;\n\n\t\t\t\t    if (cmd->opcode == O_IPLEN)\n\t\t\t\t\tx = iplen;\n\t\t\t\t    else if (cmd->opcode == O_IPTTL)\n\t\t\t\t\tx = ip->ip_ttl;\n\t\t\t\t    else /* must be IPID */\n\t\t\t\t\tx = ntohs(ip->ip_id);\n\t\t\t\t    if (cmdlen == 1) {\n\t\t\t\t\tmatch = (cmd->arg1 == x);\n\t\t\t\t\tbreak;\n\t\t\t\t    }\n\t\t\t\t    /* otherwise we have ranges */\n\t\t\t\t    p = ((ipfw_insn_u16 *)cmd)->ports;\n\t\t\t\t    i = cmdlen - 1;\n\t\t\t\t    for (; !match && i>0; i--, p += 2)\n\t\t\t\t\tmatch = (x >= p[0] && x <= p[1]);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPPRECEDENCE:\n\t\t\t\tmatch = (is_ipv4 &&\n\t\t\t\t    (cmd->arg1 == (ip->ip_tos & 0xe0)) );\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPTOS:\n\t\t\t\tmatch = (is_ipv4 &&\n\t\t\t\t    flags_match(cmd, ip->ip_tos));\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPDATALEN:\n\t\t\t\tif (proto == IPPROTO_TCP && offset == 0) {\n\t\t\t\t    struct tcphdr *tcp;\n\t\t\t\t    uint16_t x;\n\t\t\t\t    uint16_t *p;\n\t\t\t\t    int i;\n\n\t\t\t\t    tcp = TCP(ulp);\n\t\t\t\t    x = iplen -\n\t\t\t\t\t((ip->ip_hl + tcp->th_off) << 2);\n\t\t\t\t    if (cmdlen == 1) {\n\t\t\t\t\tmatch = (cmd->arg1 == x);\n\t\t\t\t\tbreak;\n\t\t\t\t    }\n\t\t\t\t    /* otherwise we have ranges */\n\t\t\t\t    p = ((ipfw_insn_u16 *)cmd)->ports;\n\t\t\t\t    i = cmdlen - 1;\n\t\t\t\t    for (; !match && i>0; i--, p += 2)\n\t\t\t\t\tmatch = (x >= p[0] && x <= p[1]);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPFLAGS:\n\t\t\t\tmatch = (proto == IPPROTO_TCP && offset == 0 &&\n\t\t\t\t    flags_match(cmd, TCP(ulp)->th_flags));\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPOPTS:\n\t\t\t\tmatch = (proto == IPPROTO_TCP && offset == 0 &&\n\t\t\t\t    tcpopts_match(TCP(ulp), cmd));\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPSEQ:\n\t\t\t\tmatch = (proto == IPPROTO_TCP && offset == 0 &&\n\t\t\t\t    ((ipfw_insn_u32 *)cmd)->d[0] ==\n\t\t\t\t\tTCP(ulp)->th_seq);\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPACK:\n\t\t\t\tmatch = (proto == IPPROTO_TCP && offset == 0 &&\n\t\t\t\t    ((ipfw_insn_u32 *)cmd)->d[0] ==\n\t\t\t\t\tTCP(ulp)->th_ack);\n\t\t\t\tbreak;\n\n\t\t\tcase O_TCPWIN:\n\t\t\t\tmatch = (proto == IPPROTO_TCP && offset == 0 &&\n\t\t\t\t    cmd->arg1 == TCP(ulp)->th_win);\n\t\t\t\tbreak;\n\n\t\t\tcase O_ESTAB:\n\t\t\t\t/* reject packets which have SYN only */\n\t\t\t\t/* XXX should i also check for TH_ACK ? */\n\t\t\t\tmatch = (proto == IPPROTO_TCP && offset == 0 &&\n\t\t\t\t    (TCP(ulp)->th_flags &\n\t\t\t\t     (TH_RST | TH_ACK | TH_SYN)) != TH_SYN);\n\t\t\t\tbreak;\n\n\t\t\tcase O_ALTQ: {\n\t\t\t\tstruct pf_mtag *at;\n\t\t\t\tipfw_insn_altq *altq = (ipfw_insn_altq *)cmd;\n\n\t\t\t\tmatch = 1;\n\t\t\t\tat = pf_find_mtag(m);\n\t\t\t\tif (at != NULL && at->qid != 0)\n\t\t\t\t\tbreak;\n\t\t\t\tat = pf_get_mtag(m);\n\t\t\t\tif (at == NULL) {\n\t\t\t\t\t/*\n\t\t\t\t\t * Let the packet fall back to the\n\t\t\t\t\t * default ALTQ.\n\t\t\t\t\t */\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tat->qid = altq->qid;\n\t\t\t\tif (is_ipv4)\n\t\t\t\t\tat->af = AF_INET;\n\t\t\t\telse\n\t\t\t\t\tat->af = AF_LINK;\n\t\t\t\tat->hdr = ip;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase O_LOG:\n\t\t\t\tipfw_log(f, hlen, args, m,\n\t\t\t\t\t    oif, offset, tablearg, ip);\n\t\t\t\tmatch = 1;\n\t\t\t\tbreak;\n\n\t\t\tcase O_PROB:\n\t\t\t\tmatch = (random()<((ipfw_insn_u32 *)cmd)->d[0]);\n\t\t\t\tbreak;\n\n\t\t\tcase O_VERREVPATH:\n\t\t\t\t/* Outgoing packets automatically pass/match */\n\t\t\t\tmatch = ((oif != NULL) ||\n\t\t\t\t    (m->m_pkthdr.rcvif == NULL) ||\n\t\t\t\t    (\n#ifdef INET6\n\t\t\t\t    is_ipv6 ?\n\t\t\t\t\tverify_path6(&(args->f_id.src_ip6),\n\t\t\t\t\t    m->m_pkthdr.rcvif) :\n#endif\n\t\t\t\t    verify_path(src_ip, m->m_pkthdr.rcvif,\n\t\t\t\t        args->f_id.fib)));\n\t\t\t\tbreak;\n\n\t\t\tcase O_VERSRCREACH:\n\t\t\t\t/* Outgoing packets automatically pass/match */\n\t\t\t\tmatch = (hlen > 0 && ((oif != NULL) ||\n#ifdef INET6\n\t\t\t\t    is_ipv6 ?\n\t\t\t\t        verify_path6(&(args->f_id.src_ip6),\n\t\t\t\t            NULL) :\n#endif\n\t\t\t\t    verify_path(src_ip, NULL, args->f_id.fib)));\n\t\t\t\tbreak;\n\n\t\t\tcase O_ANTISPOOF:\n\t\t\t\t/* Outgoing packets automatically pass/match */\n\t\t\t\tif (oif == NULL && hlen > 0 &&\n\t\t\t\t    (  (is_ipv4 && in_localaddr(src_ip))\n#ifdef INET6\n\t\t\t\t    || (is_ipv6 &&\n\t\t\t\t        in6_localaddr(&(args->f_id.src_ip6)))\n#endif\n\t\t\t\t    ))\n\t\t\t\t\tmatch =\n#ifdef INET6\n\t\t\t\t\t    is_ipv6 ? verify_path6(\n\t\t\t\t\t        &(args->f_id.src_ip6),\n\t\t\t\t\t        m->m_pkthdr.rcvif) :\n#endif\n\t\t\t\t\t    verify_path(src_ip,\n\t\t\t\t\t    \tm->m_pkthdr.rcvif,\n\t\t\t\t\t        args->f_id.fib);\n\t\t\t\telse\n\t\t\t\t\tmatch = 1;\n\t\t\t\tbreak;\n\n\t\t\tcase O_IPSEC:\n#ifdef IPSEC\n\t\t\t\tmatch = (m_tag_find(m,\n\t\t\t\t    PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL);\n#endif\n\t\t\t\t/* otherwise no match */\n\t\t\t\tbreak;\n\n#ifdef INET6\n\t\t\tcase O_IP6_SRC:\n\t\t\t\tmatch = is_ipv6 &&\n\t\t\t\t    IN6_ARE_ADDR_EQUAL(&args->f_id.src_ip6,\n\t\t\t\t    &((ipfw_insn_ip6 *)cmd)->addr6);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP6_DST:\n\t\t\t\tmatch = is_ipv6 &&\n\t\t\t\tIN6_ARE_ADDR_EQUAL(&args->f_id.dst_ip6,\n\t\t\t\t    &((ipfw_insn_ip6 *)cmd)->addr6);\n\t\t\t\tbreak;\n\t\t\tcase O_IP6_SRC_MASK:\n\t\t\tcase O_IP6_DST_MASK:\n\t\t\t\tif (is_ipv6) {\n\t\t\t\t\tint i = cmdlen - 1;\n\t\t\t\t\tstruct in6_addr p;\n\t\t\t\t\tstruct in6_addr *d =\n\t\t\t\t\t    &((ipfw_insn_ip6 *)cmd)->addr6;\n\n\t\t\t\t\tfor (; !match && i > 0; d += 2,\n\t\t\t\t\t    i -= F_INSN_SIZE(struct in6_addr)\n\t\t\t\t\t    * 2) {\n\t\t\t\t\t\tp = (cmd->opcode ==\n\t\t\t\t\t\t    O_IP6_SRC_MASK) ?\n\t\t\t\t\t\t    args->f_id.src_ip6:\n\t\t\t\t\t\t    args->f_id.dst_ip6;\n\t\t\t\t\t\tAPPLY_MASK(&p, &d[1]);\n\t\t\t\t\t\tmatch =\n\t\t\t\t\t\t    IN6_ARE_ADDR_EQUAL(&d[0],\n\t\t\t\t\t\t    &p);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase O_FLOW6ID:\n\t\t\t\tmatch = is_ipv6 &&\n\t\t\t\t    flow6id_match(args->f_id.flow_id6,\n\t\t\t\t    (ipfw_insn_u32 *) cmd);\n\t\t\t\tbreak;\n\n\t\t\tcase O_EXT_HDR:\n\t\t\t\tmatch = is_ipv6 &&\n\t\t\t\t    (ext_hd & ((ipfw_insn *) cmd)->arg1);\n\t\t\t\tbreak;\n\n\t\t\tcase O_IP6:\n\t\t\t\tmatch = is_ipv6;\n\t\t\t\tbreak;\n#endif\n\n\t\t\tcase O_IP4:\n\t\t\t\tmatch = is_ipv4;\n\t\t\t\tbreak;\n\n\t\t\tcase O_TAG: {\n\t\t\t\tstruct m_tag *mtag;\n\t\t\t\tuint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?\n\t\t\t\t    tablearg : cmd->arg1;\n\n\t\t\t\t/* Packet is already tagged with this tag? */\n\t\t\t\tmtag = m_tag_locate(m, MTAG_IPFW, tag, NULL);\n\n\t\t\t\t/* We have `untag' action when F_NOT flag is\n\t\t\t\t * present. And we must remove this mtag from\n\t\t\t\t * mbuf and reset `match' to zero (`match' will\n\t\t\t\t * be inversed later).\n\t\t\t\t * Otherwise we should allocate new mtag and\n\t\t\t\t * push it into mbuf.\n\t\t\t\t */\n\t\t\t\tif (cmd->len & F_NOT) { /* `untag' action */\n\t\t\t\t\tif (mtag != NULL)\n\t\t\t\t\t\tm_tag_delete(m, mtag);\n\t\t\t\t\tmatch = 0;\n\t\t\t\t} else if (mtag == NULL) {\n\t\t\t\t\tif ((mtag = m_tag_alloc(MTAG_IPFW,\n\t\t\t\t\t    tag, 0, M_NOWAIT)) != NULL)\n\t\t\t\t\t\tm_tag_prepend(m, mtag);\n\t\t\t\t\tmatch = 1;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase O_FIB: /* try match the specified fib */\n\t\t\t\tif (args->f_id.fib == cmd->arg1)\n\t\t\t\t\tmatch = 1;\n\t\t\t\tbreak;\n\n\t\t\tcase O_TAGGED: {\n\t\t\t\tstruct m_tag *mtag;\n\t\t\t\tuint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?\n\t\t\t\t    tablearg : cmd->arg1;\n\n\t\t\t\tif (cmdlen == 1) {\n\t\t\t\t\tmatch = m_tag_locate(m, MTAG_IPFW,\n\t\t\t\t\t    tag, NULL) != NULL;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t/* we have ranges */\n\t\t\t\tfor (mtag = m_tag_first(m);\n\t\t\t\t    mtag != NULL && !match;\n\t\t\t\t    mtag = m_tag_next(m, mtag)) {\n\t\t\t\t\tuint16_t *p;\n\t\t\t\t\tint i;\n\n\t\t\t\t\tif (mtag->m_tag_cookie != MTAG_IPFW)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tp = ((ipfw_insn_u16 *)cmd)->ports;\n\t\t\t\t\ti = cmdlen - 1;\n\t\t\t\t\tfor(; !match && i > 0; i--, p += 2)\n\t\t\t\t\t\tmatch =\n\t\t\t\t\t\t    mtag->m_tag_id >= p[0] &&\n\t\t\t\t\t\t    mtag->m_tag_id <= p[1];\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t/*\n\t\t\t * The second set of opcodes represents 'actions',\n\t\t\t * i.e. the terminal part of a rule once the packet\n\t\t\t * matches all previous patterns.\n\t\t\t * Typically there is only one action for each rule,\n\t\t\t * and the opcode is stored at the end of the rule\n\t\t\t * (but there are exceptions -- see below).\n\t\t\t *\n\t\t\t * In general, here we set retval and terminate the\n\t\t\t * outer loop (would be a 'break 3' in some language,\n\t\t\t * but we need to set l=0, done=1)\n\t\t\t *\n\t\t\t * Exceptions:\n\t\t\t * O_COUNT and O_SKIPTO actions:\n\t\t\t *   instead of terminating, we jump to the next rule\n\t\t\t *   (setting l=0), or to the SKIPTO target (setting\n\t\t\t *   f/f_len, cmd and l as needed), respectively.\n\t\t\t *\n\t\t\t * O_TAG, O_LOG and O_ALTQ action parameters:\n\t\t\t *   perform some action and set match = 1;\n\t\t\t *\n\t\t\t * O_LIMIT and O_KEEP_STATE: these opcodes are\n\t\t\t *   not real 'actions', and are stored right\n\t\t\t *   before the 'action' part of the rule.\n\t\t\t *   These opcodes try to install an entry in the\n\t\t\t *   state tables; if successful, we continue with\n\t\t\t *   the next opcode (match=1; break;), otherwise\n\t\t\t *   the packet must be dropped (set retval,\n\t\t\t *   break loops with l=0, done=1)\n\t\t\t *\n\t\t\t * O_PROBE_STATE and O_CHECK_STATE: these opcodes\n\t\t\t *   cause a lookup of the state table, and a jump\n\t\t\t *   to the 'action' part of the parent rule\n\t\t\t *   if an entry is found, or\n\t\t\t *   (CHECK_STATE only) a jump to the next rule if\n\t\t\t *   the entry is not found.\n\t\t\t *   The result of the lookup is cached so that\n\t\t\t *   further instances of these opcodes become NOPs.\n\t\t\t *   The jump to the next rule is done by setting\n\t\t\t *   l=0, cmdlen=0.\n\t\t\t */\n\t\t\tcase O_LIMIT:\n\t\t\tcase O_KEEP_STATE:\n\t\t\t\tif (ipfw_install_state(f,\n\t\t\t\t    (ipfw_insn_limit *)cmd, args, tablearg)) {\n\t\t\t\t\t/* error or limit violation */\n\t\t\t\t\tretval = IP_FW_DENY;\n\t\t\t\t\tl = 0;\t/* exit inner loop */\n\t\t\t\t\tdone = 1; /* exit outer loop */\n\t\t\t\t}\n\t\t\t\tmatch = 1;\n\t\t\t\tbreak;\n\n\t\t\tcase O_PROBE_STATE:\n\t\t\tcase O_CHECK_STATE:\n\t\t\t\t/*\n\t\t\t\t * dynamic rules are checked at the first\n\t\t\t\t * keep-state or check-state occurrence,\n\t\t\t\t * with the result being stored in dyn_dir.\n\t\t\t\t * The compiler introduces a PROBE_STATE\n\t\t\t\t * instruction for us when we have a\n\t\t\t\t * KEEP_STATE (because PROBE_STATE needs\n\t\t\t\t * to be run first).\n\t\t\t\t */\n\t\t\t\tif (dyn_dir == MATCH_UNKNOWN &&\n\t\t\t\t    (q = ipfw_lookup_dyn_rule(&args->f_id,\n\t\t\t\t     &dyn_dir, proto == IPPROTO_TCP ?\n\t\t\t\t\tTCP(ulp) : NULL))\n\t\t\t\t\t!= NULL) {\n\t\t\t\t\t/*\n\t\t\t\t\t * Found dynamic entry, update stats\n\t\t\t\t\t * and jump to the 'action' part of\n\t\t\t\t\t * the parent rule by setting\n\t\t\t\t\t * f, cmd, l and clearing cmdlen.\n\t\t\t\t\t */\n\t\t\t\t\tq->pcnt++;\n\t\t\t\t\tq->bcnt += pktlen;\n\t\t\t\t\t/* XXX we would like to have f_pos\n\t\t\t\t\t * readily accessible in the dynamic\n\t\t\t\t         * rule, instead of having to\n\t\t\t\t\t * lookup q->rule.\n\t\t\t\t\t */\n\t\t\t\t\tf = q->rule;\n\t\t\t\t\tf_pos = ipfw_find_rule(chain,\n\t\t\t\t\t\tf->rulenum, f->id);\n\t\t\t\t\tcmd = ACTION_PTR(f);\n\t\t\t\t\tl = f->cmd_len - f->act_ofs;\n\t\t\t\t\tipfw_dyn_unlock();\n\t\t\t\t\tcmdlen = 0;\n\t\t\t\t\tmatch = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t/*\n\t\t\t\t * Dynamic entry not found. If CHECK_STATE,\n\t\t\t\t * skip to next rule, if PROBE_STATE just\n\t\t\t\t * ignore and continue with next opcode.\n\t\t\t\t */\n\t\t\t\tif (cmd->opcode == O_CHECK_STATE)\n\t\t\t\t\tl = 0;\t/* exit inner loop */\n\t\t\t\tmatch = 1;\n\t\t\t\tbreak;\n\n\t\t\tcase O_ACCEPT:\n\t\t\t\tretval = 0;\t/* accept */\n\t\t\t\tl = 0;\t\t/* exit inner loop */\n\t\t\t\tdone = 1;\t/* exit outer loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_PIPE:\n\t\t\tcase O_QUEUE:\n\t\t\t\tset_match(args, f_pos, chain);\n\t\t\t\targs->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ?\n\t\t\t\t\ttablearg : cmd->arg1;\n\t\t\t\tif (cmd->opcode == O_PIPE)\n\t\t\t\t\targs->rule.info |= IPFW_IS_PIPE;\n\t\t\t\tif (V_fw_one_pass)\n\t\t\t\t\targs->rule.info |= IPFW_ONEPASS;\n\t\t\t\tretval = IP_FW_DUMMYNET;\n\t\t\t\tl = 0;          /* exit inner loop */\n\t\t\t\tdone = 1;       /* exit outer loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_DIVERT:\n\t\t\tcase O_TEE:\n\t\t\t\tif (args->eh) /* not on layer 2 */\n\t\t\t\t    break;\n\t\t\t\t/* otherwise this is terminal */\n\t\t\t\tl = 0;\t\t/* exit inner loop */\n\t\t\t\tdone = 1;\t/* exit outer loop */\n\t\t\t\tretval = (cmd->opcode == O_DIVERT) ?\n\t\t\t\t\tIP_FW_DIVERT : IP_FW_TEE;\n\t\t\t\tset_match(args, f_pos, chain);\n\t\t\t\targs->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ?\n\t\t\t\t    tablearg : cmd->arg1;\n\t\t\t\tbreak;\n\n\t\t\tcase O_COUNT:\n\t\t\t\tf->pcnt++;\t/* update stats */\n\t\t\t\tf->bcnt += pktlen;\n\t\t\t\tf->timestamp = time_uptime;\n\t\t\t\tl = 0;\t\t/* exit inner loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_SKIPTO:\n\t\t\t    f->pcnt++;\t/* update stats */\n\t\t\t    f->bcnt += pktlen;\n\t\t\t    f->timestamp = time_uptime;\n\t\t\t    /* If possible use cached f_pos (in f->next_rule),\n\t\t\t     * whose version is written in f->next_rule\n\t\t\t     * (horrible hacks to avoid changing the ABI).\n\t\t\t     */\n\t\t\t    if (cmd->arg1 != IP_FW_TABLEARG &&\n\t\t\t\t    (uintptr_t)f->x_next == chain->id) {\n\t\t\t\tf_pos = (uintptr_t)f->next_rule;\n\t\t\t    } else {\n\t\t\t\tint i = (cmd->arg1 == IP_FW_TABLEARG) ?\n\t\t\t\t\ttablearg : cmd->arg1;\n\t\t\t\t/* make sure we do not jump backward */\n\t\t\t\tif (i <= f->rulenum)\n\t\t\t\t    i = f->rulenum + 1;\n\t\t\t\tf_pos = ipfw_find_rule(chain, i, 0);\n\t\t\t\t/* update the cache */\n\t\t\t\tif (cmd->arg1 != IP_FW_TABLEARG) {\n\t\t\t\t    f->next_rule =\n\t\t\t\t\t(void *)(uintptr_t)f_pos;\n\t\t\t\t    f->x_next =\n\t\t\t\t\t(void *)(uintptr_t)chain->id;\n\t\t\t\t}\n\t\t\t    }\n\t\t\t    /*\n\t\t\t     * Skip disabled rules, and re-enter\n\t\t\t     * the inner loop with the correct\n\t\t\t     * f_pos, f, l and cmd.\n\t\t\t     * Also clear cmdlen and skip_or\n\t\t\t     */\n\t\t\t    for (; f_pos < chain->n_rules - 1 &&\n\t\t\t\t    (V_set_disable &\n\t\t\t\t     (1 << chain->map[f_pos]->set));\n\t\t\t\t    f_pos++)\n\t\t\t\t;\n\t\t\t    /* Re-enter the inner loop at the skipto rule. */\n\t\t\t    f = chain->map[f_pos];\n\t\t\t    l = f->cmd_len;\n\t\t\t    cmd = f->cmd;\n\t\t\t    match = 1;\n\t\t\t    cmdlen = 0;\n\t\t\t    skip_or = 0;\n\t\t\t    continue;\n\t\t\t    break;\t/* not reached */\n\n\t\t\tcase O_REJECT:\n\t\t\t\t/*\n\t\t\t\t * Drop the packet and send a reject notice\n\t\t\t\t * if the packet is not ICMP (or is an ICMP\n\t\t\t\t * query), and it is not multicast/broadcast.\n\t\t\t\t */\n\t\t\t\tif (hlen > 0 && is_ipv4 && offset == 0 &&\n\t\t\t\t    (proto != IPPROTO_ICMP ||\n\t\t\t\t     is_icmp_query(ICMP(ulp))) &&\n\t\t\t\t    !(m->m_flags & (M_BCAST|M_MCAST)) &&\n\t\t\t\t    !IN_MULTICAST(ntohl(dst_ip.s_addr))) {\n\t\t\t\t\tsend_reject(args, cmd->arg1, iplen, ip);\n\t\t\t\t\tm = args->m;\n\t\t\t\t}\n\t\t\t\t/* FALLTHROUGH */\n#ifdef INET6\n\t\t\tcase O_UNREACH6:\n\t\t\t\tif (hlen > 0 && is_ipv6 &&\n\t\t\t\t    ((offset & IP6F_OFF_MASK) == 0) &&\n\t\t\t\t    (proto != IPPROTO_ICMPV6 ||\n\t\t\t\t     (is_icmp6_query(icmp6_type) == 1)) &&\n\t\t\t\t    !(m->m_flags & (M_BCAST|M_MCAST)) &&\n\t\t\t\t    !IN6_IS_ADDR_MULTICAST(&args->f_id.dst_ip6)) {\n\t\t\t\t\tsend_reject6(\n\t\t\t\t\t    args, cmd->arg1, hlen,\n\t\t\t\t\t    (struct ip6_hdr *)ip);\n\t\t\t\t\tm = args->m;\n\t\t\t\t}\n\t\t\t\t/* FALLTHROUGH */\n#endif\n\t\t\tcase O_DENY:\n\t\t\t\tretval = IP_FW_DENY;\n\t\t\t\tl = 0;\t\t/* exit inner loop */\n\t\t\t\tdone = 1;\t/* exit outer loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_FORWARD_IP:\n\t\t\t\tif (args->eh)\t/* not valid on layer2 pkts */\n\t\t\t\t\tbreak;\n\t\t\t\tif (!q || dyn_dir == MATCH_FORWARD) {\n\t\t\t\t    struct sockaddr_in *sa;\n\t\t\t\t    sa = &(((ipfw_insn_sa *)cmd)->sa);\n\t\t\t\t    if (sa->sin_addr.s_addr == INADDR_ANY) {\n\t\t\t\t\tbcopy(sa, &args->hopstore,\n\t\t\t\t\t\t\tsizeof(*sa));\n\t\t\t\t\targs->hopstore.sin_addr.s_addr =\n\t\t\t\t\t\t    htonl(tablearg);\n\t\t\t\t\targs->next_hop = &args->hopstore;\n\t\t\t\t    } else {\n\t\t\t\t\targs->next_hop = sa;\n\t\t\t\t    }\n\t\t\t\t}\n\t\t\t\tretval = IP_FW_PASS;\n\t\t\t\tl = 0;          /* exit inner loop */\n\t\t\t\tdone = 1;       /* exit outer loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_NETGRAPH:\n\t\t\tcase O_NGTEE:\n\t\t\t\tset_match(args, f_pos, chain);\n\t\t\t\targs->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ?\n\t\t\t\t\ttablearg : cmd->arg1;\n\t\t\t\tif (V_fw_one_pass)\n\t\t\t\t\targs->rule.info |= IPFW_ONEPASS;\n\t\t\t\tretval = (cmd->opcode == O_NETGRAPH) ?\n\t\t\t\t    IP_FW_NETGRAPH : IP_FW_NGTEE;\n\t\t\t\tl = 0;          /* exit inner loop */\n\t\t\t\tdone = 1;       /* exit outer loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_SETFIB:\n\t\t\t\tf->pcnt++;\t/* update stats */\n\t\t\t\tf->bcnt += pktlen;\n\t\t\t\tf->timestamp = time_uptime;\n\t\t\t\tM_SETFIB(m, cmd->arg1);\n\t\t\t\targs->f_id.fib = cmd->arg1;\n\t\t\t\tl = 0;\t\t/* exit inner loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_NAT:\n \t\t\t\tif (!IPFW_NAT_LOADED) {\n\t\t\t\t    retval = IP_FW_DENY;\n\t\t\t\t} else {\n\t\t\t\t    struct cfg_nat *t;\n\t\t\t\t    int nat_id;\n\n\t\t\t\t    set_match(args, f_pos, chain);\n\t\t\t\t    t = ((ipfw_insn_nat *)cmd)->nat;\n\t\t\t\t    if (t == NULL) {\n\t\t\t\t\tnat_id = (cmd->arg1 == IP_FW_TABLEARG) ?\n\t\t\t\t\t\ttablearg : cmd->arg1;\n\t\t\t\t\tt = (*lookup_nat_ptr)(&chain->nat, nat_id);\n\n\t\t\t\t\tif (t == NULL) {\n\t\t\t\t\t    retval = IP_FW_DENY;\n\t\t\t\t\t    l = 0;\t/* exit inner loop */\n\t\t\t\t\t    done = 1;\t/* exit outer loop */\n\t\t\t\t\t    break;\n\t\t\t\t\t}\n\t\t\t\t\tif (cmd->arg1 != IP_FW_TABLEARG)\n\t\t\t\t\t    ((ipfw_insn_nat *)cmd)->nat = t;\n\t\t\t\t    }\n\t\t\t\t    retval = ipfw_nat_ptr(args, t, m);\n\t\t\t\t}\n\t\t\t\tl = 0;          /* exit inner loop */\n\t\t\t\tdone = 1;       /* exit outer loop */\n\t\t\t\tbreak;\n\n\t\t\tcase O_REASS: {\n\t\t\t\tint ip_off;\n\n\t\t\t\tf->pcnt++;\n\t\t\t\tf->bcnt += pktlen;\n\t\t\t\tl = 0;\t/* in any case exit inner loop */\n\t\t\t\tip_off = ntohs(ip->ip_off);\n\n\t\t\t\t/* if not fragmented, go to next rule */\n\t\t\t\tif ((ip_off & (IP_MF | IP_OFFMASK)) == 0)\n\t\t\t\t    break;\n\t\t\t\t/* \n\t\t\t\t * ip_reass() expects len & off in host\n\t\t\t\t * byte order.\n\t\t\t\t */\n\t\t\t\tSET_HOST_IPLEN(ip);\n\n\t\t\t\targs->m = m = ip_reass(m);\n\n\t\t\t\t/*\n\t\t\t\t * do IP header checksum fixup.\n\t\t\t\t */\n\t\t\t\tif (m == NULL) { /* fragment got swallowed */\n\t\t\t\t    retval = IP_FW_DENY;\n\t\t\t\t} else { /* good, packet complete */\n\t\t\t\t    int hlen;\n\n\t\t\t\t    ip = mtod(m, struct ip *);\n\t\t\t\t    hlen = ip->ip_hl << 2;\n\t\t\t\t    SET_NET_IPLEN(ip);\n\t\t\t\t    ip->ip_sum = 0;\n\t\t\t\t    if (hlen == sizeof(struct ip))\n\t\t\t\t\tip->ip_sum = in_cksum_hdr(ip);\n\t\t\t\t    else\n\t\t\t\t\tip->ip_sum = in_cksum(m, hlen);\n\t\t\t\t    retval = IP_FW_REASS;\n\t\t\t\t    set_match(args, f_pos, chain);\n\t\t\t\t}\n\t\t\t\tdone = 1;\t/* exit outer loop */\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tpanic(\"-- unknown opcode %d\\n\", cmd->opcode);\n\t\t\t} /* end of switch() on opcodes */\n\t\t\t/*\n\t\t\t * if we get here with l=0, then match is irrelevant.\n\t\t\t */\n\n\t\t\tif (cmd->len & F_NOT)\n\t\t\t\tmatch = !match;\n\n\t\t\tif (match) {\n\t\t\t\tif (cmd->len & F_OR)\n\t\t\t\t\tskip_or = 1;\n\t\t\t} else {\n\t\t\t\tif (!(cmd->len & F_OR)) /* not an OR block, */\n\t\t\t\t\tbreak;\t\t/* try next rule    */\n\t\t\t}\n\n\t\t}\t/* end of inner loop, scan opcodes */\n\n\t\tif (done)\n\t\t\tbreak;\n\n/* next_rule:; */\t/* try next rule\t\t*/\n\n\t}\t\t/* end of outer for, scan rules */\n\n\tif (done) {\n\t\tstruct ip_fw *rule = chain->map[f_pos];\n\t\t/* Update statistics */\n\t\trule->pcnt++;\n\t\trule->bcnt += pktlen;\n\t\trule->timestamp = time_uptime;\n\t} else {\n\t\tretval = IP_FW_DENY;\n\t\tprintf(\"ipfw: ouch!, skip past end of rules, denying packet\\n\");\n\t}\n\tIPFW_RUNLOCK(chain);\n#ifdef __FreeBSD__\n\tif (ucred_cache != NULL)\n\t\tcrfree(ucred_cache);\n#endif\n\treturn (retval);\n\npullup_failed:\n\tif (V_fw_verbose)\n\t\tprintf(\"ipfw: pullup failed\\n\");\n\treturn (IP_FW_DENY);\n}\n\n/*\n * Module and VNET glue\n */\n\n/*\n * Stuff that must be initialised only on boot or module load\n */\nstatic int\nipfw_init(void)\n{\n\tint error = 0;\n\n\tipfw_dyn_attach();\n\t/*\n \t * Only print out this stuff the first time around,\n\t * when called from the sysinit code.\n\t */\n\tprintf(\"ipfw2 \"\n#ifdef INET6\n\t\t\"(+ipv6) \"\n#endif\n\t\t\"initialized, divert %s, nat %s, \"\n\t\t\"rule-based forwarding \"\n#ifdef IPFIREWALL_FORWARD\n\t\t\"enabled, \"\n#else\n\t\t\"disabled, \"\n#endif\n\t\t\"default to %s, logging \",\n#ifdef IPDIVERT\n\t\t\"enabled\",\n#else\n\t\t\"loadable\",\n#endif\n#ifdef IPFIREWALL_NAT\n\t\t\"enabled\",\n#else\n\t\t\"loadable\",\n#endif\n\t\tdefault_to_accept ? \"accept\" : \"deny\");\n\n\t/*\n\t * Note: V_xxx variables can be accessed here but the vnet specific\n\t * initializer may not have been called yet for the VIMAGE case.\n\t * Tuneables will have been processed. We will print out values for\n\t * the default vnet. \n\t * XXX This should all be rationalized AFTER 8.0\n\t */\n\tif (V_fw_verbose == 0)\n\t\tprintf(\"disabled\\n\");\n\telse if (V_verbose_limit == 0)\n\t\tprintf(\"unlimited\\n\");\n\telse\n\t\tprintf(\"limited to %d packets/entry by default\\n\",\n\t\t    V_verbose_limit);\n\n\tipfw_log_bpf(1); /* init */\n\treturn (error);\n}\n\n/*\n * Called for the removal of the last instance only on module unload.\n */\nstatic void\nipfw_destroy(void)\n{\n\n\tipfw_log_bpf(0); /* uninit */\n\tipfw_dyn_detach();\n\tprintf(\"IP firewall unloaded\\n\");\n}\n\n/*\n * Stuff that must be initialized for every instance\n * (including the first of course).\n */\nstatic int\nvnet_ipfw_init(const void *unused)\n{\n\tint error;\n\tstruct ip_fw *rule = NULL;\n\tstruct ip_fw_chain *chain;\n\n\tchain = &V_layer3_chain;\n\n\t/* First set up some values that are compile time options */\n\tV_autoinc_step = 100;\t/* bounded to 1..1000 in add_rule() */\n\tV_fw_deny_unknown_exthdrs = 1;\n#ifdef IPFIREWALL_VERBOSE\n\tV_fw_verbose = 1;\n#endif\n#ifdef IPFIREWALL_VERBOSE_LIMIT\n\tV_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;\n#endif\n#ifdef IPFIREWALL_NAT\n\tLIST_INIT(&chain->nat);\n#endif\n\n\t/* insert the default rule and create the initial map */\n\tchain->n_rules = 1;\n\tchain->static_len = sizeof(struct ip_fw);\n\tchain->map = malloc(sizeof(struct ip_fw *), M_IPFW, M_NOWAIT | M_ZERO);\n\tif (chain->map)\n\t\trule = malloc(chain->static_len, M_IPFW, M_NOWAIT | M_ZERO);\n\tif (rule == NULL) {\n\t\tif (chain->map)\n\t\t\tfree(chain->map, M_IPFW);\n\t\tprintf(\"ipfw2: ENOSPC initializing default rule \"\n\t\t\t\"(support disabled)\\n\");\n\t\treturn (ENOSPC);\n\t}\n\terror = ipfw_init_tables(chain);\n\tif (error) {\n\t\tpanic(\"init_tables\"); /* XXX Marko fix this ! */\n\t}\n\n\t/* fill and insert the default rule */\n\trule->act_ofs = 0;\n\trule->rulenum = IPFW_DEFAULT_RULE;\n\trule->cmd_len = 1;\n\trule->set = RESVD_SET;\n\trule->cmd[0].len = 1;\n\trule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY;\n\tchain->rules = chain->default_rule = chain->map[0] = rule;\n\tchain->id = rule->id = 1;\n\n\tIPFW_LOCK_INIT(chain);\n\tipfw_dyn_init();\n\n\t/* First set up some values that are compile time options */\n\tV_ipfw_vnet_ready = 1;\t\t/* Open for business */\n\n\t/*\n\t * Hook the sockopt handler, and the layer2 (V_ip_fw_chk_ptr)\n\t * and pfil hooks for ipv4 and ipv6. Even if the latter two fail\n\t * we still keep the module alive because the sockopt and\n\t * layer2 paths are still useful.\n\t * ipfw[6]_hook return 0 on success, ENOENT on failure,\n\t * so we can ignore the exact return value and just set a flag.\n\t *\n\t * Note that V_fw[6]_enable are manipulated by a SYSCTL_PROC so\n\t * changes in the underlying (per-vnet) variables trigger\n\t * immediate hook()/unhook() calls.\n\t * In layer2 we have the same behaviour, except that V_ether_ipfw\n\t * is checked on each packet because there are no pfil hooks.\n\t */\n\tV_ip_fw_ctl_ptr = ipfw_ctl;\n\tV_ip_fw_chk_ptr = ipfw_chk;\n\terror = ipfw_attach_hooks(1);\n\treturn (error);\n}\n\n/*\n * Called for the removal of each instance.\n */\nstatic int\nvnet_ipfw_uninit(const void *unused)\n{\n\tstruct ip_fw *reap, *rule;\n\tstruct ip_fw_chain *chain = &V_layer3_chain;\n\tint i;\n\n\tV_ipfw_vnet_ready = 0; /* tell new callers to go away */\n\t/*\n\t * disconnect from ipv4, ipv6, layer2 and sockopt.\n\t * Then grab, release and grab again the WLOCK so we make\n\t * sure the update is propagated and nobody will be in.\n\t */\n\t(void)ipfw_attach_hooks(0 /* detach */);\n\tV_ip_fw_chk_ptr = NULL;\n\tV_ip_fw_ctl_ptr = NULL;\n\tIPFW_UH_WLOCK(chain);\n\tIPFW_UH_WUNLOCK(chain);\n\tIPFW_UH_WLOCK(chain);\n\n\tIPFW_WLOCK(chain);\n\tIPFW_WUNLOCK(chain);\n\tIPFW_WLOCK(chain);\n\n\tipfw_dyn_uninit(0);\t/* run the callout_drain */\n\tipfw_destroy_tables(chain);\n\treap = NULL;\n\tfor (i = 0; i < chain->n_rules; i++) {\n\t\trule = chain->map[i];\n\t\trule->x_next = reap;\n\t\treap = rule;\n\t}\n\tif (chain->map)\n\t\tfree(chain->map, M_IPFW);\n\tIPFW_WUNLOCK(chain);\n\tIPFW_UH_WUNLOCK(chain);\n\tif (reap != NULL)\n\t\tipfw_reap_rules(reap);\n\tIPFW_LOCK_DESTROY(chain);\n\tipfw_dyn_uninit(1);\t/* free the remaining parts */\n\treturn 0;\n}\n\n/*\n * Module event handler.\n * In general we have the choice of handling most of these events by the\n * event handler or by the (VNET_)SYS(UN)INIT handlers. I have chosen to\n * use the SYSINIT handlers as they are more capable of expressing the\n * flow of control during module and vnet operations, so this is just\n * a skeleton. Note there is no SYSINIT equivalent of the module\n * SHUTDOWN handler, but we don't have anything to do in that case anyhow.\n */\nstatic int\nipfw_modevent(module_t mod, int type, void *unused)\n{\n\tint err = 0;\n\n\tswitch (type) {\n\tcase MOD_LOAD:\n\t\t/* Called once at module load or\n\t \t * system boot if compiled in. */\n\t\tbreak;\n\tcase MOD_QUIESCE:\n\t\t/* Called before unload. May veto unloading. */\n\t\tbreak;\n\tcase MOD_UNLOAD:\n\t\t/* Called during unload. */\n\t\tbreak;\n\tcase MOD_SHUTDOWN:\n\t\t/* Called during system shutdown. */\n\t\tbreak;\n\tdefault:\n\t\terr = EOPNOTSUPP;\n\t\tbreak;\n\t}\n\treturn err;\n}\n\nstatic moduledata_t ipfwmod = {\n\t\"ipfw\",\n\tipfw_modevent,\n\t0\n};\n\n/* Define startup order. */\n#define\tIPFW_SI_SUB_FIREWALL\tSI_SUB_PROTO_IFATTACHDOMAIN\n#define\tIPFW_MODEVENT_ORDER\t(SI_ORDER_ANY - 255) /* On boot slot in here. */\n#define\tIPFW_MODULE_ORDER\t(IPFW_MODEVENT_ORDER + 1) /* A little later. */\n#define\tIPFW_VNET_ORDER\t\t(IPFW_MODEVENT_ORDER + 2) /* Later still. */\n\nDECLARE_MODULE(ipfw, ipfwmod, IPFW_SI_SUB_FIREWALL, IPFW_MODEVENT_ORDER);\nMODULE_VERSION(ipfw, 2);\n/* should declare some dependencies here */\n\n/*\n * Starting up. Done in order after ipfwmod() has been called.\n * VNET_SYSINIT is also called for each existing vnet and each new vnet.\n */\nSYSINIT(ipfw_init, IPFW_SI_SUB_FIREWALL, IPFW_MODULE_ORDER,\n\t    ipfw_init, NULL);\nVNET_SYSINIT(vnet_ipfw_init, IPFW_SI_SUB_FIREWALL, IPFW_VNET_ORDER,\n\t    vnet_ipfw_init, NULL);\n \n/*\n * Closing up shop. These are done in REVERSE ORDER, but still\n * after ipfwmod() has been called. Not called on reboot.\n * VNET_SYSUNINIT is also called for each exiting vnet as it exits.\n * or when the module is unloaded.\n */\nSYSUNINIT(ipfw_destroy, IPFW_SI_SUB_FIREWALL, IPFW_MODULE_ORDER,\n\t    ipfw_destroy, NULL);\nVNET_SYSUNINIT(vnet_ipfw_uninit, IPFW_SI_SUB_FIREWALL, IPFW_VNET_ORDER,\n\t    vnet_ipfw_uninit, NULL);\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_dynamic.c",
    "content": "/*-\n * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: head/sys/netinet/ipfw/ip_fw_dynamic.c 200601 2009-12-16 10:48:40Z luigi $\");\n\n#define        DEB(x)\n#define        DDB(x) x\n\n/*\n * Dynamic rule support for ipfw\n */\n\n#if !defined(KLD_MODULE)\n#include \"opt_ipfw.h\"\n#include \"opt_ipdivert.h\"\n#include \"opt_ipdn.h\"\n#include \"opt_inet.h\"\n#ifndef INET\n#error IPFIREWALL requires INET.\n#endif /* INET */\n#endif\n#include \"opt_inet6.h\"\n#include \"opt_ipsec.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/mbuf.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/socket.h>\n#include <sys/sysctl.h>\n#include <sys/syslog.h>\n#include <net/ethernet.h> /* for ETHERTYPE_IP */\n#include <net/if.h>\n#include <net/vnet.h>\n\n#include <netinet/in.h>\n#include <netinet/ip.h>\n#include <netinet/ip_var.h>\t/* ip_defttl */\n#include <netinet/ip_fw.h>\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netinet/tcp_var.h>\n#include <netinet/udp.h>\n\n#include <netinet/ip6.h>\t/* IN6_ARE_ADDR_EQUAL */\n#ifdef INET6\n#include <netinet6/in6_var.h>\n#include <netinet6/ip6_var.h>\n#endif\n\n#include <machine/in_cksum.h>\t/* XXX for in_cksum */\n\n#ifdef MAC\n#include <security/mac/mac_framework.h>\n#endif\n\n/*\n * Description of dynamic rules.\n *\n * Dynamic rules are stored in lists accessed through a hash table\n * (ipfw_dyn_v) whose size is curr_dyn_buckets. This value can\n * be modified through the sysctl variable dyn_buckets which is\n * updated when the table becomes empty.\n *\n * XXX currently there is only one list, ipfw_dyn.\n *\n * When a packet is received, its address fields are first masked\n * with the mask defined for the rule, then hashed, then matched\n * against the entries in the corresponding list.\n * Dynamic rules can be used for different purposes:\n *  + stateful rules;\n *  + enforcing limits on the number of sessions;\n *  + in-kernel NAT (not implemented yet)\n *\n * The lifetime of dynamic rules is regulated by dyn_*_lifetime,\n * measured in seconds and depending on the flags.\n *\n * The total number of dynamic rules is stored in dyn_count.\n * The max number of dynamic rules is dyn_max. When we reach\n * the maximum number of rules we do not create anymore. This is\n * done to avoid consuming too much memory, but also too much\n * time when searching on each packet (ideally, we should try instead\n * to put a limit on the length of the list on each bucket...).\n *\n * Each dynamic rule holds a pointer to the parent ipfw rule so\n * we know what action to perform. Dynamic rules are removed when\n * the parent rule is deleted. XXX we should make them survive.\n *\n * There are some limitations with dynamic rules -- we do not\n * obey the 'randomized match', and we do not do multiple\n * passes through the firewall. XXX check the latter!!!\n */\n\n/*\n * Static variables followed by global ones\n */\nstatic VNET_DEFINE(ipfw_dyn_rule **, ipfw_dyn_v);\nstatic VNET_DEFINE(u_int32_t, dyn_buckets);\nstatic VNET_DEFINE(u_int32_t, curr_dyn_buckets);\nstatic VNET_DEFINE(struct callout, ipfw_timeout);\n#define\tV_ipfw_dyn_v\t\t\tVNET(ipfw_dyn_v)\n#define\tV_dyn_buckets\t\t\tVNET(dyn_buckets)\n#define\tV_curr_dyn_buckets\t\tVNET(curr_dyn_buckets)\n#define V_ipfw_timeout                  VNET(ipfw_timeout)\n\nstatic uma_zone_t ipfw_dyn_rule_zone;\n#ifndef __FreeBSD__\nDEFINE_SPINLOCK(ipfw_dyn_mtx);\n#else\nstatic struct mtx ipfw_dyn_mtx;\t\t/* mutex guarding dynamic rules */\n#endif\n\n#define\tIPFW_DYN_LOCK_INIT() \\\n\tmtx_init(&ipfw_dyn_mtx, \"IPFW dynamic rules\", NULL, MTX_DEF)\n#define\tIPFW_DYN_LOCK_DESTROY()\tmtx_destroy(&ipfw_dyn_mtx)\n#define\tIPFW_DYN_LOCK()\t\tmtx_lock(&ipfw_dyn_mtx)\n#define\tIPFW_DYN_UNLOCK()\tmtx_unlock(&ipfw_dyn_mtx)\n#define\tIPFW_DYN_LOCK_ASSERT()\tmtx_assert(&ipfw_dyn_mtx, MA_OWNED)\n\nvoid\nipfw_dyn_unlock(void)\n{\n\tIPFW_DYN_UNLOCK();\n}\n\n/*\n * Timeouts for various events in handing dynamic rules.\n */\nstatic VNET_DEFINE(u_int32_t, dyn_ack_lifetime);\nstatic VNET_DEFINE(u_int32_t, dyn_syn_lifetime);\nstatic VNET_DEFINE(u_int32_t, dyn_fin_lifetime);\nstatic VNET_DEFINE(u_int32_t, dyn_rst_lifetime);\nstatic VNET_DEFINE(u_int32_t, dyn_udp_lifetime);\nstatic VNET_DEFINE(u_int32_t, dyn_short_lifetime);\n\n#define\tV_dyn_ack_lifetime\t\tVNET(dyn_ack_lifetime)\n#define\tV_dyn_syn_lifetime\t\tVNET(dyn_syn_lifetime)\n#define\tV_dyn_fin_lifetime\t\tVNET(dyn_fin_lifetime)\n#define\tV_dyn_rst_lifetime\t\tVNET(dyn_rst_lifetime)\n#define\tV_dyn_udp_lifetime\t\tVNET(dyn_udp_lifetime)\n#define\tV_dyn_short_lifetime\t\tVNET(dyn_short_lifetime)\n\n/*\n * Keepalives are sent if dyn_keepalive is set. They are sent every\n * dyn_keepalive_period seconds, in the last dyn_keepalive_interval\n * seconds of lifetime of a rule.\n * dyn_rst_lifetime and dyn_fin_lifetime should be strictly lower\n * than dyn_keepalive_period.\n */\n\nstatic VNET_DEFINE(u_int32_t, dyn_keepalive_interval);\nstatic VNET_DEFINE(u_int32_t, dyn_keepalive_period);\nstatic VNET_DEFINE(u_int32_t, dyn_keepalive);\n\n#define\tV_dyn_keepalive_interval\tVNET(dyn_keepalive_interval)\n#define\tV_dyn_keepalive_period\t\tVNET(dyn_keepalive_period)\n#define\tV_dyn_keepalive\t\t\tVNET(dyn_keepalive)\n\nstatic VNET_DEFINE(u_int32_t, dyn_count);\t/* # of dynamic rules */\nstatic VNET_DEFINE(u_int32_t, dyn_max);\t\t/* max # of dynamic rules */\n\n#define\tV_dyn_count\t\t\tVNET(dyn_count)\n#define\tV_dyn_max\t\t\tVNET(dyn_max)\n\n#ifdef SYSCTL_NODE\n\nSYSBEGIN(f2)\n\nSYSCTL_DECL(_net_inet_ip_fw);\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_buckets,\n    CTLFLAG_RW, &VNET_NAME(dyn_buckets), 0,\n    \"Number of dyn. buckets\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets,\n    CTLFLAG_RD, &VNET_NAME(curr_dyn_buckets), 0,\n    \"Current Number of dyn. buckets\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_count,\n    CTLFLAG_RD, &VNET_NAME(dyn_count), 0,\n    \"Number of dyn. rules\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_max,\n    CTLFLAG_RW, &VNET_NAME(dyn_max), 0,\n    \"Max number of dyn. rules\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime,\n    CTLFLAG_RW, &VNET_NAME(dyn_ack_lifetime), 0,\n    \"Lifetime of dyn. rules for acks\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_syn_lifetime,\n    CTLFLAG_RW, &VNET_NAME(dyn_syn_lifetime), 0,\n    \"Lifetime of dyn. rules for syn\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_fin_lifetime,\n    CTLFLAG_RW, &VNET_NAME(dyn_fin_lifetime), 0,\n    \"Lifetime of dyn. rules for fin\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_rst_lifetime,\n    CTLFLAG_RW, &VNET_NAME(dyn_rst_lifetime), 0,\n    \"Lifetime of dyn. rules for rst\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_udp_lifetime,\n    CTLFLAG_RW, &VNET_NAME(dyn_udp_lifetime), 0,\n    \"Lifetime of dyn. rules for UDP\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime,\n    CTLFLAG_RW, &VNET_NAME(dyn_short_lifetime), 0,\n    \"Lifetime of dyn. rules for other situations\");\nSYSCTL_VNET_UINT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive,\n    CTLFLAG_RW, &VNET_NAME(dyn_keepalive), 0,\n    \"Enable keepalives for dyn. rules\");\n\nSYSEND\n\n#endif /* SYSCTL_NODE */\n\n\nstatic __inline int\nhash_packet6(struct ipfw_flow_id *id)\n{\n\tu_int32_t i;\n\ti = (id->dst_ip6.__u6_addr.__u6_addr32[2]) ^\n\t    (id->dst_ip6.__u6_addr.__u6_addr32[3]) ^\n\t    (id->src_ip6.__u6_addr.__u6_addr32[2]) ^\n\t    (id->src_ip6.__u6_addr.__u6_addr32[3]) ^\n\t    (id->dst_port) ^ (id->src_port);\n\treturn i;\n}\n\n/*\n * IMPORTANT: the hash function for dynamic rules must be commutative\n * in source and destination (ip,port), because rules are bidirectional\n * and we want to find both in the same bucket.\n */\nstatic __inline int\nhash_packet(struct ipfw_flow_id *id)\n{\n\tu_int32_t i;\n\n#ifdef INET6\n\tif (IS_IP6_FLOW_ID(id)) \n\t\ti = hash_packet6(id);\n\telse\n#endif /* INET6 */\n\ti = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);\n\ti &= (V_curr_dyn_buckets - 1);\n\treturn i;\n}\n\nstatic __inline void\nunlink_dyn_rule_print(struct ipfw_flow_id *id)\n{\n\tstruct in_addr da;\n#ifdef INET6\n\tchar src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];\n#else\n\tchar src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];\n#endif\n\n#ifdef INET6\n\tif (IS_IP6_FLOW_ID(id)) {\n\t\tip6_sprintf(src, &id->src_ip6);\n\t\tip6_sprintf(dst, &id->dst_ip6);\n\t} else\n#endif\n\t{\n\t\tda.s_addr = htonl(id->src_ip);\n\t\tinet_ntoa_r(da, src);\n\t\tda.s_addr = htonl(id->dst_ip);\n\t\tinet_ntoa_r(da, dst);\n\t}\n\tprintf(\"ipfw: unlink entry %s %d -> %s %d, %d left\\n\",\n\t    src, id->src_port, dst, id->dst_port, V_dyn_count - 1);\n}\n\n/**\n * unlink a dynamic rule from a chain. prev is a pointer to\n * the previous one, q is a pointer to the rule to delete,\n * head is a pointer to the head of the queue.\n * Modifies q and potentially also head.\n */\n#define UNLINK_DYN_RULE(prev, head, q) {\t\t\t\t\\\n\tipfw_dyn_rule *old_q = q;\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\t/* remove a refcount to the parent */\t\t\t\t\\\n\tif (q->dyn_type == O_LIMIT)\t\t\t\t\t\\\n\t\tq->parent->count--;\t\t\t\t\t\\\n\tDEB(unlink_dyn_rule_print(&q->id);)\t\t\t\t\\\n\tif (prev != NULL)\t\t\t\t\t\t\\\n\t\tprev->next = q = q->next;\t\t\t\t\\\n\telse\t\t\t\t\t\t\t\t\\\n\t\thead = q = q->next;\t\t\t\t\t\\\n\tV_dyn_count--;\t\t\t\t\t\t\t\\\n\tuma_zfree(ipfw_dyn_rule_zone, old_q); }\n\n#define TIME_LEQ(a,b)       ((int)((a)-(b)) <= 0)\n\n/**\n * Remove dynamic rules pointing to \"rule\", or all of them if rule == NULL.\n *\n * If keep_me == NULL, rules are deleted even if not expired,\n * otherwise only expired rules are removed.\n *\n * The value of the second parameter is also used to point to identify\n * a rule we absolutely do not want to remove (e.g. because we are\n * holding a reference to it -- this is the case with O_LIMIT_PARENT\n * rules). The pointer is only used for comparison, so any non-null\n * value will do.\n */\nstatic void\nremove_dyn_rule(struct ip_fw *rule, ipfw_dyn_rule *keep_me)\n{\n\tstatic u_int32_t last_remove = 0;\n\n#define FORCE (keep_me == NULL)\n\n\tipfw_dyn_rule *prev, *q;\n\tint i, pass = 0, max_pass = 0;\n\n\tIPFW_DYN_LOCK_ASSERT();\n\n\tif (V_ipfw_dyn_v == NULL || V_dyn_count == 0)\n\t\treturn;\n\t/* do not expire more than once per second, it is useless */\n\tif (!FORCE && last_remove == time_uptime)\n\t\treturn;\n\tlast_remove = time_uptime;\n\n\t/*\n\t * because O_LIMIT refer to parent rules, during the first pass only\n\t * remove child and mark any pending LIMIT_PARENT, and remove\n\t * them in a second pass.\n\t */\nnext_pass:\n\tfor (i = 0 ; i < V_curr_dyn_buckets ; i++) {\n\t\tfor (prev=NULL, q = V_ipfw_dyn_v[i] ; q ; ) {\n\t\t\t/*\n\t\t\t * Logic can become complex here, so we split tests.\n\t\t\t */\n\t\t\tif (q == keep_me)\n\t\t\t\tgoto next;\n\t\t\tif (rule != NULL && rule != q->rule)\n\t\t\t\tgoto next; /* not the one we are looking for */\n\t\t\tif (q->dyn_type == O_LIMIT_PARENT) {\n\t\t\t\t/*\n\t\t\t\t * handle parent in the second pass,\n\t\t\t\t * record we need one.\n\t\t\t\t */\n\t\t\t\tmax_pass = 1;\n\t\t\t\tif (pass == 0)\n\t\t\t\t\tgoto next;\n\t\t\t\tif (FORCE && q->count != 0 ) {\n\t\t\t\t\t/* XXX should not happen! */\n\t\t\t\t\tprintf(\"ipfw: OUCH! cannot remove rule,\"\n\t\t\t\t\t     \" count %d\\n\", q->count);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (!FORCE &&\n\t\t\t\t    !TIME_LEQ( q->expire, time_uptime ))\n\t\t\t\t\tgoto next;\n\t\t\t}\n             if (q->dyn_type != O_LIMIT_PARENT || !q->count) {\n                     UNLINK_DYN_RULE(prev, V_ipfw_dyn_v[i], q);\n                     continue;\n             }\nnext:\n\t\t\tprev=q;\n\t\t\tq=q->next;\n\t\t}\n\t}\n\tif (pass++ < max_pass)\n\t\tgoto next_pass;\n}\n\nvoid\nipfw_remove_dyn_children(struct ip_fw *rule)\n{\n\tIPFW_DYN_LOCK();\n\tremove_dyn_rule(rule, NULL /* force removal */);\n\tIPFW_DYN_UNLOCK();\n}\n\n/**\n * lookup a dynamic rule, locked version\n */\nstatic ipfw_dyn_rule *\nlookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int *match_direction,\n    struct tcphdr *tcp)\n{\n\t/*\n\t * stateful ipfw extensions.\n\t * Lookup into dynamic session queue\n\t */\n#define MATCH_REVERSE\t0\n#define MATCH_FORWARD\t1\n#define MATCH_NONE\t2\n#define MATCH_UNKNOWN\t3\n\tint i, dir = MATCH_NONE;\n\tipfw_dyn_rule *prev, *q=NULL;\n\n\tIPFW_DYN_LOCK_ASSERT();\n\n\tif (V_ipfw_dyn_v == NULL)\n\t\tgoto done;\t/* not found */\n\ti = hash_packet( pkt );\n\tfor (prev=NULL, q = V_ipfw_dyn_v[i] ; q != NULL ; ) {\n\t\tif (q->dyn_type == O_LIMIT_PARENT && q->count)\n\t\t\tgoto next;\n\t\tif (TIME_LEQ( q->expire, time_uptime)) { /* expire entry */\n\t\t\tUNLINK_DYN_RULE(prev, V_ipfw_dyn_v[i], q);\n\t\t\tcontinue;\n\t\t}\n\t\tif (pkt->proto == q->id.proto &&\n\t\t    q->dyn_type != O_LIMIT_PARENT) {\n\t\t\tif (IS_IP6_FLOW_ID(pkt)) {\n\t\t\t    if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),\n\t\t\t\t&(q->id.src_ip6)) &&\n\t\t\t    IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),\n\t\t\t\t&(q->id.dst_ip6)) &&\n\t\t\t    pkt->src_port == q->id.src_port &&\n\t\t\t    pkt->dst_port == q->id.dst_port ) {\n\t\t\t\tdir = MATCH_FORWARD;\n\t\t\t\tbreak;\n\t\t\t    }\n\t\t\t    if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),\n\t\t\t\t    &(q->id.dst_ip6)) &&\n\t\t\t\tIN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),\n\t\t\t\t    &(q->id.src_ip6)) &&\n\t\t\t\tpkt->src_port == q->id.dst_port &&\n\t\t\t\tpkt->dst_port == q->id.src_port ) {\n\t\t\t\t    dir = MATCH_REVERSE;\n\t\t\t\t    break;\n\t\t\t    }\n\t\t\t} else {\n\t\t\t    if (pkt->src_ip == q->id.src_ip &&\n\t\t\t\tpkt->dst_ip == q->id.dst_ip &&\n\t\t\t\tpkt->src_port == q->id.src_port &&\n\t\t\t\tpkt->dst_port == q->id.dst_port ) {\n\t\t\t\t    dir = MATCH_FORWARD;\n\t\t\t\t    break;\n\t\t\t    }\n\t\t\t    if (pkt->src_ip == q->id.dst_ip &&\n\t\t\t\tpkt->dst_ip == q->id.src_ip &&\n\t\t\t\tpkt->src_port == q->id.dst_port &&\n\t\t\t\tpkt->dst_port == q->id.src_port ) {\n\t\t\t\t    dir = MATCH_REVERSE;\n\t\t\t\t    break;\n\t\t\t    }\n\t\t\t}\n\t\t}\nnext:\n\t\tprev = q;\n\t\tq = q->next;\n\t}\n\tif (q == NULL)\n\t\tgoto done; /* q = NULL, not found */\n\n\tif ( prev != NULL) { /* found and not in front */\n\t\tprev->next = q->next;\n\t\tq->next = V_ipfw_dyn_v[i];\n\t\tV_ipfw_dyn_v[i] = q;\n\t}\n\tif (pkt->proto == IPPROTO_TCP) { /* update state according to flags */\n\t\tu_char flags = pkt->_flags & (TH_FIN|TH_SYN|TH_RST);\n\n#define BOTH_SYN\t(TH_SYN | (TH_SYN << 8))\n#define BOTH_FIN\t(TH_FIN | (TH_FIN << 8))\n\t\tq->state |= (dir == MATCH_FORWARD ) ? flags : (flags << 8);\n\t\tswitch (q->state) {\n\t\tcase TH_SYN:\t\t\t\t/* opening */\n\t\t\tq->expire = time_uptime + V_dyn_syn_lifetime;\n\t\t\tbreak;\n\n\t\tcase BOTH_SYN:\t\t\t/* move to established */\n\t\tcase BOTH_SYN | TH_FIN :\t/* one side tries to close */\n\t\tcase BOTH_SYN | (TH_FIN << 8) :\n \t\t\tif (tcp) {\n#define _SEQ_GE(a,b) ((int)(a) - (int)(b) >= 0)\n\t\t\t    u_int32_t ack = ntohl(tcp->th_ack);\n\t\t\t    if (dir == MATCH_FORWARD) {\n\t\t\t\tif (q->ack_fwd == 0 || _SEQ_GE(ack, q->ack_fwd))\n\t\t\t\t    q->ack_fwd = ack;\n\t\t\t\telse { /* ignore out-of-sequence */\n\t\t\t\t    break;\n\t\t\t\t}\n\t\t\t    } else {\n\t\t\t\tif (q->ack_rev == 0 || _SEQ_GE(ack, q->ack_rev))\n\t\t\t\t    q->ack_rev = ack;\n\t\t\t\telse { /* ignore out-of-sequence */\n\t\t\t\t    break;\n\t\t\t\t}\n\t\t\t    }\n\t\t\t}\n\t\t\tq->expire = time_uptime + V_dyn_ack_lifetime;\n\t\t\tbreak;\n\n\t\tcase BOTH_SYN | BOTH_FIN:\t/* both sides closed */\n\t\t\tif (V_dyn_fin_lifetime >= V_dyn_keepalive_period)\n\t\t\t\tV_dyn_fin_lifetime = V_dyn_keepalive_period - 1;\n\t\t\tq->expire = time_uptime + V_dyn_fin_lifetime;\n\t\t\tbreak;\n\n\t\tdefault:\n#if 0\n\t\t\t/*\n\t\t\t * reset or some invalid combination, but can also\n\t\t\t * occur if we use keep-state the wrong way.\n\t\t\t */\n\t\t\tif ( (q->state & ((TH_RST << 8)|TH_RST)) == 0)\n\t\t\t\tprintf(\"invalid state: 0x%x\\n\", q->state);\n#endif\n\t\t\tif (V_dyn_rst_lifetime >= V_dyn_keepalive_period)\n\t\t\t\tV_dyn_rst_lifetime = V_dyn_keepalive_period - 1;\n\t\t\tq->expire = time_uptime + V_dyn_rst_lifetime;\n\t\t\tbreak;\n\t\t}\n\t} else if (pkt->proto == IPPROTO_UDP) {\n\t\tq->expire = time_uptime + V_dyn_udp_lifetime;\n\t} else {\n\t\t/* other protocols */\n\t\tq->expire = time_uptime + V_dyn_short_lifetime;\n\t}\ndone:\n\tif (match_direction)\n\t\t*match_direction = dir;\n\treturn q;\n}\n\nipfw_dyn_rule *\nipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction,\n    struct tcphdr *tcp)\n{\n\tipfw_dyn_rule *q;\n\n\tIPFW_DYN_LOCK();\n\tq = lookup_dyn_rule_locked(pkt, match_direction, tcp);\n\tif (q == NULL)\n\t\tIPFW_DYN_UNLOCK();\n\t/* NB: return table locked when q is not NULL */\n\treturn q;\n}\n\nstatic void\nrealloc_dynamic_table(void)\n{\n\tIPFW_DYN_LOCK_ASSERT();\n\n\t/*\n\t * Try reallocation, make sure we have a power of 2 and do\n\t * not allow more than 64k entries. In case of overflow,\n\t * default to 1024.\n\t */\n\n\tif (V_dyn_buckets > 65536)\n\t\tV_dyn_buckets = 1024;\n\tif ((V_dyn_buckets & (V_dyn_buckets-1)) != 0) { /* not a power of 2 */\n\t\tV_dyn_buckets = V_curr_dyn_buckets; /* reset */\n\t\treturn;\n\t}\n\tV_curr_dyn_buckets = V_dyn_buckets;\n\tif (V_ipfw_dyn_v != NULL)\n\t\tfree(V_ipfw_dyn_v, M_IPFW);\n\tfor (;;) {\n\t\tV_ipfw_dyn_v = malloc(V_curr_dyn_buckets * sizeof(ipfw_dyn_rule *),\n\t\t       M_IPFW, M_NOWAIT | M_ZERO);\n\t\tif (V_ipfw_dyn_v != NULL || V_curr_dyn_buckets <= 2)\n\t\t\tbreak;\n\t\tV_curr_dyn_buckets /= 2;\n\t}\n}\n\n/**\n * Install state of type 'type' for a dynamic session.\n * The hash table contains two type of rules:\n * - regular rules (O_KEEP_STATE)\n * - rules for sessions with limited number of sess per user\n *   (O_LIMIT). When they are created, the parent is\n *   increased by 1, and decreased on delete. In this case,\n *   the third parameter is the parent rule and not the chain.\n * - \"parent\" rules for the above (O_LIMIT_PARENT).\n */\nstatic ipfw_dyn_rule *\nadd_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule)\n{\n\tipfw_dyn_rule *r;\n\tint i;\n\n\tIPFW_DYN_LOCK_ASSERT();\n\n\tif (V_ipfw_dyn_v == NULL ||\n\t    (V_dyn_count == 0 && V_dyn_buckets != V_curr_dyn_buckets)) {\n\t\trealloc_dynamic_table();\n\t\tif (V_ipfw_dyn_v == NULL)\n\t\t\treturn NULL; /* failed ! */\n\t}\n\ti = hash_packet(id);\n\n\tr = uma_zalloc(ipfw_dyn_rule_zone, M_NOWAIT | M_ZERO);\n\tif (r == NULL) {\n\t\tprintf (\"ipfw: sorry cannot allocate state\\n\");\n\t\treturn NULL;\n\t}\n\n\t/* increase refcount on parent, and set pointer */\n\tif (dyn_type == O_LIMIT) {\n\t\tipfw_dyn_rule *parent = (ipfw_dyn_rule *)rule;\n\t\tif ( parent->dyn_type != O_LIMIT_PARENT)\n\t\t\tpanic(\"invalid parent\");\n\t\tparent->count++;\n\t\tr->parent = parent;\n\t\trule = parent->rule;\n\t}\n\n\tr->id = *id;\n\tr->expire = time_uptime + V_dyn_syn_lifetime;\n\tr->rule = rule;\n\tr->dyn_type = dyn_type;\n\tr->pcnt = r->bcnt = 0;\n\tr->count = 0;\n\n\tr->bucket = i;\n\tr->next = V_ipfw_dyn_v[i];\n\tV_ipfw_dyn_v[i] = r;\n\tV_dyn_count++;\n\tDEB({\n\t\tstruct in_addr da;\n#ifdef INET6\n\t\tchar src[INET6_ADDRSTRLEN];\n\t\tchar dst[INET6_ADDRSTRLEN];\n#else\n\t\tchar src[INET_ADDRSTRLEN];\n\t\tchar dst[INET_ADDRSTRLEN];\n#endif\n\n#ifdef INET6\n\t\tif (IS_IP6_FLOW_ID(&(r->id))) {\n\t\t\tip6_sprintf(src, &r->id.src_ip6);\n\t\t\tip6_sprintf(dst, &r->id.dst_ip6);\n\t\t} else\n#endif\n\t\t{\n\t\t\tda.s_addr = htonl(r->id.src_ip);\n\t\t\tinet_ntoa_r(da, src);\n\t\t\tda.s_addr = htonl(r->id.dst_ip);\n\t\t\tinet_ntoa_r(da, dst);\n\t\t}\n\t\tprintf(\"ipfw: add dyn entry ty %d %s %d -> %s %d, total %d\\n\",\n\t\t    dyn_type, src, r->id.src_port, dst, r->id.dst_port,\n\t\t    V_dyn_count);\n\t})\n\treturn r;\n}\n\n/**\n * lookup dynamic parent rule using pkt and rule as search keys.\n * If the lookup fails, then install one.\n */\nstatic ipfw_dyn_rule *\nlookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)\n{\n\tipfw_dyn_rule *q;\n\tint i;\n\n\tIPFW_DYN_LOCK_ASSERT();\n\n\tif (V_ipfw_dyn_v) {\n\t\tint is_v6 = IS_IP6_FLOW_ID(pkt);\n\t\ti = hash_packet( pkt );\n\t\tfor (q = V_ipfw_dyn_v[i] ; q != NULL ; q=q->next)\n\t\t\tif (q->dyn_type == O_LIMIT_PARENT &&\n\t\t\t    rule== q->rule &&\n\t\t\t    pkt->proto == q->id.proto &&\n\t\t\t    pkt->src_port == q->id.src_port &&\n\t\t\t    pkt->dst_port == q->id.dst_port &&\n\t\t\t    (\n\t\t\t\t(is_v6 &&\n\t\t\t\t IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),\n\t\t\t\t\t&(q->id.src_ip6)) &&\n\t\t\t\t IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),\n\t\t\t\t\t&(q->id.dst_ip6))) ||\n\t\t\t\t(!is_v6 &&\n\t\t\t\t pkt->src_ip == q->id.src_ip &&\n\t\t\t\t pkt->dst_ip == q->id.dst_ip)\n\t\t\t    )\n\t\t\t) {\n\t\t\t\tq->expire = time_uptime + V_dyn_short_lifetime;\n\t\t\t\tDEB(printf(\"ipfw: lookup_dyn_parent found 0x%p\\n\",q);)\n\t\t\t\treturn q;\n\t\t\t}\n\t}\n\treturn add_dyn_rule(pkt, O_LIMIT_PARENT, rule);\n}\n\n/**\n * Install dynamic state for rule type cmd->o.opcode\n *\n * Returns 1 (failure) if state is not installed because of errors or because\n * session limitations are enforced.\n */\nint\nipfw_install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,\n    struct ip_fw_args *args, uint32_t tablearg)\n{\n\tstatic int last_log;\n\tipfw_dyn_rule *q;\n\tstruct in_addr da;\n#ifdef INET6\n\tchar src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2];\n#else\n\tchar src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];\n#endif\n\n\tsrc[0] = '\\0';\n\tdst[0] = '\\0';\n\n\tIPFW_DYN_LOCK();\n\n\tDEB(\n#ifdef INET6\n\tif (IS_IP6_FLOW_ID(&(args->f_id))) {\n\t\tip6_sprintf(src, &args->f_id.src_ip6);\n\t\tip6_sprintf(dst, &args->f_id.dst_ip6);\n\t} else\n#endif\n\t{\n\t\tda.s_addr = htonl(args->f_id.src_ip);\n\t\tinet_ntoa_r(da, src);\n\t\tda.s_addr = htonl(args->f_id.dst_ip);\n\t\tinet_ntoa_r(da, dst);\n\t}\n\tprintf(\"ipfw: %s: type %d %s %u -> %s %u\\n\",\n\t    __func__, cmd->o.opcode, src, args->f_id.src_port,\n\t    dst, args->f_id.dst_port);\n\tsrc[0] = '\\0';\n\tdst[0] = '\\0';\n\t)\n\n\tq = lookup_dyn_rule_locked(&args->f_id, NULL, NULL);\n\n\tif (q != NULL) {\t/* should never occur */\n\t\tif (last_log != time_uptime) {\n\t\t\tlast_log = time_uptime;\n\t\t\tprintf(\"ipfw: %s: entry already present, done\\n\",\n\t\t\t    __func__);\n\t\t}\n\t\tIPFW_DYN_UNLOCK();\n\t\treturn (0);\n\t}\n\n\tif (V_dyn_count >= V_dyn_max)\n\t\t/* Run out of slots, try to remove any expired rule. */\n\t\tremove_dyn_rule(NULL, (ipfw_dyn_rule *)1);\n\n\tif (V_dyn_count >= V_dyn_max) {\n\t\tif (last_log != time_uptime) {\n\t\t\tlast_log = time_uptime;\n\t\t\tprintf(\"ipfw: %s: Too many dynamic rules\\n\", __func__);\n\t\t}\n\t\tIPFW_DYN_UNLOCK();\n\t\treturn (1);\t/* cannot install, notify caller */\n\t}\n\n\tswitch (cmd->o.opcode) {\n\tcase O_KEEP_STATE:\t/* bidir rule */\n\t\tadd_dyn_rule(&args->f_id, O_KEEP_STATE, rule);\n\t\tbreak;\n\n\tcase O_LIMIT: {\t\t/* limit number of sessions */\n\t\tstruct ipfw_flow_id id;\n\t\tipfw_dyn_rule *parent;\n\t\tuint32_t conn_limit;\n\t\tuint16_t limit_mask = cmd->limit_mask;\n\n\t\tconn_limit = (cmd->conn_limit == IP_FW_TABLEARG) ?\n\t\t    tablearg : cmd->conn_limit;\n\t\t  \n\t\tDEB(\n\t\tif (cmd->conn_limit == IP_FW_TABLEARG)\n\t\t\tprintf(\"ipfw: %s: O_LIMIT rule, conn_limit: %u \"\n\t\t\t    \"(tablearg)\\n\", __func__, conn_limit);\n\t\telse\n\t\t\tprintf(\"ipfw: %s: O_LIMIT rule, conn_limit: %u\\n\",\n\t\t\t    __func__, conn_limit);\n\t\t)\n\n\t\tid.dst_ip = id.src_ip = id.dst_port = id.src_port = 0;\n\t\tid.proto = args->f_id.proto;\n\t\tid.addr_type = args->f_id.addr_type;\n\t\tid.fib = M_GETFIB(args->m);\n\n\t\tif (IS_IP6_FLOW_ID (&(args->f_id))) {\n\t\t\tif (limit_mask & DYN_SRC_ADDR)\n\t\t\t\tid.src_ip6 = args->f_id.src_ip6;\n\t\t\tif (limit_mask & DYN_DST_ADDR)\n\t\t\t\tid.dst_ip6 = args->f_id.dst_ip6;\n\t\t} else {\n\t\t\tif (limit_mask & DYN_SRC_ADDR)\n\t\t\t\tid.src_ip = args->f_id.src_ip;\n\t\t\tif (limit_mask & DYN_DST_ADDR)\n\t\t\t\tid.dst_ip = args->f_id.dst_ip;\n\t\t}\n\t\tif (limit_mask & DYN_SRC_PORT)\n\t\t\tid.src_port = args->f_id.src_port;\n\t\tif (limit_mask & DYN_DST_PORT)\n\t\t\tid.dst_port = args->f_id.dst_port;\n\t\tif ((parent = lookup_dyn_parent(&id, rule)) == NULL) {\n\t\t\tprintf(\"ipfw: %s: add parent failed\\n\", __func__);\n\t\t\tIPFW_DYN_UNLOCK();\n\t\t\treturn (1);\n\t\t}\n\n\t\tif (parent->count >= conn_limit) {\n\t\t\t/* See if we can remove some expired rule. */\n\t\t\tremove_dyn_rule(rule, parent);\n\t\t\tif (parent->count >= conn_limit) {\n\t\t\t\tif (V_fw_verbose && last_log != time_uptime) {\n\t\t\t\t\tlast_log = time_uptime;\n#ifdef INET6\n\t\t\t\t\t/*\n\t\t\t\t\t * XXX IPv6 flows are not\n\t\t\t\t\t * supported yet.\n\t\t\t\t\t */\n\t\t\t\t\tif (IS_IP6_FLOW_ID(&(args->f_id))) {\n\t\t\t\t\t\tchar ip6buf[INET6_ADDRSTRLEN];\n\t\t\t\t\t\tsnprintf(src, sizeof(src),\n\t\t\t\t\t\t    \"[%s]\", ip6_sprintf(ip6buf,\n\t\t\t\t\t\t\t&args->f_id.src_ip6));\n\t\t\t\t\t\tsnprintf(dst, sizeof(dst),\n\t\t\t\t\t\t    \"[%s]\", ip6_sprintf(ip6buf,\n\t\t\t\t\t\t\t&args->f_id.dst_ip6));\n\t\t\t\t\t} else\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\tda.s_addr =\n\t\t\t\t\t\t    htonl(args->f_id.src_ip);\n\t\t\t\t\t\tinet_ntoa_r(da, src);\n\t\t\t\t\t\tda.s_addr =\n\t\t\t\t\t\t    htonl(args->f_id.dst_ip);\n\t\t\t\t\t\tinet_ntoa_r(da, dst);\n\t\t\t\t\t}\n\t\t\t\t\tlog(LOG_SECURITY | LOG_DEBUG,\n\t\t\t\t\t    \"ipfw: %d %s %s:%u -> %s:%u, %s\\n\",\n\t\t\t\t\t    parent->rule->rulenum,\n\t\t\t\t\t    \"drop session\",\n\t\t\t\t\t    src, (args->f_id.src_port),\n\t\t\t\t\t    dst, (args->f_id.dst_port),\n\t\t\t\t\t    \"too many entries\");\n\t\t\t\t}\n\t\t\t\tIPFW_DYN_UNLOCK();\n\t\t\t\treturn (1);\n\t\t\t}\n\t\t}\n\t\tadd_dyn_rule(&args->f_id, O_LIMIT, (struct ip_fw *)parent);\n\t\tbreak;\n\t}\n\tdefault:\n\t\tprintf(\"ipfw: %s: unknown dynamic rule type %u\\n\",\n\t\t    __func__, cmd->o.opcode);\n\t\tIPFW_DYN_UNLOCK();\n\t\treturn (1);\n\t}\n\n\t/* XXX just set lifetime */\n\tlookup_dyn_rule_locked(&args->f_id, NULL, NULL);\n\n\tIPFW_DYN_UNLOCK();\n\treturn (0);\n}\n\n/*\n * Generate a TCP packet, containing either a RST or a keepalive.\n * When flags & TH_RST, we are sending a RST packet, because of a\n * \"reset\" action matched the packet.\n * Otherwise we are sending a keepalive, and flags & TH_\n * The 'replyto' mbuf is the mbuf being replied to, if any, and is required\n * so that MAC can label the reply appropriately.\n */\nstruct mbuf *\nipfw_send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq,\n    u_int32_t ack, int flags)\n{\n\tstruct mbuf *m = NULL;\t\t/* stupid compiler */\n\tint len, dir;\n\tstruct ip *h = NULL;\t\t/* stupid compiler */\n#ifdef INET6\n\tstruct ip6_hdr *h6 = NULL;\n#endif\n\tstruct tcphdr *th = NULL;\n\n\tMGETHDR(m, M_DONTWAIT, MT_DATA);\n\tif (m == NULL)\n\t\treturn (NULL);\n\n\tM_SETFIB(m, id->fib);\n#ifdef MAC\n\tif (replyto != NULL)\n\t\tmac_netinet_firewall_reply(replyto, m);\n\telse\n\t\tmac_netinet_firewall_send(m);\n#else\n\t(void)replyto;\t\t/* don't warn about unused arg */\n#endif\n\n\tswitch (id->addr_type) {\n\tcase 4:\n\t\tlen = sizeof(struct ip) + sizeof(struct tcphdr);\n\t\tbreak;\n#ifdef INET6\n\tcase 6:\n\t\tlen = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);\n\t\tbreak;\n#endif\n\tdefault:\n\t\t/* XXX: log me?!? */\n\t\tFREE_PKT(m);\n\t\treturn (NULL);\n\t}\n\tdir = ((flags & (TH_SYN | TH_RST)) == TH_SYN);\n\n\tm->m_data += max_linkhdr;\n\tm->m_flags |= M_SKIP_FIREWALL;\n\tm->m_pkthdr.len = m->m_len = len;\n\tm->m_pkthdr.rcvif = NULL;\n\tbzero(m->m_data, len);\n\n\tswitch (id->addr_type) {\n\tcase 4:\n\t\th = mtod(m, struct ip *);\n\n\t\t/* prepare for checksum */\n\t\th->ip_p = IPPROTO_TCP;\n\t\th->ip_len = htons(sizeof(struct tcphdr));\n\t\tif (dir) {\n\t\t\th->ip_src.s_addr = htonl(id->src_ip);\n\t\t\th->ip_dst.s_addr = htonl(id->dst_ip);\n\t\t} else {\n\t\t\th->ip_src.s_addr = htonl(id->dst_ip);\n\t\t\th->ip_dst.s_addr = htonl(id->src_ip);\n\t\t}\n\n\t\tth = (struct tcphdr *)(h + 1);\n\t\tbreak;\n#ifdef INET6\n\tcase 6:\n\t\th6 = mtod(m, struct ip6_hdr *);\n\n\t\t/* prepare for checksum */\n\t\th6->ip6_nxt = IPPROTO_TCP;\n\t\th6->ip6_plen = htons(sizeof(struct tcphdr));\n\t\tif (dir) {\n\t\t\th6->ip6_src = id->src_ip6;\n\t\t\th6->ip6_dst = id->dst_ip6;\n\t\t} else {\n\t\t\th6->ip6_src = id->dst_ip6;\n\t\t\th6->ip6_dst = id->src_ip6;\n\t\t}\n\n\t\tth = (struct tcphdr *)(h6 + 1);\n\t\tbreak;\n#endif\n\t}\n\n\tif (dir) {\n\t\tth->th_sport = htons(id->src_port);\n\t\tth->th_dport = htons(id->dst_port);\n\t} else {\n\t\tth->th_sport = htons(id->dst_port);\n\t\tth->th_dport = htons(id->src_port);\n\t}\n\tth->th_off = sizeof(struct tcphdr) >> 2;\n\n\tif (flags & TH_RST) {\n\t\tif (flags & TH_ACK) {\n\t\t\tth->th_seq = htonl(ack);\n\t\t\tth->th_flags = TH_RST;\n\t\t} else {\n\t\t\tif (flags & TH_SYN)\n\t\t\t\tseq++;\n\t\t\tth->th_ack = htonl(seq);\n\t\t\tth->th_flags = TH_RST | TH_ACK;\n\t\t}\n\t} else {\n\t\t/*\n\t\t * Keepalive - use caller provided sequence numbers\n\t\t */\n\t\tth->th_seq = htonl(seq);\n\t\tth->th_ack = htonl(ack);\n\t\tth->th_flags = TH_ACK;\n\t}\n\n\tswitch (id->addr_type) {\n\tcase 4:\n\t\tth->th_sum = in_cksum(m, len);\n\n\t\t/* finish the ip header */\n\t\th->ip_v = 4;\n\t\th->ip_hl = sizeof(*h) >> 2;\n\t\th->ip_tos = IPTOS_LOWDELAY;\n\t\th->ip_off = 0;\n\t\t/* ip_len must be in host format for ip_output */\n\t\th->ip_len = len;\n\t\th->ip_ttl = V_ip_defttl;\n\t\th->ip_sum = 0;\n\t\tbreak;\n#ifdef INET6\n\tcase 6:\n\t\tth->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(*h6),\n\t\t    sizeof(struct tcphdr));\n\n\t\t/* finish the ip6 header */\n\t\th6->ip6_vfc |= IPV6_VERSION;\n\t\th6->ip6_hlim = IPV6_DEFHLIM;\n\t\tbreak;\n#endif\n\t}\n\n\treturn (m);\n}\n\n/*\n * This procedure is only used to handle keepalives. It is invoked\n * every dyn_keepalive_period\n */\n /* dummynet() and ipfw_tick() can't be static in windows */\nvoid\nipfw_tick(void * vnetx) \n{\n\tstruct mbuf *m0, *m, *mnext, **mtailp;\n#ifdef INET6\n\tstruct mbuf *m6, **m6_tailp;\n#endif\n\tint i;\n\tipfw_dyn_rule *q;\n#ifdef VIMAGE\n\tstruct vnet *vp = vnetx;\n#endif\n\n\tCURVNET_SET(vp);\n\tif (V_dyn_keepalive == 0 || V_ipfw_dyn_v == NULL || V_dyn_count == 0)\n\t\tgoto done;\n\n\t/*\n\t * We make a chain of packets to go out here -- not deferring\n\t * until after we drop the IPFW dynamic rule lock would result\n\t * in a lock order reversal with the normal packet input -> ipfw\n\t * call stack.\n\t */\n\tm0 = NULL;\n\tmtailp = &m0;\n#ifdef INET6\n\tm6 = NULL;\n\tm6_tailp = &m6;\n#endif\n\tIPFW_DYN_LOCK();\n\tfor (i = 0 ; i < V_curr_dyn_buckets ; i++) {\n\t\tfor (q = V_ipfw_dyn_v[i] ; q ; q = q->next ) {\n\t\t\tif (q->dyn_type == O_LIMIT_PARENT)\n\t\t\t\tcontinue;\n\t\t\tif (q->id.proto != IPPROTO_TCP)\n\t\t\t\tcontinue;\n\t\t\tif ( (q->state & BOTH_SYN) != BOTH_SYN)\n\t\t\t\tcontinue;\n\t\t\tif (TIME_LEQ(time_uptime + V_dyn_keepalive_interval,\n\t\t\t    q->expire))\n\t\t\t\tcontinue;\t/* too early */\n\t\t\tif (TIME_LEQ(q->expire, time_uptime))\n\t\t\t\tcontinue;\t/* too late, rule expired */\n\n\t\t\tm = ipfw_send_pkt(NULL, &(q->id), q->ack_rev - 1,\n\t\t\t\tq->ack_fwd, TH_SYN);\n\t\t\tmnext = ipfw_send_pkt(NULL, &(q->id), q->ack_fwd - 1,\n\t\t\t\tq->ack_rev, 0);\n\n\t\t\tswitch (q->id.addr_type) {\n\t\t\tcase 4:\n\t\t\t\tif (m != NULL) {\n\t\t\t\t\t*mtailp = m;\n\t\t\t\t\tmtailp = &(*mtailp)->m_nextpkt;\n\t\t\t\t}\n\t\t\t\tif (mnext != NULL) {\n\t\t\t\t\t*mtailp = mnext;\n\t\t\t\t\tmtailp = &(*mtailp)->m_nextpkt;\n\t\t\t\t}\n\t\t\t\tbreak;\n#ifdef INET6\n\t\t\tcase 6:\n\t\t\t\tif (m != NULL) {\n\t\t\t\t\t*m6_tailp = m;\n\t\t\t\t\tm6_tailp = &(*m6_tailp)->m_nextpkt;\n\t\t\t\t}\n\t\t\t\tif (mnext != NULL) {\n\t\t\t\t\t*m6_tailp = mnext;\n\t\t\t\t\tm6_tailp = &(*m6_tailp)->m_nextpkt;\n\t\t\t\t}\n\t\t\t\tbreak;\n#endif\n\t\t\t}\n\n\t\t\tm = mnext = NULL;\n\t\t}\n\t}\n\tIPFW_DYN_UNLOCK();\n\tfor (m = mnext = m0; m != NULL; m = mnext) {\n\t\tmnext = m->m_nextpkt;\n\t\tm->m_nextpkt = NULL;\n\t\tip_output(m, NULL, NULL, 0, NULL, NULL);\n\t}\n#ifdef INET6\n\tfor (m = mnext = m6; m != NULL; m = mnext) {\n\t\tmnext = m->m_nextpkt;\n\t\tm->m_nextpkt = NULL;\n\t\tip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);\n\t}\n#endif\ndone:\n\tcallout_reset_on(&V_ipfw_timeout, V_dyn_keepalive_period * hz,\n\t\t      ipfw_tick, vnetx, 0);\n\tCURVNET_RESTORE();\n}\n\nvoid\nipfw_dyn_attach(void)\n{\n        ipfw_dyn_rule_zone = uma_zcreate(\"IPFW dynamic rule\",\n            sizeof(ipfw_dyn_rule), NULL, NULL, NULL, NULL,\n            UMA_ALIGN_PTR, 0);\n\n        IPFW_DYN_LOCK_INIT();\n}\n\nvoid\nipfw_dyn_detach(void)\n{\n        uma_zdestroy(ipfw_dyn_rule_zone);\n        IPFW_DYN_LOCK_DESTROY();\n}\n\nvoid\nipfw_dyn_init(void)\n{\n        V_ipfw_dyn_v = NULL;\n        V_dyn_buckets = 256;    /* must be power of 2 */\n        V_curr_dyn_buckets = 256; /* must be power of 2 */\n \n        V_dyn_ack_lifetime = 300;\n        V_dyn_syn_lifetime = 20;\n        V_dyn_fin_lifetime = 1;\n        V_dyn_rst_lifetime = 1;\n        V_dyn_udp_lifetime = 10;\n        V_dyn_short_lifetime = 5;\n\n        V_dyn_keepalive_interval = 20;\n        V_dyn_keepalive_period = 5;\n        V_dyn_keepalive = 1;    /* do send keepalives */\n        \n        V_dyn_max = 4096;       /* max # of dynamic rules */\n        callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE);\n        callout_reset_on(&V_ipfw_timeout, hz, ipfw_tick, curvnet, 0);\n}\n\nvoid\nipfw_dyn_uninit(int pass)\n{\n\tif (pass == 0)\n\t\tcallout_drain(&V_ipfw_timeout);\n\telse {\n\t\tif (V_ipfw_dyn_v != NULL)\n\t\t\tfree(V_ipfw_dyn_v, M_IPFW);\n\t}\n}\n\nint\nipfw_dyn_len(void)\n{\n\treturn (V_ipfw_dyn_v == NULL) ? 0 :\n\t\t(V_dyn_count * sizeof(ipfw_dyn_rule));\n}\n\nvoid\nipfw_get_dynamic(char **pbp, const char *ep)\n{\n\tipfw_dyn_rule *p, *last = NULL;\n\tchar *bp;\n\tint i;\n\n\tif (V_ipfw_dyn_v == NULL)\n\t\treturn;\n\tbp = *pbp;\n\n\tIPFW_DYN_LOCK();\n\tfor (i = 0 ; i < V_curr_dyn_buckets; i++)\n\t\tfor (p = V_ipfw_dyn_v[i] ; p != NULL; p = p->next) {\n\t\t\tif (bp + sizeof *p <= ep) {\n\t\t\t\tipfw_dyn_rule *dst =\n\t\t\t\t\t(ipfw_dyn_rule *)bp;\n\t\t\t\tbcopy(p, dst, sizeof *p);\n\t\t\t\tbcopy(&(p->rule->rulenum), &(dst->rule),\n\t\t\t\t    sizeof(p->rule->rulenum));\n\t\t\t\t/*\n\t\t\t\t * store set number into high word of\n\t\t\t\t * dst->rule pointer.\n\t\t\t\t */\n\t\t\t\tbcopy(&(p->rule->set),\n\t\t\t\t    (char *)&dst->rule +\n\t\t\t\t    sizeof(p->rule->rulenum),\n\t\t\t\t    sizeof(p->rule->set));\n\t\t\t\t/*\n\t\t\t\t * store a non-null value in \"next\".\n\t\t\t\t * The userland code will interpret a\n\t\t\t\t * NULL here as a marker\n\t\t\t\t * for the last dynamic rule.\n\t\t\t\t */\n\t\t\t\tbcopy(&dst, &dst->next, sizeof(dst));\n\t\t\t\tlast = dst;\n\t\t\t\tdst->expire =\n\t\t\t\t    TIME_LEQ(dst->expire, time_uptime) ?\n\t\t\t\t\t0 : dst->expire - time_uptime ;\n\t\t\t\tbp += sizeof(ipfw_dyn_rule);\n\t\t\t}\n\t\t}\n\tIPFW_DYN_UNLOCK();\n\tif (last != NULL) /* mark last dynamic rule */\n\t\tbzero(&last->next, sizeof(last));\n\t*pbp = bp;\n}\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_log.c",
    "content": "/*-\n * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: head/sys/netinet/ipfw/ip_fw_log.c 209845 2010-07-09 11:27:33Z glebius $\");\n\n/*\n * Logging support for ipfw\n */\n\n#if !defined(KLD_MODULE)\n#include \"opt_ipfw.h\"\n#include \"opt_ipdivert.h\"\n#include \"opt_ipdn.h\"\n#include \"opt_inet.h\"\n#ifndef INET\n#error IPFIREWALL requires INET.\n#endif /* INET */\n#endif\n#include \"opt_inet6.h\"\n#include \"opt_ipsec.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/mbuf.h>\n#include <sys/kernel.h>\n#include <sys/socket.h>\n#include <sys/sysctl.h>\n#include <sys/syslog.h>\n#include <net/ethernet.h> /* for ETHERTYPE_IP */\n#include <net/if.h>\n#include <net/vnet.h>\n#include <net/if_types.h>\t/* for IFT_ETHER */\n#include <net/bpf.h>\t\t/* for BPF */\n\n#include <netinet/in.h>\n#include <netinet/ip.h>\n#include <netinet/ip_icmp.h>\n#include <netinet/ip_var.h>\n#include <netinet/ip_fw.h>\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netinet/tcp_var.h>\n#include <netinet/udp.h>\n\n#include <netinet/ip6.h>\n#include <netinet/icmp6.h>\n#ifdef INET6\n#include <netinet6/in6_var.h>\t/* ip6_sprintf() */\n#endif\n\n#ifdef MAC\n#include <security/mac/mac_framework.h>\n#endif\n\n/*\n * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T\n * Other macros just cast void * into the appropriate type\n */\n#define\tL3HDR(T, ip)\t((T *)((u_int32_t *)(ip) + (ip)->ip_hl))\n#define\tTCP(p)\t\t((struct tcphdr *)(p))\n#define\tSCTP(p)\t\t((struct sctphdr *)(p))\n#define\tUDP(p)\t\t((struct udphdr *)(p))\n#define\tICMP(p)\t\t((struct icmphdr *)(p))\n#define\tICMP6(p)\t((struct icmp6_hdr *)(p))\n\n#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0\n#define SNP(buf) buf, sizeof(buf)\n\n#ifdef WITHOUT_BPF\nvoid\nipfw_log_bpf(int onoff)\n{\n}\n#else /* !WITHOUT_BPF */\nstatic struct ifnet *log_if;\t/* hook to attach to bpf */\n\n/* we use this dummy function for all ifnet callbacks */\nstatic int\nlog_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr)\n{\n\treturn EINVAL;\n}\n\nstatic int\nipfw_log_output(struct ifnet *ifp, struct mbuf *m,\n\tstruct sockaddr *dst, struct route *ro)\n{\n\tif (m != NULL)\n\t\tm_freem(m);\n\treturn EINVAL;\n}\n\nstatic void\nipfw_log_start(struct ifnet* ifp)\n{\n\tpanic(\"ipfw_log_start() must not be called\");\n}\n\nstatic const u_char ipfwbroadcastaddr[6] =\n\t{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };\n\nvoid\nipfw_log_bpf(int onoff)\n{\n\tstruct ifnet *ifp;\n\n\tif (onoff) {\n\t\tif (log_if)\n\t\t\treturn;\n\t\tifp = if_alloc(IFT_ETHER);\n\t\tif (ifp == NULL)\n\t\t\treturn;\n\t\tif_initname(ifp, \"ipfw\", 0);\n\t\tifp->if_mtu = 65536;\n\t\tifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;\n\t\tifp->if_init = (void *)log_dummy;\n\t\tifp->if_ioctl = log_dummy;\n\t\tifp->if_start = ipfw_log_start;\n\t\tifp->if_output = ipfw_log_output;\n\t\tifp->if_addrlen = 6;\n\t\tifp->if_hdrlen = 14;\n\t\tif_attach(ifp);\n\t\tifp->if_broadcastaddr = ipfwbroadcastaddr;\n\t\tifp->if_baudrate = IF_Mbps(10);\n\t\tbpfattach(ifp, DLT_EN10MB, 14);\n\t\tlog_if = ifp;\n\t} else {\n\t\tif (log_if) {\n\t\t\tether_ifdetach(log_if);\n\t\t\tif_free(log_if);\n\t\t}\n\t\tlog_if = NULL;\n\t}\n}\n#endif /* !WITHOUT_BPF */\n\n/*\n * We enter here when we have a rule with O_LOG.\n * XXX this function alone takes about 2Kbytes of code!\n */\nvoid\nipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,\n    struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg,\n    struct ip *ip)\n{\n\tchar *action;\n\tint limit_reached = 0;\n\tchar action2[40], proto[128], fragment[32];\n\n\tif (V_fw_verbose == 0) {\n#ifndef WITHOUT_BPF\n\n\t\tif (log_if == NULL || log_if->if_bpf == NULL)\n\t\t\treturn;\n\n\t\tif (args->eh) /* layer2, use orig hdr */\n\t\t\tBPF_MTAP2(log_if, args->eh, ETHER_HDR_LEN, m);\n\t\telse\n\t\t\t/* Add fake header. Later we will store\n\t\t\t * more info in the header.\n\t\t\t */\n\t\t\tBPF_MTAP2(log_if, \"DDDDDDSSSSSS\\x08\\x00\", ETHER_HDR_LEN, m);\n#endif /* !WITHOUT_BPF */\n\t\treturn;\n\t}\n\t/* the old 'log' function */\n\tfragment[0] = '\\0';\n\tproto[0] = '\\0';\n\n\tif (f == NULL) {\t/* bogus pkt */\n\t\tif (V_verbose_limit != 0 && V_norule_counter >= V_verbose_limit)\n\t\t\treturn;\n\t\tV_norule_counter++;\n\t\tif (V_norule_counter == V_verbose_limit)\n\t\t\tlimit_reached = V_verbose_limit;\n\t\taction = \"Refuse\";\n\t} else {\t/* O_LOG is the first action, find the real one */\n\t\tipfw_insn *cmd = ACTION_PTR(f);\n\t\tipfw_insn_log *l = (ipfw_insn_log *)cmd;\n\n\t\tif (l->max_log != 0 && l->log_left == 0)\n\t\t\treturn;\n\t\tl->log_left--;\n\t\tif (l->log_left == 0)\n\t\t\tlimit_reached = l->max_log;\n\t\tcmd += F_LEN(cmd);\t/* point to first action */\n\t\tif (cmd->opcode == O_ALTQ) {\n\t\t\tipfw_insn_altq *altq = (ipfw_insn_altq *)cmd;\n\n\t\t\tsnprintf(SNPARGS(action2, 0), \"Altq %d\",\n\t\t\t\taltq->qid);\n\t\t\tcmd += F_LEN(cmd);\n\t\t}\n\t\tif (cmd->opcode == O_PROB)\n\t\t\tcmd += F_LEN(cmd);\n\n\t\tif (cmd->opcode == O_TAG)\n\t\t\tcmd += F_LEN(cmd);\n\n\t\taction = action2;\n\t\tswitch (cmd->opcode) {\n\t\tcase O_DENY:\n\t\t\taction = \"Deny\";\n\t\t\tbreak;\n\n\t\tcase O_REJECT:\n\t\t\tif (cmd->arg1==ICMP_REJECT_RST)\n\t\t\t\taction = \"Reset\";\n\t\t\telse if (cmd->arg1==ICMP_UNREACH_HOST)\n\t\t\t\taction = \"Reject\";\n\t\t\telse\n\t\t\t\tsnprintf(SNPARGS(action2, 0), \"Unreach %d\",\n\t\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_UNREACH6:\n\t\t\tif (cmd->arg1==ICMP6_UNREACH_RST)\n\t\t\t\taction = \"Reset\";\n\t\t\telse\n\t\t\t\tsnprintf(SNPARGS(action2, 0), \"Unreach %d\",\n\t\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\n\t\tcase O_ACCEPT:\n\t\t\taction = \"Accept\";\n\t\t\tbreak;\n\t\tcase O_COUNT:\n\t\t\taction = \"Count\";\n\t\t\tbreak;\n\t\tcase O_DIVERT:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"Divert %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_TEE:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"Tee %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_SETFIB:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"SetFib %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_SKIPTO:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"SkipTo %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_PIPE:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"Pipe %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_QUEUE:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"Queue %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_FORWARD_IP: {\n\t\t\tipfw_insn_sa *sa = (ipfw_insn_sa *)cmd;\n\t\t\tint len;\n\t\t\tstruct in_addr dummyaddr;\n\t\t\tif (sa->sa.sin_addr.s_addr == INADDR_ANY)\n\t\t\t\tdummyaddr.s_addr = htonl(tablearg);\n\t\t\telse\n\t\t\t\tdummyaddr.s_addr = sa->sa.sin_addr.s_addr;\n\n\t\t\tlen = snprintf(SNPARGS(action2, 0), \"Forward to %s\",\n\t\t\t\tinet_ntoa(dummyaddr));\n\n\t\t\tif (sa->sa.sin_port)\n\t\t\t\tsnprintf(SNPARGS(action2, len), \":%d\",\n\t\t\t\t    sa->sa.sin_port);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase O_NETGRAPH:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"Netgraph %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_NGTEE:\n\t\t\tsnprintf(SNPARGS(action2, 0), \"Ngtee %d\",\n\t\t\t\tcmd->arg1);\n\t\t\tbreak;\n\t\tcase O_NAT:\n\t\t\taction = \"Nat\";\n \t\t\tbreak;\n\t\tcase O_REASS:\n\t\t\taction = \"Reass\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\taction = \"UNKNOWN\";\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (hlen == 0) {\t/* non-ip */\n\t\tsnprintf(SNPARGS(proto, 0), \"MAC\");\n\n\t} else {\n\t\tint len;\n#ifdef INET6\n\t\tchar src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2];\n#else\n\t\tchar src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN];\n#endif\n\t\tstruct icmphdr *icmp;\n\t\tstruct tcphdr *tcp;\n\t\tstruct udphdr *udp;\n#ifdef INET6\n\t\tstruct ip6_hdr *ip6 = NULL;\n\t\tstruct icmp6_hdr *icmp6;\n#endif\n\t\tsrc[0] = '\\0';\n\t\tdst[0] = '\\0';\n#ifdef INET6\n\t\tif (IS_IP6_FLOW_ID(&(args->f_id))) {\n\t\t\tchar ip6buf[INET6_ADDRSTRLEN];\n\t\t\tsnprintf(src, sizeof(src), \"[%s]\",\n\t\t\t    ip6_sprintf(ip6buf, &args->f_id.src_ip6));\n\t\t\tsnprintf(dst, sizeof(dst), \"[%s]\",\n\t\t\t    ip6_sprintf(ip6buf, &args->f_id.dst_ip6));\n\n\t\t\tip6 = (struct ip6_hdr *)ip;\n\t\t\ttcp = (struct tcphdr *)(((char *)ip) + hlen);\n\t\t\tudp = (struct udphdr *)(((char *)ip) + hlen);\n\t\t} else\n#endif\n\t\t{\n\t\t\ttcp = L3HDR(struct tcphdr, ip);\n\t\t\tudp = L3HDR(struct udphdr, ip);\n\n\t\t\tinet_ntoa_r(ip->ip_src, src);\n\t\t\tinet_ntoa_r(ip->ip_dst, dst);\n\t\t}\n\n\t\tswitch (args->f_id.proto) {\n\t\tcase IPPROTO_TCP:\n\t\t\tlen = snprintf(SNPARGS(proto, 0), \"TCP %s\", src);\n\t\t\tif (offset == 0)\n\t\t\t\tsnprintf(SNPARGS(proto, len), \":%d %s:%d\",\n\t\t\t\t    ntohs(tcp->th_sport),\n\t\t\t\t    dst,\n\t\t\t\t    ntohs(tcp->th_dport));\n\t\t\telse\n\t\t\t\tsnprintf(SNPARGS(proto, len), \" %s\", dst);\n\t\t\tbreak;\n\n\t\tcase IPPROTO_UDP:\n\t\t\tlen = snprintf(SNPARGS(proto, 0), \"UDP %s\", src);\n\t\t\tif (offset == 0)\n\t\t\t\tsnprintf(SNPARGS(proto, len), \":%d %s:%d\",\n\t\t\t\t    ntohs(udp->uh_sport),\n\t\t\t\t    dst,\n\t\t\t\t    ntohs(udp->uh_dport));\n\t\t\telse\n\t\t\t\tsnprintf(SNPARGS(proto, len), \" %s\", dst);\n\t\t\tbreak;\n\n\t\tcase IPPROTO_ICMP:\n\t\t\ticmp = L3HDR(struct icmphdr, ip);\n\t\t\tif (offset == 0)\n\t\t\t\tlen = snprintf(SNPARGS(proto, 0),\n\t\t\t\t    \"ICMP:%u.%u \",\n\t\t\t\t    icmp->icmp_type, icmp->icmp_code);\n\t\t\telse\n\t\t\t\tlen = snprintf(SNPARGS(proto, 0), \"ICMP \");\n\t\t\tlen += snprintf(SNPARGS(proto, len), \"%s\", src);\n\t\t\tsnprintf(SNPARGS(proto, len), \" %s\", dst);\n\t\t\tbreak;\n#ifdef INET6\n\t\tcase IPPROTO_ICMPV6:\n\t\t\ticmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen);\n\t\t\tif (offset == 0)\n\t\t\t\tlen = snprintf(SNPARGS(proto, 0),\n\t\t\t\t    \"ICMPv6:%u.%u \",\n\t\t\t\t    icmp6->icmp6_type, icmp6->icmp6_code);\n\t\t\telse\n\t\t\t\tlen = snprintf(SNPARGS(proto, 0), \"ICMPv6 \");\n\t\t\tlen += snprintf(SNPARGS(proto, len), \"%s\", src);\n\t\t\tsnprintf(SNPARGS(proto, len), \" %s\", dst);\n\t\t\tbreak;\n#endif\n\t\tdefault:\n\t\t\tlen = snprintf(SNPARGS(proto, 0), \"P:%d %s\",\n\t\t\t    args->f_id.proto, src);\n\t\t\tsnprintf(SNPARGS(proto, len), \" %s\", dst);\n\t\t\tbreak;\n\t\t}\n\n#ifdef INET6\n\t\tif (IS_IP6_FLOW_ID(&(args->f_id))) {\n\t\t\tif (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG))\n\t\t\t\tsnprintf(SNPARGS(fragment, 0),\n\t\t\t\t    \" (frag %08x:%d@%d%s)\",\n\t\t\t\t    args->f_id.extra,\n\t\t\t\t    ntohs(ip6->ip6_plen) - hlen,\n\t\t\t\t    ntohs(offset & IP6F_OFF_MASK) << 3,\n\t\t\t\t    (offset & IP6F_MORE_FRAG) ? \"+\" : \"\");\n\t\t} else\n#endif\n\t\t{\n\t\t\tint ipoff, iplen;\n\t\t\tipoff = ntohs(ip->ip_off);\n\t\t\tiplen = ntohs(ip->ip_len);\n\t\t\tif (ipoff & (IP_MF | IP_OFFMASK))\n\t\t\t\tsnprintf(SNPARGS(fragment, 0),\n\t\t\t\t    \" (frag %d:%d@%d%s)\",\n\t\t\t\t    ntohs(ip->ip_id), iplen - (ip->ip_hl << 2),\n\t\t\t\t    offset << 3,\n\t\t\t\t    (ipoff & IP_MF) ? \"+\" : \"\");\n\t\t}\n\t}\n#ifdef __FreeBSD__\n\tif (oif || m->m_pkthdr.rcvif)\n\t\tlog(LOG_SECURITY | LOG_INFO,\n\t\t    \"ipfw: %d %s %s %s via %s%s\\n\",\n\t\t    f ? f->rulenum : -1,\n\t\t    action, proto, oif ? \"out\" : \"in\",\n\t\t    oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname,\n\t\t    fragment);\n\telse\n#endif\n\t\tlog(LOG_SECURITY | LOG_INFO,\n\t\t    \"ipfw: %d %s %s [no if info]%s\\n\",\n\t\t    f ? f->rulenum : -1,\n\t\t    action, proto, fragment);\n\tif (limit_reached)\n\t\tlog(LOG_SECURITY | LOG_NOTICE,\n\t\t    \"ipfw: limit %d reached on entry %d\\n\",\n\t\t    limit_reached, f ? f->rulenum : -1);\n}\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_lookup.c",
    "content": "/*-\n * Copyright (c) 2009 Luigi Rizzo Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_table.c 200601 2009-12-16 10:48:40Z luigi $\");\n\n/*\n * Rule and pipe lookup support for ipfw.\n *\n\nipfw and dummynet need to quickly find objects (rules, pipes)\nthat may be dynamically created or destroyed.\nTo address the problem, we label each new object with a unique\n32-bit identifier whose low K bits are the index in a lookup\ntable. All existing objects are referred by the lookup table,\nand identifiers are chosen so that for each slot there is\nat most one active object (whose identifier points to the slot).\nThis is almost a hash table, except that we can pick the\nidentifiers after looking at the table's occupation so\nwe have a trivial hash function and are collision free.\n\nWith this structure, operations are very fast and simple:\n- the table has N entries s[i] with two fields, 'id' and 'ptr',\n  with N <= M = 2^k (M is an upper bound to the size of the table);\n- initially, all slots have s[i].id = i, and the pointers\n  are used to build a freelist (tailq).\n- a slot is considered empty if ptr == NULL or s[0] <= ptr < s[N].\n  This is easy to detect and we can use ptr to build the freelist.\n- when a new object is created, we put it in the empty slot i at the\n  head of the freelist, and set the id to s[i].id;\n- when an object is destroyed, we append its slot i to the end\n  of the freelist, and set s[i].id += M (note M, not N).\n- on a lookup for id = X, we look at slot i = X & (M-1),\n  and consider the lookup successful only if the slot is not\n  empty and s[i].id == X;\n- wraps occur at most every F * 2^32/M operations, where F is\n  the number of free slots. Because F is usually a reasonable\n  fraction of M, we should not worry too much.\n- if the table fills up, we can extend it by increasing N\n- shrinking the table is more difficult as we might create\n  collisions during the rehashing.\n *\n */\n\n#include <sys/cdefs.h>\n#ifdef _KERNEL\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/rwlock.h>\nMALLOC_DEFINE(M_IPFW_LUT, \"ipfw_lookup\", \"IpFw lookup\");\n#define Malloc(n)\tmalloc(n, M_IPFW_LUT, M_WAITOK)\n#define Calloc(n)\tcalloc(n, M_IPFW_LUT, M_WAITOK | M_ZERO)\n#define Free(p)\t\tfree(p, M_IPFW_LUT)\n\n#define log(x, arg...)\n\n#else /* !_KERNEL */\n#include <sys/types.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#define Malloc(n)\tmalloc(n)\n#define Calloc(n)\tcalloc(1, n)\n#define Free(p)\t\tfree(p)\n#define log(x, arg...)\tfprintf(stderr, \"%s: \" x \"\\n\", __FUNCTION__, ##arg)\n#endif /* !_KERNEL */\n\nstruct entry {\n\tuint32_t\tid;\n\tstruct entry\t*ptr;\n};\n\nstruct lookup_table {\n\tint _size;\n\tint used;\n\tint mask; /* 2^k -1, used for hashing */\n\tstruct entry *f_head, *f_tail; /* freelist */\n\tstruct entry *\ts;\t/* slots, array of N entries */\n};\n\nstatic __inline int empty(struct lookup_table *head, const void *p)\n{\n\tconst struct entry *ep = p;\n\treturn (ep == NULL ||\n\t\t(ep >= head->s && ep < &head->s[head->_size]));\n}\n\n/*\n * init or reinit a table\n */\nstruct lookup_table *\nipfw_lut_init(struct lookup_table *head, int new_size, int mask)\n{\n\tint i;\n\tstruct entry *s;\t/* the new slots */\n\tstruct entry *fh, *ft;\t/* the freelist */\n\n\tif (head != NULL) {\n\t\tmask = head->mask;\n\t\tif (new_size <= head->_size)\n\t\t\treturn head;\n\t\tif (new_size >= mask+1) {\n\t\t\tlog(\"size larger than mask\");\n\t\t\treturn NULL;\n\t\t}\n\t} else {\n\t\tlog(\"old is null, initialize\");\n\t\thead = Calloc(sizeof(*head));\n\t\tif (head == NULL)\n\t\t\treturn NULL;\n\t\tif (new_size >= mask)\n\t\t\tmask = new_size;\n\t\tif (mask & (mask -1)) {\n\t\t\tfor (i = 1; i < mask; i += i)\n\t\t\t    ;\n\t\t\tlog(\"mask %d not 2^k, round up to %d\", mask, i);\n\t\t\tmask = i;\n\t\t}\n\t\tmask = head->mask = mask - 1;\n\t}\n\n\ts = Calloc(new_size * sizeof(*s));\n\tif (s == NULL)\n\t\treturn NULL;\n\tif (!head->s) {\n\t\thead->s = s;\n\t\thead->_size = 1;\n\t}\n\tfh = ft = NULL;\n\t/* remap the entries, adjust the freelist */\n\tfor (i = 0; i < new_size; i++) {\n\t\ts[i].id = (i >= head->_size) ? i : head->s[i].id;\n\t\tif (i < head->_size && !empty(head, head->s[i].ptr)) {\n\t\t\ts[i].ptr = head->s[i].ptr;\n\t\t\tcontinue;\n\t\t}\n\t\tif (fh == NULL)\n\t\t\tfh = &s[i];\n\t\telse\n\t\t\tft->ptr = &s[i];\n\t\tft = &s[i];\n\t}\n\thead->f_head = fh;\n\thead->f_tail = ft;\n\n\t/* write lock on the structure, to protect the readers */\n\tfh = head->s;\n\thead->s = s;\n\thead->_size = new_size;\n\t/* release write lock */\n\tif (fh != s)\n\t\tFree(fh);\n\tlog(\"done\");\n\treturn head;\n}\n\n/* insert returns the id */\nint\nipfw_lut_insert(struct lookup_table *head, void *d)\n{\n\tstruct entry *e;\n\n\te = head->f_head;\n\tif (e == NULL)\n\t\treturn -1;\n\thead->f_head = e->ptr;\n\te->ptr = d;\n\thead->used++;\n\treturn e->id;\n}\n\n/* delete, returns the original entry */\nvoid *\nipfw_lut_delete(struct lookup_table *head, int id)\n{\n\tint i = id & head->mask;\n\tvoid *result;\n\tstruct entry *e;\n\n\tif (i >= head->_size)\n\t\treturn NULL;\n\te = &head->s[i];\n\tif (e->id != id)\n\t\treturn NULL;\n\tresult = e->ptr;\n\t/* write lock to invalidate the entry to readers */\n\te->id += head->mask + 1; /* prepare for next insert */\n\te->ptr = NULL;\n\t/* release write lock */\n\tif (head->f_head == NULL)\n\t\thead->f_head = e;\n\telse\n\t\thead->f_tail->ptr = e;\n\thead->f_tail = e;\n\thead->used--;\n\treturn result;\n}\n\nvoid *\nipfw_lut_lookup(struct lookup_table *head, int id)\n{\n\tint i = id & head->mask;\n\tstruct entry *e;\n\n\tif (i >= head->_size)\n\t\treturn NULL;\n\te = &head->s[i];\n\treturn (e->id == id) ? e->ptr : NULL;\n}\n\nvoid\nipfw_lut_dump(struct lookup_table *head)\n{\n\tint i;\n\n\tlog(\"head %p size %d used %d freelist %d\",\n\t    head, head->_size, head->used, head->f_head ?\n\t\t    head->f_head - head->s : -1);\n\tfor (i = 0; i < head->_size; i++) {\n\t\tstruct entry *e = &head->s[i];\n\t\tchar ee = empty(head, e->ptr) ? 'E' : ' ';\n\t\tlog(\"%5d  %5d %c %p\", i, e->id, ee,\n\t\t    ee == 'E' && e->ptr != NULL ?\n\t\t    (void *)((struct entry *)e->ptr - head->s) : e->ptr);\n\t}\n}\n\n#ifndef _KERNEL\nvoid dump_p(struct lookup_table *p, int *map)\n{\n\tint i;\n\tfor (i = 0; i < p->_size; i++) {\n\t    int id = (int)ipfw_lut_lookup(p, map[i]);\n\t    log(\"%3d: %3d: %c\", map[i] % 64, i, id);\n\t}\n}\nint main(int argc, char *argv[])\n{\n\tint i, j, l;\n#define S 1000\n\tint map[S];\n\tstruct lookup_table *p;\n\tstruct lookup_table *p1;\n\tconst char *m = \"nel mezzo del cammin di nostra vita mi ritrovai\"\n\t\t\" in una selva oscura e la diritta via era smarrita!\";\n\n\tfprintf(stderr, \"testing lookup\\n\");\n\n\tl = strlen(m);\n\n\tp = ipfw_lut_init(NULL, 120, 33);\n\n\tipfw_lut_dump(p);\n\tfor (i = 0; i < l; i++) {\n\t    int x = m[i];\n\t    int id = ipfw_lut_insert(p, (void *)x);\n\t    //ipfw_lut_dump(p);\n\t    map[i] = id;\n\t    for (j=0; j < 10; j++) {\n\t\t    id = ipfw_lut_insert(p, (void *)'a');\n\t\t    // ipfw_lut_dump(p);\n\t\t    ipfw_lut_delete(p, id);\n\t    \t    // ipfw_lut_dump(p);\n\t    }\n\t//    ipfw_lut_dump(p);\n\t} \n\tdump_p(p, map);\n\tp1 = ipfw_lut_init(p, 23, 0);\n\tif (!p1)\n\t\treturn 1;\n\tdump_p(p1, map);\n\tp1 = ipfw_lut_init(p1, 120, 0);\n\tif (!p1)\n\t\treturn 1;\n\tdump_p(p1, map);\n\treturn 0;\n}\n#endif\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_nat.c",
    "content": "/*-\n * Copyright (c) 2008 Paolo Pisati\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_nat.c 200975 2009-12-25 01:15:39Z luigi $\");\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/eventhandler.h>\n#include <sys/malloc.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/module.h>\n#include <sys/rwlock.h>\n\n#define        IPFW_INTERNAL   /* Access to protected data structures in ip_fw.h. */\n\n#include <netinet/libalias/alias.h>\n#include <netinet/libalias/alias_local.h>\n\n#include <net/if.h>\n#include <netinet/in.h>\n#include <netinet/ip.h>\n#include <netinet/ip_var.h>\n#include <netinet/ip_fw.h>\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netinet/tcp.h>\n#include <netinet/udp.h>\n\n#include <machine/in_cksum.h>\t/* XXX for in_cksum */\n\nstatic VNET_DEFINE(eventhandler_tag, ifaddr_event_tag);\n#define\tV_ifaddr_event_tag\tVNET(ifaddr_event_tag)\n\nstatic void\nifaddr_change(void *arg, struct ifnet *ifp)\n{\n\tstruct cfg_nat *ptr;\n\tstruct ifaddr *ifa;\n\tstruct ip_fw_chain *chain;\n\n\t(void)arg;\n\tchain = &V_layer3_chain;\n\tIPFW_WLOCK(chain);\n\t/* Check every nat entry... */\n\tLIST_FOREACH(ptr, &chain->nat, _next) {\n\t\t/* ...using nic 'ifp->if_xname' as dynamic alias address. */\n\t\tif (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)\n\t\t\tcontinue;\n\t\tif_addr_rlock(ifp);\n\t\tTAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {\n\t\t\tif (ifa->ifa_addr == NULL)\n\t\t\t\tcontinue;\n\t\t\tif (ifa->ifa_addr->sa_family != AF_INET)\n\t\t\t\tcontinue;\n\t\t\tptr->ip = ((struct sockaddr_in *)\n\t\t\t    (ifa->ifa_addr))->sin_addr;\n\t\t\tLibAliasSetAddress(ptr->lib, ptr->ip);\n\t\t}\n\t\tif_addr_runlock(ifp);\n\t}\n\tIPFW_WUNLOCK(chain);\n}\n\n/*\n * delete the pointers for nat entry ix, or all of them if ix < 0\n */\nstatic void\nflush_nat_ptrs(struct ip_fw_chain *chain, const int ix)\n{\n\tint i;\n\tipfw_insn_nat *cmd;\n\n\tIPFW_WLOCK_ASSERT(chain);\n\tfor (i = 0; i < chain->n_rules; i++) {\n\t\tcmd = (ipfw_insn_nat *)ACTION_PTR(chain->map[i]);\n\t\t/* XXX skip log and the like ? */\n\t\tif (cmd->o.opcode == O_NAT && cmd->nat != NULL &&\n\t\t\t    (ix < 0 || cmd->nat->id == ix))\n\t\t\tcmd->nat = NULL;\n\t}\n}\n\nstatic void\ndel_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head)\n{\n\tstruct cfg_redir *r, *tmp_r;\n\tstruct cfg_spool *s, *tmp_s;\n\tint i, num;\n\n\tLIST_FOREACH_SAFE(r, head, _next, tmp_r) {\n\t\tnum = 1; /* Number of alias_link to delete. */\n\t\tswitch (r->mode) {\n\t\tcase REDIR_PORT:\n\t\t\tnum = r->pport_cnt;\n\t\t\t/* FALLTHROUGH */\n\t\tcase REDIR_ADDR:\n\t\tcase REDIR_PROTO:\n\t\t\t/* Delete all libalias redirect entry. */\n\t\t\tfor (i = 0; i < num; i++)\n\t\t\t\tLibAliasRedirectDelete(n->lib, r->alink[i]);\n\t\t\t/* Del spool cfg if any. */\n\t\t\tLIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {\n\t\t\t\tLIST_REMOVE(s, _next);\n\t\t\t\tfree(s, M_IPFW);\n\t\t\t}\n\t\t\tfree(r->alink, M_IPFW);\n\t\t\tLIST_REMOVE(r, _next);\n\t\t\tfree(r, M_IPFW);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintf(\"unknown redirect mode: %u\\n\", r->mode);\n\t\t\t/* XXX - panic?!?!? */\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nstatic int\nadd_redir_spool_cfg(char *buf, struct cfg_nat *ptr)\n{\n\tstruct cfg_redir *r, *ser_r;\n\tstruct cfg_spool *s, *ser_s;\n\tint cnt, off, i;\n\n\tfor (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {\n\t\tser_r = (struct cfg_redir *)&buf[off];\n\t\tr = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO);\n\t\tmemcpy(r, ser_r, SOF_REDIR);\n\t\tLIST_INIT(&r->spool_chain);\n\t\toff += SOF_REDIR;\n\t\tr->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,\n\t\t    M_IPFW, M_WAITOK | M_ZERO);\n\t\tswitch (r->mode) {\n\t\tcase REDIR_ADDR:\n\t\t\tr->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,\n\t\t\t    r->paddr);\n\t\t\tbreak;\n\t\tcase REDIR_PORT:\n\t\t\tfor (i = 0 ; i < r->pport_cnt; i++) {\n\t\t\t\t/* If remotePort is all ports, set it to 0. */\n\t\t\t\tu_short remotePortCopy = r->rport + i;\n\t\t\t\tif (r->rport_cnt == 1 && r->rport == 0)\n\t\t\t\t\tremotePortCopy = 0;\n\t\t\t\tr->alink[i] = LibAliasRedirectPort(ptr->lib,\n\t\t\t\t    r->laddr, htons(r->lport + i), r->raddr,\n\t\t\t\t    htons(remotePortCopy), r->paddr,\n\t\t\t\t    htons(r->pport + i), r->proto);\n\t\t\t\tif (r->alink[i] == NULL) {\n\t\t\t\t\tr->alink[0] = NULL;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase REDIR_PROTO:\n\t\t\tr->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,\n\t\t\t    r->raddr, r->paddr, r->proto);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintf(\"unknown redirect mode: %u\\n\", r->mode);\n\t\t\tbreak;\n\t\t}\n\t\t/* XXX perhaps return an error instead of panic ? */\n\t\tif (r->alink[0] == NULL)\n\t\t\tpanic(\"LibAliasRedirect* returned NULL\");\n\t\t/* LSNAT handling. */\n\t\tfor (i = 0; i < r->spool_cnt; i++) {\n\t\t\tser_s = (struct cfg_spool *)&buf[off];\n\t\t\ts = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO);\n\t\t\tmemcpy(s, ser_s, SOF_SPOOL);\n\t\t\tLibAliasAddServer(ptr->lib, r->alink[0],\n\t\t\t    s->addr, htons(s->port));\n\t\t\toff += SOF_SPOOL;\n\t\t\t/* Hook spool entry. */\n\t\t\tLIST_INSERT_HEAD(&r->spool_chain, s, _next);\n\t\t}\n\t\t/* And finally hook this redir entry. */\n\t\tLIST_INSERT_HEAD(&ptr->redir_chain, r, _next);\n\t}\n\treturn (1);\n}\n\nstatic int\nipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)\n{\n\tstruct mbuf *mcl;\n\tstruct ip *ip;\n\t/* XXX - libalias duct tape */\n\tint ldt, retval;\n\tchar *c;\n\n\tldt = 0;\n\tretval = 0;\n\tmcl = m_megapullup(m, m->m_pkthdr.len);\n\tif (mcl == NULL) {\n\t\targs->m = NULL;\n\t\treturn (IP_FW_DENY);\n\t}\n\tip = mtod(mcl, struct ip *);\n\n\t/*\n\t * XXX - Libalias checksum offload 'duct tape':\n\t *\n\t * locally generated packets have only pseudo-header checksum\n\t * calculated and libalias will break it[1], so mark them for\n\t * later fix.  Moreover there are cases when libalias modifies\n\t * tcp packet data[2], mark them for later fix too.\n\t *\n\t * [1] libalias was never meant to run in kernel, so it does\n\t * not have any knowledge about checksum offloading, and\n\t * expects a packet with a full internet checksum.\n\t * Unfortunately, packets generated locally will have just the\n\t * pseudo header calculated, and when libalias tries to adjust\n\t * the checksum it will actually compute a wrong value.\n\t *\n\t * [2] when libalias modifies tcp's data content, full TCP\n\t * checksum has to be recomputed: the problem is that\n\t * libalias does not have any idea about checksum offloading.\n\t * To work around this, we do not do checksumming in LibAlias,\n\t * but only mark the packets in th_x2 field. If we receive a\n\t * marked packet, we calculate correct checksum for it\n\t * aware of offloading.  Why such a terrible hack instead of\n\t * recalculating checksum for each packet?\n\t * Because the previous checksum was not checked!\n\t * Recalculating checksums for EVERY packet will hide ALL\n\t * transmission errors. Yes, marked packets still suffer from\n\t * this problem. But, sigh, natd(8) has this problem, too.\n\t *\n\t * TODO: -make libalias mbuf aware (so\n\t * it can handle delayed checksum and tso)\n\t */\n\n\tif (mcl->m_pkthdr.rcvif == NULL &&\n\t    mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA)\n\t\tldt = 1;\n\n\tc = mtod(mcl, char *);\n\tif (args->oif == NULL)\n\t\tretval = LibAliasIn(t->lib, c,\n\t\t\tmcl->m_len + M_TRAILINGSPACE(mcl));\n\telse\n\t\tretval = LibAliasOut(t->lib, c,\n\t\t\tmcl->m_len + M_TRAILINGSPACE(mcl));\n\tif (retval == PKT_ALIAS_RESPOND) {\n\t\tm->m_flags |= M_SKIP_FIREWALL;\n\t\tretval = PKT_ALIAS_OK;\n\t}\n\tif (retval != PKT_ALIAS_OK &&\n\t    retval != PKT_ALIAS_FOUND_HEADER_FRAGMENT) {\n\t\t/* XXX - should i add some logging? */\n\t\tm_free(mcl);\n\t\targs->m = NULL;\n\t\treturn (IP_FW_DENY);\n\t}\n\tmcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len);\n\n\t/*\n\t * XXX - libalias checksum offload\n\t * 'duct tape' (see above)\n\t */\n\n\tif ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&\n\t    ip->ip_p == IPPROTO_TCP) {\n\t\tstruct tcphdr \t*th;\n\n\t\tth = (struct tcphdr *)(ip + 1);\n\t\tif (th->th_x2)\n\t\t\tldt = 1;\n\t}\n\n\tif (ldt) {\n\t\tstruct tcphdr \t*th;\n\t\tstruct udphdr \t*uh;\n\t\tu_short cksum;\n\n\t\tip->ip_len = ntohs(ip->ip_len);\n\t\tcksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,\n\t\t    htons(ip->ip_p + ip->ip_len - (ip->ip_hl << 2)));\n\n\t\tswitch (ip->ip_p) {\n\t\tcase IPPROTO_TCP:\n\t\t\tth = (struct tcphdr *)(ip + 1);\n\t\t\t/*\n\t\t\t * Maybe it was set in\n\t\t\t * libalias...\n\t\t\t */\n\t\t\tth->th_x2 = 0;\n\t\t\tth->th_sum = cksum;\n\t\t\tmcl->m_pkthdr.csum_data =\n\t\t\t    offsetof(struct tcphdr, th_sum);\n\t\t\tbreak;\n\t\tcase IPPROTO_UDP:\n\t\t\tuh = (struct udphdr *)(ip + 1);\n\t\t\tuh->uh_sum = cksum;\n\t\t\tmcl->m_pkthdr.csum_data =\n\t\t\t    offsetof(struct udphdr, uh_sum);\n\t\t\tbreak;\n\t\t}\n\t\t/* No hw checksum offloading: do it ourselves */\n\t\tif ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) {\n\t\t\tin_delayed_cksum(mcl);\n\t\t\tmcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;\n\t\t}\n\t\tip->ip_len = htons(ip->ip_len);\n\t}\n\targs->m = mcl;\n\treturn (IP_FW_NAT);\n}\n\nstatic struct cfg_nat *\nlookup_nat(struct nat_list *l, int nat_id)\n{\n\tstruct cfg_nat *res;\n\n\tLIST_FOREACH(res, l, _next) {\n\t\tif (res->id == nat_id)\n\t\t\tbreak;\n\t}\n\treturn res;\n}\n\nstatic int\nipfw_nat_cfg(struct sockopt *sopt)\n{\n\tstruct cfg_nat *ptr, *ser_n;\n\tchar *buf;\n\tstruct ip_fw_chain *chain = &V_layer3_chain;\n\n\tbuf = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO);\n\tsooptcopyin(sopt, buf, NAT_BUF_LEN, sizeof(struct cfg_nat));\n\tser_n = (struct cfg_nat *)buf;\n\n\t/* check valid parameter ser_n->id > 0 ? */\n\t/*\n\t * Find/create nat rule.\n\t */\n\tIPFW_WLOCK(chain);\n\tptr = lookup_nat(&chain->nat, ser_n->id);\n\tif (ptr == NULL) {\n\t\t/* New rule: allocate and init new instance. */\n\t\tptr = malloc(sizeof(struct cfg_nat),\n\t\t    M_IPFW, M_NOWAIT | M_ZERO);\n\t\tif (ptr == NULL) {\n\t\t\tIPFW_WUNLOCK(chain);\n\t\t\tfree(buf, M_IPFW);\n\t\t\treturn (ENOSPC);\n\t\t}\n\t\tptr->lib = LibAliasInit(NULL);\n\t\tif (ptr->lib == NULL) {\n\t\t\tIPFW_WUNLOCK(chain);\n\t\t\tfree(ptr, M_IPFW);\n\t\t\tfree(buf, M_IPFW);\n\t\t\treturn (EINVAL);\n\t\t}\n\t\tLIST_INIT(&ptr->redir_chain);\n\t} else {\n\t\t/* Entry already present: temporarly unhook it. */\n\t\tLIST_REMOVE(ptr, _next);\n\t\tflush_nat_ptrs(chain, ser_n->id);\n\t}\n\tIPFW_WUNLOCK(chain);\n\n\t/*\n\t * Basic nat configuration.\n\t */\n\tptr->id = ser_n->id;\n\t/*\n\t * XXX - what if this rule doesn't nat any ip and just\n\t * redirect?\n\t * do we set aliasaddress to 0.0.0.0?\n\t */\n\tptr->ip = ser_n->ip;\n\tptr->redir_cnt = ser_n->redir_cnt;\n\tptr->mode = ser_n->mode;\n\tLibAliasSetMode(ptr->lib, ser_n->mode, ser_n->mode);\n\tLibAliasSetAddress(ptr->lib, ptr->ip);\n\tmemcpy(ptr->if_name, ser_n->if_name, IF_NAMESIZE);\n\n\t/*\n\t * Redir and LSNAT configuration.\n\t */\n\t/* Delete old cfgs. */\n\tdel_redir_spool_cfg(ptr, &ptr->redir_chain);\n\t/* Add new entries. */\n\tadd_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr);\n\tfree(buf, M_IPFW);\n\tIPFW_WLOCK(chain);\n\tLIST_INSERT_HEAD(&chain->nat, ptr, _next);\n\tIPFW_WUNLOCK(chain);\n\treturn (0);\n}\n\nstatic int\nipfw_nat_del(struct sockopt *sopt)\n{\n\tstruct cfg_nat *ptr;\n\tstruct ip_fw_chain *chain = &V_layer3_chain;\n\tint i;\n\n\tsooptcopyin(sopt, &i, sizeof i, sizeof i);\n\t/* XXX validate i */\n\tIPFW_WLOCK(chain);\n\tptr = lookup_nat(&chain->nat, i);\n\tif (ptr == NULL) {\n\t\tIPFW_WUNLOCK(chain);\n\t\treturn (EINVAL);\n\t}\n\tLIST_REMOVE(ptr, _next);\n\tflush_nat_ptrs(chain, i);\n\tIPFW_WUNLOCK(chain);\n\tdel_redir_spool_cfg(ptr, &ptr->redir_chain);\n\tLibAliasUninit(ptr->lib);\n\tfree(ptr, M_IPFW);\n\treturn (0);\n}\n\nstatic int\nipfw_nat_get_cfg(struct sockopt *sopt)\n{\n\tuint8_t *data;\n\tstruct cfg_nat *n;\n\tstruct cfg_redir *r;\n\tstruct cfg_spool *s;\n\tint nat_cnt, off;\n\tstruct ip_fw_chain *chain;\n\tint err = ENOSPC;\n\n\tchain = &V_layer3_chain;\n\tnat_cnt = 0;\n\toff = sizeof(nat_cnt);\n\n\tdata = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO);\n\tIPFW_RLOCK(chain);\n\t/* Serialize all the data. */\n\tLIST_FOREACH(n, &chain->nat, _next) {\n\t\tnat_cnt++;\n\t\tif (off + SOF_NAT >= NAT_BUF_LEN)\n\t\t\tgoto nospace;\n\t\tbcopy(n, &data[off], SOF_NAT);\n\t\toff += SOF_NAT;\n\t\tLIST_FOREACH(r, &n->redir_chain, _next) {\n\t\t\tif (off + SOF_REDIR >= NAT_BUF_LEN)\n\t\t\t\tgoto nospace;\n\t\t\tbcopy(r, &data[off], SOF_REDIR);\n\t\t\toff += SOF_REDIR;\n\t\t\tLIST_FOREACH(s, &r->spool_chain, _next) {\n\t\t\t\tif (off + SOF_SPOOL >= NAT_BUF_LEN)\n\t\t\t\t\tgoto nospace;\n\t\t\t\tbcopy(s, &data[off], SOF_SPOOL);\n\t\t\t\toff += SOF_SPOOL;\n\t\t\t}\n\t\t}\n\t}\n\terr = 0; /* all good */\nnospace:\n\tIPFW_RUNLOCK(chain);\n\tif (err == 0) {\n\t\tbcopy(&nat_cnt, data, sizeof(nat_cnt));\n\t\tsooptcopyout(sopt, data, NAT_BUF_LEN);\n\t} else {\n\t\tprintf(\"serialized data buffer not big enough:\"\n\t\t    \"please increase NAT_BUF_LEN\\n\");\n\t}\n\tfree(data, M_IPFW);\n\treturn (err);\n}\n\nstatic int\nipfw_nat_get_log(struct sockopt *sopt)\n{\n\tuint8_t *data;\n\tstruct cfg_nat *ptr;\n\tint i, size;\n\tstruct ip_fw_chain *chain;\n\n\tchain = &V_layer3_chain;\n\n\tIPFW_RLOCK(chain);\n\t/* one pass to count, one to copy the data */\n\ti = 0;\n\tLIST_FOREACH(ptr, &chain->nat, _next) {\n\t\tif (ptr->lib->logDesc == NULL)\n\t\t\tcontinue;\n\t\ti++;\n\t}\n\tsize = i * (LIBALIAS_BUF_SIZE + sizeof(int));\n\tdata = malloc(size, M_IPFW, M_NOWAIT | M_ZERO);\n\tif (data == NULL) {\n\t\tIPFW_RUNLOCK(chain);\n\t\treturn (ENOSPC);\n\t}\n\ti = 0;\n\tLIST_FOREACH(ptr, &chain->nat, _next) {\n\t\tif (ptr->lib->logDesc == NULL)\n\t\t\tcontinue;\n\t\tbcopy(&ptr->id, &data[i], sizeof(int));\n\t\ti += sizeof(int);\n\t\tbcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE);\n\t\ti += LIBALIAS_BUF_SIZE;\n\t}\n\tIPFW_RUNLOCK(chain);\n\tsooptcopyout(sopt, data, size);\n\tfree(data, M_IPFW);\n\treturn(0);\n}\n\nstatic void\nipfw_nat_init(void)\n{\n\n\tIPFW_WLOCK(&V_layer3_chain);\n\t/* init ipfw hooks */\n\tipfw_nat_ptr = ipfw_nat;\n\tlookup_nat_ptr = lookup_nat;\n\tipfw_nat_cfg_ptr = ipfw_nat_cfg;\n\tipfw_nat_del_ptr = ipfw_nat_del;\n\tipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;\n\tipfw_nat_get_log_ptr = ipfw_nat_get_log;\n\tIPFW_WUNLOCK(&V_layer3_chain);\n\tV_ifaddr_event_tag = EVENTHANDLER_REGISTER(\n\t    ifaddr_event, ifaddr_change,\n\t    NULL, EVENTHANDLER_PRI_ANY);\n}\n\nstatic void\nipfw_nat_destroy(void)\n{\n\tstruct cfg_nat *ptr, *ptr_temp;\n\tstruct ip_fw_chain *chain;\n\n\tchain = &V_layer3_chain;\n\tIPFW_WLOCK(chain);\n\tLIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {\n\t\tLIST_REMOVE(ptr, _next);\n\t\tdel_redir_spool_cfg(ptr, &ptr->redir_chain);\n\t\tLibAliasUninit(ptr->lib);\n\t\tfree(ptr, M_IPFW);\n\t}\n\tEVENTHANDLER_DEREGISTER(ifaddr_event, V_ifaddr_event_tag);\n\tflush_nat_ptrs(chain, -1 /* flush all */);\n\t/* deregister ipfw_nat */\n\tipfw_nat_ptr = NULL;\n\tlookup_nat_ptr = NULL;\n\tipfw_nat_cfg_ptr = NULL;\n\tipfw_nat_del_ptr = NULL;\n\tipfw_nat_get_cfg_ptr = NULL;\n\tipfw_nat_get_log_ptr = NULL;\n\tIPFW_WUNLOCK(chain);\n}\n\nstatic int\nipfw_nat_modevent(module_t mod, int type, void *unused)\n{\n\tint err = 0;\n\n\tswitch (type) {\n\tcase MOD_LOAD:\n\t\tipfw_nat_init();\n\t\tbreak;\n\n\tcase MOD_UNLOAD:\n\t\tipfw_nat_destroy();\n\t\tbreak;\n\n\tdefault:\n\t\treturn EOPNOTSUPP;\n\t\tbreak;\n\t}\n\treturn err;\n}\n\nstatic moduledata_t ipfw_nat_mod = {\n\t\"ipfw_nat\",\n\tipfw_nat_modevent,\n\t0\n};\n\nDECLARE_MODULE(ipfw_nat, ipfw_nat_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);\nMODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);\nMODULE_DEPEND(ipfw_nat, ipfw, 2, 2, 2);\nMODULE_VERSION(ipfw_nat, 1);\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_pfil.c",
    "content": "/*-\n * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: head/sys/netinet/ipfw/ip_fw_pfil.c 200601 2009-12-16 10:48:40Z luigi $\");\n\n#if !defined(KLD_MODULE)\n#include \"opt_ipfw.h\"\n#include \"opt_ipdn.h\"\n#include \"opt_inet.h\"\n#ifndef INET\n#error IPFIREWALL requires INET.\n#endif /* INET */\n#endif /* KLD_MODULE */\n#include \"opt_inet6.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/mbuf.h>\n#include <sys/module.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/rwlock.h>\n#include <sys/socket.h>\n#include <sys/sysctl.h>\n\n#include <net/if.h>\n#include <net/route.h>\n#include <net/pfil.h>\n#include <net/vnet.h>\n\n#include <netinet/in.h>\n#include <netinet/in_systm.h>\n#include <netinet/ip.h>\n#include <netinet/ip_var.h>\n#include <netinet/ip_fw.h>\n#include <netinet/ipfw/ip_fw_private.h>\n#include <netgraph/ng_ipfw.h>\n\n#include <machine/in_cksum.h>\n\nstatic VNET_DEFINE(int, fw_enable) = 1;\n#define V_fw_enable\tVNET(fw_enable)\n\n#ifdef INET6\nstatic VNET_DEFINE(int, fw6_enable) = 1;\n#define V_fw6_enable\tVNET(fw6_enable)\n#endif\n\nint ipfw_chg_hook(SYSCTL_HANDLER_ARGS);\n\n/* Forward declarations. */\nstatic int ipfw_divert(struct mbuf **, int, struct ipfw_rule_ref *, int);\n\n#ifdef SYSCTL_NODE\n\nSYSBEGIN(f1)\n\nSYSCTL_DECL(_net_inet_ip_fw);\nSYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable,\n    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0,\n    ipfw_chg_hook, \"I\", \"Enable ipfw\");\n#ifdef INET6\nSYSCTL_DECL(_net_inet6_ip6_fw);\nSYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable,\n    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw6_enable), 0,\n    ipfw_chg_hook, \"I\", \"Enable ipfw+6\");\n#endif /* INET6 */\n\nSYSEND\n\n#endif /* SYSCTL_NODE */\n\n/*\n * The pfilter hook to pass packets to ipfw_chk and then to\n * dummynet, divert, netgraph or other modules.\n * The packet may be consumed.\n */\nint\nipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,\n    struct inpcb *inp)\n{\n\tstruct ip_fw_args args;\n\tstruct m_tag *tag;\n\tint ipfw;\n\tint ret;\n\n\t/* all the processing now uses ip_len in net format */\n\tif (mtod(*m0, struct ip *)->ip_v == 4)\n\t\tSET_NET_IPLEN(mtod(*m0, struct ip *));\n\n\t/* convert dir to IPFW values */\n\tdir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;\n\tbzero(&args, sizeof(args));\n\nagain:\n\t/*\n\t * extract and remove the tag if present. If we are left\n\t * with onepass, optimize the outgoing path.\n\t */\n\ttag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);\n\tif (tag != NULL) {\n\t\targs.rule = *((struct ipfw_rule_ref *)(tag+1));\n\t\tm_tag_delete(*m0, tag);\n\t\tif (args.rule.info & IPFW_ONEPASS) {\n\t\t\tSET_HOST_IPLEN(mtod(*m0, struct ip *));\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\targs.m = *m0;\n\targs.oif = dir == DIR_OUT ? ifp : NULL;\n\targs.inp = inp;\n\n\tipfw = ipfw_chk(&args);\n\t*m0 = args.m;\n\n\tKASSERT(*m0 != NULL || ipfw == IP_FW_DENY, (\"%s: m0 is NULL\",\n\t    __func__));\n\n\t/* breaking out of the switch means drop */\n\tret = 0;\t/* default return value for pass */\n\tswitch (ipfw) {\n\tcase IP_FW_PASS:\n\t\t/* next_hop may be set by ipfw_chk */\n\t\tif (args.next_hop == NULL)\n\t\t\tbreak; /* pass */\n#ifndef IPFIREWALL_FORWARD\n\t\tret = EACCES;\n#else\n\t    {\n\t\tstruct m_tag *fwd_tag;\n\n\t\t/* Incoming packets should not be tagged so we do not\n\t\t * m_tag_find. Outgoing packets may be tagged, so we\n\t\t * reuse the tag if present.\n\t\t */\n\t\tfwd_tag = (dir == DIR_IN) ? NULL :\n\t\t\tm_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);\n\t\tif (fwd_tag != NULL) {\n\t\t\tm_tag_unlink(*m0, fwd_tag);\n\t\t} else {\n\t\t\tfwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,\n\t\t\t\tsizeof(struct sockaddr_in), M_NOWAIT);\n\t\t\tif (fwd_tag == NULL) {\n\t\t\t\tret = EACCES;\n\t\t\t\tbreak; /* i.e. drop */\n\t\t\t}\n\t\t}\n\t\tbcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));\n\t\tm_tag_prepend(*m0, fwd_tag);\n\n\t\tif (in_localip(args.next_hop->sin_addr))\n\t\t\t(*m0)->m_flags |= M_FASTFWD_OURS;\n\t    }\n#endif\n\t\tbreak;\n\n\tcase IP_FW_DENY:\n\t\tret = EACCES;\n\t\tbreak; /* i.e. drop */\n\n\tcase IP_FW_DUMMYNET:\n\t\tret = EACCES;\n\t\tif (ip_dn_io_ptr == NULL)\n\t\t\tbreak; /* i.e. drop */\n\t\tif (mtod(*m0, struct ip *)->ip_v == 4)\n\t\t\tret = ip_dn_io_ptr(m0, dir, &args);\n\t\telse if (mtod(*m0, struct ip *)->ip_v == 6)\n\t\t\tret = ip_dn_io_ptr(m0, dir | PROTO_IPV6, &args);\n\t\telse\n\t\t\tbreak; /* drop it */\n\t\t/*\n\t\t * XXX should read the return value.\n\t\t * dummynet normally eats the packet and sets *m0=NULL\n\t\t * unless the packet can be sent immediately. In this\n\t\t * case args is updated and we should re-run the\n\t\t * check without clearing args.\n\t\t */\n\t\tif (*m0 != NULL)\n\t\t\tgoto again;\n\t\tbreak;\n\n\tcase IP_FW_TEE:\n\tcase IP_FW_DIVERT:\n\t\tif (ip_divert_ptr == NULL) {\n\t\t\tret = EACCES;\n\t\t\tbreak; /* i.e. drop */\n\t\t}\n\t\tret = ipfw_divert(m0, dir, &args.rule,\n\t\t\t(ipfw == IP_FW_TEE) ? 1 : 0);\n\t\t/* continue processing for the original packet (tee). */\n\t\tif (*m0)\n\t\t\tgoto again;\n\t\tbreak;\n\n\tcase IP_FW_NGTEE:\n\tcase IP_FW_NETGRAPH:\n\t\tif (ng_ipfw_input_p == NULL) {\n\t\t\tret = EACCES;\n\t\t\tbreak; /* i.e. drop */\n\t\t}\n\t\tret = ng_ipfw_input_p(m0, dir, &args,\n\t\t\t(ipfw == IP_FW_NGTEE) ? 1 : 0);\n\t\tif (ipfw == IP_FW_NGTEE) /* ignore errors for NGTEE */\n\t\t\tgoto again;\t/* continue with packet */\n\t\tbreak;\n\n\tcase IP_FW_NAT:\n\t\t/* honor one-pass in case of successful nat */\n\t\tif (V_fw_one_pass)\n\t\t\tbreak; /* ret is already 0 */\n\t\tgoto again;\n\n\tcase IP_FW_REASS:\n\t\tgoto again;\t\t/* continue with packet */\n\t\n\tdefault:\n\t\tKASSERT(0, (\"%s: unknown retval\", __func__));\n\t}\n\n\tif (ret != 0) {\n\t\tif (*m0)\n\t\t\tFREE_PKT(*m0);\n\t\t*m0 = NULL;\n\t}\n\tif (*m0 && mtod(*m0, struct ip *)->ip_v == 4)\n\t\tSET_HOST_IPLEN(mtod(*m0, struct ip *));\n\treturn ret;\n}\n\n/* do the divert, return 1 on error 0 on success */\nstatic int\nipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule,\n\tint tee)\n{\n\t/*\n\t * ipfw_chk() has already tagged the packet with the divert tag.\n\t * If tee is set, copy packet and return original.\n\t * If not tee, consume packet and send it to divert socket.\n\t */\n\tstruct mbuf *clone;\n\tstruct ip *ip;\n\tstruct m_tag *tag;\n\n\t/* Cloning needed for tee? */\n\tif (tee == 0) {\n\t\tclone = *m0;\t/* use the original mbuf */\n\t\t*m0 = NULL;\n\t} else {\n\t\tclone = m_dup(*m0, M_DONTWAIT);\n\t\t/* If we cannot duplicate the mbuf, we sacrifice the divert\n\t\t * chain and continue with the tee-ed packet.\n\t\t */\n\t\tif (clone == NULL)\n\t\t\treturn 1;\n\t}\n\n\t/*\n\t * Divert listeners can normally handle non-fragmented packets,\n\t * but we can only reass in the non-tee case.\n\t * This means that listeners on a tee rule may get fragments,\n\t * and have to live with that.\n\t * Note that we now have the 'reass' ipfw option so if we care\n\t * we can do it before a 'tee'.\n\t */\n\tip = mtod(clone, struct ip *);\n\tif (!tee && ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {\n\t\tint hlen;\n\t\tstruct mbuf *reass;\n\n\t\tSET_HOST_IPLEN(ip); /* ip_reass wants host order */\n\t\treass = ip_reass(clone); /* Reassemble packet. */\n\t\tif (reass == NULL)\n\t\t\treturn 0; /* not an error */\n\t\t/* if reass = NULL then it was consumed by ip_reass */\n\t\t/*\n\t\t * IP header checksum fixup after reassembly and leave header\n\t\t * in network byte order.\n\t\t */\n\t\tip = mtod(reass, struct ip *);\n\t\thlen = ip->ip_hl << 2;\n\t\tSET_NET_IPLEN(ip);\n\t\tip->ip_sum = 0;\n\t\tif (hlen == sizeof(struct ip))\n\t\t\tip->ip_sum = in_cksum_hdr(ip);\n\t\telse\n\t\t\tip->ip_sum = in_cksum(reass, hlen);\n\t\tclone = reass;\n\t}\n\t/* attach a tag to the packet with the reinject info */\n\ttag = m_tag_alloc(MTAG_IPFW_RULE, 0,\n\t\t    sizeof(struct ipfw_rule_ref), M_NOWAIT);\n\tif (tag == NULL) {\n\t\tFREE_PKT(clone);\n\t\treturn 1;\n\t}\n\t*((struct ipfw_rule_ref *)(tag+1)) = *rule;\n\tm_tag_prepend(clone, tag);\n\n\t/* Do the dirty job... */\n\tip_divert_ptr(clone, incoming);\n\treturn 0;\n}\n\n/*\n * attach or detach hooks for a given protocol family\n */\nstatic int\nipfw_hook(int onoff, int pf)\n{\n\tstruct pfil_head *pfh;\n\n\tpfh = pfil_head_get(PFIL_TYPE_AF, pf);\n\tif (pfh == NULL)\n\t\treturn ENOENT;\n\n\t(void) (onoff ? pfil_add_hook : pfil_remove_hook)\n\t    (ipfw_check_hook, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);\n\n\treturn 0;\n}\n\nint\nipfw_attach_hooks(int arg)\n{\n\tint error = 0;\n\n\tif (arg == 0) /* detach */\n\t\tipfw_hook(0, AF_INET);\n\telse if (V_fw_enable && ipfw_hook(1, AF_INET) != 0) {\n                error = ENOENT; /* see ip_fw_pfil.c::ipfw_hook() */\n                printf(\"ipfw_hook() error\\n\");\n        }\n#ifdef INET6\n\tif (arg == 0) /* detach */\n\t\tipfw_hook(0, AF_INET6);\n\telse if (V_fw6_enable && ipfw_hook(1, AF_INET6) != 0) {\n                error = ENOENT;\n                printf(\"ipfw6_hook() error\\n\");\n        }\n#endif\n\treturn error;\n}\n\nint\nipfw_chg_hook(SYSCTL_HANDLER_ARGS)\n{\n\tint enable;\n\tint oldenable;\n\tint error;\n\tint af;\n\n\tif (arg1 == &VNET_NAME(fw_enable)) {\n\t\tenable = V_fw_enable;\n\t\taf = AF_INET;\n\t}\n#ifdef INET6\n\telse if (arg1 == &VNET_NAME(fw6_enable)) {\n\t\tenable = V_fw6_enable;\n\t\taf = AF_INET6;\n\t}\n#endif\n\telse \n\t\treturn (EINVAL);\n\n\toldenable = enable;\n\n\terror = sysctl_handle_int(oidp, &enable, 0, req);\n\n\tif (error)\n\t\treturn (error);\n\n\tenable = (enable) ? 1 : 0;\n\n\tif (enable == oldenable)\n\t\treturn (0);\n\n\terror = ipfw_hook(enable, af);\n\tif (error)\n\t\treturn (error);\n\tif (af == AF_INET)\n\t\tV_fw_enable = enable;\n#ifdef INET6\n\telse if (af == AF_INET6)\n\t\tV_fw6_enable = enable;\n#endif\n\n\treturn (0);\n}\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_private.h",
    "content": "/*-\n * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD: head/sys/netinet/ipfw/ip_fw_private.h 200601 2009-12-16 10:48:40Z luigi $\n */\n\n#ifndef _IPFW2_PRIVATE_H\n#define _IPFW2_PRIVATE_H\n\n/*\n * Internal constants and data structures used by ipfw components\n * and not meant to be exported outside the kernel.\n */\n\n#ifdef _KERNEL\n\n/*\n * For platforms that do not have SYSCTL support, we wrap the\n * SYSCTL_* into a function (one per file) to collect the values\n * into an array at module initialization. The wrapping macros,\n * SYSBEGIN() and SYSEND, are empty in the default case.\n */\n#ifndef SYSBEGIN\n#define SYSBEGIN(x)\n#endif\n#ifndef SYSEND\n#define SYSEND\n#endif\n\n/* Return values from ipfw_chk() */\nenum {\n\tIP_FW_PASS = 0,\n\tIP_FW_DENY,\n\tIP_FW_DIVERT,\n\tIP_FW_TEE,\n\tIP_FW_DUMMYNET,\n\tIP_FW_NETGRAPH,\n\tIP_FW_NGTEE,\n\tIP_FW_NAT,\n\tIP_FW_REASS,\n};\n\n/*\n * Structure for collecting parameters to dummynet for ip6_output forwarding\n */\nstruct _ip6dn_args {\n       struct ip6_pktopts *opt_or;\n       struct route_in6 ro_or;\n       int flags_or;\n       struct ip6_moptions *im6o_or;\n       struct ifnet *origifp_or;\n       struct ifnet *ifp_or;\n       struct sockaddr_in6 dst_or;\n       u_long mtu_or;\n       struct route_in6 ro_pmtu_or;\n};\n\n\n/*\n * Arguments for calling ipfw_chk() and dummynet_io(). We put them\n * all into a structure because this way it is easier and more\n * efficient to pass variables around and extend the interface.\n */\nstruct ip_fw_args {\n\tstruct mbuf\t*m;\t\t/* the mbuf chain\t\t*/\n\tstruct ifnet\t*oif;\t\t/* output interface\t\t*/\n\tstruct sockaddr_in *next_hop;\t/* forward address\t\t*/\n\n\t/*\n\t * On return, it points to the matching rule.\n\t * On entry, rule.slot > 0 means the info is valid and\n\t * contains the the starting rule for an ipfw search.\n\t * If chain_id == chain->id && slot >0 then jump to that slot.\n\t * Otherwise, we locate the first rule >= rulenum:rule_id\n\t */\n\tstruct ipfw_rule_ref rule;\t/* match/restart info\t\t*/\n\n\tstruct ether_header *eh;\t/* for bridged packets\t\t*/\n\n\tstruct ipfw_flow_id f_id;\t/* grabbed from IP header\t*/\n\t//uint32_t\tcookie;\t\t/* a cookie depending on rule action */\n\tstruct inpcb\t*inp;\n\n\tstruct _ip6dn_args\tdummypar; /* dummynet->ip6_output */\n\tstruct sockaddr_in hopstore;\t/* store here if cannot use a pointer */\n};\n\nMALLOC_DECLARE(M_IPFW);\n\n/*\n * Hooks sometime need to know the direction of the packet\n * (divert, dummynet, netgraph, ...)\n * We use a generic definition here, with bit0-1 indicating the\n * direction, bit 2 indicating layer2 or 3, bit 3-4 indicating the\n * specific protocol\n * indicating the protocol (if necessary)\n */\nenum {\n\tDIR_MASK =\t0x3,\n\tDIR_OUT =\t0,\n\tDIR_IN =\t1,\n\tDIR_FWD =\t2,\n\tDIR_DROP =\t3,\n\tPROTO_LAYER2 =\t0x4, /* set for layer 2 */\n\t/* PROTO_DEFAULT = 0, */\n\tPROTO_IPV4 =\t0x08,\n\tPROTO_IPV6 =\t0x10,\n\tPROTO_IFB =\t0x0c, /* layer2 + ifbridge */\n   /*\tPROTO_OLDBDG =\t0x14, unused, old bridge */\n};\n\n/* wrapper for freeing a packet, in case we need to do more work */\n#ifndef FREE_PKT\n#if defined(__linux__) || defined(_WIN32)\n#define FREE_PKT(m)\tnetisr_dispatch(-1, m)\n#else\n#define FREE_PKT(m)\tm_freem(m)\n#endif\n#endif /* !FREE_PKT */\n\n/*\n * Function definitions.\n */\n\n/* attach (arg = 1) or detach (arg = 0) hooks */\nint ipfw_attach_hooks(int);\n#ifdef NOTYET\nvoid ipfw_nat_destroy(void);\n#endif\n\n/* In ip_fw_log.c */\nstruct ip;\nvoid ipfw_log_bpf(int);\nvoid ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,\n\tstruct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg,\n\tstruct ip *ip);\nVNET_DECLARE(u_int64_t, norule_counter);\n#define\tV_norule_counter\tVNET(norule_counter)\nVNET_DECLARE(int, verbose_limit);\n#define\tV_verbose_limit\t\tVNET(verbose_limit)\n\n/* In ip_fw_dynamic.c */\n\nenum { /* result for matching dynamic rules */\n\tMATCH_REVERSE = 0,\n\tMATCH_FORWARD,\n\tMATCH_NONE,\n\tMATCH_UNKNOWN,\n};\n\n/*\n * The lock for dynamic rules is only used once outside the file,\n * and only to release the result of lookup_dyn_rule().\n * Eventually we may implement it with a callback on the function.\n */\nvoid ipfw_dyn_unlock(void);\n\nstruct tcphdr;\nstruct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,\n    u_int32_t, u_int32_t, int);\nint ipfw_install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,\n    struct ip_fw_args *args, uint32_t tablearg);\nipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt,\n\tint *match_direction, struct tcphdr *tcp);\nvoid ipfw_remove_dyn_children(struct ip_fw *rule);\nvoid ipfw_get_dynamic(char **bp, const char *ep);\n\nvoid ipfw_dyn_attach(void);\t/* uma_zcreate .... */\nvoid ipfw_dyn_detach(void);\t/* uma_zdestroy ... */\nvoid ipfw_dyn_init(void);\t/* per-vnet initialization */\nvoid ipfw_dyn_uninit(int);\t/* per-vnet deinitialization */\nint ipfw_dyn_len(void);\n\n/* common variables */\nVNET_DECLARE(int, fw_one_pass);\n#define\tV_fw_one_pass\t\tVNET(fw_one_pass)\n\nVNET_DECLARE(int, fw_verbose);\n#define\tV_fw_verbose\t\tVNET(fw_verbose)\n\nVNET_DECLARE(struct ip_fw_chain, layer3_chain);\n#define\tV_layer3_chain\t\tVNET(layer3_chain)\n\nVNET_DECLARE(u_int32_t, set_disable);\n#define\tV_set_disable\t\tVNET(set_disable)\n\nVNET_DECLARE(int, autoinc_step);\n#define V_autoinc_step\t\tVNET(autoinc_step)\n\nstruct ip_fw_chain {\n\tstruct ip_fw\t*rules;\t\t/* list of rules */\n\tstruct ip_fw\t*reap;\t\t/* list of rules to reap */\n\tstruct ip_fw\t*default_rule;\n\tint\t\tn_rules;\t/* number of static rules */\n\tint\t\tstatic_len;\t/* total len of static rules */\n\tstruct ip_fw\t**map;\t\t/* array of rule ptrs to ease lookup */\n\tLIST_HEAD(nat_list, cfg_nat) nat;       /* list of nat entries */\n\tstruct radix_node_head *tables[IPFW_TABLES_MAX];\n#if defined( __linux__ ) || defined( _WIN32 )\n\tspinlock_t rwmtx;\n\tspinlock_t uh_lock;\n#else\n\tstruct rwlock\trwmtx;\n\tstruct rwlock\tuh_lock;\t/* lock for upper half */\n#endif\n\tuint32_t\tid;\t\t/* ruleset id */\n};\n\nstruct sockopt;\t/* used by tcp_var.h */\n\n/*\n * The lock is heavily used by ip_fw2.c (the main file) and ip_fw_nat.c\n * so the variable and the macros must be here.\n */\n\n#define\tIPFW_LOCK_INIT(_chain) do {\t\t\t\\\n\trw_init(&(_chain)->rwmtx, \"IPFW static rules\");\t\\\n\trw_init(&(_chain)->uh_lock, \"IPFW UH lock\");\t\\\n\t} while (0)\n\n#define\tIPFW_LOCK_DESTROY(_chain) do {\t\t\t\\\n\trw_destroy(&(_chain)->rwmtx);\t\t\t\\\n\trw_destroy(&(_chain)->uh_lock);\t\t\t\\\n\t} while (0)\n\n#define\tIPFW_WLOCK_ASSERT(_chain)\trw_assert(&(_chain)->rwmtx, RA_WLOCKED)\n\n#define IPFW_RLOCK(p) rw_rlock(&(p)->rwmtx)\n#define IPFW_RUNLOCK(p) rw_runlock(&(p)->rwmtx)\n#define IPFW_WLOCK(p) rw_wlock(&(p)->rwmtx)\n#define IPFW_WUNLOCK(p) rw_wunlock(&(p)->rwmtx)\n\n#define IPFW_UH_RLOCK(p) rw_rlock(&(p)->uh_lock)\n#define IPFW_UH_RUNLOCK(p) rw_runlock(&(p)->uh_lock)\n#define IPFW_UH_WLOCK(p) rw_wlock(&(p)->uh_lock)\n#define IPFW_UH_WUNLOCK(p) rw_wunlock(&(p)->uh_lock)\n\n/* In ip_fw_sockopt.c */\nint ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id);\nint ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule);\nint ipfw_ctl(struct sockopt *sopt);\nint ipfw_chk(struct ip_fw_args *args);\nvoid ipfw_reap_rules(struct ip_fw *head);\n\n/* In ip_fw_pfil */\nint ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,\n     struct inpcb *inp);\n\n/* In ip_fw_table.c */\nstruct radix_node;\nint ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,\n    uint32_t *val);\nint ipfw_init_tables(struct ip_fw_chain *ch);\nvoid ipfw_destroy_tables(struct ip_fw_chain *ch);\nint ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl);\nint ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,\n    uint8_t mlen, uint32_t value);\nint ipfw_dump_table_entry(struct radix_node *rn, void *arg);\nint ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,\n    uint8_t mlen);\nint ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);\nint ipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);\n\n/* In ip_fw_nat.c -- XXX to be moved to ip_var.h */\n\nextern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);\n\ntypedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);\ntypedef int ipfw_nat_cfg_t(struct sockopt *);\n\nextern ipfw_nat_t *ipfw_nat_ptr;\n#define IPFW_NAT_LOADED (ipfw_nat_ptr != NULL)\n\nextern ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;\nextern ipfw_nat_cfg_t *ipfw_nat_del_ptr;\nextern ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;\nextern ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;\n\n#endif /* _KERNEL */\n#endif /* _IPFW2_PRIVATE_H */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_sockopt.c",
    "content": "/*-\n * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa\n *\n * Supported by: Valeria Paoli\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: head/sys/netinet/ipfw/ip_fw_sockopt.c 206339 2010-04-07 08:23:58Z luigi $\");\n\n/*\n * Sockopt support for ipfw. The routines here implement\n * the upper half of the ipfw code.\n */\n\n#if !defined(KLD_MODULE)\n#include \"opt_ipfw.h\"\n#include \"opt_ipdivert.h\"\n#include \"opt_ipdn.h\"\n#include \"opt_inet.h\"\n#ifndef INET\n#error IPFIREWALL requires INET.\n#endif /* INET */\n#endif\n#include \"opt_inet6.h\"\n#include \"opt_ipsec.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/mbuf.h>\t/* struct m_tag used by nested headers */\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/priv.h>\n#include <sys/proc.h>\n#include <sys/rwlock.h>\n#include <sys/socket.h>\n#include <sys/socketvar.h>\n#include <sys/sysctl.h>\n#include <sys/syslog.h>\n#include <net/if.h>\n#include <net/route.h>\n#include <net/vnet.h>\n\n#include <netinet/in.h>\n#include <netinet/ip_var.h> /* hooks */\n#include <netinet/ip_fw.h>\n#include <netinet/ipfw/ip_fw_private.h>\n\n#ifdef MAC\n#include <security/mac/mac_framework.h>\n#endif\n\nMALLOC_DEFINE(M_IPFW, \"IpFw/IpAcct\", \"IpFw/IpAcct chain's\");\n\n/*\n * static variables followed by global ones (none in this file)\n */\n\n/*\n * Find the smallest rule >= key, id.\n * We could use bsearch but it is so simple that we code it directly\n */\nint\nipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id)\n{\n\tint i, lo, hi;\n\tstruct ip_fw *r;\n\n  \tfor (lo = 0, hi = chain->n_rules - 1; lo < hi;) {\n\t\ti = (lo + hi) / 2;\n\t\tr = chain->map[i];\n\t\tif (r->rulenum < key)\n\t\t\tlo = i + 1;\t/* continue from the next one */\n\t\telse if (r->rulenum > key)\n\t\t\thi = i;\t\t/* this might be good */\n\t\telse if (r->id < id)\n\t\t\tlo = i + 1;\t/* continue from the next one */\n\t\telse /* r->id >= id */\n\t\t\thi = i;\t\t/* this might be good */\n\t};\n\treturn hi;\n}\n\n/*\n * allocate a new map, returns the chain locked. extra is the number\n * of entries to add or delete.\n */\nstatic struct ip_fw **\nget_map(struct ip_fw_chain *chain, int extra, int locked)\n{\n\n\tfor (;;) {\n\t\tstruct ip_fw **map;\n\t\tint i;\n\n\t\ti = chain->n_rules + extra;\n\t\tmap = malloc(i * sizeof(struct ip_fw *), M_IPFW,\n\t\t\tlocked ? M_NOWAIT : M_WAITOK);\n\t\tif (map == NULL) {\n\t\t\tprintf(\"%s: cannot allocate map\\n\", __FUNCTION__);\n\t\t\treturn NULL;\n\t\t}\n\t\tif (!locked)\n\t\t\tIPFW_UH_WLOCK(chain);\n\t\tif (i >= chain->n_rules + extra) /* good */\n\t\t\treturn map;\n\t\t/* otherwise we lost the race, free and retry */\n\t\tif (!locked)\n\t\t\tIPFW_UH_WUNLOCK(chain);\n\t\tfree(map, M_IPFW);\n\t}\n}\n\n/*\n * swap the maps. It is supposed to be called with IPFW_UH_WLOCK\n */\nstatic struct ip_fw **\nswap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len)\n{\n\tstruct ip_fw **old_map;\n\n\tIPFW_WLOCK(chain);\n\tchain->id++;\n\tchain->n_rules = new_len;\n\told_map = chain->map;\n\tchain->map = new_map;\n\tIPFW_WUNLOCK(chain);\n\treturn old_map;\n}\n\n/*\n * Add a new rule to the list. Copy the rule into a malloc'ed area, then\n * possibly create a rule number and add the rule to the list.\n * Update the rule_number in the input struct so the caller knows it as well.\n * XXX DO NOT USE FOR THE DEFAULT RULE.\n * Must be called without IPFW_UH held\n */\nint\nipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)\n{\n\tstruct ip_fw *rule;\n\tint i, l, insert_before;\n\tstruct ip_fw **map;\t/* the new array of pointers */\n\n\tif (chain->rules == NULL || input_rule->rulenum > IPFW_DEFAULT_RULE-1)\n\t\treturn (EINVAL);\n\n\tl = RULESIZE(input_rule);\n\trule = malloc(l, M_IPFW, M_WAITOK | M_ZERO);\n\tif (rule == NULL)\n\t\treturn (ENOSPC);\n\t/* get_map returns with IPFW_UH_WLOCK if successful */\n\tmap = get_map(chain, 1, 0 /* not locked */);\n\tif (map == NULL) {\n\t\tfree(rule, M_IPFW);\n\t\treturn ENOSPC;\n\t}\n\n\tbcopy(input_rule, rule, l);\n\t/* clear fields not settable from userland */\n\trule->x_next = NULL;\n\trule->next_rule = NULL;\n\trule->pcnt = 0;\n\trule->bcnt = 0;\n\trule->timestamp = 0;\n\n\tif (V_autoinc_step < 1)\n\t\tV_autoinc_step = 1;\n\telse if (V_autoinc_step > 1000)\n\t\tV_autoinc_step = 1000;\n\t/* find the insertion point, we will insert before */\n\tinsert_before = rule->rulenum ? rule->rulenum + 1 : IPFW_DEFAULT_RULE;\n\ti = ipfw_find_rule(chain, insert_before, 0);\n\t/* duplicate first part */\n\tif (i > 0)\n\t\tbcopy(chain->map, map, i * sizeof(struct ip_fw *));\n\tmap[i] = rule;\n\t/* duplicate remaining part, we always have the default rule */\n\tbcopy(chain->map + i, map + i + 1,\n\t\tsizeof(struct ip_fw *) *(chain->n_rules - i));\n\tif (rule->rulenum == 0) {\n\t\t/* write back the number */\n\t\trule->rulenum = i > 0 ? map[i-1]->rulenum : 0;\n\t\tif (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)\n\t\t\trule->rulenum += V_autoinc_step;\n\t\tinput_rule->rulenum = rule->rulenum;\n\t}\n\n\trule->id = chain->id + 1;\n\tmap = swap_map(chain, map, chain->n_rules + 1);\n\tchain->static_len += l;\n\tIPFW_UH_WUNLOCK(chain);\n\tif (map)\n\t\tfree(map, M_IPFW);\n\treturn (0);\n}\n\n/*\n * Reclaim storage associated with a list of rules.  This is\n * typically the list created using remove_rule.\n * A NULL pointer on input is handled correctly.\n */\nvoid\nipfw_reap_rules(struct ip_fw *head)\n{\n\tstruct ip_fw *rule;\n\n\twhile ((rule = head) != NULL) {\n\t\thead = head->x_next;\n\t\tfree(rule, M_IPFW);\n\t}\n}\n\n/*\n * Used by del_entry() to check if a rule should be kept.\n * Returns 1 if the rule must be kept, 0 otherwise.\n *\n * Called with cmd = {0,1,5}.\n * cmd == 0 matches on rule numbers, excludes rules in RESVD_SET if n == 0 ;\n * cmd == 1 matches on set numbers only, rule numbers are ignored;\n * cmd == 5 matches on rule and set numbers.\n *\n * n == 0 is a wildcard for rule numbers, there is no wildcard for sets.\n *\n * Rules to keep are\n *\t(default || reserved || !match_set || !match_number)\n * where\n *   default ::= (rule->rulenum == IPFW_DEFAULT_RULE)\n *\t// the default rule is always protected\n *\n *   reserved ::= (cmd == 0 && n == 0 && rule->set == RESVD_SET)\n *\t// RESVD_SET is protected only if cmd == 0 and n == 0 (\"ipfw flush\")\n *\n *   match_set ::= (cmd == 0 || rule->set == set)\n *\t// set number is ignored for cmd == 0\n *\n *   match_number ::= (cmd == 1 || n == 0 || n == rule->rulenum)\n *\t// number is ignored for cmd == 1 or n == 0\n *\n */\nstatic int\nkeep_rule(struct ip_fw *rule, uint8_t cmd, uint8_t set, uint32_t n)\n{\n\treturn\n\t\t (rule->rulenum == IPFW_DEFAULT_RULE)\t\t||\n\t\t (cmd == 0 && n == 0 && rule->set == RESVD_SET)\t||\n\t\t!(cmd == 0 || rule->set == set)\t\t\t||\n\t\t!(cmd == 1 || n == 0 || n == rule->rulenum);\n}\n\n/**\n * Remove all rules with given number, or do set manipulation.\n * Assumes chain != NULL && *chain != NULL.\n *\n * The argument is an uint32_t. The low 16 bit are the rule or set number;\n * the next 8 bits are the new set; the top 8 bits indicate the command:\n *\n *\t0\tdelete rules numbered \"rulenum\"\n *\t1\tdelete rules in set \"rulenum\"\n *\t2\tmove rules \"rulenum\" to set \"new_set\"\n *\t3\tmove rules from set \"rulenum\" to set \"new_set\"\n *\t4\tswap sets \"rulenum\" and \"new_set\"\n *\t5\tdelete rules \"rulenum\" and set \"new_set\"\n */\nstatic int\ndel_entry(struct ip_fw_chain *chain, uint32_t arg)\n{\n\tstruct ip_fw *rule;\n\tuint32_t num;\t/* rule number or old_set */\n\tuint8_t cmd, new_set;\n\tint start, end, i, ofs, n;\n\tstruct ip_fw **map = NULL;\n\tint error = 0;\n\n\tnum = arg & 0xffff;\n\tcmd = (arg >> 24) & 0xff;\n\tnew_set = (arg >> 16) & 0xff;\n\n\tif (cmd > 5 || new_set > RESVD_SET)\n\t\treturn EINVAL;\n\tif (cmd == 0 || cmd == 2 || cmd == 5) {\n\t\tif (num >= IPFW_DEFAULT_RULE)\n\t\t\treturn EINVAL;\n\t} else {\n\t\tif (num > RESVD_SET)\t/* old_set */\n\t\t\treturn EINVAL;\n\t}\n\n\tIPFW_UH_WLOCK(chain);\t/* arbitrate writers */\n\tchain->reap = NULL;\t/* prepare for deletions */\n\n\tswitch (cmd) {\n\tcase 0:\t/* delete rules \"num\" (num == 0 matches all) */\n\tcase 1:\t/* delete all rules in set N */\n\tcase 5: /* delete rules with number N and set \"new_set\". */\n\n\t\t/*\n\t\t * Locate first rule to delete (start), the rule after\n\t\t * the last one to delete (end), and count how many\n\t\t * rules to delete (n). Always use keep_rule() to\n\t\t * determine which rules to keep.\n\t\t */\n\t\tn = 0;\n\t\tif (cmd == 1) {\n\t\t\t/* look for a specific set including RESVD_SET.\n\t\t\t * Must scan the entire range, ignore num.\n\t\t\t */\n\t\t\tnew_set = num;\n\t\t\tfor (start = -1, end = i = 0; i < chain->n_rules; i++) {\n\t\t\t\tif (keep_rule(chain->map[i], cmd, new_set, 0))\n\t\t\t\t\tcontinue;\n\t\t\t\tif (start < 0)\n\t\t\t\t\tstart = i;\n\t\t\t\tend = i;\n\t\t\t\tn++;\n\t\t\t}\n\t\t\tend++;\t/* first non-matching */\n\t\t} else {\n\t\t\t/* Optimized search on rule numbers */\n\t\t\tstart = ipfw_find_rule(chain, num, 0);\n\t\t\tfor (end = start; end < chain->n_rules; end++) {\n\t\t\t\trule = chain->map[end];\n\t\t\t\tif (num > 0 && rule->rulenum != num)\n\t\t\t\t\tbreak;\n\t\t\t\tif (!keep_rule(rule, cmd, new_set, num))\n\t\t\t\t\tn++;\n\t\t\t}\n\t\t}\n\n\t\tif (n == 0) {\n\t\t\t/* A flush request (arg == 0) on empty ruleset\n\t\t\t * returns with no error. On the contrary,\n\t\t\t * if there is no match on a specific request,\n\t\t\t * we return EINVAL.\n\t\t\t */\n\t\t\terror = (arg == 0) ? 0 : EINVAL;\n\t\t\tbreak;\n\t\t}\n\n\t\t/* We have something to delete. Allocate the new map */\n\t\tmap = get_map(chain, -n, 1 /* locked */);\n\t\tif (map == NULL) {\n\t\t\terror = EINVAL;\n\t\t\tbreak;\n\t\t}\n\n\t\t/* 1. bcopy the initial part of the map */\n\t\tif (start > 0)\n\t\t\tbcopy(chain->map, map, start * sizeof(struct ip_fw *));\n\t\t/* 2. copy active rules between start and end */\n\t\tfor (i = ofs = start; i < end; i++) {\n\t\t\trule = chain->map[i];\n\t\t\tif (keep_rule(rule, cmd, new_set, num))\n\t\t\t\tmap[ofs++] = rule;\n\t\t}\n\t\t/* 3. copy the final part of the map */\n\t\tbcopy(chain->map + end, map + ofs,\n\t\t\t(chain->n_rules - end) * sizeof(struct ip_fw *));\n\t\t/* 4. swap the maps (under BH_LOCK) */\n\t\tmap = swap_map(chain, map, chain->n_rules - n);\n\t\t/* 5. now remove the rules deleted from the old map */\n\t\tfor (i = start; i < end; i++) {\n\t\t\tint l;\n\t\t\trule = map[i];\n\t\t\tif (keep_rule(rule, cmd, new_set, num))\n\t\t\t\tcontinue;\n\t\t\tl = RULESIZE(rule);\n\t\t\tchain->static_len -= l;\n\t\t\tipfw_remove_dyn_children(rule);\n\t\t\trule->x_next = chain->reap;\n\t\t\tchain->reap = rule;\n\t\t}\n\t\tbreak;\n\n\t/*\n\t * In the next 3 cases the loop stops at (n_rules - 1)\n\t * because the default rule is never eligible..\n\t */\n\n\tcase 2:\t/* move rules with given RULE number to new set */\n\t\tfor (i = 0; i < chain->n_rules - 1; i++) {\n\t\t\trule = chain->map[i];\n\t\t\tif (rule->rulenum == num)\n\t\t\t\trule->set = new_set;\n\t\t}\n\t\tbreak;\n\n\tcase 3: /* move rules with given SET number to new set */\n\t\tfor (i = 0; i < chain->n_rules - 1; i++) {\n\t\t\trule = chain->map[i];\n\t\t\tif (rule->set == num)\n\t\t\t\trule->set = new_set;\n\t\t}\n\t\tbreak;\n\n\tcase 4: /* swap two sets */\n\t\tfor (i = 0; i < chain->n_rules - 1; i++) {\n\t\t\trule = chain->map[i];\n\t\t\tif (rule->set == num)\n\t\t\t\trule->set = new_set;\n\t\t\telse if (rule->set == new_set)\n\t\t\t\trule->set = num;\n\t\t}\n\t\tbreak;\n\t}\n\n\trule = chain->reap;\n\tchain->reap = NULL;\n\tIPFW_UH_WUNLOCK(chain);\n\tipfw_reap_rules(rule);\n\tif (map)\n\t\tfree(map, M_IPFW);\n\treturn error;\n}\n\n/*\n * Clear counters for a specific rule.\n * Normally run under IPFW_UH_RLOCK, but these are idempotent ops\n * so we only care that rules do not disappear.\n */\nstatic void\nclear_counters(struct ip_fw *rule, int log_only)\n{\n\tipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule);\n\n\tif (log_only == 0) {\n\t\trule->bcnt = rule->pcnt = 0;\n\t\trule->timestamp = 0;\n\t}\n\tif (l->o.opcode == O_LOG)\n\t\tl->log_left = l->max_log;\n}\n\n/**\n * Reset some or all counters on firewall rules.\n * The argument `arg' is an u_int32_t. The low 16 bit are the rule number,\n * the next 8 bits are the set number, the top 8 bits are the command:\n *\t0\twork with rules from all set's;\n *\t1\twork with rules only from specified set.\n * Specified rule number is zero if we want to clear all entries.\n * log_only is 1 if we only want to reset logs, zero otherwise.\n */\nstatic int\nzero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)\n{\n\tstruct ip_fw *rule;\n\tchar *msg;\n\tint i;\n\n\tuint16_t rulenum = arg & 0xffff;\n\tuint8_t set = (arg >> 16) & 0xff;\n\tuint8_t cmd = (arg >> 24) & 0xff;\n\n\tif (cmd > 1)\n\t\treturn (EINVAL);\n\tif (cmd == 1 && set > RESVD_SET)\n\t\treturn (EINVAL);\n\n\tIPFW_UH_RLOCK(chain);\n\tif (rulenum == 0) {\n\t\tV_norule_counter = 0;\n\t\tfor (i = 0; i < chain->n_rules; i++) {\n\t\t\trule = chain->map[i];\n\t\t\t/* Skip rules not in our set. */\n\t\t\tif (cmd == 1 && rule->set != set)\n\t\t\t\tcontinue;\n\t\t\tclear_counters(rule, log_only);\n\t\t}\n\t\tmsg = log_only ? \"All logging counts reset\" :\n\t\t    \"Accounting cleared\";\n\t} else {\n\t\tint cleared = 0;\n\t\tfor (i = 0; i < chain->n_rules; i++) {\n\t\t\trule = chain->map[i];\n\t\t\tif (rule->rulenum == rulenum) {\n\t\t\t\tif (cmd == 0 || rule->set == set)\n\t\t\t\t\tclear_counters(rule, log_only);\n\t\t\t\tcleared = 1;\n\t\t\t}\n\t\t\tif (rule->rulenum > rulenum)\n\t\t\t\tbreak;\n\t\t}\n\t\tif (!cleared) {\t/* we did not find any matching rules */\n\t\t\tIPFW_UH_RUNLOCK(chain);\n\t\t\treturn (EINVAL);\n\t\t}\n\t\tmsg = log_only ? \"logging count reset\" : \"cleared\";\n\t}\n\tIPFW_UH_RUNLOCK(chain);\n\n\tif (V_fw_verbose) {\n\t\tint lev = LOG_SECURITY | LOG_NOTICE;\n\n\t\tif (rulenum)\n\t\t\tlog(lev, \"ipfw: Entry %d %s.\\n\", rulenum, msg);\n\t\telse\n\t\t\tlog(lev, \"ipfw: %s.\\n\", msg);\n\t}\n\treturn (0);\n}\n\n/*\n * Check validity of the structure before insert.\n * Rules are simple, so this mostly need to check rule sizes.\n */\nstatic int\ncheck_ipfw_struct(struct ip_fw *rule, int size)\n{\n\tint l, cmdlen = 0;\n\tint have_action=0;\n\tipfw_insn *cmd;\n\n\tif (size < sizeof(*rule)) {\n\t\tprintf(\"ipfw: rule too short\\n\");\n\t\treturn (EINVAL);\n\t}\n\t/* first, check for valid size */\n\tl = RULESIZE(rule);\n\tif (l != size) {\n\t\tprintf(\"ipfw: size mismatch (have %d want %d)\\n\", size, l);\n\t\treturn (EINVAL);\n\t}\n\tif (rule->act_ofs >= rule->cmd_len) {\n\t\tprintf(\"ipfw: bogus action offset (%u > %u)\\n\",\n\t\t    rule->act_ofs, rule->cmd_len - 1);\n\t\treturn (EINVAL);\n\t}\n\t/*\n\t * Now go for the individual checks. Very simple ones, basically only\n\t * instruction sizes.\n\t */\n\tfor (l = rule->cmd_len, cmd = rule->cmd ;\n\t\t\tl > 0 ; l -= cmdlen, cmd += cmdlen) {\n\t\tcmdlen = F_LEN(cmd);\n\t\tif (cmdlen > l) {\n\t\t\tprintf(\"ipfw: opcode %d size truncated\\n\",\n\t\t\t    cmd->opcode);\n\t\t\treturn EINVAL;\n\t\t}\n\t\tswitch (cmd->opcode) {\n\t\tcase O_PROBE_STATE:\n\t\tcase O_KEEP_STATE:\n\t\tcase O_PROTO:\n\t\tcase O_IP_SRC_ME:\n\t\tcase O_IP_DST_ME:\n\t\tcase O_LAYER2:\n\t\tcase O_IN:\n\t\tcase O_FRAG:\n\t\tcase O_DIVERTED:\n\t\tcase O_IPOPT:\n\t\tcase O_IPTOS:\n\t\tcase O_IPPRECEDENCE:\n\t\tcase O_IPVER:\n\t\tcase O_TCPWIN:\n\t\tcase O_TCPFLAGS:\n\t\tcase O_TCPOPTS:\n\t\tcase O_ESTAB:\n\t\tcase O_VERREVPATH:\n\t\tcase O_VERSRCREACH:\n\t\tcase O_ANTISPOOF:\n\t\tcase O_IPSEC:\n#ifdef INET6\n\t\tcase O_IP6_SRC_ME:\n\t\tcase O_IP6_DST_ME:\n\t\tcase O_EXT_HDR:\n\t\tcase O_IP6:\n#endif\n\t\tcase O_IP4:\n\t\tcase O_TAG:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_FIB:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn))\n\t\t\t\tgoto bad_size;\n\t\t\tif (cmd->arg1 >= rt_numfibs) {\n\t\t\t\tprintf(\"ipfw: invalid fib number %d\\n\",\n\t\t\t\t\tcmd->arg1);\n\t\t\t\treturn EINVAL;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase O_SETFIB:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn))\n\t\t\t\tgoto bad_size;\n\t\t\tif (cmd->arg1 >= rt_numfibs) {\n\t\t\t\tprintf(\"ipfw: invalid fib number %d\\n\",\n\t\t\t\t\tcmd->arg1);\n\t\t\t\treturn EINVAL;\n\t\t\t}\n\t\t\tgoto check_action;\n\n\t\tcase O_UID:\n\t\tcase O_GID:\n\t\tcase O_JAIL:\n\t\tcase O_IP_SRC:\n\t\tcase O_IP_DST:\n\t\tcase O_TCPSEQ:\n\t\tcase O_TCPACK:\n\t\tcase O_PROB:\n\t\tcase O_ICMPTYPE:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_u32))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_LIMIT:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_limit))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_LOG:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_log))\n\t\t\t\tgoto bad_size;\n\n\t\t\t((ipfw_insn_log *)cmd)->log_left =\n\t\t\t    ((ipfw_insn_log *)cmd)->max_log;\n\n\t\t\tbreak;\n\n\t\tcase O_IP_SRC_MASK:\n\t\tcase O_IP_DST_MASK:\n\t\t\t/* only odd command lengths */\n\t\t\tif ( !(cmdlen & 1) || cmdlen > 31)\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_IP_SRC_SET:\n\t\tcase O_IP_DST_SET:\n\t\t\tif (cmd->arg1 == 0 || cmd->arg1 > 256) {\n\t\t\t\tprintf(\"ipfw: invalid set size %d\\n\",\n\t\t\t\t\tcmd->arg1);\n\t\t\t\treturn EINVAL;\n\t\t\t}\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +\n\t\t\t    (cmd->arg1+31)/32 )\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_IP_SRC_LOOKUP:\n\t\tcase O_IP_DST_LOOKUP:\n\t\t\tif (cmd->arg1 >= IPFW_TABLES_MAX) {\n\t\t\t\tprintf(\"ipfw: invalid table number %d\\n\",\n\t\t\t\t    cmd->arg1);\n\t\t\t\treturn (EINVAL);\n\t\t\t}\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn) &&\n\t\t\t    cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&\n\t\t\t    cmdlen != F_INSN_SIZE(ipfw_insn_u32))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_MACADDR2:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_mac))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_NOP:\n\t\tcase O_IPID:\n\t\tcase O_IPTTL:\n\t\tcase O_IPLEN:\n\t\tcase O_TCPDATALEN:\n\t\tcase O_TAGGED:\n\t\t\tif (cmdlen < 1 || cmdlen > 31)\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_MAC_TYPE:\n\t\tcase O_IP_SRCPORT:\n\t\tcase O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */\n\t\t\tif (cmdlen < 2 || cmdlen > 31)\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_RECV:\n\t\tcase O_XMIT:\n\t\tcase O_VIA:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_if))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_ALTQ:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_altq))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_PIPE:\n\t\tcase O_QUEUE:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn))\n\t\t\t\tgoto bad_size;\n\t\t\tgoto check_action;\n\n\t\tcase O_FORWARD_IP:\n#ifdef\tIPFIREWALL_FORWARD\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_sa))\n\t\t\t\tgoto bad_size;\n\t\t\tgoto check_action;\n#else\n\t\t\treturn EINVAL;\n#endif\n\n\t\tcase O_DIVERT:\n\t\tcase O_TEE:\n\t\t\tif (ip_divert_ptr == NULL)\n\t\t\t\treturn EINVAL;\n\t\t\telse\n\t\t\t\tgoto check_size;\n\t\tcase O_NETGRAPH:\n\t\tcase O_NGTEE:\n\t\t\tif (ng_ipfw_input_p == NULL)\n\t\t\t\treturn EINVAL;\n\t\t\telse\n\t\t\t\tgoto check_size;\n\t\tcase O_NAT:\n\t\t\tif (!IPFW_NAT_LOADED)\n\t\t\t\treturn EINVAL;\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_nat))\n \t\t\t\tgoto bad_size;\t\t\n \t\t\tgoto check_action;\n\t\tcase O_FORWARD_MAC: /* XXX not implemented yet */\n\t\tcase O_CHECK_STATE:\n\t\tcase O_COUNT:\n\t\tcase O_ACCEPT:\n\t\tcase O_DENY:\n\t\tcase O_REJECT:\n#ifdef INET6\n\t\tcase O_UNREACH6:\n#endif\n\t\tcase O_SKIPTO:\n\t\tcase O_REASS:\ncheck_size:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn))\n\t\t\t\tgoto bad_size;\ncheck_action:\n\t\t\tif (have_action) {\n\t\t\t\tprintf(\"ipfw: opcode %d, multiple actions\"\n\t\t\t\t\t\" not allowed\\n\",\n\t\t\t\t\tcmd->opcode);\n\t\t\t\treturn EINVAL;\n\t\t\t}\n\t\t\thave_action = 1;\n\t\t\tif (l != cmdlen) {\n\t\t\t\tprintf(\"ipfw: opcode %d, action must be\"\n\t\t\t\t\t\" last opcode\\n\",\n\t\t\t\t\tcmd->opcode);\n\t\t\t\treturn EINVAL;\n\t\t\t}\n\t\t\tbreak;\n#ifdef INET6\n\t\tcase O_IP6_SRC:\n\t\tcase O_IP6_DST:\n\t\t\tif (cmdlen != F_INSN_SIZE(struct in6_addr) +\n\t\t\t    F_INSN_SIZE(ipfw_insn))\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_FLOW6ID:\n\t\t\tif (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +\n\t\t\t    ((ipfw_insn_u32 *)cmd)->o.arg1)\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\n\t\tcase O_IP6_SRC_MASK:\n\t\tcase O_IP6_DST_MASK:\n\t\t\tif ( !(cmdlen & 1) || cmdlen > 127)\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n\t\tcase O_ICMP6TYPE:\n\t\t\tif( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )\n\t\t\t\tgoto bad_size;\n\t\t\tbreak;\n#endif\n\n\t\tdefault:\n\t\t\tswitch (cmd->opcode) {\n#ifndef INET6\n\t\t\tcase O_IP6_SRC_ME:\n\t\t\tcase O_IP6_DST_ME:\n\t\t\tcase O_EXT_HDR:\n\t\t\tcase O_IP6:\n\t\t\tcase O_UNREACH6:\n\t\t\tcase O_IP6_SRC:\n\t\t\tcase O_IP6_DST:\n\t\t\tcase O_FLOW6ID:\n\t\t\tcase O_IP6_SRC_MASK:\n\t\t\tcase O_IP6_DST_MASK:\n\t\t\tcase O_ICMP6TYPE:\n\t\t\t\tprintf(\"ipfw: no IPv6 support in kernel\\n\");\n\t\t\t\treturn EPROTONOSUPPORT;\n#endif\n\t\t\tdefault:\n\t\t\t\tprintf(\"ipfw: opcode %d, unknown opcode\\n\",\n\t\t\t\t\tcmd->opcode);\n\t\t\t\treturn EINVAL;\n\t\t\t}\n\t\t}\n\t}\n\tif (have_action == 0) {\n\t\tprintf(\"ipfw: missing action\\n\");\n\t\treturn EINVAL;\n\t}\n\treturn 0;\n\nbad_size:\n\tprintf(\"ipfw: opcode %d size %d wrong\\n\",\n\t\tcmd->opcode, cmdlen);\n\treturn EINVAL;\n}\n\n\n/*\n * Translation of requests for compatibility with FreeBSD 7.2/8.\n * a static variable tells us if we have an old client from userland,\n * and if necessary we translate requests and responses between the\n * two formats.\n */\nstatic int is7 = 0;\n\nstruct ip_fw7 {\n\tstruct ip_fw7\t*next;\t\t/* linked list of rules     */\n\tstruct ip_fw7\t*next_rule;\t/* ptr to next [skipto] rule    */\n\t/* 'next_rule' is used to pass up 'set_disable' status      */\n\n\tuint16_t\tact_ofs;\t/* offset of action in 32-bit units */\n\tuint16_t\tcmd_len;\t/* # of 32-bit words in cmd */\n\tuint16_t\trulenum;\t/* rule number          */\n\tuint8_t\t\tset;\t\t/* rule set (0..31)     */\n\t// #define RESVD_SET   31  /* set for default and persistent rules */\n\tuint8_t\t\t_pad;\t\t/* padding          */\n\t// uint32_t        id;             /* rule id, only in v.8 */\n\t/* These fields are present in all rules.           */\n\tuint64_t\tpcnt;\t\t/* Packet counter       */\n\tuint64_t\tbcnt;\t\t/* Byte counter         */\n\tuint32_t\ttimestamp;\t/* tv_sec of last match     */\n\n\tipfw_insn\tcmd[1];\t\t/* storage for commands     */\n};\n\n\tint convert_rule_to_7(struct ip_fw *rule);\nint convert_rule_to_8(struct ip_fw *rule);\n\n#ifndef RULESIZE7\n#define RULESIZE7(rule)  (sizeof(struct ip_fw7) + \\\n\t((struct ip_fw7 *)(rule))->cmd_len * 4 - 4)\n#endif\n\n\n/*\n * Copy the static and dynamic rules to the supplied buffer\n * and return the amount of space actually used.\n * Must be run under IPFW_UH_RLOCK\n */\nstatic size_t\nipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)\n{\n\tchar *bp = buf;\n\tchar *ep = bp + space;\n\tstruct ip_fw *rule, *dst;\n\tint l, i;\n\ttime_t\tboot_seconds;\n\n        boot_seconds = boottime.tv_sec;\n\tfor (i = 0; i < chain->n_rules; i++) {\n\t\trule = chain->map[i];\n\n\t\tif (is7) {\n\t\t    /* Convert rule to FreeBSd 7.2 format */\n\t\t    l = RULESIZE7(rule);\n\t\t    if (bp + l + sizeof(uint32_t) <= ep) {\n\t\t\tint error;\n\t\t\tbcopy(rule, bp, l + sizeof(uint32_t));\n\t\t\terror = convert_rule_to_7((struct ip_fw *) bp);\n\t\t\tif (error)\n\t\t\t\treturn 0; /*XXX correct? */\n\t\t\t/*\n\t\t\t * XXX HACK. Store the disable mask in the \"next\"\n\t\t\t * pointer in a wild attempt to keep the ABI the same.\n\t\t\t * Why do we do this on EVERY rule?\n\t\t\t */\n\t\t\tbcopy(&V_set_disable,\n\t\t\t\t&(((struct ip_fw7 *)bp)->next_rule),\n\t\t\t\tsizeof(V_set_disable));\n\t\t\tif (((struct ip_fw7 *)bp)->timestamp)\n\t\t\t    ((struct ip_fw7 *)bp)->timestamp += boot_seconds;\n\t\t\tbp += l;\n\t\t    }\n\t\t    continue; /* go to next rule */\n\t\t}\n\n\t\t/* normal mode, don't touch rules */\n\t\tl = RULESIZE(rule);\n\t\tif (bp + l > ep) { /* should not happen */\n\t\t\tprintf(\"overflow dumping static rules\\n\");\n\t\t\tbreak;\n\t\t}\n\t\tdst = (struct ip_fw *)bp;\n\t\tbcopy(rule, dst, l);\n\t\t/*\n\t\t * XXX HACK. Store the disable mask in the \"next\"\n\t\t * pointer in a wild attempt to keep the ABI the same.\n\t\t * Why do we do this on EVERY rule?\n\t\t */\n\t\tbcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable));\n\t\tif (dst->timestamp)\n\t\t\tdst->timestamp += boot_seconds;\n\t\tbp += l;\n\t}\n\tipfw_get_dynamic(&bp, ep); /* protected by the dynamic lock */\n\treturn (bp - (char *)buf);\n}\n\n\n/**\n * {set|get}sockopt parser.\n */\nint\nipfw_ctl(struct sockopt *sopt)\n{\n#define\tRULE_MAXSIZE\t(256*sizeof(u_int32_t))\n\tint error;\n\tsize_t size;\n\tstruct ip_fw *buf, *rule;\n\tstruct ip_fw_chain *chain;\n\tu_int32_t rulenum[2];\n\n\terror = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);\n\tif (error)\n\t\treturn (error);\n\n\t/*\n\t * Disallow modifications in really-really secure mode, but still allow\n\t * the logging counters to be reset.\n\t */\n\tif (sopt->sopt_name == IP_FW_ADD ||\n\t    (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) {\n\t\terror = securelevel_ge(sopt->sopt_td->td_ucred, 3);\n\t\tif (error)\n\t\t\treturn (error);\n\t}\n\n\tchain = &V_layer3_chain;\n\terror = 0;\n\n\tswitch (sopt->sopt_name) {\n\tcase IP_FW_GET:\n\t\t/*\n\t\t * pass up a copy of the current rules. Static rules\n\t\t * come first (the last of which has number IPFW_DEFAULT_RULE),\n\t\t * followed by a possibly empty list of dynamic rule.\n\t\t * The last dynamic rule has NULL in the \"next\" field.\n\t\t *\n\t\t * Note that the calculated size is used to bound the\n\t\t * amount of data returned to the user.  The rule set may\n\t\t * change between calculating the size and returning the\n\t\t * data in which case we'll just return what fits.\n\t\t */\n\t\tfor (;;) {\n\t\t\tint len = 0, want;\n\n\t\t\tsize = chain->static_len;\n\t\t\tsize += ipfw_dyn_len();\n\t\t\tif (size >= sopt->sopt_valsize)\n\t\t\t\tbreak;\n\t\t\tbuf = malloc(size, M_TEMP, M_WAITOK);\n\t\t\tif (buf == NULL)\n\t\t\t\tbreak;\n\t\t\tIPFW_UH_RLOCK(chain);\n\t\t\t/* check again how much space we need */\n\t\t\twant = chain->static_len + ipfw_dyn_len();\n\t\t\tif (size >= want)\n\t\t\t\tlen = ipfw_getrules(chain, buf, size);\n\t\t\tIPFW_UH_RUNLOCK(chain);\n\t\t\tif (size >= want)\n\t\t\t\terror = sooptcopyout(sopt, buf, len);\n\t\t\tfree(buf, M_TEMP);\n\t\t\tif (size >= want)\n\t\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_FLUSH:\n\t\t/* locking is done within del_entry() */\n\t\terror = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */\n\t\tbreak;\n\n\tcase IP_FW_ADD:\n\t\trule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);\n\t\terror = sooptcopyin(sopt, rule, RULE_MAXSIZE,\n\t\t\tsizeof(struct ip_fw7) );\n\n\t\t/*\n\t\t * If the size of commands equals RULESIZE7 then we assume\n\t\t * a FreeBSD7.2 binary is talking to us (set is7=1).\n\t\t * is7 is persistent so the next 'ipfw list' command\n\t\t * will use this format.\n\t\t * NOTE: If wrong version is guessed (this can happen if\n\t\t *       the first ipfw command is 'ipfw [pipe] list')\n\t\t *       the ipfw binary may crash or loop infinitly...\n\t\t */\n\t\tif (sopt->sopt_valsize == RULESIZE7(rule)) {\n\t\t    is7 = 1;\n\t\t    error = convert_rule_to_8(rule);\n\t\t    if (error)\n\t\t\treturn error;\n\t\t    if (error == 0)\n\t\t\terror = check_ipfw_struct(rule, RULESIZE(rule));\n\t\t} else {\n\t\t    is7 = 0;\n\t\tif (error == 0)\n\t\t\terror = check_ipfw_struct(rule, sopt->sopt_valsize);\n\t\t}\n\t\tif (error == 0) {\n\t\t\t/* locking is done within ipfw_add_rule() */\n\t\t\terror = ipfw_add_rule(chain, rule);\n\t\t\tsize = RULESIZE(rule);\n\t\t\tif (!error && sopt->sopt_dir == SOPT_GET) {\n\t\t\t\tif (is7) {\n\t\t\t\t\terror = convert_rule_to_7(rule);\n\t\t\t\t\tsize = RULESIZE7(rule);\n\t\t\t\t\tif (error)\n\t\t\t\t\t\treturn error;\n\t\t\t\t}\n\t\t\t\terror = sooptcopyout(sopt, rule, size);\n\t\t}\n\t\t}\n\t\tfree(rule, M_TEMP);\n\t\tbreak;\n\n\tcase IP_FW_DEL:\n\t\t/*\n\t\t * IP_FW_DEL is used for deleting single rules or sets,\n\t\t * and (ab)used to atomically manipulate sets. Argument size\n\t\t * is used to distinguish between the two:\n\t\t *    sizeof(u_int32_t)\n\t\t *\tdelete single rule or set of rules,\n\t\t *\tor reassign rules (or sets) to a different set.\n\t\t *    2*sizeof(u_int32_t)\n\t\t *\tatomic disable/enable sets.\n\t\t *\tfirst u_int32_t contains sets to be disabled,\n\t\t *\tsecond u_int32_t contains sets to be enabled.\n\t\t */\n\t\terror = sooptcopyin(sopt, rulenum,\n\t\t\t2*sizeof(u_int32_t), sizeof(u_int32_t));\n\t\tif (error)\n\t\t\tbreak;\n\t\tsize = sopt->sopt_valsize;\n\t\tif (size == sizeof(u_int32_t) && rulenum[0] != 0) {\n\t\t\t/* delete or reassign, locking done in del_entry() */\n\t\t\terror = del_entry(chain, rulenum[0]);\n\t\t} else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */\n\t\t\tIPFW_UH_WLOCK(chain);\n\t\t\tV_set_disable =\n\t\t\t    (V_set_disable | rulenum[0]) & ~rulenum[1] &\n\t\t\t    ~(1<<RESVD_SET); /* set RESVD_SET always enabled */\n\t\t\tIPFW_UH_WUNLOCK(chain);\n\t\t} else\n\t\t\terror = EINVAL;\n\t\tbreak;\n\n\tcase IP_FW_ZERO:\n\tcase IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */\n\t\trulenum[0] = 0;\n\t\tif (sopt->sopt_val != 0) {\n\t\t    error = sooptcopyin(sopt, rulenum,\n\t\t\t    sizeof(u_int32_t), sizeof(u_int32_t));\n\t\t    if (error)\n\t\t\tbreak;\n\t\t}\n\t\terror = zero_entry(chain, rulenum[0],\n\t\t\tsopt->sopt_name == IP_FW_RESETLOG);\n\t\tbreak;\n\n\t/*--- TABLE manipulations are protected by the IPFW_LOCK ---*/\n\tcase IP_FW_TABLE_ADD:\n\t\t{\n\t\t\tipfw_table_entry ent;\n\n\t\t\terror = sooptcopyin(sopt, &ent,\n\t\t\t    sizeof(ent), sizeof(ent));\n\t\t\tif (error)\n\t\t\t\tbreak;\n\t\t\terror = ipfw_add_table_entry(chain, ent.tbl,\n\t\t\t    ent.addr, ent.masklen, ent.value);\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_TABLE_DEL:\n\t\t{\n\t\t\tipfw_table_entry ent;\n\n\t\t\terror = sooptcopyin(sopt, &ent,\n\t\t\t    sizeof(ent), sizeof(ent));\n\t\t\tif (error)\n\t\t\t\tbreak;\n\t\t\terror = ipfw_del_table_entry(chain, ent.tbl,\n\t\t\t    ent.addr, ent.masklen);\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_TABLE_FLUSH:\n\t\t{\n\t\t\tu_int16_t tbl;\n\n\t\t\terror = sooptcopyin(sopt, &tbl,\n\t\t\t    sizeof(tbl), sizeof(tbl));\n\t\t\tif (error)\n\t\t\t\tbreak;\n\t\t\tIPFW_WLOCK(chain);\n\t\t\terror = ipfw_flush_table(chain, tbl);\n\t\t\tIPFW_WUNLOCK(chain);\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_TABLE_GETSIZE:\n\t\t{\n\t\t\tu_int32_t tbl, cnt;\n\n\t\t\tif ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),\n\t\t\t    sizeof(tbl))))\n\t\t\t\tbreak;\n\t\t\tIPFW_RLOCK(chain);\n\t\t\terror = ipfw_count_table(chain, tbl, &cnt);\n\t\t\tIPFW_RUNLOCK(chain);\n\t\t\tif (error)\n\t\t\t\tbreak;\n\t\t\terror = sooptcopyout(sopt, &cnt, sizeof(cnt));\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_TABLE_LIST:\n\t\t{\n\t\t\tipfw_table *tbl;\n\n\t\t\tif (sopt->sopt_valsize < sizeof(*tbl)) {\n\t\t\t\terror = EINVAL;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tsize = sopt->sopt_valsize;\n\t\t\ttbl = malloc(size, M_TEMP, M_WAITOK);\n\t\t\terror = sooptcopyin(sopt, tbl, size, sizeof(*tbl));\n\t\t\tif (error) {\n\t\t\t\tfree(tbl, M_TEMP);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttbl->size = (size - sizeof(*tbl)) /\n\t\t\t    sizeof(ipfw_table_entry);\n\t\t\tIPFW_RLOCK(chain);\n\t\t\terror = ipfw_dump_table(chain, tbl);\n\t\t\tIPFW_RUNLOCK(chain);\n\t\t\tif (error) {\n\t\t\t\tfree(tbl, M_TEMP);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\terror = sooptcopyout(sopt, tbl, size);\n\t\t\tfree(tbl, M_TEMP);\n\t\t}\n\t\tbreak;\n\n\t/*--- NAT operations are protected by the IPFW_LOCK ---*/\n\tcase IP_FW_NAT_CFG:\n\t\tif (IPFW_NAT_LOADED)\n\t\t\terror = ipfw_nat_cfg_ptr(sopt);\n\t\telse {\n\t\t\tprintf(\"IP_FW_NAT_CFG: %s\\n\",\n\t\t\t    \"ipfw_nat not present, please load it\");\n\t\t\terror = EINVAL;\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_NAT_DEL:\n\t\tif (IPFW_NAT_LOADED)\n\t\t\terror = ipfw_nat_del_ptr(sopt);\n\t\telse {\n\t\t\tprintf(\"IP_FW_NAT_DEL: %s\\n\",\n\t\t\t    \"ipfw_nat not present, please load it\");\n\t\t\terror = EINVAL;\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_NAT_GET_CONFIG:\n\t\tif (IPFW_NAT_LOADED)\n\t\t\terror = ipfw_nat_get_cfg_ptr(sopt);\n\t\telse {\n\t\t\tprintf(\"IP_FW_NAT_GET_CFG: %s\\n\",\n\t\t\t    \"ipfw_nat not present, please load it\");\n\t\t\terror = EINVAL;\n\t\t}\n\t\tbreak;\n\n\tcase IP_FW_NAT_GET_LOG:\n\t\tif (IPFW_NAT_LOADED)\n\t\t\terror = ipfw_nat_get_log_ptr(sopt);\n\t\telse {\n\t\t\tprintf(\"IP_FW_NAT_GET_LOG: %s\\n\",\n\t\t\t    \"ipfw_nat not present, please load it\");\n\t\t\terror = EINVAL;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tprintf(\"ipfw: ipfw_ctl invalid option %d\\n\", sopt->sopt_name);\n\t\terror = EINVAL;\n\t}\n\n\treturn (error);\n#undef RULE_MAXSIZE\n}\n\n\n#define\tRULE_MAXSIZE\t(256*sizeof(u_int32_t))\n\n/* Functions to convert rules 7.2 <==> 8.0 */\nint\nconvert_rule_to_7(struct ip_fw *rule)\n{\n\t/* Used to modify original rule */\n\tstruct ip_fw7 *rule7 = (struct ip_fw7 *)rule;\n\t/* copy of original rule, version 8 */\n\tstruct ip_fw *tmp;\n\n\t/* Used to copy commands */\n\tipfw_insn *ccmd, *dst;\n\tint ll = 0, ccmdlen = 0;\n\n\ttmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);\n\tif (tmp == NULL) {\n\t\treturn 1; //XXX error\n\t}\n\tbcopy(rule, tmp, RULE_MAXSIZE);\n\n\t/* Copy fields */\n\trule7->_pad = tmp->_pad;\n\trule7->set = tmp->set;\n\trule7->rulenum = tmp->rulenum;\n\trule7->cmd_len = tmp->cmd_len;\n\trule7->act_ofs = tmp->act_ofs;\n\trule7->next_rule = (struct ip_fw7 *)tmp->next_rule;\n\trule7->next = (struct ip_fw7 *)tmp->x_next;\n\trule7->cmd_len = tmp->cmd_len;\n\trule7->pcnt = tmp->pcnt;\n\trule7->bcnt = tmp->bcnt;\n\trule7->timestamp = tmp->timestamp;\n\n\t/* Copy commands */\n\tfor (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ;\n\t\t\tll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {\n\t\tccmdlen = F_LEN(ccmd);\n\n\t\tbcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));\n\n\t\tif (dst->opcode > O_NAT)\n\t\t\t/* O_REASS doesn't exists in 7.2 version, so\n\t\t\t * decrement opcode if it is after O_REASS\n\t\t\t */\n\t\t\tdst->opcode--;\n\n\t\tif (ccmdlen > ll) {\n\t\t\tprintf(\"ipfw: opcode %d size truncated\\n\",\n\t\t\t\tccmd->opcode);\n\t\t\treturn EINVAL;\n\t\t}\n\t}\n\tfree(tmp, M_TEMP);\n\n\treturn 0;\n}\n\nint\nconvert_rule_to_8(struct ip_fw *rule)\n{\n\t/* Used to modify original rule */\n\tstruct ip_fw7 *rule7 = (struct ip_fw7 *) rule;\n\n\t/* Used to copy commands */\n\tipfw_insn *ccmd, *dst;\n\tint ll = 0, ccmdlen = 0;\n\n\t/* Copy of original rule */\n\tstruct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);\n\tif (tmp == NULL) {\n\t\treturn 1; //XXX error\n\t}\n\n\tbcopy(rule7, tmp, RULE_MAXSIZE);\n\n\tfor (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ;\n\t\t\tll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {\n\t\tccmdlen = F_LEN(ccmd);\n\t\t\n\t\tbcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));\n\n\t\tif (dst->opcode > O_NAT)\n\t\t\t/* O_REASS doesn't exists in 7.2 version, so\n\t\t\t * increment opcode if it is after O_REASS\n\t\t\t */\n\t\t\tdst->opcode++;\n\n\t\tif (ccmdlen > ll) {\n\t\t\tprintf(\"ipfw: opcode %d size truncated\\n\",\n\t\t\t    ccmd->opcode);\n\t\t\treturn EINVAL;\n\t\t}\n\t}\n\n\trule->_pad = tmp->_pad;\n\trule->set = tmp->set;\n\trule->rulenum = tmp->rulenum;\n\trule->cmd_len = tmp->cmd_len;\n\trule->act_ofs = tmp->act_ofs;\n\trule->next_rule = (struct ip_fw *)tmp->next_rule;\n\trule->x_next = (struct ip_fw *)tmp->next;\n\trule->cmd_len = tmp->cmd_len;\n\trule->id = 0; /* XXX see if is ok = 0 */\n\trule->pcnt = tmp->pcnt;\n\trule->bcnt = tmp->bcnt;\n\trule->timestamp = tmp->timestamp;\n\n\tfree (tmp, M_TEMP);\n\treturn 0;\n}\n\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/ipfw/ip_fw_table.c",
    "content": "/*-\n * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n__FBSDID(\"$FreeBSD: head/sys/netinet/ipfw/ip_fw_table.c 200601 2009-12-16 10:48:40Z luigi $\");\n\n/*\n * Lookup table support for ipfw\n *\n * Lookup tables are implemented (at the moment) using the radix\n * tree used for routing tables. Tables store key-value entries, where\n * keys are network prefixes (addr/masklen), and values are integers.\n * As a degenerate case we can interpret keys as 32-bit integers\n * (with a /32 mask).\n *\n * The table is protected by the IPFW lock even for manipulation coming\n * from userland, because operations are typically fast.\n */\n\n#if !defined(KLD_MODULE)\n#include \"opt_ipfw.h\"\n#include \"opt_ipdivert.h\"\n#include \"opt_ipdn.h\"\n#include \"opt_inet.h\"\n#ifndef INET\n#error IPFIREWALL requires INET.\n#endif /* INET */\n#endif\n#include \"opt_inet6.h\"\n#include \"opt_ipsec.h\"\n\n#include <sys/param.h>\n#include <sys/systm.h>\n#include <sys/malloc.h>\n#include <sys/kernel.h>\n#include <sys/lock.h>\n#include <sys/rwlock.h>\n#include <sys/socket.h>\n#include <net/if.h>\t/* ip_fw.h requires IFNAMSIZ */\n#include <net/radix.h>\n#include <net/route.h>\n#include <net/vnet.h>\n\n#include <netinet/in.h>\n#include <netinet/ip_var.h>\t/* struct ipfw_rule_ref */\n#include <netinet/ip_fw.h>\n#include <sys/queue.h> /* LIST_HEAD */\n#include <netinet/ipfw/ip_fw_private.h>\n\n#ifdef MAC\n#include <security/mac/mac_framework.h>\n#endif\n\nMALLOC_DEFINE(M_IPFW_TBL, \"ipfw_tbl\", \"IpFw tables\");\n\nstruct table_entry {\n\tstruct radix_node\trn[2];\n\tstruct sockaddr_in\taddr, mask;\n\tu_int32_t\t\tvalue;\n};\n\n/*\n * The radix code expects addr and mask to be array of bytes,\n * with the first byte being the length of the array. rn_inithead\n * is called with the offset in bits of the lookup key within the\n * array. If we use a sockaddr_in as the underlying type,\n * sin_len is conveniently located at offset 0, sin_addr is at\n * offset 4 and normally aligned.\n * But for portability, let's avoid assumption and make the code explicit\n */\n#define KEY_LEN(v)\t*((uint8_t *)&(v))\n#define KEY_OFS\t\t(8*offsetof(struct sockaddr_in, sin_addr))\n\nint\nipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,\n    uint8_t mlen, uint32_t value)\n{\n\tstruct radix_node_head *rnh;\n\tstruct table_entry *ent;\n\tstruct radix_node *rn;\n\n\tif (tbl >= IPFW_TABLES_MAX)\n\t\treturn (EINVAL);\n\trnh = ch->tables[tbl];\n\tent = malloc(sizeof(*ent), M_IPFW_TBL, M_NOWAIT | M_ZERO);\n\tif (ent == NULL)\n\t\treturn (ENOMEM);\n\tent->value = value;\n\tKEY_LEN(ent->addr) = KEY_LEN(ent->mask) = 8;\n\tent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);\n\tent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;\n\tIPFW_WLOCK(ch);\n\trn = rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent);\n\tif (rn == NULL) {\n\t\tIPFW_WUNLOCK(ch);\n\t\tfree(ent, M_IPFW_TBL);\n\t\treturn (EEXIST);\n\t}\n\tIPFW_WUNLOCK(ch);\n\treturn (0);\n}\n\nint\nipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,\n    uint8_t mlen)\n{\n\tstruct radix_node_head *rnh;\n\tstruct table_entry *ent;\n\tstruct sockaddr_in sa, mask;\n\n\tif (tbl >= IPFW_TABLES_MAX)\n\t\treturn (EINVAL);\n\trnh = ch->tables[tbl];\n\tKEY_LEN(sa) = KEY_LEN(mask) = 8;\n\tmask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);\n\tsa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;\n\tIPFW_WLOCK(ch);\n\tent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh);\n\tif (ent == NULL) {\n\t\tIPFW_WUNLOCK(ch);\n\t\treturn (ESRCH);\n\t}\n\tIPFW_WUNLOCK(ch);\n\tfree(ent, M_IPFW_TBL);\n\treturn (0);\n}\n\nstatic int\nflush_table_entry(struct radix_node *rn, void *arg)\n{\n\tstruct radix_node_head * const rnh = arg;\n\tstruct table_entry *ent;\n\n\tent = (struct table_entry *)\n\t    rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);\n\tif (ent != NULL)\n\t\tfree(ent, M_IPFW_TBL);\n\treturn (0);\n}\n\nint\nipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl)\n{\n\tstruct radix_node_head *rnh;\n\n\tIPFW_WLOCK_ASSERT(ch);\n\n\tif (tbl >= IPFW_TABLES_MAX)\n\t\treturn (EINVAL);\n\trnh = ch->tables[tbl];\n\tKASSERT(rnh != NULL, (\"NULL IPFW table\"));\n\trnh->rnh_walktree(rnh, flush_table_entry, rnh);\n\treturn (0);\n}\n\nvoid\nipfw_destroy_tables(struct ip_fw_chain *ch)\n{\n\tuint16_t tbl;\n\tstruct radix_node_head *rnh;\n\n\tIPFW_WLOCK_ASSERT(ch);\n\n\tfor (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++) {\n\t\tipfw_flush_table(ch, tbl);\n\t\trnh = ch->tables[tbl];\n\t\trn_detachhead((void **)&rnh);\n\t}\n}\n\nint\nipfw_init_tables(struct ip_fw_chain *ch)\n{ \n\tint i;\n\tuint16_t j;\n\n\tfor (i = 0; i < IPFW_TABLES_MAX; i++) {\n\t\tif (!rn_inithead((void **)&ch->tables[i], KEY_OFS)) {\n\t\t\tfor (j = 0; j < i; j++) {\n\t\t\t\t(void) ipfw_flush_table(ch, j);\n\t\t\t}\n\t\t\treturn (ENOMEM);\n\t\t}\n\t}\n\treturn (0);\n}\n\nint\nipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,\n    uint32_t *val)\n{\n\tstruct radix_node_head *rnh;\n\tstruct table_entry *ent;\n\tstruct sockaddr_in sa;\n\n\tif (tbl >= IPFW_TABLES_MAX)\n\t\treturn (0);\n\trnh = ch->tables[tbl];\n\tKEY_LEN(sa) = 8;\n\tsa.sin_addr.s_addr = addr;\n\tent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh));\n\tif (ent != NULL) {\n\t\t*val = ent->value;\n\t\treturn (1);\n\t}\n\treturn (0);\n}\n\nstatic int\ncount_table_entry(struct radix_node *rn, void *arg)\n{\n\tu_int32_t * const cnt = arg;\n\n\t(*cnt)++;\n\treturn (0);\n}\n\nint\nipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt)\n{\n\tstruct radix_node_head *rnh;\n\n\tif (tbl >= IPFW_TABLES_MAX)\n\t\treturn (EINVAL);\n\trnh = ch->tables[tbl];\n\t*cnt = 0;\n\trnh->rnh_walktree(rnh, count_table_entry, cnt);\n\treturn (0);\n}\n\nstatic int\ndump_table_entry(struct radix_node *rn, void *arg)\n{\n\tstruct table_entry * const n = (struct table_entry *)rn;\n\tipfw_table * const tbl = arg;\n\tipfw_table_entry *ent;\n\n\tif (tbl->cnt == tbl->size)\n\t\treturn (1);\n\tent = &tbl->ent[tbl->cnt];\n\tent->tbl = tbl->tbl;\n\tif (in_nullhost(n->mask.sin_addr))\n\t\tent->masklen = 0;\n\telse\n\t\tent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));\n\tent->addr = n->addr.sin_addr.s_addr;\n\tent->value = n->value;\n\ttbl->cnt++;\n\treturn (0);\n}\n\nint\nipfw_dump_table(struct ip_fw_chain *ch, ipfw_table *tbl)\n{\n\tstruct radix_node_head *rnh;\n\n\tif (tbl->tbl >= IPFW_TABLES_MAX)\n\t\treturn (EINVAL);\n\trnh = ch->tables[tbl->tbl];\n\ttbl->cnt = 0;\n\trnh->rnh_walktree(rnh, dump_table_entry, tbl);\n\treturn (0);\n}\n/* end of file */\n"
  },
  {
    "path": "sys/netinet/tcp.h",
    "content": "/*-\n * Copyright (c) 1982, 1986, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)tcp.h\t8.1 (Berkeley) 6/10/93\n * $FreeBSD: src/sys/netinet/tcp.h,v 1.40.2.2 2008/07/31 06:10:25 kmacy Exp $\n */\n\n#ifndef _NETINET_TCP_H_\n#define _NETINET_TCP_H_\n\n#include <sys/cdefs.h>\n\n#define __BSD_VISIBLE 1\n\n#if __BSD_VISIBLE\n\ntypedef\tu_int32_t tcp_seq;\n\n#define tcp6_seq\ttcp_seq\t/* for KAME src sync over BSD*'s */\n#define tcp6hdr\t\ttcphdr\t/* for KAME src sync over BSD*'s */\n\n/*\n * TCP header.\n * Per RFC 793, September, 1981.\n */\nstruct tcphdr {\n\tu_short\tth_sport;\t\t/* source port */\n\tu_short\tth_dport;\t\t/* destination port */\n\ttcp_seq\tth_seq;\t\t\t/* sequence number */\n\ttcp_seq\tth_ack;\t\t\t/* acknowledgement number */\n#if BYTE_ORDER == LITTLE_ENDIAN\n\tu_char\tth_x2:4,\t\t/* (unused) */\n\t\tth_off:4;\t\t/* data offset */\n#endif\n#if BYTE_ORDER == BIG_ENDIAN\n\tu_char\tth_off:4,\t\t/* data offset */\n\t\tth_x2:4;\t\t/* (unused) */\n#endif\n\tu_char\tth_flags;\n#define\tTH_FIN\t0x01\n#define\tTH_SYN\t0x02\n#define\tTH_RST\t0x04\n#define\tTH_PUSH\t0x08\n#define\tTH_ACK\t0x10\n#define\tTH_URG\t0x20\n#define\tTH_ECE\t0x40\n#define\tTH_CWR\t0x80\n#define\tTH_FLAGS\t(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|TH_ECE|TH_CWR)\n#define\tPRINT_TH_FLAGS\t\"\\20\\1FIN\\2SYN\\3RST\\4PUSH\\5ACK\\6URG\\7ECE\\10CWR\"\n\n\tu_short\tth_win;\t\t\t/* window */\n\tu_short\tth_sum;\t\t\t/* checksum */\n\tu_short\tth_urp;\t\t\t/* urgent pointer */\n};\n\n#define\tTCPOPT_EOL\t\t0\n#define\t   TCPOLEN_EOL\t\t\t1\n#define\tTCPOPT_PAD\t\t0\t\t/* padding after EOL */\n#define\t   TCPOLEN_PAD\t\t\t1\n#define\tTCPOPT_NOP\t\t1\n#define\t   TCPOLEN_NOP\t\t\t1\n#define\tTCPOPT_MAXSEG\t\t2\n#define    TCPOLEN_MAXSEG\t\t4\n#define TCPOPT_WINDOW\t\t3\n#define    TCPOLEN_WINDOW\t\t3\n#define TCPOPT_SACK_PERMITTED\t4\n#define    TCPOLEN_SACK_PERMITTED\t2\n#define TCPOPT_SACK\t\t5\n#define\t   TCPOLEN_SACKHDR\t\t2\n#define    TCPOLEN_SACK\t\t\t8\t/* 2*sizeof(tcp_seq) */\n#define TCPOPT_TIMESTAMP\t8\n#define    TCPOLEN_TIMESTAMP\t\t10\n#define    TCPOLEN_TSTAMP_APPA\t\t(TCPOLEN_TIMESTAMP+2) /* appendix A */\n#define\tTCPOPT_SIGNATURE\t19\t\t/* Keyed MD5: RFC 2385 */\n#define\t   TCPOLEN_SIGNATURE\t\t18\n\n/* Miscellaneous constants */\n#define\tMAX_SACK_BLKS\t6\t/* Max # SACK blocks stored at receiver side */\n#define\tTCP_MAX_SACK\t4\t/* MAX # SACKs sent in any segment */\n\n\n/*\n * Default maximum segment size for TCP.\n * With an IP MTU of 576, this is 536,\n * but 512 is probably more convenient.\n * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).\n */\n#define\tTCP_MSS\t512\n/*\n * TCP_MINMSS is defined to be 216 which is fine for the smallest\n * link MTU (256 bytes, AX.25 packet radio) in the Internet.\n * However it is very unlikely to come across such low MTU interfaces\n * these days (anno dato 2003).\n * See tcp_subr.c tcp_minmss SYSCTL declaration for more comments.\n * Setting this to \"0\" disables the minmss check.\n */\n#define\tTCP_MINMSS 216\n\n/*\n * Default maximum segment size for TCP6.\n * With an IP6 MSS of 1280, this is 1220,\n * but 1024 is probably more convenient. (xxx kazu in doubt)\n * This should be defined as MIN(1024, IP6_MSS - sizeof (struct tcpip6hdr))\n */\n#define\tTCP6_MSS\t1024\n\n#define\tTCP_MAXWIN\t65535\t/* largest value for (unscaled) window */\n#define\tTTCP_CLIENT_SND_WND\t4096\t/* dflt send window for T/TCP client */\n\n#define TCP_MAX_WINSHIFT\t14\t/* maximum window shift */\n\n#define TCP_MAXBURST\t\t4\t/* maximum segments in a burst */\n\n#define TCP_MAXHLEN\t(0xf<<2)\t/* max length of header in bytes */\n#define TCP_MAXOLEN\t(TCP_MAXHLEN - sizeof(struct tcphdr))\n\t\t\t\t\t/* max space left for options */\n#endif /* __BSD_VISIBLE */\n\n/*\n * User-settable options (used with setsockopt).\n */\n#define\tTCP_NODELAY\t0x01\t/* don't delay send to coalesce packets */\n#if __BSD_VISIBLE\n#define\tTCP_MAXSEG\t0x02\t/* set maximum segment size */\n#define TCP_NOPUSH\t0x04\t/* don't push last block of write */\n#define TCP_NOOPT\t0x08\t/* don't use TCP options */\n#define TCP_MD5SIG\t0x10\t/* use MD5 digests (RFC2385) */\n#define\tTCP_INFO\t0x20\t/* retrieve tcp_info structure */\n#define\tTCP_CONGESTION\t0x40\t/* get/set congestion control algorithm */\n\n#define\tTCP_CA_NAME_MAX\t16\t/* max congestion control name length */\n\n#define\tTCPI_OPT_TIMESTAMPS\t0x01\n#define\tTCPI_OPT_SACK\t\t0x02\n#define\tTCPI_OPT_WSCALE\t\t0x04\n#define\tTCPI_OPT_ECN\t\t0x08\n#define\tTCPI_OPT_TOE\t\t0x10\n\n/*\n * The TCP_INFO socket option comes from the Linux 2.6 TCP API, and permits\n * the caller to query certain information about the state of a TCP\n * connection.  We provide an overlapping set of fields with the Linux\n * implementation, but since this is a fixed size structure, room has been\n * left for growth.  In order to maximize potential future compatibility with\n * the Linux API, the same variable names and order have been adopted, and\n * padding left to make room for omitted fields in case they are added later.\n *\n * XXX: This is currently an unstable ABI/API, in that it is expected to\n * change.\n */\nstruct tcp_info {\n\tu_int8_t\ttcpi_state;\t\t/* TCP FSM state. */\n\tu_int8_t\t__tcpi_ca_state;\n\tu_int8_t\t__tcpi_retransmits;\n\tu_int8_t\t__tcpi_probes;\n\tu_int8_t\t__tcpi_backoff;\n\tu_int8_t\ttcpi_options;\t\t/* Options enabled on conn. */\n\tu_int8_t\ttcpi_snd_wscale:4,\t/* RFC1323 send shift value. */\n\t\t\ttcpi_rcv_wscale:4;\t/* RFC1323 recv shift value. */\n\n\tu_int32_t\t__tcpi_rto;\n\tu_int32_t\t__tcpi_ato;\n\tu_int32_t\t__tcpi_snd_mss;\n\tu_int32_t\t__tcpi_rcv_mss;\n\n\tu_int32_t\t__tcpi_unacked;\n\tu_int32_t\t__tcpi_sacked;\n\tu_int32_t\t__tcpi_lost;\n\tu_int32_t\t__tcpi_retrans;\n\tu_int32_t\t__tcpi_fackets;\n\n\t/* Times; measurements in usecs. */\n\tu_int32_t\t__tcpi_last_data_sent;\n\tu_int32_t\t__tcpi_last_ack_sent;\t/* Also unimpl. on Linux? */\n\tu_int32_t\t__tcpi_last_data_recv;\n\tu_int32_t\t__tcpi_last_ack_recv;\n\n\t/* Metrics; variable units. */\n\tu_int32_t\t__tcpi_pmtu;\n\tu_int32_t\t__tcpi_rcv_ssthresh;\n\tu_int32_t\ttcpi_rtt;\t\t/* Smoothed RTT in usecs. */\n\tu_int32_t\ttcpi_rttvar;\t\t/* RTT variance in usecs. */\n\tu_int32_t\ttcpi_snd_ssthresh;\t/* Slow start threshold. */\n\tu_int32_t\ttcpi_snd_cwnd;\t\t/* Send congestion window. */\n\tu_int32_t\t__tcpi_advmss;\n\tu_int32_t\t__tcpi_reordering;\n\n\tu_int32_t\t__tcpi_rcv_rtt;\n\tu_int32_t\ttcpi_rcv_space;\t\t/* Advertised recv window. */\n\n\t/* FreeBSD extensions to tcp_info. */\n\tu_int32_t\ttcpi_snd_wnd;\t\t/* Advertised send window. */\n\tu_int32_t\ttcpi_snd_bwnd;\t\t/* Bandwidth send window. */\n\tu_int32_t\ttcpi_snd_nxt;\t\t/* Next egress seqno */\n\tu_int32_t\ttcpi_rcv_nxt;\t\t/* Next ingress seqno */\n\tu_int32_t\ttcpi_toe_tid;\t\t/* HWTID for TOE endpoints */\n\t\n\t/* Padding to grow without breaking ABI. */\n\tu_int32_t\t__tcpi_pad[29];\t\t/* Padding. */\n};\n#endif\n\n#endif /* !_NETINET_TCP_H_ */\n"
  },
  {
    "path": "sys/netinet/tcp_var.h",
    "content": "#ifndef _NETINET_TCP_VAR_H_\n#define _NETINET_TCP_VAR_H_\n#include <netinet/tcp.h>\n#endif /* !_NETINET_TCP_VAR_H_ */\n"
  },
  {
    "path": "sys/netinet/udp.h",
    "content": "/*-\n * Copyright (c) 1982, 1986, 1993\n *\tThe Regents of the University of California.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)udp.h\t8.1 (Berkeley) 6/10/93\n * $FreeBSD: src/sys/netinet/udp.h,v 1.10 2007/02/20 10:13:11 rwatson Exp $\n */\n\n#ifndef _NETINET_UDP_H_\n#define\t_NETINET_UDP_H_\n\n/*\n * UDP protocol header.\n * Per RFC 768, September, 1981.\n */\nstruct udphdr {\n\tu_short\tuh_sport;\t\t/* source port */\n\tu_short\tuh_dport;\t\t/* destination port */\n\tu_short\tuh_ulen;\t\t/* udp length */\n\tu_short\tuh_sum;\t\t\t/* udp checksum */\n};\n\n/* \n * User-settable options (used with setsockopt).\n */\n#define\tUDP_ENCAP\t\t\t0x01\n\n\n/*\n * UDP Encapsulation of IPsec Packets options.\n */\n/* Encapsulation types. */\n#define\tUDP_ENCAP_ESPINUDP_NON_IKE \t1 /* draft-ietf-ipsec-nat-t-ike-00/01 */\n#define\tUDP_ENCAP_ESPINUDP\t\t2 /* draft-ietf-ipsec-udp-encaps-02+ */\n\n/* Default ESP in UDP encapsulation port. */\n#define\tUDP_ENCAP_ESPINUDP_PORT\t\t500\n\n/* Maximum UDP fragment size for ESP over UDP. */\n#define\tUDP_ENCAP_ESPINUDP_MAXFRAGLEN\t552\n\n#endif\n"
  },
  {
    "path": "sys/sys/cdefs.h",
    "content": "#ifndef _CDEFS_H_\n#define _CDEFS_H_\n\n/*\n * various compiler macros and common functions\n */\n\n#ifndef __packed\n#define __packed       __attribute__ ((__packed__))\n#endif\n\n#ifndef __aligned\n#define __aligned(x) __attribute__((__aligned__(x)))\n#endif\n\n/* defined as assert */\nvoid panic(const char *fmt, ...);\n\n#define KASSERT(exp,msg) do {                                           \\\n        if (__predict_false(!(exp)))                                    \\\n                panic msg;                                              \\\n} while (0)\n\n/* don't bother to optimize */\n#ifndef __predict_false\n#define __predict_false(x)   (x)\t/* __builtin_expect((exp), 0) */\n#endif\n\n#endif /* !_CDEFS_H_ */\n"
  },
  {
    "path": "sys/sys/kernel.h",
    "content": "/*\n * from freebsd's kernel.h\n */\n#ifndef _SYS_KERNEL_H_\n#define _SYS_KERNEL_H_\n\n#define SYSINIT(a, b, c, d, e)  \\\n        void *sysinit_ ## d = d\n#define VNET_SYSINIT(a, b, c, d, e)  \\\n        void *sysinit_ ## d = d\n#define SYSUNINIT(a, b, c, d, e)  \\\n        void *sysuninit_ ## d = d\n#define VNET_SYSUNINIT(a, b, c, d, e)  \\\n        void *sysuninit_ ## d = d\n\n/*\n * Some enumerated orders; \"ANY\" sorts last.\n */\nenum sysinit_elem_order {\n        SI_ORDER_FIRST          = 0x0000000,    /* first*/\n        SI_ORDER_SECOND         = 0x0000001,    /* second*/\n        SI_ORDER_THIRD          = 0x0000002,    /* third*/\n        SI_ORDER_MIDDLE         = 0x1000000,    /* somewhere in the middle */\n        SI_ORDER_ANY            = 0xfffffff     /* last*/\n};\n#endif\n"
  },
  {
    "path": "sys/sys/malloc.h",
    "content": "#ifndef _SYS_MALLOC_H_\n#define _SYS_MALLOC_H_\n\n/*\n * No matter what, try to get clear memory and be non-blocking.\n * XXX check if 2.4 has a native way to zero memory,\n * XXX obey to the flags (M_NOWAIT <-> GPF_ATOMIC, M_WAIT <-> GPF_KERNEL)\n */\n#ifndef _WIN32 /* this is the linux version */\n\n/*\n * XXX On zeroshell (2.6.25.17) we get a load error\n *\t__you_cannot_kmalloc_that_much\n * which is triggered when kmalloc() is called with a large\n * compile-time constant argument (include/linux/slab_def.h)\n *\n * I think it may be a compiler (or source) bug because there is no\n * evidence that such a large request is made.\n * Making the _size argument to kmalloc volatile prevents the compiler\n * from making the mistake, though it is clearly not ideal.\n */\n\n#if !defined (LINUX_24) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)\n#define malloc(_size, type, flags)\t\t\t\\\n\t({ volatile int _v = _size; kmalloc(_v, GFP_ATOMIC | __GFP_ZERO); })\n#else /* LINUX <= 2.6.22 and LINUX_24 */\n/* linux 2.6.22 does not zero allocated memory */\n#define malloc(_size, type, flags)\t\t\t\\\n\t({ int _s = _size;\t\t\t\t\\\n\tvoid *_ret = kmalloc(_s, GFP_ATOMIC);\t\t\\\n\tif (_ret) memset(_ret, 0, _s);\t\t\t\\\n        (_ret);\t\t\t\t\t\t\\\n        })\n#endif /* LINUX <= 2.6.22 */\n\n#define calloc(_n, _s) malloc((_n * _s), NULL, GFP_ATOMIC | __GFP_ZERO)\n#define free(_var, type) kfree(_var)\n\n#else /* _WIN32, the windows version */\n\n/*\n * ntddk.h uses win_malloc() and MmFreeContiguousMemory().\n * wipfw uses\n * ExAllocatePoolWithTag(, pool, len, tag)\n * ExFreePoolWithTag(ptr, tag)\n */\n#define malloc(_size, _type, _flags) my_alloc(_size)\n#define calloc(_size, _type, _flags) my_alloc(_size)\n\nvoid *my_alloc(int _size);\n/* the 'tag' version does not work without -Gz in the linker */\n#define free(_var, type) ExFreePool(_var)\n//#define free(_var, type) ExFreePoolWithTag(_var, 'wfpi')\n\n#endif /* _WIN32 */\n\n#define M_NOWAIT        0x0001          /* do not block */\n#define M_ZERO          0x0100          /* bzero the allocation */\n#endif /* _SYS_MALLOC_H_ */\n"
  },
  {
    "path": "sys/sys/mbuf.h",
    "content": "/*\n * Copyright (C) 2009 Luigi Rizzo, Universita` di Pisa\n *\n * BSD copyright.\n *\n * A simple compatibility interface to map mbufs onto sk_buff\n */\n\n#ifndef _SYS_MBUF_H_\n#define\t_SYS_MBUF_H_\n\n#include <sys/malloc.h>\t\t/* we use free() */\n/* hopefully queue.h is already included by someone else */\n#include <sys/queue.h>\n#ifdef _KERNEL\n\n/* bzero not present on linux, but this should go in glue.h */\n// #define bzero(s, n) memset(s, 0, n)\n\n/*\n * We implement a very simplified UMA allocator where the backend\n * is simply malloc, and uma_zone only stores the length of the components.\n */\ntypedef int uma_zone_t;\t\t/* the zone size */\n\n#define uma_zcreate(name, len, _3, _4, _5, _6, _7, _8)\t(len)\n\n\n#define uma_zfree(zone, item)\tfree(item, M_IPFW)\n#define uma_zalloc(zone, flags) malloc(zone, M_IPFW, flags)\n#define uma_zdestroy(zone)\tdo {} while (0)\n\n/*-\n * Macros for type conversion:\n * mtod(m, t)\t-- Convert mbuf pointer to data pointer of correct type.\n */\n#define\tmtod(m, t)\t((t)((m)->m_data))\n\n#endif /* _KERNEL */\n\n/*\n * Packet tag structure (see below for details).\n */\nstruct m_tag {\n\tSLIST_ENTRY(m_tag)\tm_tag_link;\t/* List of packet tags */\n\tu_int16_t\t\tm_tag_id;\t/* Tag ID */\n\tu_int16_t\t\tm_tag_len;\t/* Length of data */\n\tu_int32_t\t\tm_tag_cookie;\t/* ABI/Module ID */\n\tvoid\t\t\t(*m_tag_free)(struct m_tag *);\n};\n\n#if defined(__linux__) || defined( _WIN32 )\n\n/*\n * Auxiliary structure to store values from the sk_buf.\n * Note that we should not alter the sk_buff, and if we do\n * so make sure to keep the values in sync between the mbuf\n * and the sk_buff (especially m_len and m_pkthdr.len).\n */\n\nstruct mbuf {\n\tstruct mbuf *m_next;\n\tstruct mbuf *m_nextpkt;\n\tchar *m_data; // XXX was void *\n\tint m_len;\t/* length in this mbuf */\n\tint m_flags;\n#ifdef __linux__\n#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)\n\tstruct nf_info *queue_entry;\n#else\n\tstruct nf_queue_entry *queue_entry;\n#endif\n#else /* _WIN32 */\n\tint\t\tdirection;\t/* could go in rcvif */\n\tNDIS_HANDLE\tcontext;\t/* replaces queue_entry or skb ?*/\n\tPNDIS_PACKET\tpkt;\n#endif\n\tstruct sk_buff *m_skb;\n\tstruct {\n#ifdef __linux__\n\t\tstruct net_device *rcvif;\n#else\n\t\tstruct ifnet *rcvif;\n#endif\n\t\tint len;\t/* total packet len */\n\t\tSLIST_HEAD (packet_tags, m_tag) tags;\n\t} m_pkthdr;\n};\n\n#define M_SKIP_FIREWALL\t0x01\t\t/* skip firewall processing */\n#define M_BCAST         0x02 /* send/received as link-level broadcast */\n#define M_MCAST         0x04 /* send/received as link-level multicast */\n\n#define M_DONTWAIT      M_NOWAIT\t/* should not be here... */\n\n\n/*\n * m_dup() is used in the TEE case, currently unsupported so we\n * just return.\n */\nstatic __inline struct mbuf\t*m_dup(struct mbuf *m, int n)\n{\n\t(void)m; (void)n;\n\treturn NULL;\n};\n\n#define\tMTAG_ABI_COMPAT\t\t0\t\t/* compatibility ABI */\nstatic __inline struct m_tag *\nm_tag_find(struct mbuf *m, int type, struct m_tag *start)\n{\n\t(void)m; (void)type; (void)start;\n\treturn NULL;\n};\n\n\nstatic __inline void\nm_tag_prepend(struct mbuf *m, struct m_tag *t)\n{\n\tSLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);\n}\n\n/*\n * Return the next tag in the list of tags associated with an mbuf.\n */\nstatic __inline struct m_tag *\nm_tag_next(struct mbuf *m, struct m_tag *t)\n{\n \n        return (SLIST_NEXT(t, m_tag_link));\n}\n\n/*\n * Create an mtag of the given type\n */\nstatic __inline struct m_tag *\nm_tag_alloc(uint32_t cookie, int type, int length, int wait)\n{\n\tint l = length + sizeof(struct m_tag);\n\tstruct m_tag *m = malloc(l, 0, M_NOWAIT);\n\tif (m) {\n\t\tmemset(m, 0, l);\n\t\tm->m_tag_id = type;\n\t\tm->m_tag_len = length;\n\t\tm->m_tag_cookie = cookie;\n\t}\n\treturn m;\n};\n\nstatic __inline struct m_tag *\nm_tag_get(int type, int length, int wait)\n{\n\treturn m_tag_alloc(MTAG_ABI_COMPAT, type, length, wait);\n}\n\nstatic __inline struct m_tag *\nm_tag_first(struct mbuf *m)\n{\n\treturn SLIST_FIRST(&m->m_pkthdr.tags);\n};\n\nstatic __inline void\nm_tag_delete(struct mbuf *m, struct m_tag *t)\n{\n};\n\nstatic __inline struct m_tag *\nm_tag_locate(struct mbuf *m, u_int32_t n, int x, struct m_tag *t)\n{\n\tstruct m_tag *tag;\n\n\ttag = m_tag_first(m);\n\tif (tag == NULL)\n\t\treturn NULL;\n\n\tif (tag->m_tag_cookie != n || tag->m_tag_id != x)\n\t\treturn NULL;\n\telse\n\t\treturn tag;\n};\n\n#define M_SETFIB(_m, _fib)\t/* nothing on linux */\n\nstatic __inline void\nm_freem(struct mbuf *m)\n{\n\tstruct m_tag *t;\n\n\t/* free the m_tag chain */\n\twhile ( (t = SLIST_FIRST(&m->m_pkthdr.tags) ) ) {\n\t\tSLIST_REMOVE_HEAD(&m->m_pkthdr.tags, m_tag_link);\n\t\tfree(t, 0);\n\t}\n\n\t/* free the mbuf */\n\tfree(m, M_IPFW);\n};\n\n/* m_pullup is not supported, there is a macro in missing.h */\n\n#define M_GETFIB(_m)\t0\n\n/* macro used to create a new mbuf */\n#define MT_DATA         1       /* dynamic (data) allocation */\n#define MSIZE           256     /* size of an mbuf */\n#define MGETHDR(_m, _how, _type)   ((_m) = m_gethdr((_how), (_type)))\n\n/* allocate and init a new mbuf using the same structure of FreeBSD */\nstatic __inline struct mbuf *\nm_gethdr(int how, short type)\n{\n\tstruct mbuf *m;\n\n\tm = malloc(MSIZE, M_IPFW, M_NOWAIT);\n\n\tif (m == NULL) {\n\t\treturn m;\n\t}\n\n\t/* here we have MSIZE - sizeof(struct mbuf) available */\n\tm->m_data = (char *)(m + 1);\n\n\treturn m;\n}\n\n#endif /* __linux__ || _WIN32 */\n\n/*\n * Persistent tags stay with an mbuf until the mbuf is reclaimed.  Otherwise\n * tags are expected to ``vanish'' when they pass through a network\n * interface.  For most interfaces this happens normally as the tags are\n * reclaimed when the mbuf is free'd.  However in some special cases\n * reclaiming must be done manually.  An example is packets that pass through\n * the loopback interface.  Also, one must be careful to do this when\n * ``turning around'' packets (e.g., icmp_reflect).\n *\n * To mark a tag persistent bit-or this flag in when defining the tag id.\n * The tag will then be treated as described above.\n */\n#define\tMTAG_PERSISTENT\t\t\t\t0x800\n\n#define\tPACKET_TAG_NONE\t\t\t\t0  /* Nadda */\n\n/* Packet tags for use with PACKET_ABI_COMPAT. */\n#define\tPACKET_TAG_IPSEC_IN_DONE\t\t1  /* IPsec applied, in */\n#define\tPACKET_TAG_IPSEC_OUT_DONE\t\t2  /* IPsec applied, out */\n#define\tPACKET_TAG_IPSEC_IN_CRYPTO_DONE\t\t3  /* NIC IPsec crypto done */\n#define\tPACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED\t4  /* NIC IPsec crypto req'ed */\n#define\tPACKET_TAG_IPSEC_IN_COULD_DO_CRYPTO\t5  /* NIC notifies IPsec */\n#define\tPACKET_TAG_IPSEC_PENDING_TDB\t\t6  /* Reminder to do IPsec */\n#define\tPACKET_TAG_BRIDGE\t\t\t7  /* Bridge processing done */\n#define\tPACKET_TAG_GIF\t\t\t\t8  /* GIF processing done */\n#define\tPACKET_TAG_GRE\t\t\t\t9  /* GRE processing done */\n#define\tPACKET_TAG_IN_PACKET_CHECKSUM\t\t10 /* NIC checksumming done */\n#define\tPACKET_TAG_ENCAP\t\t\t11 /* Encap.  processing */\n#define\tPACKET_TAG_IPSEC_SOCKET\t\t\t12 /* IPSEC socket ref */\n#define\tPACKET_TAG_IPSEC_HISTORY\t\t13 /* IPSEC history */\n#define\tPACKET_TAG_IPV6_INPUT\t\t\t14 /* IPV6 input processing */\n#define\tPACKET_TAG_DUMMYNET\t\t\t15 /* dummynet info */\n#define\tPACKET_TAG_DIVERT\t\t\t17 /* divert info */\n#define\tPACKET_TAG_IPFORWARD\t\t\t18 /* ipforward info */\n#define\tPACKET_TAG_MACLABEL\t(19 | MTAG_PERSISTENT) /* MAC label */\n#define\tPACKET_TAG_PF\t\t\t\t21 /* PF + ALTQ information */\n#define\tPACKET_TAG_RTSOCKFAM\t\t\t25 /* rtsock sa family */\n#define\tPACKET_TAG_IPOPTIONS\t\t\t27 /* Saved IP options */\n#define\tPACKET_TAG_CARP                         28 /* CARP info */\n\n#endif /* !_SYS_MBUF_H_ */\n"
  },
  {
    "path": "sys/sys/module.h",
    "content": "/*\n * trivial module support\n */\n#ifndef _SYS_MODULE_H_\n#define _SYS_MODULE_H_\ntypedef struct module *module_t;\ntypedef int (*modeventhand_t)(module_t, int /* modeventtype_t */, void *);\n \ntypedef enum modeventtype {\n        MOD_LOAD,\n        MOD_UNLOAD,\n        MOD_SHUTDOWN,\n        MOD_QUIESCE\n} modeventtype_t;\n \ntypedef struct moduledata {\n        const char      *name;          /* module name */\n        modeventhand_t  evhand;         /* event handler */\n        void            *priv;          /* extra data */\n} moduledata_t;\n\n/*\n * Hook the module descriptor, md, into our list of things to do.\n * We should in principle respect the order of loading.\n *\n * XXX use the gcc .init functions\n */\n#define DECLARE_MODULE(a, md, c,d)\t\t\t\t\\\n    moduledata_t *moddesc_##a = &md;\n\n/*\n * XXX MODULE_VERSION is define in linux too\n */\n#define MODULE_DEPEND(a,b,c,d,e)\n#if defined( __linux__ ) || defined( _WIN32 )\n#undef MODULE_VERSION\n#define MODULE_VERSION(a,b)\n#endif\n\n#endif\t/* _SYS_MODULE_H_ */\n\n"
  },
  {
    "path": "sys/sys/param.h",
    "content": "#ifndef _SYS_PARAM_H_\n#define _SYS_PARAM_H_\n\n/*\n * number of additional groups\n */\n#ifndef LINUX_24\n#define NGROUPS\t\t16\n#endif\n\n#endif /* _SYS_PARAM_H_ */\n"
  },
  {
    "path": "sys/sys/queue.h",
    "content": "/*-\n * Copyright (c) 1991, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)queue.h\t8.5 (Berkeley) 8/20/94\n * $FreeBSD: src/sys/sys/queue.h,v 1.68 2006/10/24 11:20:29 ru Exp $\n */\n\n#ifndef _SYS_QUEUE_H_\n#define\t_SYS_QUEUE_H_\n\n//#include <sys/cdefs.h>\n\n/*\n * This file defines four types of data structures: singly-linked lists,\n * singly-linked tail queues, lists and tail queues.\n *\n * A singly-linked list is headed by a single forward pointer. The elements\n * are singly linked for minimum space and pointer manipulation overhead at\n * the expense of O(n) removal for arbitrary elements. New elements can be\n * added to the list after an existing element or at the head of the list.\n * Elements being removed from the head of the list should use the explicit\n * macro for this purpose for optimum efficiency. A singly-linked list may\n * only be traversed in the forward direction.  Singly-linked lists are ideal\n * for applications with large datasets and few or no removals or for\n * implementing a LIFO queue.\n *\n * A singly-linked tail queue is headed by a pair of pointers, one to the\n * head of the list and the other to the tail of the list. The elements are\n * singly linked for minimum space and pointer manipulation overhead at the\n * expense of O(n) removal for arbitrary elements. New elements can be added\n * to the list after an existing element, at the head of the list, or at the\n * end of the list. Elements being removed from the head of the tail queue\n * should use the explicit macro for this purpose for optimum efficiency.\n * A singly-linked tail queue may only be traversed in the forward direction.\n * Singly-linked tail queues are ideal for applications with large datasets\n * and few or no removals or for implementing a FIFO queue.\n *\n * A list is headed by a single forward pointer (or an array of forward\n * pointers for a hash table header). The elements are doubly linked\n * so that an arbitrary element can be removed without a need to\n * traverse the list. New elements can be added to the list before\n * or after an existing element or at the head of the list. A list\n * may only be traversed in the forward direction.\n *\n * A tail queue is headed by a pair of pointers, one to the head of the\n * list and the other to the tail of the list. The elements are doubly\n * linked so that an arbitrary element can be removed without a need to\n * traverse the list. New elements can be added to the list before or\n * after an existing element, at the head of the list, or at the end of\n * the list. A tail queue may be traversed in either direction.\n *\n * For details on the use of these macros, see the queue(3) manual page.\n *\n *\n *\t\t\t\tSLIST\tLIST\tSTAILQ\tTAILQ\n * _HEAD\t\t\t+\t+\t+\t+\n * _HEAD_INITIALIZER\t\t+\t+\t+\t+\n * _ENTRY\t\t\t+\t+\t+\t+\n * _INIT\t\t\t+\t+\t+\t+\n * _EMPTY\t\t\t+\t+\t+\t+\n * _FIRST\t\t\t+\t+\t+\t+\n * _NEXT\t\t\t+\t+\t+\t+\n * _PREV\t\t\t-\t-\t-\t+\n * _LAST\t\t\t-\t-\t+\t+\n * _FOREACH\t\t\t+\t+\t+\t+\n * _FOREACH_SAFE\t\t+\t+\t+\t+\n * _FOREACH_REVERSE\t\t-\t-\t-\t+\n * _FOREACH_REVERSE_SAFE\t-\t-\t-\t+\n * _INSERT_HEAD\t\t\t+\t+\t+\t+\n * _INSERT_BEFORE\t\t-\t+\t-\t+\n * _INSERT_AFTER\t\t+\t+\t+\t+\n * _INSERT_TAIL\t\t\t-\t-\t+\t+\n * _CONCAT\t\t\t-\t-\t+\t+\n * _REMOVE_HEAD\t\t\t+\t-\t+\t-\n * _REMOVE\t\t\t+\t+\t+\t+\n *\n */\n#ifdef QUEUE_MACRO_DEBUG\n/* Store the last 2 places the queue element or head was altered */\nstruct qm_trace {\n\tchar * lastfile;\n\tint lastline;\n\tchar * prevfile;\n\tint prevline;\n};\n\n#define\tTRACEBUF\tstruct qm_trace trace;\n#define\tTRASHIT(x)\tdo {(x) = (void *)-1;} while (0)\n\n#define\tQMD_TRACE_HEAD(head) do {\t\t\t\t\t\\\n\t(head)->trace.prevline = (head)->trace.lastline;\t\t\\\n\t(head)->trace.prevfile = (head)->trace.lastfile;\t\t\\\n\t(head)->trace.lastline = __LINE__;\t\t\t\t\\\n\t(head)->trace.lastfile = __FILE__;\t\t\t\t\\\n} while (0)\n\n#define\tQMD_TRACE_ELEM(elem) do {\t\t\t\t\t\\\n\t(elem)->trace.prevline = (elem)->trace.lastline;\t\t\\\n\t(elem)->trace.prevfile = (elem)->trace.lastfile;\t\t\\\n\t(elem)->trace.lastline = __LINE__;\t\t\t\t\\\n\t(elem)->trace.lastfile = __FILE__;\t\t\t\t\\\n} while (0)\n\n#else\n#define\tQMD_TRACE_ELEM(elem)\n#define\tQMD_TRACE_HEAD(head)\n#define\tTRACEBUF\n#define\tTRASHIT(x)\n#endif\t/* QUEUE_MACRO_DEBUG */\n\n/*\n * Singly-linked List declarations.\n */\n#define\tSLIST_HEAD(name, type)\t\t\t\t\t\t\\\nstruct name {\t\t\t\t\t\t\t\t\\\n\tstruct type *slh_first;\t/* first element */\t\t\t\\\n}\n\n#define\tSLIST_HEAD_INITIALIZER(head)\t\t\t\t\t\\\n\t{ NULL }\n\n#if defined( _WIN32 ) && defined(SLIST_ENTRY)\n#undef SLIST_ENTRY\n#endif\n#define\tSLIST_ENTRY(type)\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\tstruct type *sle_next;\t/* next element */\t\t\t\\\n}\n\n/*\n * Singly-linked List functions.\n */\n#define\tSLIST_EMPTY(head)\t((head)->slh_first == NULL)\n\n#define\tSLIST_FIRST(head)\t((head)->slh_first)\n\n#define\tSLIST_FOREACH(var, head, field)\t\t\t\t\t\\\n\tfor ((var) = SLIST_FIRST((head));\t\t\t\t\\\n\t    (var);\t\t\t\t\t\t\t\\\n\t    (var) = SLIST_NEXT((var), field))\n\n#define\tSLIST_FOREACH_SAFE(var, head, field, tvar)\t\t\t\\\n\tfor ((var) = SLIST_FIRST((head));\t\t\t\t\\\n\t    (var) && ((tvar) = SLIST_NEXT((var), field), 1);\t\t\\\n\t    (var) = (tvar))\n\n#define\tSLIST_FOREACH_PREVPTR(var, varp, head, field)\t\t\t\\\n\tfor ((varp) = &SLIST_FIRST((head));\t\t\t\t\\\n\t    ((var) = *(varp)) != NULL;\t\t\t\t\t\\\n\t    (varp) = &SLIST_NEXT((var), field))\n\n#define\tSLIST_INIT(head) do {\t\t\t\t\t\t\\\n\tSLIST_FIRST((head)) = NULL;\t\t\t\t\t\\\n} while (0)\n\n#define\tSLIST_INSERT_AFTER(slistelm, elm, field) do {\t\t\t\\\n\tSLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);\t\\\n\tSLIST_NEXT((slistelm), field) = (elm);\t\t\t\t\\\n} while (0)\n\n#define\tSLIST_INSERT_HEAD(head, elm, field) do {\t\t\t\\\n\tSLIST_NEXT((elm), field) = SLIST_FIRST((head));\t\t\t\\\n\tSLIST_FIRST((head)) = (elm);\t\t\t\t\t\\\n} while (0)\n\n#define\tSLIST_NEXT(elm, field)\t((elm)->field.sle_next)\n\n#define\tSLIST_REMOVE(head, elm, type, field) do {\t\t\t\\\n\tif (SLIST_FIRST((head)) == (elm)) {\t\t\t\t\\\n\t\tSLIST_REMOVE_HEAD((head), field);\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\telse {\t\t\t\t\t\t\t\t\\\n\t\tstruct type *curelm = SLIST_FIRST((head));\t\t\\\n\t\twhile (SLIST_NEXT(curelm, field) != (elm))\t\t\\\n\t\t\tcurelm = SLIST_NEXT(curelm, field);\t\t\\\n\t\tSLIST_NEXT(curelm, field) =\t\t\t\t\\\n\t\t    SLIST_NEXT(SLIST_NEXT(curelm, field), field);\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tTRASHIT((elm)->field.sle_next);\t\t\t\t\t\\\n} while (0)\n\n#define\tSLIST_REMOVE_HEAD(head, field) do {\t\t\t\t\\\n\tSLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);\t\\\n} while (0)\n\n/*\n * Singly-linked Tail queue declarations.\n */\n#define\tSTAILQ_HEAD(name, type)\t\t\t\t\t\t\\\nstruct name {\t\t\t\t\t\t\t\t\\\n\tstruct type *stqh_first;/* first element */\t\t\t\\\n\tstruct type **stqh_last;/* addr of last next element */\t\t\\\n}\n\n#define\tSTAILQ_HEAD_INITIALIZER(head)\t\t\t\t\t\\\n\t{ NULL, &(head).stqh_first }\n\n#define\tSTAILQ_ENTRY(type)\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\tstruct type *stqe_next;\t/* next element */\t\t\t\\\n}\n\n/*\n * Singly-linked Tail queue functions.\n */\n#define\tSTAILQ_CONCAT(head1, head2) do {\t\t\t\t\\\n\tif (!STAILQ_EMPTY((head2))) {\t\t\t\t\t\\\n\t\t*(head1)->stqh_last = (head2)->stqh_first;\t\t\\\n\t\t(head1)->stqh_last = (head2)->stqh_last;\t\t\\\n\t\tSTAILQ_INIT((head2));\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n} while (0)\n\n#define\tSTAILQ_EMPTY(head)\t((head)->stqh_first == NULL)\n\n#define\tSTAILQ_FIRST(head)\t((head)->stqh_first)\n\n#define\tSTAILQ_FOREACH(var, head, field)\t\t\t\t\\\n\tfor((var) = STAILQ_FIRST((head));\t\t\t\t\\\n\t   (var);\t\t\t\t\t\t\t\\\n\t   (var) = STAILQ_NEXT((var), field))\n\n\n#define\tSTAILQ_FOREACH_SAFE(var, head, field, tvar)\t\t\t\\\n\tfor ((var) = STAILQ_FIRST((head));\t\t\t\t\\\n\t    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);\t\t\\\n\t    (var) = (tvar))\n\n#define\tSTAILQ_INIT(head) do {\t\t\t\t\t\t\\\n\tSTAILQ_FIRST((head)) = NULL;\t\t\t\t\t\\\n\t(head)->stqh_last = &STAILQ_FIRST((head));\t\t\t\\\n} while (0)\n\n#define\tSTAILQ_INSERT_AFTER(head, tqelm, elm, field) do {\t\t\\\n\tif ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\\\n\t\t(head)->stqh_last = &STAILQ_NEXT((elm), field);\t\t\\\n\tSTAILQ_NEXT((tqelm), field) = (elm);\t\t\t\t\\\n} while (0)\n\n#define\tSTAILQ_INSERT_HEAD(head, elm, field) do {\t\t\t\\\n\tif ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)\t\\\n\t\t(head)->stqh_last = &STAILQ_NEXT((elm), field);\t\t\\\n\tSTAILQ_FIRST((head)) = (elm);\t\t\t\t\t\\\n} while (0)\n\n#define\tSTAILQ_INSERT_TAIL(head, elm, field) do {\t\t\t\\\n\tSTAILQ_NEXT((elm), field) = NULL;\t\t\t\t\\\n\t*(head)->stqh_last = (elm);\t\t\t\t\t\\\n\t(head)->stqh_last = &STAILQ_NEXT((elm), field);\t\t\t\\\n} while (0)\n\n#define\tSTAILQ_LAST(head, type, field)\t\t\t\t\t\\\n\t(STAILQ_EMPTY((head)) ?\t\t\t\t\t\t\\\n\t\tNULL :\t\t\t\t\t\t\t\\\n\t        ((struct type *)(void *)\t\t\t\t\\\n\t\t((char *)((head)->stqh_last) - __offsetof(struct type, field))))\n\n#define\tSTAILQ_NEXT(elm, field)\t((elm)->field.stqe_next)\n\n#define\tSTAILQ_REMOVE(head, elm, type, field) do {\t\t\t\\\n\tif (STAILQ_FIRST((head)) == (elm)) {\t\t\t\t\\\n\t\tSTAILQ_REMOVE_HEAD((head), field);\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\telse {\t\t\t\t\t\t\t\t\\\n\t\tstruct type *curelm = STAILQ_FIRST((head));\t\t\\\n\t\twhile (STAILQ_NEXT(curelm, field) != (elm))\t\t\\\n\t\t\tcurelm = STAILQ_NEXT(curelm, field);\t\t\\\n\t\tif ((STAILQ_NEXT(curelm, field) =\t\t\t\\\n\t\t     STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\\\n\t\t\t(head)->stqh_last = &STAILQ_NEXT((curelm), field);\\\n\t}\t\t\t\t\t\t\t\t\\\n\tTRASHIT((elm)->field.stqe_next);\t\t\t\t\\\n} while (0)\n\n#define\tSTAILQ_REMOVE_HEAD(head, field) do {\t\t\t\t\\\n\tif ((STAILQ_FIRST((head)) =\t\t\t\t\t\\\n\t     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)\t\t\\\n\t\t(head)->stqh_last = &STAILQ_FIRST((head));\t\t\\\n} while (0)\n\n#ifndef LIST_HEAD\n/*\n * List declarations.\n */\n#define\tLIST_HEAD(name, type)\t\t\t\t\t\t\\\nstruct name {\t\t\t\t\t\t\t\t\\\n\tstruct type *lh_first;\t/* first element */\t\t\t\\\n}\n\n#define\tLIST_HEAD_INITIALIZER(head)\t\t\t\t\t\\\n\t{ NULL }\n\n#define\tLIST_ENTRY(type)\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\tstruct type *le_next;\t/* next element */\t\t\t\\\n\tstruct type **le_prev;\t/* address of previous next element */\t\\\n}\n\n/*\n * List functions.\n */\n\n#if (defined(_KERNEL) && defined(INVARIANTS))\n#define\tQMD_LIST_CHECK_HEAD(head, field) do {\t\t\t\t\\\n\tif (LIST_FIRST((head)) != NULL &&\t\t\t\t\\\n\t    LIST_FIRST((head))->field.le_prev !=\t\t\t\\\n\t     &LIST_FIRST((head)))\t\t\t\t\t\\\n\t\tpanic(\"Bad list head %p first->prev != head\", (head));\t\\\n} while (0)\n\n#define\tQMD_LIST_CHECK_NEXT(elm, field) do {\t\t\t\t\\\n\tif (LIST_NEXT((elm), field) != NULL &&\t\t\t\t\\\n\t    LIST_NEXT((elm), field)->field.le_prev !=\t\t\t\\\n\t     &((elm)->field.le_next))\t\t\t\t\t\\\n\t     \tpanic(\"Bad link elm %p next->prev != elm\", (elm));\t\\\n} while (0)\n\n#define\tQMD_LIST_CHECK_PREV(elm, field) do {\t\t\t\t\\\n\tif (*(elm)->field.le_prev != (elm))\t\t\t\t\\\n\t\tpanic(\"Bad link elm %p prev->next != elm\", (elm));\t\\\n} while (0)\n#else\n#define\tQMD_LIST_CHECK_HEAD(head, field)\n#define\tQMD_LIST_CHECK_NEXT(elm, field)\n#define\tQMD_LIST_CHECK_PREV(elm, field)\n#endif /* (_KERNEL && INVARIANTS) */\n\n#define\tLIST_EMPTY(head)\t((head)->lh_first == NULL)\n\n#define\tLIST_FIRST(head)\t((head)->lh_first)\n\n#define\tLIST_FOREACH(var, head, field)\t\t\t\t\t\\\n\tfor ((var) = LIST_FIRST((head));\t\t\t\t\\\n\t    (var);\t\t\t\t\t\t\t\\\n\t    (var) = LIST_NEXT((var), field))\n\n#define\tLIST_FOREACH_SAFE(var, head, field, tvar)\t\t\t\\\n\tfor ((var) = LIST_FIRST((head));\t\t\t\t\\\n\t    (var) && ((tvar) = LIST_NEXT((var), field), 1);\t\t\\\n\t    (var) = (tvar))\n\n#define\tLIST_INIT(head) do {\t\t\t\t\t\t\\\n\tLIST_FIRST((head)) = NULL;\t\t\t\t\t\\\n} while (0)\n\n#define\tLIST_INSERT_AFTER(listelm, elm, field) do {\t\t\t\\\n\tQMD_LIST_CHECK_NEXT(listelm, field);\t\t\t\t\\\n\tif ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\\\n\t\tLIST_NEXT((listelm), field)->field.le_prev =\t\t\\\n\t\t    &LIST_NEXT((elm), field);\t\t\t\t\\\n\tLIST_NEXT((listelm), field) = (elm);\t\t\t\t\\\n\t(elm)->field.le_prev = &LIST_NEXT((listelm), field);\t\t\\\n} while (0)\n\n#define\tLIST_INSERT_BEFORE(listelm, elm, field) do {\t\t\t\\\n\tQMD_LIST_CHECK_PREV(listelm, field);\t\t\t\t\\\n\t(elm)->field.le_prev = (listelm)->field.le_prev;\t\t\\\n\tLIST_NEXT((elm), field) = (listelm);\t\t\t\t\\\n\t*(listelm)->field.le_prev = (elm);\t\t\t\t\\\n\t(listelm)->field.le_prev = &LIST_NEXT((elm), field);\t\t\\\n} while (0)\n\n#define\tLIST_INSERT_HEAD(head, elm, field) do {\t\t\t\t\\\n\tQMD_LIST_CHECK_HEAD((head), field);\t\t\t\t\\\n\tif ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)\t\\\n\t\tLIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\\\n\tLIST_FIRST((head)) = (elm);\t\t\t\t\t\\\n\t(elm)->field.le_prev = &LIST_FIRST((head));\t\t\t\\\n} while (0)\n\n#define\tLIST_NEXT(elm, field)\t((elm)->field.le_next)\n\n#define\tLIST_REMOVE(elm, field) do {\t\t\t\t\t\\\n\tQMD_LIST_CHECK_NEXT(elm, field);\t\t\t\t\\\n\tQMD_LIST_CHECK_PREV(elm, field);\t\t\t\t\\\n\tif (LIST_NEXT((elm), field) != NULL)\t\t\t\t\\\n\t\tLIST_NEXT((elm), field)->field.le_prev = \t\t\\\n\t\t    (elm)->field.le_prev;\t\t\t\t\\\n\t*(elm)->field.le_prev = LIST_NEXT((elm), field);\t\t\\\n\tTRASHIT((elm)->field.le_next);\t\t\t\t\t\\\n\tTRASHIT((elm)->field.le_prev);\t\t\t\t\t\\\n} while (0)\n#endif /* LIST_HEAD */\n\n/*\n * Tail queue declarations.\n */\n#define\tTAILQ_HEAD(name, type)\t\t\t\t\t\t\\\nstruct name {\t\t\t\t\t\t\t\t\\\n\tstruct type *tqh_first;\t/* first element */\t\t\t\\\n\tstruct type **tqh_last;\t/* addr of last next element */\t\t\\\n\tTRACEBUF\t\t\t\t\t\t\t\\\n}\n\n#define\tTAILQ_HEAD_INITIALIZER(head)\t\t\t\t\t\\\n\t{ NULL, &(head).tqh_first }\n\n#define\tTAILQ_ENTRY(type)\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\tstruct type *tqe_next;\t/* next element */\t\t\t\\\n\tstruct type **tqe_prev;\t/* address of previous next element */\t\\\n\tTRACEBUF\t\t\t\t\t\t\t\\\n}\n\n/*\n * Tail queue functions.\n */\n#if (defined(_KERNEL) && defined(INVARIANTS))\n#define\tQMD_TAILQ_CHECK_HEAD(head, field) do {\t\t\t\t\\\n\tif (!TAILQ_EMPTY(head) &&\t\t\t\t\t\\\n\t    TAILQ_FIRST((head))->field.tqe_prev !=\t\t\t\\\n\t     &TAILQ_FIRST((head)))\t\t\t\t\t\\\n\t\tpanic(\"Bad tailq head %p first->prev != head\", (head));\t\\\n} while (0)\n\n#define\tQMD_TAILQ_CHECK_TAIL(head, field) do {\t\t\t\t\\\n\tif (*(head)->tqh_last != NULL)\t\t\t\t\t\\\n\t    \tpanic(\"Bad tailq NEXT(%p->tqh_last) != NULL\", (head)); \t\\\n} while (0)\n\n#define\tQMD_TAILQ_CHECK_NEXT(elm, field) do {\t\t\t\t\\\n\tif (TAILQ_NEXT((elm), field) != NULL &&\t\t\t\t\\\n\t    TAILQ_NEXT((elm), field)->field.tqe_prev !=\t\t\t\\\n\t     &((elm)->field.tqe_next))\t\t\t\t\t\\\n\t\tpanic(\"Bad link elm %p next->prev != elm\", (elm));\t\\\n} while (0)\n\n#define\tQMD_TAILQ_CHECK_PREV(elm, field) do {\t\t\t\t\\\n\tif (*(elm)->field.tqe_prev != (elm))\t\t\t\t\\\n\t\tpanic(\"Bad link elm %p prev->next != elm\", (elm));\t\\\n} while (0)\n#else\n#define\tQMD_TAILQ_CHECK_HEAD(head, field)\n#define\tQMD_TAILQ_CHECK_TAIL(head, headname)\n#define\tQMD_TAILQ_CHECK_NEXT(elm, field)\n#define\tQMD_TAILQ_CHECK_PREV(elm, field)\n#endif /* (_KERNEL && INVARIANTS) */\n\n#define\tTAILQ_CONCAT(head1, head2, field) do {\t\t\t\t\\\n\tif (!TAILQ_EMPTY(head2)) {\t\t\t\t\t\\\n\t\t*(head1)->tqh_last = (head2)->tqh_first;\t\t\\\n\t\t(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;\t\\\n\t\t(head1)->tqh_last = (head2)->tqh_last;\t\t\t\\\n\t\tTAILQ_INIT((head2));\t\t\t\t\t\\\n\t\tQMD_TRACE_HEAD(head1);\t\t\t\t\t\\\n\t\tQMD_TRACE_HEAD(head2);\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n} while (0)\n\n#define\tTAILQ_EMPTY(head)\t((head)->tqh_first == NULL)\n\n#define\tTAILQ_FIRST(head)\t((head)->tqh_first)\n\n#define\tTAILQ_FOREACH(var, head, field)\t\t\t\t\t\\\n\tfor ((var) = TAILQ_FIRST((head));\t\t\t\t\\\n\t    (var);\t\t\t\t\t\t\t\\\n\t    (var) = TAILQ_NEXT((var), field))\n\n#define\tTAILQ_FOREACH_SAFE(var, head, field, tvar)\t\t\t\\\n\tfor ((var) = TAILQ_FIRST((head));\t\t\t\t\\\n\t    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);\t\t\\\n\t    (var) = (tvar))\n\n#define\tTAILQ_FOREACH_REVERSE(var, head, headname, field)\t\t\\\n\tfor ((var) = TAILQ_LAST((head), headname);\t\t\t\\\n\t    (var);\t\t\t\t\t\t\t\\\n\t    (var) = TAILQ_PREV((var), headname, field))\n\n#define\tTAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)\t\\\n\tfor ((var) = TAILQ_LAST((head), headname);\t\t\t\\\n\t    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);\t\\\n\t    (var) = (tvar))\n\n#define\tTAILQ_INIT(head) do {\t\t\t\t\t\t\\\n\tTAILQ_FIRST((head)) = NULL;\t\t\t\t\t\\\n\t(head)->tqh_last = &TAILQ_FIRST((head));\t\t\t\\\n\tQMD_TRACE_HEAD(head);\t\t\t\t\t\t\\\n} while (0)\n\n#define\tTAILQ_INSERT_AFTER(head, listelm, elm, field) do {\t\t\\\n\tQMD_TAILQ_CHECK_NEXT(listelm, field);\t\t\t\t\\\n\tif ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\\\n\t\tTAILQ_NEXT((elm), field)->field.tqe_prev = \t\t\\\n\t\t    &TAILQ_NEXT((elm), field);\t\t\t\t\\\n\telse {\t\t\t\t\t\t\t\t\\\n\t\t(head)->tqh_last = &TAILQ_NEXT((elm), field);\t\t\\\n\t\tQMD_TRACE_HEAD(head);\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tTAILQ_NEXT((listelm), field) = (elm);\t\t\t\t\\\n\t(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);\t\t\\\n\tQMD_TRACE_ELEM(&(elm)->field);\t\t\t\t\t\\\n\tQMD_TRACE_ELEM(&listelm->field);\t\t\t\t\\\n} while (0)\n\n#define\tTAILQ_INSERT_BEFORE(listelm, elm, field) do {\t\t\t\\\n\tQMD_TAILQ_CHECK_PREV(listelm, field);\t\t\t\t\\\n\t(elm)->field.tqe_prev = (listelm)->field.tqe_prev;\t\t\\\n\tTAILQ_NEXT((elm), field) = (listelm);\t\t\t\t\\\n\t*(listelm)->field.tqe_prev = (elm);\t\t\t\t\\\n\t(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);\t\t\\\n\tQMD_TRACE_ELEM(&(elm)->field);\t\t\t\t\t\\\n\tQMD_TRACE_ELEM(&listelm->field);\t\t\t\t\\\n} while (0)\n\n#define\tTAILQ_INSERT_HEAD(head, elm, field) do {\t\t\t\\\n\tQMD_TAILQ_CHECK_HEAD(head, field);\t\t\t\t\\\n\tif ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)\t\\\n\t\tTAILQ_FIRST((head))->field.tqe_prev =\t\t\t\\\n\t\t    &TAILQ_NEXT((elm), field);\t\t\t\t\\\n\telse\t\t\t\t\t\t\t\t\\\n\t\t(head)->tqh_last = &TAILQ_NEXT((elm), field);\t\t\\\n\tTAILQ_FIRST((head)) = (elm);\t\t\t\t\t\\\n\t(elm)->field.tqe_prev = &TAILQ_FIRST((head));\t\t\t\\\n\tQMD_TRACE_HEAD(head);\t\t\t\t\t\t\\\n\tQMD_TRACE_ELEM(&(elm)->field);\t\t\t\t\t\\\n} while (0)\n\n#define\tTAILQ_INSERT_TAIL(head, elm, field) do {\t\t\t\\\n\tQMD_TAILQ_CHECK_TAIL(head, field);\t\t\t\t\\\n\tTAILQ_NEXT((elm), field) = NULL;\t\t\t\t\\\n\t(elm)->field.tqe_prev = (head)->tqh_last;\t\t\t\\\n\t*(head)->tqh_last = (elm);\t\t\t\t\t\\\n\t(head)->tqh_last = &TAILQ_NEXT((elm), field);\t\t\t\\\n\tQMD_TRACE_HEAD(head);\t\t\t\t\t\t\\\n\tQMD_TRACE_ELEM(&(elm)->field);\t\t\t\t\t\\\n} while (0)\n\n#define\tTAILQ_LAST(head, headname)\t\t\t\t\t\\\n\t(*(((struct headname *)((head)->tqh_last))->tqh_last))\n\n#define\tTAILQ_NEXT(elm, field) ((elm)->field.tqe_next)\n\n#define\tTAILQ_PREV(elm, headname, field)\t\t\t\t\\\n\t(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))\n\n#define\tTAILQ_REMOVE(head, elm, field) do {\t\t\t\t\\\n\tQMD_TAILQ_CHECK_NEXT(elm, field);\t\t\t\t\\\n\tQMD_TAILQ_CHECK_PREV(elm, field);\t\t\t\t\\\n\tif ((TAILQ_NEXT((elm), field)) != NULL)\t\t\t\t\\\n\t\tTAILQ_NEXT((elm), field)->field.tqe_prev = \t\t\\\n\t\t    (elm)->field.tqe_prev;\t\t\t\t\\\n\telse {\t\t\t\t\t\t\t\t\\\n\t\t(head)->tqh_last = (elm)->field.tqe_prev;\t\t\\\n\t\tQMD_TRACE_HEAD(head);\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\t*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);\t\t\\\n\tTRASHIT((elm)->field.tqe_next);\t\t\t\t\t\\\n\tTRASHIT((elm)->field.tqe_prev);\t\t\t\t\t\\\n\tQMD_TRACE_ELEM(&(elm)->field);\t\t\t\t\t\\\n} while (0)\n\n\n#ifdef _KERNEL\n\n/*\n * XXX insque() and remque() are an old way of handling certain queues.\n * They bogusly assumes that all queue heads look alike.\n */\n\nstruct quehead {\n\tstruct quehead *qh_link;\n\tstruct quehead *qh_rlink;\n};\n\n#ifdef __CC_SUPPORTS___INLINE\n\nstatic __inline void\ninsque(void *a, void *b)\n{\n\tstruct quehead *element = (struct quehead *)a,\n\t\t *head = (struct quehead *)b;\n\n\telement->qh_link = head->qh_link;\n\telement->qh_rlink = head;\n\thead->qh_link = element;\n\telement->qh_link->qh_rlink = element;\n}\n\nstatic __inline void\nremque(void *a)\n{\n\tstruct quehead *element = (struct quehead *)a;\n\n\telement->qh_link->qh_rlink = element->qh_rlink;\n\telement->qh_rlink->qh_link = element->qh_link;\n\telement->qh_rlink = 0;\n}\n\n#else /* !__CC_SUPPORTS___INLINE */\n\nvoid\tinsque(void *a, void *b);\nvoid\tremque(void *a);\n\n#endif /* __CC_SUPPORTS___INLINE */\n\n#endif /* _KERNEL */\n\n#endif /* !_SYS_QUEUE_H_ */\n"
  },
  {
    "path": "sys/sys/syslog.h",
    "content": "#ifndef _SYS_SYSLOG_H_\n#define _SYS_SYSLOG_H_\n/* XXX find linux equivalent */\n#define LOG_SECURITY 0\n#define LOG_NOTICE 0\n#define LOG_DEBUG 0\n#endif /* _SYS_SYSLOG_H_ */\n"
  },
  {
    "path": "sys/sys/systm.h",
    "content": "#ifndef _SYS_SYSTM_H_\n#define _SYS_SYSTM_H_\n\n#define CALLOUT_ACTIVE          0x0002 /* callout is currently active */\n#define CALLOUT_MPSAFE          0x0008 /* callout handler is mp safe */\n\n#ifndef _WIN32\t/* this is the linux version */\n/* callout support, in <sys/callout.h> on FreeBSD */\n/*\n * callout support on linux module is done using timers\n */\n#include <linux/timer.h>\n#ifdef LINUX_24\n#include <linux/sched.h>        /* jiffies definition is here in 2.4 */\n#endif\n#define callout timer_list\nstatic __inline int\ncallout_reset_on(struct callout *co, int ticks, void (*fn)(void *), void *arg, int cpu)\n{\n        co->expires = jiffies + ticks;\n        co->function = (void (*)(unsigned long))fn;\n        co->data = (unsigned long)arg;\n\t/*\n\t * Linux 2.6.31 and above has add_timer_on(co, cpu),\n\t * otherwise add_timer() always schedules a callout on the same\n\t * CPU used the first time, so we don't need more.\n\t */\n        add_timer(co);\n        return 0;\n}\n\n#define callout_init(co, safe)  init_timer(co)\n#define callout_drain(co)       del_timer(co)\n#define callout_stop(co)        del_timer(co)\n\n#else /* _WIN32 */\n#include <ndis.h>\n\n/* This is the windows part for callout support */\nstruct callout {\n\tKTIMER thetimer;\n\tKDPC timerdpc;\n\tint dpcinitialized;\n\tLARGE_INTEGER duetime;\n};\n\nvoid dummynet (void*);\nVOID dummynet_dpc(\n    __in struct _KDPC  *Dpc,\n    __in_opt PVOID  DeferredContext,\n    __in_opt PVOID  SystemArgument1,\n    __in_opt PVOID  SystemArgument2\n    );\n\nVOID ipfw_dpc(\n    __in struct _KDPC  *Dpc,\n    __in_opt PVOID  DeferredContext,\n    __in_opt PVOID  SystemArgument1,\n    __in_opt PVOID  SystemArgument2\n    );\n\n/* callout_reset must handle two problems:\n * - dummynet() scheduler must be run always on the same processor\n * because do_gettimeofday() is based on cpu performance counter, and\n * _occasionally_ can leap backward in time if we query another cpu.\n * typically this won't happen that much, and the cpu will almost always\n * be the same even without the affinity restriction, but better to be sure.\n * - ipfw_tick() does not have the granularity requirements of dummynet()\n * but we need to pass a pointer as argument.\n *\n * for these reasons, if we are called for dummynet() timer,\n * KeInitializeDpc is called only once as it should be, and the thread\n * is forced on cpu0 (which is always present), while if we're called\n * for ipfw_tick(), we re-initialize the DPC each time, using\n * parameter DeferredContext to pass the needed pointer. since this\n * timer is called only once a sec, this won't hurt that much.\n */\nstatic __inline int\ncallout_reset_on(struct callout *co, int ticks, void (*fn)(void *), void *arg, int cpu) \n{\n\tif(fn == &dummynet)\n\t{\n\t\tif(co->dpcinitialized == 0)\n\t\t{\n\t\t\tKeInitializeDpc(&co->timerdpc, dummynet_dpc, NULL);\n\t\t\tKeSetTargetProcessorDpc(&co->timerdpc, cpu);\n\t\t\tco->dpcinitialized = 1;\n\t\t}\n\t}\n\telse\n\t{\n\t\tKeInitializeDpc(&co->timerdpc, ipfw_dpc, arg);\n\t}\n\tco->duetime.QuadPart = (-ticks)*10000;\n\tKeSetTimer(&co->thetimer, co->duetime, &co->timerdpc);\n\treturn 0;\n}\n\nstatic __inline void\ncallout_init(struct callout* co, int safe)\n{\n\tprintf(\"%s: initializing timer at %p\\n\",__FUNCTION__,co);\n\tKeInitializeTimer(&co->thetimer);\n}\n\nstatic __inline int\ncallout_drain(struct callout* co)\n{\n\tBOOLEAN canceled = KeCancelTimer(&co->thetimer);\n\twhile (canceled != TRUE)\n\t{\n\t\tcanceled = KeCancelTimer(&co->thetimer);\n\t}\n\tprintf(\"%s: stopping timer at %p\\n\",__FUNCTION__,co);\n\treturn 0;\n}\n\nstatic __inline int\ncallout_stop(struct callout* co)\n{\n\treturn callout_drain(co);\n}\n\n#endif /* _WIN32 */\n\n#endif /* _SYS_SYSTM_H_ */\n"
  },
  {
    "path": "sys/sys/taskqueue.h",
    "content": "#ifndef _SYS_TASKQUEUE_H_\n#define _SYS_TASKQUEUE_H_\n\n/*\n * Remap taskqueue to direct calls\n */\n\n#ifdef _WIN32\nstruct task {\n\tvoid (*func)(void*, int);\n};\n#define taskqueue_enqueue(tq, ta)\t(ta)->func(NULL,1)\n#define TASK_INIT(a,b,c,d) do { \t\t\t\t\\\n\t(a)->func = (c); } while (0)\n#else\nstruct task {\n\tvoid (*func)(void);\n};\n#define taskqueue_enqueue(tq, ta)\t(ta)->func()\n#define TASK_INIT(a,b,c,d) do { \t\t\t\t\\\n\t(a)->func = (void (*)(void))c; } while (0)\n\n#endif\n#define taskqueue_create_fast(_a, _b, _c, _d)\tNULL\n#define taskqueue_start_threads(_a, _b, _c, _d)\n\n#define\ttaskqueue_drain(_a, _b)\t/* XXX to be completed */\n#define\ttaskqueue_free(_a)\t/* XXX to be completed */\n\n#define PRI_MIN                 (0)             /* Highest priority. */\n#define PRI_MIN_ITHD            (PRI_MIN)\n#define PI_NET                  (PRI_MIN_ITHD + 16)\n\n#endif /* !_SYS_TASKQUEUE_H_ */\n"
  },
  {
    "path": "tcc_glue.h",
    "content": "/*\n * Copyright (c) 2010 Luigi Rizzo, Universita` di Pisa\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n/*\n * headers to build userland ipfw under tcc.\n */\n \n#ifndef _TCC_GLUE_H\n#define\t_TCC_GLUE_H\n\n//#define\t__restrict\n#define\tNULL\t((void *)0)\ntypedef int size_t;\ntypedef unsigned char\tu_char;\ntypedef unsigned char\tuint8_t;\ntypedef unsigned char\tu_int8_t;\ntypedef unsigned short\tu_short;\ntypedef unsigned short\tuint16_t;\ntypedef unsigned short\tu_int16_t;\ntypedef int\t\t__int32_t;\ntypedef int\t\tint32_t;\ntypedef int\t\tsocklen_t;\ntypedef int\t\tpid_t;\ntypedef unsigned int\ttime_t;\ntypedef unsigned int\tuint;\ntypedef unsigned int\tu_int;\ntypedef unsigned int\tuint32_t;\ntypedef unsigned int\tu_int32_t;\ntypedef unsigned int\tgid_t;\ntypedef unsigned int\tuid_t;\ntypedef unsigned long\tu_long;\ntypedef unsigned long\tuintptr_t;\ntypedef long long int\tint64_t;\ntypedef unsigned long long\tint uint64_t;\ntypedef unsigned long long\tint u_int64_t;\n\ntypedef uint32_t\tin_addr_t;\nstruct in_addr {\n\tuint32_t\ts_addr;\n};\nstruct sockaddr_in {\n\tuint8_t _sin_len;\n        uint8_t\tsin_family;\n        uint16_t\tsin_port;\n        struct  in_addr sin_addr;\n        char    sin_zero[8];\n};\n#define IFNAMSIZ\t16\n#define INET6_ADDRSTRLEN\t64\n\nstruct in6_addr {\n        union {\n                uint8_t         __s6_addr8[16];\n                uint16_t        __s6_addr16[8];\n                uint32_t        __s6_addr32[4];\n        } __u6; // _addr;                    /* 128-bit IP6 address */\n};\n\n\n#define LITTLE_ENDIAN 1234\n#define BYTE_ORDER LITTLE_ENDIAN\n\n/* to be revised */\n#define\tEX_OK\t\t0\n#define\tEX_DATAERR\t1\n#define\tEX_OSERR\t2\n#define\tEX_UNAVAILABLE\t3\n#define\tEX_USAGE\t4\n#define\tEX_NOHOST\t5\n\n#define\tEEXIST\t\t1\n#define\tEINVAL\t\t2\n#define\tERANGE\t\t3\n#define\tESRCH\t\t4\n\n#define\tIPPROTO_IP\t\t1\n#define\tIPPROTO_IPV6\t\t2\n#define\tIPPROTO_RAW\t\t100\n\n#define\tIPTOS_LOWDELAY\t\t100\n#define\tIPTOS_MINCOST\t\t101\n#define\tIPTOS_RELIABILITY\t102\n#define\tIPTOS_THROUGHPUT\t103\n#define\tSOCK_RAW\t\t12\n#define\tAF_INET\t\t\t2\n#define\tAF_INET6\t\t28\n\n#define\tINADDR_ANY\t\t0\n\n\n#define bcmp(src, dst, len)\tmemcmp(src, dst, len)\n#define bcopy(src, dst, len)\tmemcpy(dst, src, len)\n#define bzero(p, len)\tmemset(p, 0, len)\n#define index(s, c)\tstrchr(s, c)\n\nchar *strsep(char **stringp, const char *delim);\n\nvoid    warn(const char *, ...);\n//void    warnx(const char *, ...);\n#define warnx warn\nvoid    err(int, const char *, ...);\n#define\terrx err\n\nuint16_t\thtons(uint16_t)__attribute__ ((stdcall));\nuint16_t\tntohs(uint16_t)__attribute__ ((stdcall));\nuint32_t\thtonl(uint32_t)__attribute__ ((stdcall));\nuint32_t\tntohl(uint32_t)__attribute__ ((stdcall));\nint inet_aton(const char *cp, struct in_addr *pin)__attribute__ ((stdcall));;\nchar * inet_ntoa(struct in_addr)__attribute__ ((stdcall));;\nconst char * inet_ntop(int af, const void * src, char * dst,\n         socklen_t size)__attribute__ ((stdcall));;\nint inet_pton(int af, const char * src, void * dst)__attribute__ ((stdcall));;\n\nstruct group {\n\tgid_t\tgr_gid;\n\tchar\tgr_name[16];\n};\nstruct passwd {\n\tuid_t\tpw_uid;\n\tchar\tpw_name[16];\n};\n\n#define getpwnam(s)\t(NULL)\n#define getpwuid(s)\t(NULL)\n\n#define getgrnam(x) (NULL)\n#define getgrgid(x) (NULL)\n\nint getopt(int argc, char * const argv[], const char *optstring);\n\nint getsockopt(int s, int level, int optname, void * optval,\n         socklen_t * optlen);\n\nint setsockopt(int s, int level, int optname, const void *optval,\n         socklen_t optlen);\n\nstruct  protoent {\n        char    *p_name;           /* official protocol name */\n        char    **p_aliases;  /* alias list */\n        short   p_proto;                /* protocol # */\n};\n\nstruct  servent {\n        char    *s_name;           /* official service name */\n        char    **s_aliases;  /* alias list */\n        short   s_port;                 /* port # */\n        char    *s_proto;          /* protocol to use */\n};\n\nstruct  hostent {\n        char    *h_name;           /* official name of host */\n        char    **h_aliases;  /* alias list */\n        short   h_addrtype;             /* host address type */\n        short   h_length;               /* length of address */\n        char    **h_addr_list; /* list of addresses */\n#define h_addr  h_addr_list[0]          /* address, for backward compat */\n};\n\nstruct hostent* gethostbyaddr(const char* addr, int len, int type)__attribute__ ((stdcall));\nstruct hostent* gethostbyname(const char *name)__attribute__ ((stdcall));\n\nstruct protoent* getprotobynumber(int number)__attribute__ ((stdcall));\nstruct protoent* getprotobyname(const char* name)__attribute__ ((stdcall));\n\nstruct servent* getservbyport(int port, const char* proto)__attribute__ ((stdcall));\nstruct servent* getservbyname(const char* name, const char* proto) __attribute__ ((stdcall));\n\nextern int optind;\nextern char *optarg;\n\n#include <windef.h>\n\n#define WSADESCRIPTION_LEN      256\n#define WSASYS_STATUS_LEN       128\n\ntypedef struct WSAData {\n        WORD                    wVersion;\n        WORD                    wHighVersion;\n        char                    szDescription[WSADESCRIPTION_LEN+1];\n        char                    szSystemStatus[WSASYS_STATUS_LEN+1];\n        unsigned short          iMaxSockets;\n        unsigned short          iMaxUdpDg;\n        char FAR *              lpVendorInfo;\n} WSADATA, * LPWSADATA;\n\nint WSAStartup(\n    WORD wVersionRequested,\n    LPWSADATA lpWSAData\n    );\n\nint\nWSACleanup(void);\n\nint WSAGetLastError();\n\n/* return error on process handling */\n#define\tpipe(f)\t\t(-1)\n#define\tkill(p, s)\t(-1)\n#define\twaitpid(w,s,o)\t(-1)\n#define fork(x)\t\t(-1)\n#define execvp(f, a)\t(-1)\n\n#define _W_INT(i)       (i)\n#define _WSTATUS(x)     (_W_INT(x) & 0177)\n#define WIFEXITED(x)    (_WSTATUS(x) == 0)\n#define WEXITSTATUS(x)  (_W_INT(x) >> 8)\n#define _WSTOPPED       0177            /* _WSTATUS if process is stopped */\n#define WIFSIGNALED(x)  (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0)\n#define WTERMSIG(x)     (_WSTATUS(x))\n\n#endif /* _TCC_GLUE_H */\n"
  },
  {
    "path": "test/Makefile",
    "content": "#\n# $Id: Makefile 5626 2010-03-04 21:55:22Z luigi $\n#\n# Makefile for building userland tests\n# this is written in a form compatible with gmake\n\nSCHED_SRCS = test_dn_sched.c\nSCHED_SRCS += dn_sched_fifo.c\nSCHED_SRCS += dn_sched_wf2q.c\nSCHED_SRCS += dn_sched_qfq.c\nSCHED_SRCS += dn_sched_rr.c\nSCHED_SRCS += dn_heap.c\nSCHED_SRCS += main.c\n\nSCHED_OBJS=$(SCHED_SRCS:.c=.o)\n\nHEAP_SRCS = dn_heap.c test_dn_heap.c\nHEAP_OBJS=$(HEAP_SRCS:.c=.o)\n\nVPATH=\t.:../dummynet2\n\n#CFLAGS = -I../dummynet2/include -I. -Wall -Werror -O3 -DIPFW\nCFLAGS = -I. -I../dummynet2/include/netinet/ipfw -DIPFW\nCFLAGS +=  -Wall -Werror\nCFLAGS += -g -O3\nTARGETS= test_sched # no test_heap by default\n\nall: $(TARGETS)\n\ntest_heap : $(HEAP_OBJS)\n\t$(CC) -o $@ $(HEAP_OBJS)\n\ntest_sched : $(SCHED_OBJS)\n\t$(CC) -o $@ $(SCHED_OBJS)\n\n$(SCHED_OBJS): dn_test.h\nmain.o: mylist.h\n\nclean:\n\t- rm *.o $(TARGETS) *.core\n\nALLSRCS = $(SCHED_SRCS) dn_test.h mylist.h \\\n\tdn_sched.h dn_heap.h ip_dn_private.h Makefile\nTMPBASE = /tmp/testXYZ\nTMPDIR = $(TMPBASE)/test\n\ntgz:\n\t-rm -rf $(TMPDIR)\n\tmkdir -p $(TMPDIR)\n\t-cp -p $(ALLSRCS) $(TMPDIR)\n\t-(cd ..; cp -p $(ALLSRCS) $(TMPDIR))\n\tls -la  $(TMPDIR)\n\t(cd $(TMPBASE); tar cvzf /tmp/test.tgz test)\n"
  },
  {
    "path": "test/basic_ipfw.sh",
    "content": "#!/bin/sh\n\nIPFW=./ipfw/ipfw\nPING=/bin/ping\nRH=127.0.0.1\t\t# remote host\nR=10\t\t\t# test rule number\nP=1\t\t\t# test pipe number\n\nabort()\n{ \necho $* \n}\n\n#insmod dummynet2/ipfw_mod.ko\n#$IPFW show > /dev/null\n#$IPFW pipe show \necho \"Flushing rules, do you agree ?\"\n$IPFW flush\n\n# test_msg rule counter\nclean() \n{ \n\t$IPFW delete $R 2> /dev/null\n\t$IPFW pipe $P delete 2> /dev/null\n}\n\n# simple counter/allow test\necho -n \"counter/allow test...\"\nclean\n$IPFW add $R allow icmp from any to 127.0.0.1 > /dev/null\n$PING -f -c100 $RH > /dev/null\ncounter=`$IPFW show | grep $R | head -n 1 | cut -d \" \" -f3`\n[ ! $counter -eq 400 ] && abort \"Wrong counter $counter 400\"\necho \"...OK\"\n\n# simple drop test\necho -n \"deny test...\"\nclean\n$IPFW add $R deny icmp from any to 127.0.0.1 > /dev/null\n$PING -f -c10 -W 1 $RH > /dev/null\ncounter=`$IPFW show | grep $R | head -n 1 | cut -d \" \" -f4`\n[ ! $counter -eq 10 ] && abort \"Wrong counter $counter 10\"\necho \"...OK\"\n\n# pipe delay test\necho -n \"pipe delay test...\"\nclean\n$IPFW pipe $P config delay 2000ms >/dev/null\n$IPFW add $R pipe $P icmp from any to $RH >/dev/null\n$PING -f -c10 -W 1 $RH > /dev/null\ncounter1=`$IPFW show | grep $R | head -n 1 | cut -d \" \" -f4`\nsleep 2\ncounter2=`$IPFW show | grep $R | head -n 1 | cut -d \" \" -f4`\n[ ! $counter1 -eq 10 ] && abort \"Wrong counter $counter 10\"\n[ ! $counter2 -eq 20 ] && abort \"Wrong counter $counter 20\"\necho \"...OK\"\n\n# pipe bw test\necho -n \"pipe bw test...\"\nclean\n$IPFW pipe $P config bw 2Kbit/s >/dev/null\n$IPFW add $R pipe $P icmp from any to $RH >/dev/null\n$PING -i 0.1 -c10 -W 1 $RH > /dev/null\ncounter=`$IPFW show | grep $R | head -n 1 | cut -d \" \" -f4`\n[ $counter -gt 30 ] && abort \"Wrong counter $counter should be < 30\"\nsleep 1\ncounter=`$IPFW show | grep $R | head -n 1 | cut -d \" \" -f4`\n[ $counter -gt 30 ] && abort \"Wrong counter $counter should be < 30\"\necho \"...OK\"\n\n# Final clean\nclean\n"
  },
  {
    "path": "test/dn_test.h",
    "content": "/*\n * $Id: dn_test.h 5626 2010-03-04 21:55:22Z luigi $\n *\n * userspace compatibility code for dummynet schedulers\n */\n\n#ifndef _DN_TEST_H\n#define _DN_TEST_H\n#include <inttypes.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <strings.h>\t/* bzero, ffs, ... */\n#include <string.h>\t/* strcmp */\n#include <errno.h>\n#include <sys/queue.h>\n#include <sys/time.h>\n\nextern int debug;\n#define ND(fmt, args...) do {} while (0)\n#define D1(fmt, args...) do {} while (0)\n#define D(fmt, args...) fprintf(stderr, \"%-8s \" fmt \"\\n\",      \\\n        __FUNCTION__, ## args)\n#define DX(lev, fmt, args...) do {              \\\n        if (debug > lev) D(fmt, ## args); } while (0)\n\n\n#define offsetof(t,m) (int)((&((t *)0L)->m))\n\n#include <mylist.h>\n\n/* prevent include of other system headers */\n#define\t_NETINET_IP_VAR_H_\t/* ip_fw_args */\n#define _IPFW2_H\n#define _SYS_MBUF_H_\n\nenum\t{\n\tDN_QUEUE,\n};\n\nenum\t{\n\tDN_SCHED_FIFO,\n\tDN_SCHED_WF2QP,\n};\n\nstruct dn_id {\n\tint type, subtype, len, id;\n};\nstruct dn_fs {\n\tint par[4];\t/* flowset parameters */\n\n\t/* simulation entries.\n\t * 'index' is not strictly necessary\n\t * y is used for the inverse mapping ,\n\t */\n\tint index;\n\tint y;\t/* inverse mapping */\n\tint base_y;\t/* inverse mapping */\n\tint next_y;\t/* inverse mapping */\n\tint n_flows;\n\tint first_flow;\n\tint next_flow;\t/* first_flow + n_flows */\n\t/*\n\t * when generating, let 'cur' go from 0 to n_flows-1,\n\t * then point to flow first_flow + cur\n\t */\n\tint\tcur;\n};\nstruct dn_sch {\n};\nstruct dn_flow {\n\tstruct dn_id oid;\n\tint length;\n\tint len_bytes;\n\tint drops;\n\tuint64_t tot_bytes;\n\tuint32_t flow_id;\n\tstruct list_head h;\t/* used by the generator */\n};\nstruct dn_link {\n};\n\nstruct ip_fw_args {\n};\n\nstruct mbuf {\n        struct {\n                int len;\n        } m_pkthdr;\n        struct mbuf *m_nextpkt;\n\tint flow_id;\t/* for testing, index of a flow */\n\t//int flowset_id;\t/* for testing, index of a flowset */\n\tvoid *cfg;\t/* config args */\n};\n\n#define MALLOC_DECLARE(x)\n#define KASSERT(x, y)\tdo { if (!(x)) printf y ; exit(0); } while (0)\nstruct ipfw_flow_id {\n};\n\ntypedef void * module_t;\nstruct _md_t {\n\tconst char *name;\n\tint (*f)(module_t, int, void *);\n\tvoid *p;\n};\ntypedef struct _md_t moduledata_t;\n#define DECLARE_MODULE(name, b, c, d)\t\\\n\tmoduledata_t *_g_##name = & b\n#define MODULE_DEPEND(a, b, c, d, e)\n\n#ifdef IPFW\n#include <dn_heap.h>\n#include <ip_dn_private.h>\n#include <dn_sched.h>\n#else\nstruct dn_queue {\n        struct dn_fsk *fs;             /* parent flowset. */\n        struct dn_sch_inst *_si;\t/* parent sched instance. */\n};\nstruct dn_schk {\n};\nstruct dn_fsk {\n\tstruct dn_fs fs;\n\tstruct dn_schk *sched;\n};\nstruct dn_sch_inst {\n\tstruct dn_schk *sched;\n};\nstruct dn_alg {\n\tint type;\n\tconst char *name;\n\tvoid *enqueue, *dequeue;\n\tint q_datalen, si_datalen, schk_datalen;\n\tint (*config)(struct dn_schk *);\n\tint (*new_sched)(struct dn_sch_inst *);\n\tint (*new_fsk)(struct dn_fsk *);\n        int (*new_queue)(struct dn_queue *q);\n};\n\n#endif\n\n#ifndef __FreeBSD__\nint fls(int);\n#endif\n\nstatic inline void\nmq_append(struct mq *q, struct mbuf *m)\n{\n        if (q->head == NULL)\n                q->head = m;\n        else\n                q->tail->m_nextpkt = m;\n        q->tail = m;\n        m->m_nextpkt = NULL;\n}\n\n#endif /* _DN_TEST_H */\n"
  },
  {
    "path": "test/dynrules.sh",
    "content": "#!/bin/sh\n#\n# 20100507 marta, quick test for dyn rules\n# ./ipfw/ipfw -d show |grep \\ 80\n\nIPFW_MOD=dummynet2/ipfw_mod.ko\nIPFW=ipfw/ipfw\n\n# main\n# remove any previous loaded module\n/sbin/rmmod ipfw_mod \n/sbin/insmod ${IPFW_MOD}\necho \"25\" >  /sys/module/ipfw_mod/parameters/dyn_ack_lifetime\n${IPFW} add 1 check-state\n${IPFW} add 9 allow all from any to any keep-state\n${IPFW} add 10 allow all from any to onelab1.iet.unipi.it keep-state\n\ntelnet 72.14.234.104 80 \n\n\n"
  },
  {
    "path": "test/interpolation.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n\n/* gcc interpolation.c -o interpolation */\n\nvoid    \nerr(int eval, const char *fmt, ...) \n{\n}           \nvoid    \nerrx(int eval, const char *fmt, ...) \n{\n}           \n        \n\n#define ED_MAX_SAMPLES_NO 1000\n#define ED_MAX_LINE_LEN 128\n#define EX_DATAERR 1\n#define EX_UNAVAILABLE  3\n#define ED_TOK_DELAY    \"delay\"\n#define ED_TOK_PROB     \"prob\"\n#define ED_SEPARATORS   \" \\t\\n\"\n#define ED_TOK_PROFILE_NO \"profile_no\"\n\n\nstruct point {\n\tdouble prob;\t\t/* y */\n\tdouble delay;\t\t/* x */\n};\n\nstruct profile {\n        char    filename[128];                   /* profile filename */\n        int     samples[ED_MAX_SAMPLES_NO+1];    /* may be shorter */\n        int     samples_no;                     /* actual len of samples[] */\n};\n\n/*\n * returns 1 if s is a non-negative number, with at least one '.'\n */\nstatic int\nis_valid_number(const char *s)\n{\n#if 0\n        int i, dots_found = 0;\n        int len = strlen(s);\n\n        for (i = 0; i<len; ++i)\n                if (!isdigit(s[i]) && (s[i] !='.' || ++dots_found > 1))\n                        return 0;\n#endif\n        return 1;\n}\n\nstatic int\ncompare_points(const void *vp1, const void *vp2)\n{\n\tconst struct point *p1 = vp1;\n\tconst struct point *p2 = vp2;\n\tdouble res = 0;\n\n\tres = p1->prob - p2->prob;\n\tif (res == 0)\n\t\tres = p1->delay - p2->delay;\n\tif (res < 0)\n\t\treturn -1;\n\telse if (res > 0)\n\t\treturn 1;\n\telse\n\t\treturn 0;\n}\n\n#define ED_EFMT(s) 1,\"error in %s at line %d: \"#s,filename,lineno\n\n/*\n * The points defined by the user are stored in the ponts structure.\n * The number of user defined points is stored in points_no.\n *       We assume that The last point for the '1' value of the\n *       probability should be defined. (XXX add checks for this)\n * The user defined sampling value is stored in samples_no.\n * The resulting samples are in the \"samples\" pointer.\n */\nstatic void\ninterpolate_samples(struct point *p, int points_no, \n\t\tint *samples, int samples_no, const char *filename)\n{\n\tdouble dy;\t\t/* delta on the y axis */\n\tdouble y;\t\t/* current value of y */\n\tdouble x;\t\t/* current value of x */\n\tdouble m;\t\t/* the y slope */\n\tint i;\t\t\t/* samples index */\n\tint curr;\t\t/* points current index */\n\n\tdy = 1.0/samples_no;\n\ty = 0;\n\n\tfor (i=0, curr = 0; i < samples_no; i++, y+=dy) {\n\t\t/* This statment move the curr pointer to the next point\n\t\t * skipping the points with the same x value. We are\n\t\t * guaranteed to exit from the loop because the\n\t\t * last possible value of y is stricly less than 1\n\t\t * and the last possible value of the y points is 1 */\n\t\twhile ( y >= p[curr+1].prob ) curr++;\n\n\t\t/* compute the slope of the curve */\n\t\tm = (p[curr+1].delay - p[curr].delay) / (p[curr+1].prob - p[curr].prob);\n\t\t/* compute the x value starting from the current point */\n\t\tx = p[curr].delay + (y - p[curr].prob) * m;\n\t\tsamples[i] = x;\n\t}\n\n\t/* add the last sample */\n\tsamples[i] = p[curr+1].delay;\n}\n\n#if 0\nstatic void\ninterpolate_samples_old(struct point *points, int points_no, \n\t\tint *samples, int samples_no, const char *filename)\n{\n\tint i;\t\t/* pointer to the sampled array */\n\tint j = 0;\t/* pointer to user defined samples */\n\tdouble dy;\t/* delta y */\n\tdouble y;\t/* current value of y */\n\tint x;\t\t/* computed value of x */\n\tdouble m;\t/* slope of the line */\n\tdouble y1, x1, y2, x2;\t/* two points of the current line */\n\n\t/* make sure that there are enough points. */\n\t/* XXX Duplicated shoule be removed */\n\tif (points_no < 3)\n\t    errx(EX_DATAERR, \"%s too few samples, need at least %d\",\n\t\tfilename, 3);\n\n\tqsort(points, points_no, sizeof(struct point), compare_points);\n\n\tsamples_no--;\n\tdy = 1.0/samples_no;\n\tprintf(\"\\nsamples no is %d dy is %f \", samples_no, dy);\n\n\t/* start with the first two points */\n\ty1 = points[j].prob * samples_no;\n\tx1 = points[j].delay;\n\tj++;\n\ty2 = points[j].prob * samples_no;\n\tx2 = points[j].delay;\n\n\tm = (y2-y1)/(x2-x1);\n\tprintf(\"\\nStart\");\n\tprintf(\"\\n\\tCurrent points x1 y1 %f %f next point x2y2 %f %f m %f\\n\",\n\t\t x1, y1, x2, y2, m);\n\n\ty = 0;\n\tx = x1;\n\n\tfor(i=0; i < samples_no+1; i++, y+=dy) {\n\t\tprintf(\"\\ni:%d j:%d y:%f real y:%f\", i, j, y, y*samples_no);\n\t\tif ( (y*samples_no) >= y2 ) { /* move to the next point */\n\t\t\tj++;\n\t\t\tif ( j >= points_no ) {\n\t\t\t\tprintf(\"\\n\\tNo more points, exit with j: %d i: %d and y:%f %f\\n\",\n\t\t\t\t\t j, i, y, (y*samples_no));\n\t\t\t\tbreak;\t/* no more user defined points */\n\t\t\t}\n\t\t\t/* load a new point */\n\t\t\ty1 = y2;\n\t\t\tx1 = x2;\n\t\t\ty2 = points[j].prob * samples_no;\n\t\t\tx2 = points[j].delay;\n\t\t\tm = (y2-y1)/(x2-x1);\n\t\t\tif (x1==x2) { /* m = infinito */\n\t\t\t\tm = -1;\n\t\t\t\tx = x2;\n\t\t\t}\n\t\t\t/* very small m problem */\n\t\t\tprintf (\"\\ndelta %f\\n\", (y1 - y2));\n\t\t\tif (abs(y1 - y2) < 0.00001) { /* m = 0 XXX Should this magic number depend on samples_no ? */\n\t\t\t\tm = 0;\n\t\t\t\tx = x2;\n\t\t\t}\n\t\t\tprintf(\"\\n\\tCurrent points x1 y1 %f %f next point x2y2 %f %f (%f/%f)=m \\n\",\n\t\t\t\t x1, y1, x2, y2, (y2-y1), (x2-x1), m);\n\t\t}\n\t\tprintf(\"\\n\\tcompute step y %f x[%d]=%d \",\n\t\t\ty, i, x);\n\t\tif ((m != -1) && ( m != 0 )) {\n\t\t\tx = x + (dy * samples_no)/m;\n\t\t}\n\t\tsamples[i] = x;\n\t\tprintf(\" dy %f x new %d\\n\", dy*samples_no, x);\n\t\tprintf(\" m %f (dy * samples_no)/m %f \\n\", m, (dy * samples_no)/m);\n\t}\n\n\tx = samples[i-1];\n\tprintf(\"Finish i is %d samples_no is %d\\n\", i, samples_no);\n\t/* The last point has a probability less than 1 */\n\tfor (; i <= samples_no; i++)\n\t\tsamples[i] = x;\n}\n#endif\n\nstatic void\nload_profile(struct profile *p)\n{\n\tFILE    *f;\t\t\t/* file handler */\n\tchar    line[ED_MAX_LINE_LEN];\n\tint     lineno = 0;\n\tint     do_points = 0;\n\tint     delay_first = -1;\n\tint i;\n\n\tstruct\tpoint points[1000]; /* MAX_POINTS_NO */\n\tint     points_no = 0;\n\n\tchar *filename = p->filename;\n\tf = fopen(filename, \"r\");\n\tif (f == NULL) {\n\t    err(EX_UNAVAILABLE, \"fopen: %s\", filename);\n\t}\n\n\n\twhile (fgets(line, ED_MAX_LINE_LEN, f)) {         /* read commands */\n\t\tchar *s, *cur = line, *name = NULL, *arg = NULL;\n\n\t\t++lineno;\n\n\t\t/* parse the line */\n\t\twhile (cur) {\n\t\t\ts = strsep(&cur, ED_SEPARATORS);\n\t\t\tif (s == NULL || *s == '#')\n\t\t\t\tbreak;\n\t\t\tif (*s == '\\0')\n\t\t\t\tcontinue;\n\t\t\tif (arg)\n\t\t\t\terrx(ED_EFMT(\"too many arguments\"));\n\t\t\tif (name == NULL)\n\t\t\t\tname = s;\n\t\t\telse\n\t\t\t\targ = s;\n\t\t}\n\n\t\tif (name == NULL)\n\t\t\tcontinue;\n\n\t\tif (!strcasecmp(name, ED_TOK_DELAY)) {\n\t\t    if (do_points)\n\t\t\terrx(ED_EFMT(\"duplicated token: %s\"), name);\n\t\t    delay_first = 1;\n\t\t    do_points = 1;\n\t\t    continue;\n\t\t} else if (!strcasecmp(name, ED_TOK_PROB)) {\n\t\t    if (do_points)\n\t\t\terrx(ED_EFMT(\"duplicated token: %s\"), name);\n\t\t    delay_first = 0;\n\t\t    do_points = 1;\n\t\t    continue;\n\t\t}\n\t\tif (!strcasecmp(name, ED_TOK_PROFILE_NO)) {\n\t\t\tint p_no = atof(arg);\n\t\t\tif (p_no <= 0) {\n\t\t\t\tp_no = 100;\n\t\t\t\tprintf(\"invalid interpolation samples, using %d\\n\",\n\t\t\t\t\t p_no);\n\t\t\t}\n\t\t\tif (p_no > ED_MAX_SAMPLES_NO) {\n\t\t\t\tp_no = ED_MAX_SAMPLES_NO;\n\t\t\t\tprintf(\"invalid interpolation samples, using %d\\n\",\n\t\t\t\t\t p_no);\n\t\t\t}\n\n\t\t\tp->samples_no = p_no;\n\t\t    continue;\n\n\t\t} else if (do_points) {\n\t\t    if (!is_valid_number(name) || !is_valid_number(arg))\n\t\t\terrx(ED_EFMT(\"invalid point found\"));\n\t\t    if (delay_first) {\n\t\t\tpoints[points_no].delay = atof(name);\n\t\t\tpoints[points_no].prob = atof(arg);\n\t\t    } else {\n\t\t\tpoints[points_no].delay = atof(arg);\n\t\t\tpoints[points_no].prob = atof(name);\n\t\t    }\n\t\t    if (points[points_no].prob > 1.0)\n\t\t\terrx(ED_EFMT(\"probability greater than 1.0\"));\n\t\t    ++points_no;\n\t/* XXX no more that 1000 */\n\t\t    continue;\n\t\t} else {\n\t\t    errx(ED_EFMT(\"unrecognised command '%s'\"), name);\n\t\t}\n\t}\n\n\tfor(i=0; i < p->samples_no; i++) {\n\t\tp->samples[i] = 666;\n\t}\n\n\t/* This code assume the user define a value of X for the sampling value,\n\t * and that:\n\t * - the value stored in the emulator structure is X;\n\t * - the allocated structure for the samples is X+1;\n\t */\n\tinterpolate_samples(points, points_no, p->samples, p->samples_no, filename);\n\n\t// User defined samples\n\tprintf(\"\\nLoaded %d points:\\n\", points_no);\n\tfor(i=0; i < points_no; i++) {\n\t\tprintf(\"%f %f\\n\", points[i].prob, points[i].delay);\n\t}\n\tprintf(\"\\n\");\n\tprintf(\"The sample value is %d \\n\", p->samples_no);\n\n}\n\nint main(int argc, char **argv)\n{\n\tif (argc < 2) {\n\t\tprintf(\"Usage: ./interpolation <filename>\\n\");\n\t\treturn -1;\n\t}\n\n\tchar *filename;\n\tfilename = argv[1];\n\n\tstruct profile p;\n\tint i;\n\n\tstrncpy(p.filename, filename, 128);\n\tload_profile(&p);\n\tprintf(\"-----------\\n\");\n\tfor (i=0; i<=p.samples_no; i++)\n\t\tprintf(\"%d %d\\n\", i, p.samples[i]);\n\tprintf(\"-----------\\n\");\n\treturn 0;\n}\n"
  },
  {
    "path": "test/main.c",
    "content": "/*\n * $Id: main.c 5626 2010-03-04 21:55:22Z luigi $\n *\n * Testing program for schedulers\n *\n * The framework include a simple controller which, at each\n * iteration, decides whether we can enqueue and/or dequeue.\n * Then the mainloop runs the required number of tests,\n * keeping track of statistics.\n */\n\n#include \"dn_test.h\"\n\nstruct q_list {\n\tstruct list_head h;\n};\n\nstruct cfg_s {\n\tint ac;\n\tchar * const *av;\n\n\tconst char *name;\n\tint loops;\n\tstruct timeval time;\n\n\t/* running counters */\n\tuint32_t\t_enqueue;\n\tuint32_t\tdrop;\n\tuint32_t\tpending;\n\tuint32_t\tdequeue;\n\n\t/* generator parameters */\n\tint th_min, th_max;\n\tint maxburst;\n\tint lmin, lmax;\t/* packet len */\n\tint flows;\t/* number of flows */\n\tint flowsets;\t/* number of flowsets */\n\tint wsum;\t/* sum of weights of all flows */\n\tint max_y;\t/* max random number in the generation */\n\tint cur_y, cur_fs;\t/* used in generation, between 0 and max_y - 1 */\n\tconst char *fs_config; /* flowset config */\n\tint can_dequeue;\n\tint burst;\t/* count of packets sent in a burst */\n\tstruct mbuf *tosend;\t/* packet to send -- also flag to enqueue */\n\n\tstruct mbuf *freelist;\n\n\tstruct mbuf *head, *tail;\t/* a simple tailq */\n\n\t/* scheduler hooks */\n\tint (*enq)(struct dn_sch_inst *, struct dn_queue *,\n\t\tstruct mbuf *);\n\tstruct mbuf * (*deq)(struct dn_sch_inst *);\n\t/* size of the three fields including sched-specific areas */\n\tint schk_len;\n\tint q_len; /* size of a queue including sched-fields */\n\tint si_len; /* size of a sch_inst including sched-fields */\n\tchar *q;\t/* array of flow queues */\n\t\t/* use a char* because size is variable */\n\tstruct dn_fsk *fs;\t/* array of flowsets */\n\tstruct dn_sch_inst *si;\n\tstruct dn_schk *sched;\n\n\t/* generator state */\n\tint state;\t\t/* 0 = going up, 1: going down */\n\n\t/*\n\t * We keep lists for each backlog level, and always serve\n\t * the one with shortest backlog. llmask contains a bitmap\n\t * of lists, and ll are the heads of the lists. The last\n\t * entry (BACKLOG) contains all entries considered 'full'\n\t * XXX to optimize things, entry i could contain queues with\n\t * 2^{i-1}+1 .. 2^i entries.\n\t */\n#define BACKLOG\t30\n\tuint32_t\tllmask;\n\tstruct list_head ll[BACKLOG + 10];\n};\n\n/* FI2Q and Q2FI converts from flow_id to dn_queue and back.\n * We cannot easily use pointer arithmetic because it is variable size.\n  */\n#define FI2Q(c, i)\t((struct dn_queue *)((c)->q + (c)->q_len * (i)))\n#define Q2FI(c, q)\t(((char *)(q) - (c)->q)/(c)->q_len)\n\nint debug = 0;\n\nstruct dn_parms dn_cfg;\n\nstatic void controller(struct cfg_s *c);\n\n/* release a packet: put the mbuf in the freelist, and the queue in\n * the bucket.\n */\nint\ndrop(struct cfg_s *c, struct mbuf *m)\n{\n\tstruct dn_queue *q;\n\tint i;\n\n\tc->drop++;\n\tq = FI2Q(c, m->flow_id);\n\ti = q->ni.length; // XXX or ffs...\n\n\tND(\"q %p id %d current length %d\", q, m->flow_id, i);\n\tif (i < BACKLOG) {\n\t\tstruct list_head *h = &q->ni.h;\n\t\tc->llmask &= ~(1<<(i+1));\n\t\tc->llmask |= (1<<(i));\n\t\tlist_del(h);\n\t\tlist_add_tail(h, &c->ll[i]);\n\t}\n\tm->m_nextpkt = c->freelist;\n\tc->freelist = m;\n\treturn 0;\n}\n\n/* dequeue returns NON-NULL when a packet is dropped */\nstatic int\nenqueue(struct cfg_s *c, void *_m)\n{\n\tstruct mbuf *m = _m;\n\tif (c->enq)\n\t\treturn c->enq(c->si, FI2Q(c, m->flow_id), m);\n\tif (c->head == NULL)\n\t\tc->head = m;\n\telse\n\t\tc->tail->m_nextpkt = m;\n\tc->tail = m;\n\treturn 0; /* default - success */\n}\n\n/* dequeue returns NON-NULL when a packet is available */\nstatic void *\ndequeue(struct cfg_s *c)\n{\n\tstruct mbuf *m;\n\tif (c->deq)\n\t\treturn c->deq(c->si);\n\tif ((m = c->head)) {\n\t\tm = c->head;\n\t\tc->head = m->m_nextpkt;\n\t\tm->m_nextpkt = NULL;\n\t}\n\treturn m;\n}\n\nstatic int\nmainloop(struct cfg_s *c)\n{\n\tint i;\n\tstruct mbuf *m;\n\n\tfor (i=0; i < c->loops; i++) {\n\t\t/* implement histeresis */\n\t\tcontroller(c);\n\t\tDX(3, \"loop %d enq %d send %p rx %d\",\n\t\t\ti, c->_enqueue, c->tosend, c->can_dequeue);\n\t\tif ( (m = c->tosend) ) {\n\t\t\tc->_enqueue++;\n\t\t\tif (enqueue(c, m)) {\n\t\t\t\tdrop(c, m);\n\t\t\t\tND(\"loop %d enqueue fail\", i );\n\t\t\t} else {\n\t\t\t\tND(\"enqueue ok\");\n\t\t\t\tc->pending++;\n\t\t\t}\n\t\t}\n\t\tif (c->can_dequeue) {\n\t\t\tc->dequeue++;\n\t\t\tif ((m = dequeue(c))) {\n\t\t\t\tc->pending--;\n\t\t\t\tdrop(c, m);\n\t\t\t\tc->drop--;\t/* compensate */\n\t\t\t}\n\t\t}\n\t}\n\tDX(1, \"mainloop ends %d\", i);\n\treturn 0;\n}\n\nint\ndump(struct cfg_s *c)\n{\n\tint i;\n\tstruct dn_queue *q;\n\n\tfor (i=0; i < c->flows; i++) {\n\t\tq = FI2Q(c, i);\n\t\tDX(1, \"queue %4d tot %10lld\", i, q->ni.tot_bytes);\n\t}\n\tDX(1, \"done %d loops\\n\", c->loops);\n\treturn 0;\n}\n\n/* interpret a number in human form */\nstatic long\ngetnum(const char *s, char **next, const char *key)\n{\n\tchar *end = NULL;\n\tlong l;\n\n\tif (next)\t/* default */\n\t\t*next = NULL;\n\tif (s && *s) {\n\t\tDX(3, \"token is <%s> %s\", s, key ? key : \"-\");\n\t\tl = strtol(s, &end, 0);\n\t} else {\n\t\tDX(3, \"empty string\");\n\t\tl = -1;\n\t}\n\tif (l < 0) {\n\t\tDX(2, \"invalid %s for %s\", s ? s : \"NULL\", (key ? key : \"\") );\n\t\treturn 0;\t// invalid \n\t}\n\tif (!end || !*end)\n\t\treturn l;\n\tif (*end == 'n')\n\t\tl = -l;\t/* multiply by n */\n\telse if (*end == 'K')\n\t\tl = l*1000;\n\telse if (*end == 'M')\n\t\tl = l*1000000;\n\telse if (*end == 'k')\n\t\tl = l*1024;\n\telse if (*end == 'm')\n\t\tl = l*1024*1024;\n\telse if (*end == 'w')\n\t\t;\n\telse {/* not recognized */\n\t\tD(\"suffix %s for %s, next %p\", end, key, next);\n\t\tend--;\n\t}\n\tend++;\n\tDX(3, \"suffix now %s for %s, next %p\", end, key, next);\n\tif (next && *end) {\n\t\tDX(3, \"setting next to %s for %s\", end, key);\n\t\t*next = end;\n\t}\n\treturn l;\n}\n\n/*\n * flowsets are a comma-separated list of\n *     weight:maxlen:flows\n * indicating how many flows are hooked to that fs.\n * Both weight and range can be min-max-steps.\n * In a first pass we just count the number of flowsets and flows,\n * in a second pass we complete the setup.\n */\nstatic void\nparse_flowsets(struct cfg_s *c, const char *fs, int pass)\n{\n\tchar *s, *cur, *next;\n\tint n_flows = 0, n_fs = 0, wsum = 0;\n\tint i, j;\n\tstruct dn_fs *prev = NULL;\n\n\tDX(3, \"--- pass %d flows %d flowsets %d\", pass, c->flows, c->flowsets);\n\tif (pass == 0)\n\t\tc->fs_config = fs;\n\ts = c->fs_config ? strdup(c->fs_config) : NULL;\n\tif (s == NULL) {\n\t\tif (pass == 0)\n\t\t\tD(\"no fsconfig\");\n\t\treturn;\n\t}\n\tfor (next = s; (cur = strsep(&next, \",\"));) {\n\t\tchar *p = NULL;\n\t\tint w, w_h, w_steps, wi;\n\t\tint len, len_h, l_steps, li;\n\t\tint flows;\n\n\t\tw = getnum(strsep(&cur, \":\"), &p, \"weight\");\n\t\tif (w <= 0)\n\t\t\tw = 1;\n\t\tw_h = p ? getnum(p+1, &p, \"weight_max\") : w;\n\t\tw_steps = p ? getnum(p+1, &p, \"w_steps\") : (w_h == w ?1:2);\n\t\tlen = getnum(strsep(&cur, \":\"), &p, \"len\");\n\t\tif (len <= 0)\n\t\t\tlen = 1000;\n\t\tlen_h = p ? getnum(p+1, &p, \"len_max\") : len;\n\t\tl_steps = p ? getnum(p+1, &p, \"l_steps\") : (len_h == len ? 1 : 2);\n\t\tflows = getnum(strsep(&cur, \":\"), NULL, \"flows\");\n\t\tif (flows == 0)\n\t\t\tflows = 1;\n\t\tDX(4, \"weight %d..%d (%d) len %d..%d (%d) flows %d\",\n\t\t\tw, w_h, w_steps, len, len_h, l_steps, flows);\n\t\tif (w == 0 || w_h < w || len == 0 || len_h < len ||\n\t\t\t\tflows == 0) {\n\t\t\tDX(4,\"wrong parameters %s\", fs);\n\t\t\treturn;\n\t\t}\n\t\tn_flows += flows * w_steps * l_steps;\n\t\tfor (i = 0; i < w_steps; i++) {\n\t\t\twi = w + ((w_h - w)* i)/(w_steps == 1 ? 1 : (w_steps-1));\n\t\t\tfor (j = 0; j < l_steps; j++, n_fs++) {\n\t\t\t\tstruct dn_fs *fs = &c->fs[n_fs].fs; // tentative\n\t\t\t\tint x;\n\n\t\t\t\tli = len + ((len_h - len)* j)/(l_steps == 1 ? 1 : (l_steps-1));\n\t\t\t\tx = (wi*2048)/li;\n\t\t\t\tDX(3, \"----- fs %4d weight %4d lmax %4d X %4d flows %d\",\n\t\t\t\t\tn_fs, wi, li, x, flows);\n\t\t\t\tif (pass == 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (c->fs == NULL || c->flowsets <= n_fs) {\n\t\t\t\t\tD(\"error in number of flowsets\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\twsum += wi * flows;\n\t\t\t\tfs->par[0] = wi;\n\t\t\t\tfs->par[1] = li;\n\t\t\t\tfs->index = n_fs;\n\t\t\t\tfs->n_flows = flows;\n\t\t\t\tfs->cur = fs->first_flow = prev==NULL ? 0 : prev->next_flow;\n\t\t\t\tfs->next_flow = fs->first_flow + fs->n_flows;\n\t\t\t\tfs->y = x * flows;\n\t\t\t\tfs->base_y = (prev == NULL) ? 0 : prev->next_y;\n\t\t\t\tfs->next_y = fs->base_y + fs->y;\n\t\t\t\tprev = fs;\n\t\t\t}\n\t\t}\n\t}\n\tc->max_y = prev ? prev->base_y + prev->y : 0;\n\tc->flows = n_flows;\n\tc->flowsets = n_fs;\n\tc->wsum = wsum;\n\tif (pass == 0)\n\t\treturn;\n\n\t/* now link all flows to their parent flowsets */\n\tDX(1,\"%d flows on %d flowsets max_y %d\", c->flows, c->flowsets, c->max_y);\n\tfor (i=0; i < c->flowsets; i++) {\n\t\tstruct dn_fs *fs = &c->fs[i].fs;\n\t\tDX(1, \"fs %3d w %5d l %4d flow %5d .. %5d y %6d .. %6d\",\n\t\t\ti, fs->par[0], fs->par[1],\n\t\t\tfs->first_flow, fs->next_flow,\n\t\t\tfs->base_y, fs->next_y);\n\t\tfor (j = fs->first_flow; j < fs->next_flow; j++) {\n\t\t\tstruct dn_queue *q = FI2Q(c, j);\n\t\t\tq->fs = &c->fs[i];\n\t\t}\n\t}\n}\n\nstatic int\ninit(struct cfg_s *c)\n{\n\tint i;\n\tint ac = c->ac;\n\tchar * const *av = c->av;\n\n\tc->si_len = sizeof(struct dn_sch_inst);\n\tc->q_len = sizeof(struct dn_queue);\n\tmoduledata_t *mod = NULL;\n\tstruct dn_alg *p = NULL;\n\n\tc->th_min = 0;\n\tc->th_max = -20;/* 20 packets per flow */\n\tc->lmin = c->lmax = 1280;\t/* packet len */\n\tc->flows = 1;\n\tc->flowsets = 1;\n\tc->name = \"null\";\n\tac--; av++;\n\twhile (ac > 1) {\n\t\tif (!strcmp(*av, \"-n\")) {\n\t\t\tc->loops = getnum(av[1], NULL, av[0]);\n\t\t} else if (!strcmp(*av, \"-d\")) {\n\t\t\tdebug = atoi(av[1]);\n\t\t} else if (!strcmp(*av, \"-alg\")) {\n\t\t\textern moduledata_t *_g_dn_fifo;\n\t\t\textern moduledata_t *_g_dn_wf2qp;\n\t\t\textern moduledata_t *_g_dn_rr;\n\t\t\textern moduledata_t *_g_dn_qfq;\n#ifdef WITH_KPS\n\t\t\textern moduledata_t *_g_dn_kps;\n#endif\n\t\t\tif (!strcmp(av[1], \"rr\"))\n\t\t\t\tmod = _g_dn_rr;\n\t\t\telse if (!strcmp(av[1], \"wf2qp\"))\n\t\t\t\tmod = _g_dn_wf2qp;\n\t\t\telse if (!strcmp(av[1], \"fifo\"))\n\t\t\t\tmod = _g_dn_fifo;\n\t\t\telse if (!strcmp(av[1], \"qfq\"))\n\t\t\t\tmod = _g_dn_qfq;\n#ifdef WITH_KPS\n\t\t\telse if (!strcmp(av[1], \"kps\"))\n\t\t\t\tmod = _g_dn_kps;\n#endif\n\t\t\telse\n\t\t\t\tmod = NULL;\n\t\t\tc->name = mod ? mod->name : \"NULL\";\n\t\t\tDX(3, \"using scheduler %s\", c->name);\n\t\t} else if (!strcmp(*av, \"-len\")) {\n\t\t\tc->lmin = getnum(av[1], NULL, av[0]);\n\t\t\tc->lmax = c->lmin;\n\t\t\tDX(3, \"setting max to %d\", c->th_max);\n\t\t} else if (!strcmp(*av, \"-burst\")) {\n\t\t\tc->maxburst = getnum(av[1], NULL, av[0]);\n\t\t\tDX(3, \"setting max to %d\", c->th_max);\n\t\t} else if (!strcmp(*av, \"-qmax\")) {\n\t\t\tc->th_max = getnum(av[1], NULL, av[0]);\n\t\t\tDX(3, \"setting max to %d\", c->th_max);\n\t\t} else if (!strcmp(*av, \"-qmin\")) {\n\t\t\tc->th_min = getnum(av[1], NULL, av[0]);\n\t\t\tDX(3, \"setting min to %d\", c->th_min);\n\t\t} else if (!strcmp(*av, \"-flows\")) {\n\t\t\tc->flows = getnum(av[1], NULL, av[0]);\n\t\t\tDX(3, \"setting flows to %d\", c->flows);\n\t\t} else if (!strcmp(*av, \"-flowsets\")) {\n\t\t\tparse_flowsets(c, av[1], 0);\n\t\t\tDX(3, \"setting flowsets to %d\", c->flowsets);\n\t\t} else {\n\t\t\tD(\"option %s not recognised, ignore\", *av);\n\t\t}\n\t\tac -= 2; av += 2;\n\t}\n\tif (c->maxburst <= 0)\n\t\tc->maxburst = 1;\n\tif (c->loops <= 0)\n\t\tc->loops = 1;\n\tif (c->flows <= 0)\n\t\tc->flows = 1;\n\tif (c->flowsets <= 0)\n\t\tc->flowsets = 1;\n\tif (c->lmin <= 0)\n\t\tc->lmin = 1;\n\tif (c->lmax <= 0)\n\t\tc->lmax = 1;\n\t/* multiply by N */\n\tif (c->th_min < 0)\n\t\tc->th_min = c->flows * -c->th_min;\n\tif (c->th_max < 0)\n\t\tc->th_max = c->flows * -c->th_max;\n\tif (c->th_max <= c->th_min)\n\t\tc->th_max = c->th_min + 1;\n\tif (mod) {\n\t\tp = mod->p;\n\t\tDX(3, \"using module %s f %p p %p\", mod->name, mod->f, mod->p);\n\t\tDX(3, \"modname %s ty %d\", p->name, p->type);\n\t\tc->enq = p->enqueue;\n\t\tc->deq = p->dequeue;\n\t\tc->si_len += p->si_datalen;\n\t\tc->q_len += p->q_datalen;\n\t\tc->schk_len += p->schk_datalen;\n\t}\n\t/* allocate queues, flowsets and one scheduler */\n\tc->q = calloc(c->flows, c->q_len);\n\tc->fs = calloc(c->flowsets, sizeof(struct dn_fsk));\n\tc->si = calloc(1, c->si_len);\n\tc->sched = calloc(c->flows, c->schk_len);\n\tif (c->q == NULL || c->fs == NULL) {\n\t\tD(\"error allocating memory for flows\");\n\t\texit(1);\n\t}\n\tc->si->sched = c->sched;\n\tif (p) {\n\t\tif (p->config)\n\t\t\tp->config(c->sched);\n\t\tif (p->new_sched)\n\t\t\tp->new_sched(c->si);\n\t}\n\t/* parse_flowsets links queues to their flowsets */\n\tparse_flowsets(c, av[1], 1);\n\t/* complete the work calling new_fsk */\n\tfor (i = 0; i < c->flowsets; i++) {\n\t\tif (c->fs[i].fs.par[1] == 0)\n\t\t\tc->fs[i].fs.par[1] = 1000;\t/* default pkt len */\n\t\tc->fs[i].sched = c->sched;\n\t\tif (p && p->new_fsk)\n\t\t\tp->new_fsk(&c->fs[i]);\n\t}\n\n\t/* initialize the lists for the generator, and put\n\t * all flows in the list for backlog = 0\n\t */\n\tfor (i=0; i <= BACKLOG+5; i++)\n\t\tINIT_LIST_HEAD(&c->ll[i]);\n\n\tfor (i = 0; i < c->flows; i++) {\n\t\tstruct dn_queue *q = FI2Q(c, i);\n\t\tif (q->fs == NULL)\n\t\t\tq->fs = &c->fs[0]; /* XXX */\n\t\tq->_si = c->si;\n\t\tif (p && p->new_queue)\n\t\t\tp->new_queue(q);\n\t\tINIT_LIST_HEAD(&q->ni.h);\n\t\tlist_add_tail(&q->ni.h, &c->ll[0]);\n\t}\n\tc->llmask = 1;\n\treturn 0;\n}\n\n\nint\nmain(int ac, char *av[])\n{\n\tstruct cfg_s c;\n\tstruct timeval end;\n\tdouble ll;\n\tint i;\n\tchar msg[40];\n\n\tbzero(&c, sizeof(c));\n\tc.ac = ac;\n\tc.av = av;\n\tinit(&c);\n\tgettimeofday(&c.time, NULL);\n\tmainloop(&c);\n\tgettimeofday(&end, NULL);\n\tend.tv_sec -= c.time.tv_sec;\n\tend.tv_usec -= c.time.tv_usec;\n\tif (end.tv_usec < 0) {\n\t\tend.tv_usec += 1000000;\n\t\tend.tv_sec--;\n\t}\n\tc.time = end;\n\tll = end.tv_sec*1000000 + end.tv_usec;\n\tll *= 1000;\t/* convert to nanoseconds */\n\tll /= c._enqueue;\n\tsprintf(msg, \"1::%d\", c.flows);\n\tD(\"%-8s n %d %d time %d.%06d %8.3f qlen %d %d flows %s drops %d\",\n\t\tc.name, c._enqueue, c.loops,\n\t\t(int)c.time.tv_sec, (int)c.time.tv_usec, ll,\n\t\tc.th_min, c.th_max,\n\t\tc.fs_config ? c.fs_config : msg, c.drop);\n\tdump(&c);\n\tDX(1, \"done ac %d av %p\", ac, av);\n\tfor (i=0; i < ac; i++)\n\t\tDX(1, \"arg %d %s\", i, av[i]);\n\treturn 0;\n}\n\n/*\n * The controller decides whether in this iteration we should send\n * (the packet is in c->tosend) and/or receive (flag c->can_dequeue)\n */\nstatic void\ncontroller(struct cfg_s *c)\n{\n\tstruct mbuf *m;\n\tstruct dn_fs *fs;\n\tint flow_id;\n\n\t/* histeresis between max and min */\n\tif (c->state == 0 && c->pending >= c->th_max)\n\t\tc->state = 1;\n\telse if (c->state == 1 && c->pending <= c->th_min)\n\t\tc->state = 0;\n\tND(1, \"state %d pending %2d\", c->state, c->pending);\n\tc->can_dequeue = c->state;\n\tc->tosend = NULL;\n\tif (c->state)\n\t\treturn;\n\n    if (1) {\n\tint i;\n\tstruct dn_queue *q;\n\tstruct list_head *h;\n\n\ti = ffs(c->llmask) - 1;\n\tif (i < 0) {\n\t\tDX(2, \"no candidate\");\n\t\tc->can_dequeue = 1;\n\t\treturn;\n\t}\n\th = &c->ll[i];\n\tND(1, \"backlog %d p %p prev %p next %p\", i, h, h->prev, h->next);\n\tq = list_first_entry(h, struct dn_queue, ni.h);\n\tlist_del(&q->ni.h);\n\tflow_id = Q2FI(c, q);\n\tDX(2, \"extracted flow %p %d backlog %d\", q, flow_id, i);\n\tif (list_empty(h)) {\n\t\tND(2, \"backlog %d empty\", i);\n\t\tc->llmask &= ~(1<<i);\n\t}\n\tND(1, \"before %d p %p prev %p next %p\", i+1, h+1, h[1].prev, h[1].next);\n\tlist_add_tail(&q->ni.h, h+1);\n\tND(1, \" after %d p %p prev %p next %p\", i+1, h+1, h[1].prev, h[1].next);\n\tif (i < BACKLOG) {\n\t\tND(2, \"backlog %d full\", i+1);\n\t\tc->llmask |= 1<<(1+i);\n\t}\n\tfs = &q->fs->fs;\n\tc->cur_fs = q->fs - c->fs;\n\tfs->cur = flow_id;\n    } else {\n\t/* XXX this does not work ? */\n\t/* now decide whom to send the packet, and the length */\n\t/* lookup in the flow table */\n\tif (c->cur_y >= c->max_y) {\t/* handle wraparound */\n\t\tc->cur_y = 0;\n\t\tc->cur_fs = 0;\n\t}\n\tfs = &c->fs[c->cur_fs].fs;\n\tflow_id = fs->cur++;\n\tif (fs->cur >= fs->next_flow)\n\t\tfs->cur = fs->first_flow;\n\tc->cur_y++;\n\tif (c->cur_y >= fs->next_y)\n\t\tc->cur_fs++;\n    }\n\n\t/* construct a packet */\n\tif (c->freelist) {\n\t\tm = c->tosend = c->freelist;\n\t\tc->freelist = c->freelist->m_nextpkt;\n\t} else {\n\t\tm = c->tosend = calloc(1, sizeof(struct mbuf));\n\t}\n\tif (m == NULL)\n\t\treturn;\n\n\tm->cfg = c;\n\tm->m_nextpkt = NULL;\n\tm->m_pkthdr.len = fs->par[1]; // XXX maxlen\n\tm->flow_id = flow_id;\n\n\tND(2,\"y %6d flow %5d fs %3d weight %4d len %4d\",\n\t\tc->cur_y, m->flow_id, c->cur_fs,\n\t\tfs->par[0], m->m_pkthdr.len);\n\n}\n\n/*\nPacket allocation:\nto achieve a distribution that matches weights, for each X=w/lmax class\nwe should generate a number of packets proportional to Y = X times the number\nof flows in the class.\nSo we construct an array with the cumulative distribution of Y's,\nand use it to identify the flow via inverse mapping (if the Y's are\nnot too many we can use an array for the lookup). In practice,\neach flow will have X entries [virtually] pointing to it.\n\n*/\n"
  },
  {
    "path": "test/memory_leak.sh",
    "content": "#!/bin/sh\n# this script execute N times the command CMD\n# collecting the memory usage on a file.\n# The value of the Dirty memory should not increase\n# between tests.\n\nBASE_NAME=ipfw_r5808_\nN=10000\nCMD1=\"/sbin/insmod ../dummynet2/ipfw_mod.ko\"\nCMD2=\"/sbin/rmmod ipfw_mod\"\n\n# main\n# remove any previous loaded module\n/sbin/rmmod ipfw_mod \n\n# pre\n\nfor n in `seq $N`; do\n\t$CMD1\n\t$CMD2\n\t[ $n = 10 ] && cat /proc/meminfo > /tmp/${BASE_NAME}_${n}\n\t[ $n = 100 ] && cat /proc/meminfo > /tmp/${BASE_NAME}_${n}\n\t[ $n = 1000 ] && cat /proc/meminfo > /tmp/${BASE_NAME}_${n}\ndone;\n\n# post\n"
  },
  {
    "path": "test/mylist.h",
    "content": "/*\n * $Id: mylist.h 5626 2010-03-04 21:55:22Z luigi $\n *\n * linux-like bidirectional lists\n */\n\n#ifndef _MYLIST_H\n#define _MYLIST_H\nstruct list_head {\n        struct list_head *prev, *next;\n};\n\n#define INIT_LIST_HEAD(l) do {  (l)->prev = (l)->next = (l); } while (0)\n#define list_empty(l)   ( (l)->next == l )\nstatic inline void\n__list_add(struct list_head *o, struct list_head *prev,\n        struct list_head *next)\n{\n        next->prev = o;\n        o->next = next;\n        o->prev = prev;\n        prev->next = o;\n}\n \nstatic inline void\nlist_add_tail(struct list_head *o, struct list_head *head)\n{\n        __list_add(o, head->prev, head);\n}\n\n#define list_first_entry(pL, ty, member)        \\\n        (ty *)((char *)((pL)->next) - offsetof(ty, member))\n\nstatic inline void\n__list_del(struct list_head *prev, struct list_head *next)\n{\n        next->prev = prev;\n        prev->next = next;\n}\n\nstatic inline void\nlist_del(struct list_head *entry)\n{\n\tND(\"called on %p\", entry);\n        __list_del(entry->prev, entry->next);\n        entry->next = entry->prev = NULL;\n}\n\n#endif /* _MYLIST_H */\n"
  },
  {
    "path": "test/profile_bench1",
    "content": "profile_no 100\ndelay prob\n207 0.000264\n255 0.034117\n270 0.072280\n279 0.106749\n288 0.148604\n298 0.184304\n302 0.202194\n353 0.384541\n423 0.588842\n510 0.782126\n516 0.800970\n545 0.845706\n553 0.861411\n573 0.889430\n586 0.912117\n620 0.920003\n661 0.938308\n695 0.944191\n740 0.949112\n765 0.952598\n848 0.957109\n1379 0.983768\n1555 0.983778\n1649 1\n"
  },
  {
    "path": "test/profile_bench2",
    "content": "samples 10\ndelay prob\n0 0\n250 0\n250 0.5\n500 0.5\n500 1\n"
  },
  {
    "path": "test/profile_bench3",
    "content": "profile_no 100\ndelay prob\n0 0\n50 0.5\n100 1\n"
  },
  {
    "path": "test/test_dn_heap.c",
    "content": "/*-\n * Copyright (c) 1998-2002,2010 Luigi Rizzo, Universita` di Pisa\n * All rights reserved\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * Userland code for testing binary heaps and hash tables\n *\n * $Id: test_dn_heap.c 6131 2010-04-22 15:37:36Z svn_panicucci $\n */\n\n#include <sys/cdefs.h>\n#include <sys/param.h>\n\n#include <stdio.h>\n#include <strings.h>\n#include <stdlib.h>\n#include \"dn_test.h\"\n#include  \"dn_heap.h\"\n#define log(x, arg...)\tfprintf(stderr, ## arg)\n#define panic(x...)\tfprintf(stderr, ## x), exit(1)\n\n#include <string.h>\n\nstruct x {\n\tstruct x *ht_link;\n\tchar buf[0];\n};\n\nuint32_t hf(uintptr_t key, int flags, void *arg)\n{\n\treturn (flags & DNHT_KEY_IS_OBJ) ?\n\t\t((struct x *)key)->buf[0] : *(char *)key;\n}\n\nint matchf(void *obj, uintptr_t key, int flags, void *arg)\n{\n\tchar *s = (flags & DNHT_KEY_IS_OBJ) ?\n\t\t((struct x *)key)->buf : (char *)key;\n\treturn (strcmp(((struct x *)obj)->buf, s) == 0);\n}\n\nvoid *newfn(uintptr_t key, int flags, void *arg)\n{\n\tchar *s = (char *)key;\n\tstruct x *p = malloc(sizeof(*p) + 1 + strlen(s));\n\tif (p)\n\t\tstrcpy(p->buf, s);\n\treturn p;\n}\n\nchar *strings[] = {\n\t\"undici\", \"unico\", \"doppio\", \"devoto\",\n\t\"uno\", \"due\", \"tre\", \"quattro\", \"cinque\", \"sei\",\n\t\"uno\", \"due\", \"tre\", \"quattro\", \"cinque\", \"sei\",\n\tNULL,\n};\n\nint doprint(void *_x, void *arg)\n{\n\tstruct x *x = _x;\n\tprintf(\"found element <%s>\\n\", x->buf);\n\treturn (int)arg;\n}\n\nstatic void\ntest_hash()\n{\n\tchar **p;\n\tstruct dn_ht *h;\n\tuintptr_t x = 0;\n\tuintptr_t x1 = 0;\n\n\t/* first, find and allocate */\n\th = dn_ht_init(NULL, 10, 0, hf, matchf, newfn);\n\n\tfor (p = strings; *p; p++) {\n\t\tdn_ht_find(h, (uintptr_t)*p, DNHT_INSERT, NULL);\n\t}\n\tdn_ht_scan(h, doprint, 0);\n\tprintf(\"/* second -- find without allocate */\\n\");\n\th = dn_ht_init(NULL, 10, 0, hf, matchf, NULL);\n\tfor (p = strings; *p; p++) {\n\t\tvoid **y = newfn((uintptr_t)*p, 0, NULL);\n\t\tif (x == 0)\n\t\t\tx = (uintptr_t)y;\n\t\telse {\n\t\t\tif (x1 == 0)\n\t\t\t\tx1 = (uintptr_t)*p;\n\t\t}\n\t\tdn_ht_find(h, (uintptr_t)y, DNHT_INSERT | DNHT_KEY_IS_OBJ, NULL);\n\t}\n\tdn_ht_scan(h, doprint, 0);\n\tprintf(\"remove %p gives %p\\n\", (void *)x,\n\t\tdn_ht_find(h, x, DNHT_KEY_IS_OBJ | DNHT_REMOVE, NULL));\n\tprintf(\"remove %p gives %p\\n\", (void *)x,\n\t\tdn_ht_find(h, x, DNHT_KEY_IS_OBJ | DNHT_REMOVE, NULL));\n\tprintf(\"remove %p gives %p\\n\", (void *)x,\n\t\tdn_ht_find(h, x1, DNHT_REMOVE, NULL));\n\tprintf(\"remove %p gives %p\\n\", (void *)x,\n\t\tdn_ht_find(h, x1, DNHT_REMOVE, NULL));\n\tdn_ht_scan(h, doprint, 0);\n}\n\nint\nmain(int argc, char *argv[])\n{\n\tstruct dn_heap h;\n\tint i, n, n2, n3;\n\n\ttest_hash();\n\treturn 0;\n\n\t/* n = elements, n2 = cycles */\n\tn = (argc > 1) ? atoi(argv[1]) : 0;\n\tif (n <= 0 || n > 1000000)\n\t\tn = 100;\n\tn2 = (argc > 2) ? atoi(argv[2]) : 0;\n\tif (n2 <= 0)\n\t\tn = 1000000;\n\tn3 = (argc > 3) ? atoi(argv[3]) : 0;\n\tbzero(&h, sizeof(h));\n\theap_init(&h, n, -1);\n\twhile (n2-- > 0) {\n\t\tuint64_t prevk = 0;\n\t\tfor (i=0; i < n; i++)\n\t\t\theap_insert(&h, n3 ? n-i: random(), (void *)(100+i));\n\t\t\n\t\tfor (i=0; h.elements > 0; i++) {\n\t\t\tuint64_t k = h.p[0].key;\n\t\t\tif (k < prevk)\n\t\t\t\tpanic(\"wrong sequence\\n\");\n\t\t\tprevk = k;\n\t\t\tif (0)\n\t\t\tprintf(\"%d key %llu, val %p\\n\",\n\t\t\t\ti, h.p[0].key, h.p[0].object);\n\t\t\theap_extract(&h, NULL);\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "test/test_dn_sched.c",
    "content": "/*\n * $Id: test_dn_sched.c 5626 2010-03-04 21:55:22Z luigi $\n *\n * library functions for userland testing of dummynet schedulers\n */\n\n#include \"dn_test.h\"\n\nvoid\nm_freem(struct mbuf *m)\n{\n\tprintf(\"free %p\\n\", m);\n}\n\nint\ndn_sched_modevent(module_t mod, int cmd, void *arg)\n{\n\treturn 0;\n}\n\nvoid\ndn_free_pkts(struct mbuf *m)\n{\n\tstruct mbuf *x;\n\twhile ( (x = m) ) {\n\t\tm = m->m_nextpkt;\n\t\tm_freem(x);\n\t}\n}\n\t\t\nint\ndn_delete_queue(void *_q, void *do_free)\n{\n\tstruct dn_queue *q = _q;\n        if (q->mq.head)\n                dn_free_pkts(q->mq.head);\n        free(q);\n        return 0;\n}\n\n/*\n * This is a simplified function for testing purposes, which does\n * not implement statistics or random loss.\n * Enqueue a packet in q, subject to space and queue management policy\n * (whose parameters are in q->fs).\n * Update stats for the queue and the scheduler.\n * Return 0 on success, 1 on drop. The packet is consumed anyways.\n */\nint\ndn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)\n{\n        if (drop)\n                goto drop;\n        if (q->ni.length >= 200)\n                goto drop;\n        mq_append(&q->mq, m);\n        q->ni.length++;\n        q->ni.tot_bytes += m->m_pkthdr.len;\n        return 0;\n\ndrop:\n        q->ni.drops++;\n        return 1;\n}\n\nint\nipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg)\n{\n        if (*v < lo) {\n                *v = dflt;\n        } else if (*v > hi) {\n                *v = hi;\n        }\n        return *v;\n}\n\n#ifndef __FreeBSD__\nint\nfls(int mask)\n{\n        int bit;\n \n        if (mask == 0)\n                return (0);\n        for (bit = 1; mask != 1; bit++)\n                mask = (unsigned int)mask >> 1;\n        return (bit);\n}\n#endif\n"
  }
]